deepline 0.1.194 → 0.1.195

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.
@@ -105,10 +105,10 @@ export const SDK_RELEASE = {
105
105
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
106
106
  // fields shipped in 0.1.153.
107
107
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
108
- version: '0.1.194',
108
+ version: '0.1.195',
109
109
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
110
110
  supportPolicy: {
111
- latest: '0.1.194',
111
+ latest: '0.1.195',
112
112
  minimumSupported: '0.1.53',
113
113
  deprecatedBelow: '0.1.53',
114
114
  commandMinimumSupported: [
@@ -2,6 +2,8 @@ const CLOUDFLARE_DURABLE_OBJECT_RESET_RE =
2
2
  /Durable Object.*(?:code (?:was|has been) updated|storage caused object)/;
3
3
  const CLOUDFLARE_WORKER_SUBREQUEST_LIMIT_RE =
4
4
  /Too many subrequests by single Worker invocation/i;
5
+ const VERCEL_RUNTIME_API_DEPLOYMENT_MISSING_RE =
6
+ /runtime API 404:[\s\S]*(?:DeploymentNotFound|DEPLOYMENT_NOT_FOUND|requested deployment .*exist|deployment could not be found on Vercel)/i;
5
7
 
6
8
  export const PLATFORM_DEPLOY_INTERRUPTED_MESSAGE =
7
9
  'Run interrupted by a platform deploy. Deepline retries this automatically when possible; if this error is still visible, re-run the same command.';
@@ -68,6 +70,15 @@ export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
68
70
  cause,
69
71
  };
70
72
  }
73
+ if (VERCEL_RUNTIME_API_DEPLOYMENT_MISSING_RE.test(cause)) {
74
+ return {
75
+ code: 'PLATFORM_DEPLOY_INTERRUPTED',
76
+ phase: 'runtime',
77
+ message: PLATFORM_DEPLOY_INTERRUPTED_MESSAGE,
78
+ retryable: true,
79
+ cause,
80
+ };
81
+ }
71
82
  if (CLOUDFLARE_WORKER_SUBREQUEST_LIMIT_RE.test(cause)) {
72
83
  return {
73
84
  code: 'PLATFORM_WORKER_SUBREQUEST_INTERRUPTED',
package/dist/cli/index.js CHANGED
@@ -623,10 +623,10 @@ var SDK_RELEASE = {
623
623
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
624
624
  // fields shipped in 0.1.153.
625
625
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
626
- version: "0.1.194",
626
+ version: "0.1.195",
627
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
628
628
  supportPolicy: {
629
- latest: "0.1.194",
629
+ latest: "0.1.195",
630
630
  minimumSupported: "0.1.53",
631
631
  deprecatedBelow: "0.1.53",
632
632
  commandMinimumSupported: [
@@ -1017,8 +1017,8 @@ var HttpClient = class {
1017
1017
  }
1018
1018
  const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
1019
1019
  const msg = typeof errorValue === "string" ? errorValue : errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string" ? errorValue.message : typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string" ? parsed.message : `HTTP ${response.status}`;
1020
- const apiErrorCode = errorValue && typeof errorValue === "object" && typeof errorValue.code === "string" ? errorValue.code : typeof parsed === "object" && parsed && typeof parsed.code === "string" ? parsed.code : "API_ERROR";
1021
- lastError = new DeeplineError(msg, response.status, apiErrorCode, {
1020
+ const apiErrorCode2 = errorValue && typeof errorValue === "object" && typeof errorValue.code === "string" ? errorValue.code : typeof parsed === "object" && parsed && typeof parsed.code === "string" ? parsed.code : "API_ERROR";
1021
+ lastError = new DeeplineError(msg, response.status, apiErrorCode2, {
1022
1022
  response: parsed
1023
1023
  });
1024
1024
  if (retryableApiError && attempt < maxRetries) {
@@ -2554,6 +2554,7 @@ var DeeplineClient = class {
2554
2554
  stopAll: (options2) => this.stopAllRuns(options2)
2555
2555
  };
2556
2556
  this.billing = {
2557
+ topUp: (options2) => this.topUpBillingBalance(options2),
2557
2558
  plans: () => this.getBillingPlans(),
2558
2559
  subscription: {
2559
2560
  status: () => this.getBillingSubscriptionStatus(),
@@ -4235,6 +4236,28 @@ var DeeplineClient = class {
4235
4236
  async getBillingPlans() {
4236
4237
  return this.http.get("/api/v2/billing/catalog/current");
4237
4238
  }
4239
+ /**
4240
+ * Charge the saved payment method and add Deepline credits to the active
4241
+ * workspace. Prefer `client.billing.topUp(...)`.
4242
+ *
4243
+ * @throws {@link DeeplineError} with `statusCode: 409` when checkout is
4244
+ * required because the workspace has no saved payment method or the card
4245
+ * requires confirmation.
4246
+ */
4247
+ async topUpBillingBalance(options) {
4248
+ return this.http.post(
4249
+ "/api/v2/billing/top-up",
4250
+ {
4251
+ credits: options.credits,
4252
+ ...options.idempotencyKey ? { idempotency_key: options.idempotencyKey } : {}
4253
+ },
4254
+ void 0,
4255
+ // The idempotency key makes a retry at the product layer safe, but the
4256
+ // CLI should not hide ambiguous local delivery failures behind implicit
4257
+ // transport retries for a payment mutation.
4258
+ { maxRetries: 0, exactUrlOnly: true }
4259
+ );
4260
+ }
4238
4261
  /**
4239
4262
  * Subscription state for the active workspace: active plan, whether a
4240
4263
  * Stripe subscription backs it, renewal/cancellation facts, and remaining
@@ -5726,11 +5749,14 @@ Examples:
5726
5749
 
5727
5750
  // src/cli/commands/billing.ts
5728
5751
  var import_commander = require("commander");
5752
+ var import_node_crypto2 = require("crypto");
5729
5753
  var import_promises2 = require("fs/promises");
5730
5754
  var import_node_path6 = require("path");
5731
5755
  var import_sync3 = require("csv-stringify/sync");
5732
5756
  var SUBSCRIPTION_STATUS_NEXT_COMMAND = "deepline billing subscription status --json";
5733
5757
  var SUBSCRIPTION_CANCEL_PATH = "/api/v2/billing/subscription/cancel";
5758
+ var BILLING_TOP_UP_PATH = "/api/v2/billing/top-up";
5759
+ var DEFAULT_BALANCE_RECOVERY_CREDITS = 100;
5734
5760
  function billingFailureFromError(error, options) {
5735
5761
  if (error instanceof AuthError) {
5736
5762
  return {
@@ -5779,6 +5805,107 @@ function reportBillingFailure(failure, options) {
5779
5805
  );
5780
5806
  process.exitCode = failure.exitCode;
5781
5807
  }
5808
+ function parseTopUpCredits(raw) {
5809
+ const trimmed = String(raw ?? "").trim();
5810
+ if (!/^\d+$/.test(trimmed)) return null;
5811
+ const parsed = Number(trimmed);
5812
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) return null;
5813
+ return parsed;
5814
+ }
5815
+ function topUpIdempotencyKey(raw) {
5816
+ if (typeof raw === "string") {
5817
+ const trimmed = raw.trim();
5818
+ if (trimmed) return trimmed.slice(0, 120);
5819
+ }
5820
+ return `cli_topup:${Date.now()}:${(0, import_node_crypto2.randomUUID)()}`;
5821
+ }
5822
+ function checkoutCommandForCredits(credits) {
5823
+ return `deepline billing checkout --credits ${credits} --no-open --json`;
5824
+ }
5825
+ function approvedTopUpCommandForCredits(credits) {
5826
+ return `deepline billing top-up ${credits} --json`;
5827
+ }
5828
+ function balanceRecoveryForCredits(credits = DEFAULT_BALANCE_RECOVERY_CREDITS) {
5829
+ return {
5830
+ recommended_credits: credits,
5831
+ requires_user_approval: true,
5832
+ message: "Ask the user whether they want to add Deepline credits before taking payment-related action.",
5833
+ top_up_command: approvedTopUpCommandForCredits(credits),
5834
+ checkout_command: checkoutCommandForCredits(credits)
5835
+ };
5836
+ }
5837
+ function shellQuote(value) {
5838
+ return `'${value.replace(/'/g, `'\\''`)}'`;
5839
+ }
5840
+ function topUpRetryCommand(credits, idempotencyKey) {
5841
+ return `deepline billing top-up ${credits} --idempotency-key ${shellQuote(idempotencyKey)} --json`;
5842
+ }
5843
+ function apiErrorCode(error) {
5844
+ const response = error.details?.response;
5845
+ if (response && typeof response === "object" && !Array.isArray(response)) {
5846
+ const code = response.code;
5847
+ if (typeof code === "string" && code.trim()) {
5848
+ return code.trim();
5849
+ }
5850
+ }
5851
+ return error.code ?? "BILLING_API_ERROR";
5852
+ }
5853
+ function billingTopUpFailureFromError(error, input2) {
5854
+ if (error instanceof AuthError || error instanceof ConfigError) {
5855
+ return {
5856
+ exitCode: 3,
5857
+ code: "AUTH_ERROR",
5858
+ message: error.message,
5859
+ next: "deepline auth status --json"
5860
+ };
5861
+ }
5862
+ if (!(error instanceof DeeplineError) || typeof error.statusCode !== "number") {
5863
+ if (error instanceof DeeplineError) {
5864
+ return {
5865
+ exitCode: 5,
5866
+ code: "TOP_UP_STATUS_UNKNOWN",
5867
+ message: `${error.message} The top-up may have reached Deepline. Retry only with the same idempotency key to avoid a duplicate charge.`,
5868
+ next: topUpRetryCommand(input2.credits, input2.idempotencyKey)
5869
+ };
5870
+ }
5871
+ return null;
5872
+ }
5873
+ const code = apiErrorCode(error);
5874
+ if (error.statusCode === 400) {
5875
+ return {
5876
+ exitCode: 2,
5877
+ code: "INVALID_CREDITS",
5878
+ message: error.message,
5879
+ next: "deepline billing plans --json"
5880
+ };
5881
+ }
5882
+ if (error.statusCode === 409) {
5883
+ const checkoutNext = checkoutCommandForCredits(input2.credits);
5884
+ return {
5885
+ exitCode: 4,
5886
+ code: code === "requires_action" ? "PAYMENT_REQUIRES_ACTION" : "MISSING_PAYMENT_METHOD",
5887
+ message: error.message,
5888
+ next: checkoutNext
5889
+ };
5890
+ }
5891
+ if (error.statusCode === 402) {
5892
+ return {
5893
+ exitCode: 5,
5894
+ code: "PAYMENT_FAILED",
5895
+ message: error.message,
5896
+ next: checkoutCommandForCredits(input2.credits)
5897
+ };
5898
+ }
5899
+ if (error.statusCode >= 500) {
5900
+ return {
5901
+ exitCode: 5,
5902
+ code: "BILLING_SERVER_ERROR",
5903
+ message: `${error.message} Retry only with the same idempotency key to avoid a duplicate charge.`,
5904
+ next: topUpRetryCommand(input2.credits, input2.idempotencyKey)
5905
+ };
5906
+ }
5907
+ return null;
5908
+ }
5782
5909
  function humanize(value) {
5783
5910
  return String(value || "").split("_").filter(Boolean).map((token) => token[0]?.toUpperCase() + token.slice(1)).join(" ") || "Unknown";
5784
5911
  }
@@ -5876,13 +6003,29 @@ async function handleBalance(options) {
5876
6003
  "/api/v2/billing/balance"
5877
6004
  );
5878
6005
  const status = String(payload.balance_status || "");
5879
- const lines = status === "no_billing" ? [
5880
- "Balance: 0 credits",
5881
- "Billing: No billing account or payment method set up for this workspace."
5882
- ] : [`Balance: ${payload.balance ?? "(unknown)"} credits`];
6006
+ const needsCredits = status === "no_billing" || status === "zero_balance" || status === "payment_method_only";
6007
+ const recovery = needsCredits ? balanceRecoveryForCredits() : null;
6008
+ const lines = [`Balance: ${payload.balance ?? "(unknown)"} credits`];
6009
+ if (status === "no_billing") {
6010
+ lines.push(
6011
+ "Billing: No billing account or payment method set up for this workspace."
6012
+ );
6013
+ } else if (status === "zero_balance") {
6014
+ lines.push("Billing: This workspace has no Deepline credits available.");
6015
+ } else if (status === "payment_method_only") {
6016
+ lines.push(
6017
+ "Billing: A payment method is saved, but this workspace has no Deepline credits available."
6018
+ );
6019
+ }
6020
+ if (recovery) {
6021
+ lines.push(recovery.message);
6022
+ lines.push(`If the user approves, run: ${recovery.top_up_command}`);
6023
+ lines.push(`If checkout is required, run: ${recovery.checkout_command}`);
6024
+ }
5883
6025
  printCommandEnvelope(
5884
6026
  {
5885
6027
  ...payload,
6028
+ ...recovery ? { recovery } : {},
5886
6029
  render: { sections: [{ title: "billing balance", lines }] }
5887
6030
  },
5888
6031
  { json: options.json }
@@ -6376,6 +6519,99 @@ async function handleCheckout(options) {
6376
6519
  { json: options.json }
6377
6520
  );
6378
6521
  }
6522
+ async function handleTopUp(creditsRaw, options) {
6523
+ const credits = parseTopUpCredits(creditsRaw);
6524
+ if (credits === null) {
6525
+ reportBillingFailure(
6526
+ {
6527
+ exitCode: 2,
6528
+ code: "INVALID_CREDITS",
6529
+ message: "<credits> must be a positive integer Deepline credit amount.",
6530
+ next: "deepline billing plans --json"
6531
+ },
6532
+ options
6533
+ );
6534
+ return;
6535
+ }
6536
+ const idempotencyKey = topUpIdempotencyKey(options.idempotencyKey);
6537
+ if (options.dryRun) {
6538
+ printCommandEnvelope(
6539
+ {
6540
+ ok: true,
6541
+ dry_run: true,
6542
+ credits,
6543
+ idempotency_key: idempotencyKey,
6544
+ planned_request: {
6545
+ method: "POST",
6546
+ path: BILLING_TOP_UP_PATH,
6547
+ body: { credits, idempotency_key: idempotencyKey }
6548
+ },
6549
+ render: {
6550
+ sections: [
6551
+ {
6552
+ title: "billing top-up (dry run)",
6553
+ lines: [
6554
+ `Credits: ${credits}`,
6555
+ `Idempotency key: ${idempotencyKey}`,
6556
+ `Planned request: POST ${BILLING_TOP_UP_PATH}`,
6557
+ "No payment request was sent. Re-run without --dry-run to apply."
6558
+ ]
6559
+ }
6560
+ ]
6561
+ }
6562
+ },
6563
+ { json: options.json }
6564
+ );
6565
+ return;
6566
+ }
6567
+ const client2 = new DeeplineClient();
6568
+ let payload;
6569
+ try {
6570
+ payload = await client2.billing.topUp({ credits, idempotencyKey });
6571
+ } catch (error) {
6572
+ const failure = billingTopUpFailureFromError(error, {
6573
+ credits,
6574
+ idempotencyKey
6575
+ });
6576
+ if (!failure) throw error;
6577
+ reportBillingFailure(failure, options);
6578
+ return;
6579
+ }
6580
+ const amountText = invoiceAmountText(payload.amount_cents, payload.currency);
6581
+ const paymentLabel = payload.payment_method?.label ?? [
6582
+ payload.payment_method?.brand ? humanize(payload.payment_method.brand) : null,
6583
+ payload.payment_method?.last4 ? `ending in ${payload.payment_method.last4}` : null
6584
+ ].filter(Boolean).join(" ");
6585
+ const compactEnvelope = {
6586
+ ok: true,
6587
+ credits: payload.credits,
6588
+ amount_cents: payload.amount_cents,
6589
+ currency: payload.currency,
6590
+ balance_credits: payload.balance,
6591
+ idempotency_key: idempotencyKey
6592
+ };
6593
+ const fullEnvelope = {
6594
+ ...payload,
6595
+ balance_credits: payload.balance,
6596
+ idempotency_key: idempotencyKey,
6597
+ render: {
6598
+ sections: [
6599
+ {
6600
+ title: "billing top-up",
6601
+ lines: [
6602
+ `Added: ${payload.credits} Deepline Credits`,
6603
+ `Charged: ${amountText}`,
6604
+ `Balance: ${payload.balance} Deepline Credits`,
6605
+ ...paymentLabel ? [`Payment method: ${paymentLabel}`] : []
6606
+ ]
6607
+ }
6608
+ ]
6609
+ }
6610
+ };
6611
+ printCommandEnvelope(options.compact ? compactEnvelope : fullEnvelope, {
6612
+ json: options.json
6613
+ });
6614
+ }
6379
6615
  async function handleRedeemCode(code, options) {
6380
6616
  const { http } = getAuthedHttpClient();
6381
6617
  const payload = await http.post(
@@ -6412,6 +6648,7 @@ Examples:
6412
6648
  deepline billing subscription status --json
6413
6649
 
6414
6650
  # Buy credits or a plan
6651
+ deepline billing top-up 1000 --json
6415
6652
  deepline billing checkout --credits 1000 --no-open --json
6416
6653
  deepline billing subscribe runtime-395-2026-07-v1 --no-open --json
6417
6654
  deepline billing redeem-code --code ABC123 --no-open --json
@@ -6551,6 +6788,25 @@ Examples:
6551
6788
  deepline billing checkout --credits 1000 --discount-code LAUNCH --no-open
6552
6789
  `
6553
6790
  ).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);
6791
+ billing.command("top-up").description("Charge the saved payment method and add Deepline credits.").addHelpText(
6792
+ "after",
6793
+ `
6794
+ Notes:
6795
+ Mutates workspace billing by charging the saved payment method for the active
6796
+ workspace, then adding purchased Deepline credits. If no saved payment method
6797
+ is available, use the checkout command printed in the error response.
6798
+ --dry-run prints the planned request and idempotency key without charging.
6799
+
6800
+ Examples:
6801
+ deepline billing top-up 1000
6802
+ deepline billing top-up 1000 --json
6803
+ deepline billing top-up 1000 --dry-run --json
6804
+ deepline billing top-up 1000 --idempotency-key refill-2026-07-08 --json
6805
+ `
6806
+ ).argument("<credits>", "Positive integer Deepline credit amount").option(
6807
+ "--idempotency-key <key>",
6808
+ "Stable retry key for the same intended top-up"
6809
+ ).option("--dry-run", "Print the planned top-up without charging").option("--compact", "Keep only high-signal fields in JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleTopUp);
6554
6810
  billing.command("plans").description("Show published plans and the plan you are on.").addHelpText(
6555
6811
  "after",
6556
6812
  `
@@ -6671,7 +6927,7 @@ Examples:
6671
6927
 
6672
6928
  // src/cli/commands/csv.ts
6673
6929
  var import_node_child_process = require("child_process");
6674
- var import_node_crypto2 = require("crypto");
6930
+ var import_node_crypto3 = require("crypto");
6675
6931
  var import_node_fs7 = require("fs");
6676
6932
  var import_node_os7 = require("os");
6677
6933
  var import_node_path8 = require("path");
@@ -7568,7 +7824,7 @@ async function handleCsvRenderStart(options) {
7568
7824
  ensureCsvRenderStateDir();
7569
7825
  const logPath = csvRenderLogPath();
7570
7826
  const logFd = (0, import_node_fs7.openSync)(logPath, "w");
7571
- const token = (0, import_node_crypto2.randomUUID)();
7827
+ const token = (0, import_node_crypto3.randomUUID)();
7572
7828
  const child = (0, import_node_child_process.spawn)(
7573
7829
  process.execPath,
7574
7830
  ["-e", CSV_RENDER_SERVER_SOURCE],
@@ -8152,7 +8408,7 @@ var import_node_os8 = require("os");
8152
8408
  var import_node_path12 = require("path");
8153
8409
 
8154
8410
  // src/cli/commands/play.ts
8155
- var import_node_crypto3 = require("crypto");
8411
+ var import_node_crypto4 = require("crypto");
8156
8412
  var import_node_fs10 = require("fs");
8157
8413
  var import_node_path11 = require("path");
8158
8414
  var import_sync5 = require("csv-parse/sync");
@@ -10951,7 +11207,7 @@ function stageFile(logicalPath, absolutePath) {
10951
11207
  return {
10952
11208
  logicalPath,
10953
11209
  contentBase64: buffer.toString("base64"),
10954
- contentHash: (0, import_node_crypto3.createHash)("sha256").update(buffer).digest("hex"),
11210
+ contentHash: (0, import_node_crypto4.createHash)("sha256").update(buffer).digest("hex"),
10955
11211
  contentType: absolutePath.toLowerCase().endsWith(".csv") ? "text/csv" : absolutePath.toLowerCase().endsWith(".json") ? "application/json" : "application/octet-stream",
10956
11212
  bytes: buffer.byteLength
10957
11213
  };
@@ -12306,6 +12562,19 @@ function formatCreditAmount(value) {
12306
12562
  }
12307
12563
  return Number(value.toFixed(8)).toString();
12308
12564
  }
12565
+ function recommendedTopUpCredits(value) {
12566
+ const parsed = typeof value === "number" && Number.isFinite(value) ? value : typeof value === "string" && value.trim() ? Number(value) : NaN;
12567
+ return Math.max(100, Number.isFinite(parsed) ? Math.ceil(parsed) : 100);
12568
+ }
12569
+ function insufficientCreditsRecoveryCommands(billing) {
12570
+ const topUpCredits = recommendedTopUpCredits(
12571
+ billing.recommended_add_credits ?? billing.needed_credits
12572
+ );
12573
+ return {
12574
+ topUp: `deepline billing top-up ${topUpCredits} --json`,
12575
+ checkout: `deepline billing checkout --credits ${topUpCredits} --no-open --json`
12576
+ };
12577
+ }
12309
12578
  function extractJsonObjectFromText(text) {
12310
12579
  const start = text.indexOf("{");
12311
12580
  if (start < 0) {
@@ -12398,8 +12667,9 @@ function formatInsufficientCreditsMessage(input2) {
12398
12667
  const billingUrl = getStringField(input2.billing, "billing_url");
12399
12668
  const workspace = getStringField(input2.billing, "workspace_id") ?? getStringField(input2.billing, "workspaceId");
12400
12669
  const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
12670
+ const recovery = insufficientCreditsRecoveryCommands(input2.billing);
12401
12671
  const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
12402
- return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
12672
+ return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix} Ask the user if they want to add Deepline credits. If they approve, run: ${recovery.topUp}. If checkout is required, run: ${recovery.checkout}.`;
12403
12673
  }
12404
12674
  function buildInsufficientCreditsSummaryLines(input2) {
12405
12675
  const progress = input2.status.progress;
@@ -12415,11 +12685,15 @@ function buildInsufficientCreditsSummaryLines(input2) {
12415
12685
  const recommended = formatCreditAmount(
12416
12686
  input2.billing.recommended_add_credits ?? input2.billing.needed_credits
12417
12687
  );
12688
+ const recovery = insufficientCreditsRecoveryCommands(input2.billing);
12418
12689
  if (billingUrl) {
12419
12690
  lines.push(
12420
12691
  recommended !== "-" ? ` add credits: add >=${recommended} at ${billingUrl}` : ` add credits: ${billingUrl}`
12421
12692
  );
12422
12693
  }
12694
+ lines.push(" ask user: ask whether they want to add Deepline credits");
12695
+ lines.push(` top up after approval: ${recovery.topUp}`);
12696
+ lines.push(` checkout fallback: ${recovery.checkout}`);
12423
12697
  const runId = input2.status.runId?.trim();
12424
12698
  if (runId) {
12425
12699
  lines.push(` inspect: deepline runs get ${runId} --json`);
@@ -21551,7 +21825,7 @@ var import_node_fs11 = require("fs");
21551
21825
  var import_node_os9 = require("os");
21552
21826
  var import_node_path13 = require("path");
21553
21827
  var import_node_zlib = require("zlib");
21554
- var import_node_crypto4 = require("crypto");
21828
+ var import_node_crypto5 = require("crypto");
21555
21829
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
21556
21830
  var UUID_IN_TEXT_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
21557
21831
  var MAX_SESSION_UPLOAD_BYTES = 35e5;
@@ -21913,7 +22187,7 @@ async function uploadPayload(path, payload) {
21913
22187
  return await http.post(path, payload);
21914
22188
  }
21915
22189
  async function uploadChunkedSessions(sessions, options) {
21916
- const uploadId = (0, import_node_crypto4.randomUUID)();
22190
+ const uploadId = (0, import_node_crypto5.randomUUID)();
21917
22191
  for (const session of sessions) {
21918
22192
  const bytes = Buffer.from(session.encodedContent, "base64");
21919
22193
  const chunks = [];
@@ -23739,14 +24013,14 @@ Examples:
23739
24013
 
23740
24014
  // src/cli/commands/quickstart.ts
23741
24015
  var import_node_child_process2 = require("child_process");
23742
- var import_node_crypto5 = require("crypto");
24016
+ var import_node_crypto6 = require("crypto");
23743
24017
  var import_node_http = require("http");
23744
24018
  var EXIT_OK2 = 0;
23745
24019
  var EXIT_AUTH2 = 1;
23746
24020
  var EXIT_SERVER3 = 2;
23747
24021
  var MAX_PROMPT_LENGTH = 8e3;
23748
24022
  var MAX_BODY_BYTES = 64 * 1024;
23749
- function shellQuote(arg) {
24023
+ function shellQuote2(arg) {
23750
24024
  return `'${arg.replace(/'/g, `'\\''`)}'`;
23751
24025
  }
23752
24026
  function hasClaudeBinary() {
@@ -23868,7 +24142,7 @@ async function handleQuickstart(options) {
23868
24142
  return EXIT_AUTH2;
23869
24143
  }
23870
24144
  }
23871
- const state = (0, import_node_crypto5.randomBytes)(32).toString("hex");
24145
+ const state = (0, import_node_crypto6.randomBytes)(32).toString("hex");
23872
24146
  let resolveSelection;
23873
24147
  const selectionPromise = new Promise((resolve14) => {
23874
24148
  resolveSelection = resolve14;
@@ -23919,7 +24193,7 @@ async function handleQuickstart(options) {
23919
24193
  }
23920
24194
  progress.complete();
23921
24195
  const { prompt, workflowId } = outcome;
23922
- const claudeCommand = `claude ${shellQuote(prompt)}`;
24196
+ const claudeCommand = `claude ${shellQuote2(prompt)}`;
23923
24197
  const claudeAvailable = hasClaudeBinary();
23924
24198
  const willLaunch = options.launch !== false && !jsonOutput && interactive && claudeAvailable;
23925
24199
  printCommandEnvelope(
@@ -25841,7 +26115,7 @@ function parseExecuteOptions(args) {
25841
26115
  function safeFileStem(value) {
25842
26116
  return value.trim().replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "tool";
25843
26117
  }
25844
- function shellQuote2(value) {
26118
+ function shellQuote3(value) {
25845
26119
  return `'${value.replace(/'/g, `'\\''`)}'`;
25846
26120
  }
25847
26121
  function powerShellQuote(value) {
@@ -25911,7 +26185,7 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
25911
26185
  path: scriptPath,
25912
26186
  sourceCode: script,
25913
26187
  projectDir,
25914
- macCopyCommand: `mkdir -p ${shellQuote2(projectDir)} && cp ${shellQuote2(scriptPath)} ${shellQuote2(`${projectDir}/${fileName}`)}`,
26188
+ macCopyCommand: `mkdir -p ${shellQuote3(projectDir)} && cp ${shellQuote3(scriptPath)} ${shellQuote3(`${projectDir}/${fileName}`)}`,
25915
26189
  windowsCopyCommand: `New-Item -ItemType Directory -Force -Path ${powerShellQuote(projectDir.replace(/\//g, "\\"))} | Out-Null; Copy-Item -LiteralPath ${powerShellQuote(scriptPath)} -Destination ${powerShellQuote(`${projectDir.replace(/\//g, "\\")}\\${fileName}`)}`
25916
26190
  };
25917
26191
  }
@@ -25934,7 +26208,7 @@ function buildToolExecuteBaseEnvelope(input2) {
25934
26208
  envelope,
25935
26209
  "output"
25936
26210
  );
25937
- const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote2(JSON.stringify(input2.params))} --json`;
26211
+ const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote3(JSON.stringify(input2.params))} --json`;
25938
26212
  const actions = input2.listConversion ? [
25939
26213
  {
25940
26214
  label: "next",
@@ -26240,7 +26514,7 @@ var import_promises5 = require("fs/promises");
26240
26514
  var import_node_path17 = require("path");
26241
26515
 
26242
26516
  // src/cli/workflow-to-play.ts
26243
- var import_node_crypto6 = require("crypto");
26517
+ var import_node_crypto7 = require("crypto");
26244
26518
 
26245
26519
  // ../shared_libs/plays/secret-guardrails.ts
26246
26520
  var SECRET_ENV_PATTERN = /\bprocess(?:\.env|\[['"]env['"]\])(?:\.|\[['"])([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PRIVATE[_-]?KEY|ACCESS[_-]?KEY)[A-Z0-9_]*)(?:['"]\])?/g;
@@ -26383,7 +26657,7 @@ function sanitizePlayNameSegment(value) {
26383
26657
  }
26384
26658
  function deriveWorkflowPlayName(workflowName) {
26385
26659
  const base = sanitizePlayNameSegment(workflowName) || "workflow";
26386
- const suffix = (0, import_node_crypto6.createHash)("sha256").update(workflowName).digest("hex").slice(0, 8);
26660
+ const suffix = (0, import_node_crypto7.createHash)("sha256").update(workflowName).digest("hex").slice(0, 8);
26387
26661
  const reserved = suffix.length + 1;
26388
26662
  const allowedBase = Math.max(1, MAX_PLAY_NAME_LENGTH - reserved);
26389
26663
  let name = `${base.slice(0, allowedBase)}_${suffix}`;
@@ -27003,7 +27277,7 @@ function hasCommand(command) {
27003
27277
  });
27004
27278
  return result.status === 0;
27005
27279
  }
27006
- function shellQuote3(arg) {
27280
+ function shellQuote4(arg) {
27007
27281
  return `'${arg.replace(/'/g, `'\\''`)}'`;
27008
27282
  }
27009
27283
  function resolveSkillsInstallCommands(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
@@ -27011,7 +27285,7 @@ function resolveSkillsInstallCommands(baseUrl, skillNames = DEFAULT_SDK_SKILL_NA
27011
27285
  const npxInstall = {
27012
27286
  command: "npx",
27013
27287
  args: npxArgs,
27014
- manualCommand: `npx ${npxArgs.map(shellQuote3).join(" ")}`
27288
+ manualCommand: `npx ${npxArgs.map(shellQuote4).join(" ")}`
27015
27289
  };
27016
27290
  if (hasCommand("bunx")) {
27017
27291
  const bunxArgs = buildBunxSkillsInstallArgs(baseUrl, skillNames);
@@ -27019,7 +27293,7 @@ function resolveSkillsInstallCommands(baseUrl, skillNames = DEFAULT_SDK_SKILL_NA
27019
27293
  {
27020
27294
  command: "bunx",
27021
27295
  args: bunxArgs,
27022
- manualCommand: `bunx ${bunxArgs.map(shellQuote3).join(" ")}`
27296
+ manualCommand: `bunx ${bunxArgs.map(shellQuote4).join(" ")}`
27023
27297
  },
27024
27298
  npxInstall
27025
27299
  ];
@@ -27186,14 +27460,14 @@ function posixShellQuote(value) {
27186
27460
  function windowsCmdQuote(value) {
27187
27461
  return `"${value.replace(/"/g, '""')}"`;
27188
27462
  }
27189
- function shellQuote4(value) {
27463
+ function shellQuote5(value) {
27190
27464
  if (process.platform === "win32") {
27191
27465
  return /^[A-Za-z0-9_./:@%+=,-]+$/.test(value) ? value : windowsCmdQuote(value);
27192
27466
  }
27193
27467
  return posixShellQuote(value);
27194
27468
  }
27195
27469
  function buildSourceUpdateCommand(sourceRoot) {
27196
- const quotedRoot = shellQuote4(sourceRoot);
27470
+ const quotedRoot = shellQuote5(sourceRoot);
27197
27471
  const cdCommand = process.platform === "win32" ? `cd /d ${quotedRoot}` : `cd ${quotedRoot}`;
27198
27472
  return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
27199
27473
  }
@@ -27205,7 +27479,7 @@ function buildSidecarProjectConfigCommand(versionDir, nodeBin) {
27205
27479
  "fs.mkdirSync(dir,{recursive:true});",
27206
27480
  `fs.writeFileSync(path.join(dir,'package.json'),${JSON.stringify(NPM_SDK_SIDECAR_PACKAGE_JSON)});`
27207
27481
  ].join("");
27208
- return `${shellQuote4(nodeBin)} -e ${shellQuote4(script)} ${shellQuote4(versionDir)}`;
27482
+ return `${shellQuote5(nodeBin)} -e ${shellQuote5(script)} ${shellQuote5(versionDir)}`;
27209
27483
  }
27210
27484
  function sidecarStateDir(input2) {
27211
27485
  const scope = input2.env.DEEPLINE_CONFIG_SCOPE?.trim();
@@ -27244,7 +27518,7 @@ function resolvePythonSidecarUpdatePlan(options) {
27244
27518
  const packageSpec = options.packageSpec || "deepline@latest";
27245
27519
  const npmCommand = "npm";
27246
27520
  const versionDir = (0, import_node_path19.join)(stateDir, "versions", "<version>");
27247
- const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${shellQuote4(versionDir)} ${NPM_SDK_INSTALL_COMMON_FLAGS.map(shellQuote4).join(" ")} ${shellQuote4(packageSpec)}`;
27521
+ const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${shellQuote5(versionDir)} ${NPM_SDK_INSTALL_COMMON_FLAGS.map(shellQuote5).join(" ")} ${shellQuote5(packageSpec)}`;
27248
27522
  return {
27249
27523
  kind: "python-sidecar",
27250
27524
  stateDir,
@@ -27324,7 +27598,7 @@ function resolveUpdatePlan(options = {}) {
27324
27598
  command,
27325
27599
  args,
27326
27600
  ...installPrefix ? { installPrefix } : {},
27327
- manualCommand: `${command} ${args.map(shellQuote4).join(" ")}`
27601
+ manualCommand: `${command} ${args.map(shellQuote5).join(" ")}`
27328
27602
  };
27329
27603
  }
27330
27604
  var AUTO_UPDATE_FAILURE_FILE = ".auto-update-failure.json";
@@ -27485,9 +27759,9 @@ function writeSidecarLauncher(input2) {
27485
27759
  input2.path,
27486
27760
  [
27487
27761
  "#!/usr/bin/env sh",
27488
- `export DEEPLINE_HOST_URL=${shellQuote4(input2.hostUrl)}`,
27489
- `export DEEPLINE_CONFIG_SCOPE=${shellQuote4(input2.scope)}`,
27490
- `exec ${shellQuote4(input2.nodeBin)} ${shellQuote4(input2.entryPath)} "$@"`,
27762
+ `export DEEPLINE_HOST_URL=${shellQuote5(input2.hostUrl)}`,
27763
+ `export DEEPLINE_CONFIG_SCOPE=${shellQuote5(input2.scope)}`,
27764
+ `exec ${shellQuote5(input2.nodeBin)} ${shellQuote5(input2.entryPath)} "$@"`,
27491
27765
  ""
27492
27766
  ].join("\n"),
27493
27767
  { encoding: "utf8", mode: 493 }