deepline 0.3.90 → 0.3.92

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.
Files changed (87) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +101 -6
  2. package/dist/bundling-sources/sdk/src/monitor-fleet-contract.ts +2 -556
  3. package/dist/bundling-sources/sdk/src/monitor-fleets.ts +2 -2
  4. package/dist/bundling-sources/sdk/src/release.ts +7 -12
  5. package/dist/bundling-sources/sdk/src/types.ts +6 -1
  6. package/dist/bundling-sources/shared_libs/integration-contracts/monitor-fleet-contract.ts +549 -0
  7. package/dist/bundling-sources/shared_libs/monitors/fleets/errors.ts +96 -0
  8. package/dist/bundling-sources/shared_libs/monitors/fleets/limits.ts +8 -0
  9. package/dist/bundling-sources/shared_libs/monitors/fleets/plan.ts +320 -0
  10. package/dist/bundling-sources/shared_libs/monitors/fleets/verdict.ts +106 -0
  11. package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +5 -1
  12. package/dist/bundling-sources/shared_libs/monitors/monitor-fleet-limits.ts +2 -12
  13. package/dist/bundling-sources/shared_libs/monitors/package.json +107 -5
  14. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +12 -7
  15. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +48 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +1 -1
  17. package/dist/bundling-sources/shared_libs/play-runtime/db-session-lease-store.ts +578 -0
  18. package/dist/bundling-sources/shared_libs/play-runtime/deployment/commands/roll-execution-relay.ts +521 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/deployment/commands/roll-receipt-gateway.ts +1378 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/deployment/commands/runtime-topology.ts +1024 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-gateway-route-probe.ts +193 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machine-lifecycle.ts +104 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +1844 -0
  24. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +21 -0
  25. package/dist/bundling-sources/shared_libs/play-runtime/deployment/process-tree.ts +40 -0
  26. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-drain.ts +262 -0
  27. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-surface.ts +98 -0
  28. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-topology.ts +303 -0
  29. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-tuple-publication-guardian.ts +70 -0
  30. package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-tuple-recovery.ts +519 -0
  31. package/dist/bundling-sources/shared_libs/play-runtime/deployment/vercel-fly-rollback-alignment.ts +280 -0
  32. package/dist/bundling-sources/shared_libs/play-runtime/deployment/vercel-production-gate.ts +159 -0
  33. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/memory-store.ts +114 -0
  34. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +44 -5
  35. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/child-play-resolver.ts +26 -0
  36. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +3662 -0
  37. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/progress-sidecar.ts +47 -0
  38. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-deadline.ts +84 -0
  39. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-gateway-transport.ts +91 -0
  40. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-heartbeat.ts +424 -0
  41. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +321 -0
  42. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-sheet-persistence-retry.ts +110 -0
  43. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-terminal-push.ts +625 -0
  44. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +46 -3
  45. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +1 -1
  46. package/dist/bundling-sources/shared_libs/play-runtime/webhook-receipt-retry.ts +50 -0
  47. package/dist/bundling-sources/shared_libs/plays/bundling/repository-adapter.ts +24 -0
  48. package/dist/bundling-sources/shared_libs/plays/child-run-projection.ts +174 -0
  49. package/dist/bundling-sources/shared_libs/plays/deploy/api-client.ts +267 -0
  50. package/dist/bundling-sources/shared_libs/plays/deploy/control-plane-types.ts +73 -0
  51. package/dist/bundling-sources/shared_libs/plays/deploy/manifest.ts +162 -0
  52. package/dist/bundling-sources/shared_libs/plays/deploy/project-serializer.ts +87 -0
  53. package/dist/bundling-sources/shared_libs/plays/deploy/source-file-path.ts +26 -0
  54. package/dist/bundling-sources/shared_libs/plays/deploy/target-paths.ts +36 -0
  55. package/dist/bundling-sources/shared_libs/plays/launch/input-contract.ts +400 -0
  56. package/dist/bundling-sources/shared_libs/plays/launch/prepare.ts +96 -0
  57. package/dist/bundling-sources/shared_libs/plays/local-file-discovery.ts +385 -0
  58. package/dist/bundling-sources/shared_libs/plays/play-grep-search.ts +79 -6
  59. package/dist/bundling-sources/shared_libs/plays/play-reference.ts +117 -0
  60. package/dist/bundling-sources/shared_libs/plays/run-input-summary.ts +260 -0
  61. package/dist/bundling-sources/shared_libs/plays/run-summary-types.ts +49 -0
  62. package/dist/bundling-sources/shared_libs/plays/secrets/errors.ts +19 -0
  63. package/dist/bundling-sources/shared_libs/plays/sheet-filter.ts +347 -0
  64. package/dist/bundling-sources/shared_libs/plays/standard-webhooks.ts +117 -0
  65. package/dist/bundling-sources/shared_libs/plays/status-result.ts +388 -0
  66. package/dist/bundling-sources/shared_libs/plays/transform-factor-structure.ts +377 -0
  67. package/dist/bundling-sources/shared_libs/plays/webhook-payload.ts +113 -0
  68. package/dist/cli/index.js +369 -162
  69. package/dist/cli/index.mjs +369 -162
  70. package/dist/{compiler-manifest-BaJfE-5H.d.mts → compiler-manifest-x14KL83E.d.mts} +1 -1
  71. package/dist/{compiler-manifest-BaJfE-5H.d.ts → compiler-manifest-x14KL83E.d.ts} +1 -1
  72. package/dist/index.d.mts +45 -8
  73. package/dist/index.d.ts +45 -8
  74. package/dist/index.js +61 -14
  75. package/dist/index.mjs +61 -14
  76. package/dist/install-integrity.json +54 -2
  77. package/dist/monitor-fleet-contract.d.mts +3 -10
  78. package/dist/monitor-fleet-contract.d.ts +3 -10
  79. package/dist/monitor-fleet-contract.js +2 -0
  80. package/dist/monitor-fleet-contract.mjs +1 -1
  81. package/dist/plays/bundle-play-file.d.mts +2 -2
  82. package/dist/plays/bundle-play-file.d.ts +2 -2
  83. package/dist/release.d.mts +3 -3
  84. package/dist/release.d.ts +3 -3
  85. package/dist/release.js +7 -12
  86. package/dist/release.mjs +7 -12
  87. package/package.json +2 -2
@@ -1270,27 +1270,22 @@ var SDK_RELEASE = {
1270
1270
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1271
1271
  // getters keep their established compatibility behavior.
1272
1272
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
1273
- // 0.3.90 is the first deliberately versioned SDK release for API v3. Play
1274
- // grep hard-cuts to the single Convex full-text index; it does not retain a
1275
- // registry/scanner reader for any SDK/API major.
1276
- version: "0.3.90",
1277
- updateSummary: "Play grep now uses one source-only Convex full-text index. It no longer scans the registry, pages through the complete indexed match set, and rejects retired grep modes. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
1273
+ // 0.3.90 is the first deliberately versioned SDK release for API v3.
1274
+ version: "0.3.92",
1275
+ updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
1278
1276
  packageCapabilities: {
1279
1277
  updatePreferences: 1
1280
1278
  },
1281
1279
  contracts: {
1282
1280
  api: {
1283
1281
  name: "sdk-http-api",
1284
- // API v3 hard-cuts Play grep to the canonical Convex index. API v2 stays
1285
- // admitted for the explicit SDK support window, but it selects neither a
1286
- // registry scanner nor another grep reader: every accepted grep request
1287
- // uses the same indexed query and retired flags fail at the API boundary.
1282
+ // Concise Play grep has the current wire id. Older ids follow the
1283
+ // standard API support window.
1288
1284
  currentMajor: 3,
1289
1285
  supportedMajors: [3, 2],
1290
- // The first wire id is emitted by the current SDK. Remaining ids are
1291
- // accepted only while the API v2 support window is open.
1286
+ // Older ids remain subject to the API support window.
1292
1287
  legacyWireIds: [
1293
- "2026-09-play-grep-convex-index-hard-cutover",
1288
+ "2026-09-play-grep-concise-results",
1294
1289
  "2026-07-admin-cli-local-cutover",
1295
1290
  "2026-07-native-monitor-launch-hard-cutover"
1296
1291
  ]
@@ -5162,9 +5157,19 @@ var DeeplineClient = class {
5162
5157
  targetStatus: () => this.getTargetBillingStatus(),
5163
5158
  autoRecharge: {
5164
5159
  get: () => this.getTargetAutoRecharge(),
5160
+ trigger: (options2) => this.http.post(
5161
+ "/api/v2/billing/auto-recharge/trigger",
5162
+ {},
5163
+ {
5164
+ "Idempotency-Key": requireTargetBillingIdempotencyKey(
5165
+ options2?.idempotencyKey ?? globalThis.crypto.randomUUID()
5166
+ )
5167
+ }
5168
+ ),
5165
5169
  update: (options2) => this.updateTargetAutoRecharge(options2)
5166
5170
  },
5167
5171
  purchaseCredits: (options2) => this.purchaseTargetBillingCredits(options2),
5172
+ recoverCreditPurchase: (options2) => this.recoverTargetBillingCreditPurchase(options2),
5168
5173
  transitionPlan: (options2) => this.transitionTargetBillingPlan(options2),
5169
5174
  portalSession: () => this.createTargetBillingPortalSession()
5170
5175
  };
@@ -5333,6 +5338,14 @@ var DeeplineClient = class {
5333
5338
  if (options.playName !== void 0) params.set("play", options.playName);
5334
5339
  return this.http.get(`/api/v2/secrets?${params.toString()}`);
5335
5340
  }
5341
+ /** Add, replace, or clear the non-sensitive note attached to one secret. */
5342
+ async updateSecretNote(secretId, note) {
5343
+ const response = await this.http.patch(
5344
+ `/api/v2/secrets/${encodeURIComponent(secretId)}`,
5345
+ { note }
5346
+ );
5347
+ return response.secret;
5348
+ }
5336
5349
  // ——————————————————————————————————————————————————————————
5337
5350
  // Tools
5338
5351
  // ——————————————————————————————————————————————————————————
@@ -7526,7 +7539,8 @@ var DeeplineClient = class {
7526
7539
  options.enabled ? {
7527
7540
  enabled: true,
7528
7541
  threshold_credits: options.thresholdCredits,
7529
- refill_to_credits: options.refillToCredits
7542
+ refill_to_credits: options.refillToCredits,
7543
+ ...options.purchaseLimitCents !== void 0 ? { purchase_limit_cents: options.purchaseLimitCents } : {}
7530
7544
  } : { enabled: false },
7531
7545
  { "Idempotency-Key": idempotencyKey }
7532
7546
  );
@@ -7547,6 +7561,39 @@ var DeeplineClient = class {
7547
7561
  { maxRetries: 0, exactUrlOnly: true }
7548
7562
  );
7549
7563
  }
7564
+ /** Recover only the original workspace, credit amount, and purchase key; never charge. */
7565
+ async recoverTargetBillingCreditPurchase(options) {
7566
+ if (typeof options.idempotencyKey !== "string") {
7567
+ throw new DeeplineError(
7568
+ "The original billing idempotencyKey is required.",
7569
+ void 0,
7570
+ "INVALID_BILLING_IDEMPOTENCY_KEY"
7571
+ );
7572
+ }
7573
+ const idempotencyKey = requireTargetBillingIdempotencyKey(
7574
+ options.idempotencyKey
7575
+ );
7576
+ if (!Number.isSafeInteger(options.credits) || options.credits <= 0) {
7577
+ throw new DeeplineError(
7578
+ "credits must be a positive safe integer.",
7579
+ void 0,
7580
+ "INVALID_CREDITS"
7581
+ );
7582
+ }
7583
+ if (typeof options.orgId !== "string" || !options.orgId.trim() || options.orgId !== options.orgId.trim()) {
7584
+ throw new DeeplineError(
7585
+ "The original orgId is required without surrounding whitespace.",
7586
+ void 0,
7587
+ "INVALID_ORG_ID"
7588
+ );
7589
+ }
7590
+ return this.http.post(
7591
+ "/api/v2/billing/credit-purchases/recover",
7592
+ { credits: options.credits, org_id: options.orgId },
7593
+ { "Idempotency-Key": idempotencyKey },
7594
+ { maxRetries: 0, exactUrlOnly: true }
7595
+ );
7596
+ }
7550
7597
  /**
7551
7598
  * Start, change, cancel, or restore a target plan through one idempotent
7552
7599
  * commercial operation.
@@ -9986,6 +10033,17 @@ async function handleBalance(options) {
9986
10033
  const needsCredits = status === "no_billing" || status === "zero_balance" || status === "payment_method_only";
9987
10034
  const recovery = needsCredits ? balanceRecoveryForCredits() : null;
9988
10035
  const lines = [`Balance: ${payload.balance ?? "(unknown)"} credits`];
10036
+ const temporaryHolds = payload.temporary_hold_credits;
10037
+ if (typeof temporaryHolds === "number" && temporaryHolds > 0) {
10038
+ lines.push(
10039
+ `Temporarily reserved: ${temporaryHolds} credits \u2014 not charged; unused credits are released after final usage is calculated.`
10040
+ );
10041
+ } else if (temporaryHolds === null) {
10042
+ lines.push("Temporary reservation status is temporarily unavailable.");
10043
+ }
10044
+ if (payload.temporary_hold_credits_truncated === true) {
10045
+ lines.push("Temporary reservation total may be incomplete.");
10046
+ }
9989
10047
  if (status === "no_billing") {
9990
10048
  lines.push(
9991
10049
  "Billing: No billing account or payment method set up for this workspace."
@@ -10036,7 +10094,7 @@ async function handleUsage(options) {
10036
10094
  `Balance: ${payload.balance ?? "(unknown)"}`,
10037
10095
  `Last 30 days usage: ${last30Usage ?? "(unknown)"}`,
10038
10096
  ...Number.isFinite(temporaryHolds) && temporaryHolds > 0 ? [`Temporary holds: ${temporaryHolds}`] : [],
10039
- `Monthly limit: ${quota.enabled ? quota.monthly_credits_limit ?? "(unknown)" : "off"}`,
10097
+ `Monthly spend guidance: ${quota.enabled ? quota.monthly_credits_limit ?? "(unknown)" : "off"}`,
10040
10098
  ...options.runId && recent.run_id ? [
10041
10099
  `Run spend: ${(payload.run ?? {}).spent_credits ?? "(unknown)"} Deepline Credits`
10042
10100
  ] : [],
@@ -10068,9 +10126,9 @@ async function handleLimit(options) {
10068
10126
  "/api/v2/billing/limit"
10069
10127
  );
10070
10128
  const lines = payload.enabled ? [
10071
- `Monthly limit: ${payload.monthly_credits_limit ?? "(unknown)"}`,
10072
- `Remaining before cap: ${payload.remaining_credits ?? "(unknown)"}`
10073
- ] : ["Monthly limit: off"];
10129
+ `Monthly spend guidance: ${payload.monthly_credits_limit ?? "(unknown)"}`,
10130
+ "Enforcement: advisory; available balance remains the exact admission control."
10131
+ ] : ["Monthly spend guidance: off"];
10074
10132
  printCommandEnvelope(
10075
10133
  {
10076
10134
  ...payload,
@@ -10092,7 +10150,7 @@ async function handleSetLimit(credits, options) {
10092
10150
  sections: [
10093
10151
  {
10094
10152
  title: "billing limit",
10095
- lines: [`Monthly billing limit set to ${credits} credits.`]
10153
+ lines: [`Monthly spend guidance set to ${credits} credits.`]
10096
10154
  }
10097
10155
  ]
10098
10156
  }
@@ -10112,7 +10170,7 @@ async function handleLimitOff(options) {
10112
10170
  sections: [
10113
10171
  {
10114
10172
  title: "billing limit",
10115
- lines: ["Monthly billing limit is now off."]
10173
+ lines: ["Monthly spend guidance is now off."]
10116
10174
  }
10117
10175
  ]
10118
10176
  }
@@ -10248,42 +10306,28 @@ function planPriceText(priceUsd, priceInterval) {
10248
10306
  }
10249
10307
  return `$${priceUsd}${priceInterval ? `/${priceInterval}` : ""}`;
10250
10308
  }
10251
- function planRolloverText(rollover) {
10252
- const mode = rollover?.mode ?? "none";
10253
- if (mode === "none") return "no rollover";
10254
- if (mode === "bounded") {
10255
- return `rollover up to ${rollover?.max_credits ?? "(unknown)"} credits`;
10256
- }
10257
- return `rollover ${mode}`;
10309
+ function targetPlanLine(plan) {
10310
+ return `${plan.name} (${plan.sku}) | ${planPriceText(plan.recurring_price_usd, plan.interval)} | ${plan.included_credits} included credits/month | $${plan.purchased_credit_price_usd}/purchased credit | ${plan.acquisition_enabled ? "available" : "unavailable"}`;
10258
10311
  }
10259
10312
  async function handlePlans(options) {
10260
- const { http } = getAuthedHttpClient();
10261
- const payload = await http.get(
10262
- "/api/v2/billing/catalog/current"
10313
+ const client2 = new DeeplineClient();
10314
+ const payload = await client2.billing.targetPlans();
10315
+ const listedCurrentPlan = payload.plans.find(
10316
+ (plan) => plan.sku === payload.current_plan_sku
10263
10317
  );
10264
- const activePlan = payload.active_plan ?? {};
10265
- const plans = Array.isArray(payload.plans) ? payload.plans : [];
10266
- const meters = Array.isArray(payload.meters) ? payload.meters : Array.isArray(payload.metrics) ? payload.metrics : [];
10318
+ const currentPlan = listedCurrentPlan ?? (await client2.billing.targetStatus()).plan;
10267
10319
  const lines = [
10268
- `Catalog: ${payload.catalog_id ?? "(unknown)"} (version ${payload.catalog_version ?? "(unknown)"})`,
10269
- `Active plan: ${activePlan.public_name ?? "(unknown)"} (${activePlan.plan_version_id ?? "(unknown)"})`,
10270
- `Assigned by: ${activePlan.assigned_by ?? "default"} | subscription: ${activePlan.has_subscription ? "yes" : "no"}`,
10271
- ...plans.length === 0 ? ["Plans: none published"] : [
10272
- "Plans:",
10273
- ...plans.map(
10274
- (plan) => `${plan.public_name ?? "(unknown)"} (${plan.plan_version_id ?? "(unknown)"}) | ${planPriceText(plan.price_usd, plan.price_interval)} | ${plan.monthly_grant_credits ?? 0} credits/cycle | ${planRolloverText(plan.rollover)} | ${plan.acquirable ? "acquirable" : "not acquirable"}`
10275
- )
10276
- ],
10277
- ...meters.length === 0 ? ["Metrics: none"] : [
10278
- "Metrics:",
10279
- ...meters.map(
10280
- (meter) => `${meter.id ?? "(unknown)"} | ${meter.name ?? "(unknown)"}`
10281
- )
10282
- ]
10320
+ `Current plan: ${currentPlan.name} (${currentPlan.sku}) | ${planPriceText(currentPlan.recurring_price_usd, currentPlan.interval)} | ${currentPlan.included_credits ?? "(unknown)"} included credits/month`,
10321
+ `Pending plan: ${payload.pending_plan_sku ?? "none"}`,
10322
+ `Plan changes: ${payload.acquisition_enabled ? "enabled" : "disabled"}`,
10323
+ ...payload.plans.length === 0 ? ["Plans: none available"] : ["Plans:", ...payload.plans.map(targetPlanLine)],
10324
+ "Change plan: deepline billing change-plan <plan_sku> --json"
10283
10325
  ];
10326
+ const legacyPayload = shouldEmitJson(options.json) ? await client2.billing.plans() : null;
10284
10327
  printCommandEnvelope(
10285
10328
  {
10286
- ...payload,
10329
+ ...legacyPayload ?? payload,
10330
+ ...legacyPayload ? { target_billing: payload } : {},
10287
10331
  render: { sections: [{ title: "billing plans", lines }] }
10288
10332
  },
10289
10333
  { json: options.json }
@@ -10658,7 +10702,10 @@ async function handleAutoRechargeStatus(options) {
10658
10702
  const lines = [
10659
10703
  `State: ${state}`,
10660
10704
  ...payload.threshold_credits !== null ? [`Threshold: ${payload.threshold_credits} credits`] : [],
10661
- ...payload.refill_to_credits !== null ? [`Refill balance to: ${payload.refill_to_credits} credits`] : []
10705
+ ...payload.refill_to_credits !== null ? [`Refill balance to: ${payload.refill_to_credits} credits`] : [],
10706
+ ...payload.purchase_limit_cents !== void 0 ? [
10707
+ payload.purchase_limit_cents === null ? "Automatic purchase cap: none" : `Automatic purchase cap: $${(payload.purchase_limit_cents / 100).toFixed(2)} per rolling 30 days`
10708
+ ] : []
10662
10709
  ];
10663
10710
  printCommandEnvelope(
10664
10711
  {
@@ -10672,6 +10719,18 @@ async function handleAutoRechargeStatus(options) {
10672
10719
  async function handleAutoRechargeSet(options) {
10673
10720
  const thresholdCredits = parseTopUpCredits(options.thresholdCredits);
10674
10721
  const refillToCredits = parseTopUpCredits(options.refillToCredits);
10722
+ const rollingLimitCents = options.purchaseLimitCents === void 0 ? void 0 : options.purchaseLimitCents === "none" ? null : Number(options.purchaseLimitCents);
10723
+ if (rollingLimitCents !== void 0 && rollingLimitCents !== null && (!Number.isSafeInteger(rollingLimitCents) || rollingLimitCents <= 0)) {
10724
+ reportBillingFailure(
10725
+ {
10726
+ exitCode: 2,
10727
+ code: "INVALID_AUTO_RECHARGE_CONFIGURATION",
10728
+ message: "--purchase-limit-cents must be a positive whole number of USD cents or none."
10729
+ },
10730
+ options
10731
+ );
10732
+ return;
10733
+ }
10675
10734
  if (thresholdCredits === null || refillToCredits === null || refillToCredits <= thresholdCredits) {
10676
10735
  reportBillingFailure(
10677
10736
  {
@@ -10696,7 +10755,8 @@ async function handleAutoRechargeSet(options) {
10696
10755
  body: {
10697
10756
  enabled: true,
10698
10757
  threshold_credits: thresholdCredits,
10699
- refill_to_credits: refillToCredits
10758
+ refill_to_credits: refillToCredits,
10759
+ ...rollingLimitCents !== void 0 ? { purchase_limit_cents: rollingLimitCents } : {}
10700
10760
  }
10701
10761
  }
10702
10762
  },
@@ -10708,6 +10768,7 @@ async function handleAutoRechargeSet(options) {
10708
10768
  enabled: true,
10709
10769
  thresholdCredits,
10710
10770
  refillToCredits,
10771
+ ...rollingLimitCents !== void 0 ? { purchaseLimitCents: rollingLimitCents } : {},
10711
10772
  idempotencyKey
10712
10773
  });
10713
10774
  printCommandEnvelope(
@@ -10765,6 +10826,60 @@ async function handleBuyCredits(creditsRaw, options) {
10765
10826
  { json: options.json }
10766
10827
  );
10767
10828
  }
10829
+ async function handleTopUpRecover(creditsRaw, options) {
10830
+ const credits = parseTopUpCredits(creditsRaw);
10831
+ if (credits === null) {
10832
+ reportBillingFailure(
10833
+ {
10834
+ exitCode: 2,
10835
+ code: "INVALID_CREDITS",
10836
+ message: "<credits> must be a positive integer."
10837
+ },
10838
+ options
10839
+ );
10840
+ return;
10841
+ }
10842
+ const failure = !options.orgId?.trim() || options.orgId !== options.orgId.trim() ? {
10843
+ code: "INVALID_ORG_ID",
10844
+ message: "--org-id must be the original workspace ID without surrounding whitespace."
10845
+ } : !options.idempotencyKey || options.idempotencyKey.length > 200 || options.idempotencyKey !== options.idempotencyKey.trim() ? {
10846
+ code: "INVALID_BILLING_IDEMPOTENCY_KEY",
10847
+ message: "--idempotency-key must be the original key (1\u2013200 characters without surrounding whitespace)."
10848
+ } : null;
10849
+ if (failure) {
10850
+ reportBillingFailure(
10851
+ {
10852
+ exitCode: 2,
10853
+ ...failure
10854
+ },
10855
+ options
10856
+ );
10857
+ return;
10858
+ }
10859
+ if (options.dryRun) {
10860
+ printCommandEnvelope(
10861
+ {
10862
+ ok: true,
10863
+ dry_run: true,
10864
+ method: "POST",
10865
+ path: "/api/v2/billing/credit-purchases/recover",
10866
+ idempotency_key: options.idempotencyKey,
10867
+ body: { credits, org_id: options.orgId }
10868
+ },
10869
+ { json: options.json }
10870
+ );
10871
+ return;
10872
+ }
10873
+ const payload = await new DeeplineClient().billing.recoverCreditPurchase({
10874
+ credits,
10875
+ orgId: options.orgId,
10876
+ idempotencyKey: options.idempotencyKey
10877
+ });
10878
+ printCommandEnvelope(
10879
+ { ok: true, idempotency_key: options.idempotencyKey, ...payload },
10880
+ { json: options.json }
10881
+ );
10882
+ }
10768
10883
  async function handleTargetPlan(planSku, options) {
10769
10884
  if (planSku !== "payg-v1" && planSku !== "builder-v1" && planSku !== "growth-v1" && planSku !== "growth-canary-v1" && planSku !== "team-v1") {
10770
10885
  reportBillingFailure(
@@ -10882,35 +10997,36 @@ Examples:
10882
10997
  "--cursor <cursor>",
10883
10998
  "Recent-call cursor from the previous response"
10884
10999
  ).option("--run-id <run_id>", "Show recent usage for one play run").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleUsage);
10885
- billing.command("limit").description("Show configured monthly limit state.").addHelpText(
11000
+ billing.command("limit").description("Show configured monthly spend guidance.").addHelpText(
10886
11001
  "after",
10887
11002
  `
10888
11003
  Notes:
10889
- Read-only. Shows whether the monthly workspace cap is enabled and how many
10890
- Deepline credits remain before the cap.
11004
+ Read-only. Shows whether monthly workspace spend guidance is enabled.
11005
+ Guidance does not reject funded work; available balance remains exact.
10891
11006
 
10892
11007
  Examples:
10893
11008
  deepline billing limit
10894
11009
  deepline billing limit --json
10895
11010
  `
10896
11011
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLimit);
10897
- billing.command("set-limit").description("Set monthly credit cap.").addHelpText(
11012
+ billing.command("set-limit").description("Set monthly spend guidance.").addHelpText(
10898
11013
  "after",
10899
11014
  `
10900
11015
  Notes:
10901
11016
  Mutates workspace billing settings. The argument is a Deepline credit amount,
10902
- not dollars and not provider credits.
11017
+ not dollars and not provider credits. Guidance is advisory; it does not
11018
+ replace the exact available-balance admission check.
10903
11019
 
10904
11020
  Examples:
10905
11021
  deepline billing set-limit 500
10906
11022
  deepline billing set-limit 500 --json
10907
11023
  `
10908
11024
  ).argument("<credits>", "Monthly credits limit").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleSetLimit);
10909
- billing.command("off").description("Disable monthly credit cap.").addHelpText(
11025
+ billing.command("off").description("Disable monthly spend guidance.").addHelpText(
10910
11026
  "after",
10911
11027
  `
10912
11028
  Notes:
10913
- Mutates workspace billing settings by removing the monthly Deepline credit cap.
11029
+ Mutates workspace billing settings by removing monthly Deepline spend guidance.
10914
11030
 
10915
11031
  Examples:
10916
11032
  deepline billing off
@@ -11008,6 +11124,18 @@ Examples:
11008
11124
  "Stable retry key for the same intended top-up"
11009
11125
  ).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);
11010
11126
  billing.command("buy").description("Buy credits through the target billing contract.").argument("<credits>", "Positive integer Deepline credit amount").option("--idempotency-key <key>", "Stable retry key").option("--json", "Emit JSON output").action(handleBuyCredits);
11127
+ billing.command("top-up-recover").description(
11128
+ "Inspect or retire an original top-up intent without starting a payment."
11129
+ ).argument("<credits>", "Original positive integer Deepline credit amount").requiredOption(
11130
+ "--org-id <original-org>",
11131
+ "Original workspace ID (must match the authenticated workspace)"
11132
+ ).requiredOption(
11133
+ "--idempotency-key <original-key>",
11134
+ "Original purchase key; never generates a new key"
11135
+ ).option("--dry-run", "Print the recovery request without changing state").option("--json", "Emit JSON output. Also automatic when stdout is piped").addHelpText(
11136
+ "after",
11137
+ "\nAn absent intent is durably retired; an existing operation is returned unchanged.\nThis command never starts a payment. Use the original amount, workspace, and key.\nExample:\n deepline billing top-up-recover 1000 --org-id org_original --idempotency-key original-purchase-key --json\n"
11138
+ ).action(handleTopUpRecover);
11011
11139
  billing.command("status").description("Show normalized target billing state.").option("--json", "Emit JSON output").action(handleTargetStatus);
11012
11140
  billing.command("auto-recharge").description("Inspect and manage automatic Deepline credit recharge.").addHelpText(
11013
11141
  "after",
@@ -11028,11 +11156,21 @@ Examples:
11028
11156
  ).requiredOption(
11029
11157
  "--refill-to-credits <credits>",
11030
11158
  "Recharge the balance to this amount"
11159
+ ).option(
11160
+ "--purchase-limit-cents <cents>",
11161
+ "Limit automatic purchases over rolling 30 days (USD cents)"
11031
11162
  ).option("--idempotency-key <key>", "Stable retry key").option("--dry-run", "Print the planned update without applying it").option("--json", "Emit JSON output").action(handleAutoRechargeSet)
11032
11163
  ).addCommand(
11033
11164
  new Command("off").description(
11034
11165
  "Disable automatic recharge without clearing saved amounts."
11035
11166
  ).option("--idempotency-key <key>", "Stable retry key").option("--dry-run", "Print the planned update without applying it").option("--json", "Emit JSON output").action(handleAutoRechargeOff)
11167
+ ).addCommand(
11168
+ new Command("trigger").description(
11169
+ "Evaluate capped automatic recharge and resume any pending purchase."
11170
+ ).option("--json", "Emit JSON output").action(async (options) => {
11171
+ const result = await new DeeplineClient().billing.autoRecharge.trigger();
11172
+ printCommandEnvelope({ ok: true, ...result }, { json: options.json });
11173
+ })
11036
11174
  );
11037
11175
  billing.command("change-plan").description("Start or change the target billing plan.").argument(
11038
11176
  "<plan_sku>",
@@ -11044,11 +11182,11 @@ Examples:
11044
11182
  "after",
11045
11183
  `
11046
11184
  Notes:
11047
- Read-only. Answers "what plans exist and what am I on": each plan's price,
11048
- monthly grant credits, rollover policy, and whether it is open for
11049
- subscription, plus the catalog's usage metrics. All amounts are Deepline
11050
- credits and Deepline-facing USD, never raw provider spend. Subscribe to a
11051
- listed plan with: deepline billing subscribe <plan_version_id>
11185
+ Read-only. Shows the current target billing plan, pending plan, and every
11186
+ visible plan's recurring price, included credits, purchased-credit price,
11187
+ and current acquisition availability. All amounts are Deepline credits and
11188
+ Deepline-facing USD, never raw provider spend. Change to an available plan
11189
+ with: deepline billing change-plan <plan_sku>
11052
11190
 
11053
11191
  Examples:
11054
11192
  deepline billing plans
@@ -11070,7 +11208,7 @@ Examples:
11070
11208
  deepline billing subscribe runtime-395-2026-07-v1
11071
11209
  deepline billing subscribe runtime-395-2026-07-v1 --no-open --json
11072
11210
  `
11073
- ).argument("<plan_version_id>", "Plan version id from `billing plans`").option("--no-open", "Print the checkout URL without opening a browser").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleSubscribe);
11211
+ ).argument("<plan_version_id>", "Legacy billing plan version id").option("--no-open", "Print the checkout URL without opening a browser").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleSubscribe);
11074
11212
  billing.command("subscription").description("Inspect and manage subscription state for the workspace.").addHelpText(
11075
11213
  "after",
11076
11214
  `
@@ -11337,6 +11475,7 @@ function mergeCanonicalRowsInfo(left, right) {
11337
11475
  ...right.recoveredReturnPaths ?? []
11338
11476
  ])
11339
11477
  ];
11478
+ const currentTable = left.currentTable || right.currentTable;
11340
11479
  return {
11341
11480
  ...fallback,
11342
11481
  ...preferred,
@@ -11350,6 +11489,7 @@ function mergeCanonicalRowsInfo(left, right) {
11350
11489
  tableNamespace: preferred.tableNamespace ?? fallback.tableNamespace,
11351
11490
  ...left.recovered || right.recovered ? { recovered: true } : {},
11352
11491
  ...recoveredReturnPaths2.length ? { recoveredReturnPaths: recoveredReturnPaths2 } : {},
11492
+ ...currentTable ? { currentTable: true } : {},
11353
11493
  ...exportUnavailableReason ? {
11354
11494
  exportUnavailableReason,
11355
11495
  ...unavailableSource?.exportUnavailableMessage ? {
@@ -11410,6 +11550,11 @@ function isSerializedDataset(value) {
11410
11550
  function isPackagedDatasetOutput(value) {
11411
11551
  return isRecord8(value) && value.kind === "dataset" && isRecord8(value.preview) && Array.isArray(value.preview.rows);
11412
11552
  }
11553
+ function hasCurrentTableExport(value) {
11554
+ if (!isRecord8(value) || !isRecord8(value.actions)) return false;
11555
+ const exportCsv = value.actions.exportCsv;
11556
+ return isRecord8(exportCsv) && isRecord8(exportCsv.scope) && exportCsv.scope.kind === "database" && exportCsv.scope.mutability === "current";
11557
+ }
11413
11558
  function recoveredReturnPaths(value) {
11414
11559
  if (!Array.isArray(value)) return [];
11415
11560
  return [
@@ -11516,6 +11661,7 @@ function canonicalRowsInfoFromCandidate(input2) {
11516
11661
  datasetId: typeof candidate.value.datasetId === "string" ? candidate.value.datasetId : null,
11517
11662
  tableNamespace: typeof candidate.value.tableNamespace === "string" ? candidate.value.tableNamespace : null,
11518
11663
  ...candidate.value.recovered === true ? { recovered: true } : {},
11664
+ ...hasCurrentTableExport(candidate.value) ? { currentTable: true } : {},
11519
11665
  ...recoveredReturnPaths(candidate.value.recoveredReturnPaths).length ? {
11520
11666
  recoveredReturnPaths: recoveredReturnPaths(
11521
11667
  candidate.value.recoveredReturnPaths
@@ -21005,11 +21151,15 @@ function formatPackageDatasetActionLines(packaged) {
21005
21151
  ` ${category} dataset ${path}: ${rowCount === null ? "unknown rows" : `${formatInteger(rowCount)} ${rowCount === 1 ? "row" : "rows"}`}`
21006
21152
  );
21007
21153
  }
21008
- const exportCommand = actionToCommand(actions.exportCsv);
21154
+ const exportAction = readRecord(actions.exportCsv);
21155
+ const exportCommand = actionToCommand(exportAction);
21156
+ const exportScope = readRecord(exportAction?.scope);
21009
21157
  const currentQueryCommand = actionToCommand(actions.queryCurrentTable);
21010
21158
  const legacyQueryCommand = actionToCommand(actions.query);
21011
21159
  if (exportCommand) {
21012
- lines.push(` export this run: ${exportCommand}`);
21160
+ lines.push(
21161
+ exportScope?.kind === "database" ? ` export current table (may include other runs): ${exportCommand}` : ` export this run: ${exportCommand}`
21162
+ );
21013
21163
  }
21014
21164
  if (currentQueryCommand) {
21015
21165
  lines.push(` query current table: ${currentQueryCommand}`);
@@ -21418,33 +21568,29 @@ function sqlSafeExportColumnName(id) {
21418
21568
  async function fetchBackingDatasetRows(input2) {
21419
21569
  const playName = extractRunPlayName(input2.status);
21420
21570
  const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
21571
+ const currentTable = input2.rowsInfo.currentTable === true;
21421
21572
  if (!playName || !tableNamespace) {
21422
21573
  return null;
21423
21574
  }
21424
21575
  const sheetRows = [];
21425
21576
  let offset = 0;
21426
- let expectedTotal = input2.rowsInfo.totalRows;
21427
21577
  while (true) {
21428
21578
  const page = await input2.client.runs.exportDatasetRows({
21429
21579
  playName,
21430
21580
  tableNamespace,
21431
- runId: input2.status.runId,
21581
+ ...currentTable ? {} : { runId: input2.status.runId },
21432
21582
  limit: RUN_EXPORT_PAGE_SIZE,
21433
21583
  offset,
21434
21584
  rowMode: "all"
21435
21585
  });
21436
21586
  sheetRows.push(...page.rows);
21437
- const summaryTotal = page.summary?.stats?.total;
21438
- if (typeof summaryTotal === "number" && Number.isFinite(summaryTotal)) {
21439
- expectedTotal = Math.max(expectedTotal, Math.trunc(summaryTotal));
21440
- }
21441
- if (page.rows.length < RUN_EXPORT_PAGE_SIZE || sheetRows.length >= expectedTotal) {
21587
+ if (page.rows.length < RUN_EXPORT_PAGE_SIZE) {
21442
21588
  break;
21443
21589
  }
21444
21590
  offset += page.rows.length;
21445
21591
  }
21446
21592
  const rows = sheetRows.map(exportableSheetRow).filter((row) => Boolean(row));
21447
- if (rows.length < input2.rowsInfo.totalRows) {
21593
+ if (!currentTable && rows.length < input2.rowsInfo.totalRows || currentTable && rows.length === 0 && input2.rowsInfo.totalRows > 0) {
21448
21594
  return null;
21449
21595
  }
21450
21596
  const columns = mergeExportColumns(
@@ -21457,6 +21603,7 @@ async function fetchBackingDatasetRows(input2) {
21457
21603
  columns,
21458
21604
  totalRows: rows.length,
21459
21605
  complete: true,
21606
+ ...currentTable ? { currentTable: true } : {},
21460
21607
  source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
21461
21608
  };
21462
21609
  }
@@ -21481,12 +21628,14 @@ function assertDatasetHasExportableRows(input2) {
21481
21628
  if (input2.rowsInfo.rows.length > 0) {
21482
21629
  return input2.rowsInfo;
21483
21630
  }
21631
+ if (input2.rowsInfo.currentTable === true && input2.rowsInfo.totalRows === 0) {
21632
+ return input2.rowsInfo;
21633
+ }
21484
21634
  const datasetLabel = input2.datasetPath ?? input2.rowsInfo.tableNamespace ?? input2.rowsInfo.source ?? "result.rows";
21485
21635
  const available = input2.availableRows.map((info) => info.tableNamespace ?? info.source).filter((name) => typeof name === "string");
21486
21636
  const runStatus = String(input2.status.status ?? "").toLowerCase();
21487
- const failedBeforePersisting = runStatus !== "completed";
21488
21637
  throw new DeeplineError(
21489
- `Run ${input2.status.runId} has zero rows to export from dataset '${datasetLabel}'.` + (failedBeforePersisting ? ` The run status is '${runStatus || "unknown"}', so it likely failed before persisting rows to this dataset \u2014 provider calls may have been billed without a durable row. Fix the run's failure cause and re-run to resume.` : " The run completed but this dataset materialized no rows.") + (available.length > 0 ? ` Available datasets: ${available.join(", ")}.` : " No datasets were materialized for this run."),
21638
+ `Run ${input2.status.runId} has zero rows to export from dataset '${datasetLabel}'. The run status is '${runStatus || "unknown"}', so it likely failed before persisting rows to this dataset \u2014 provider calls may have been billed without a durable row. Fix the run's failure cause and re-run to resume.` + (available.length > 0 ? ` Available datasets: ${available.join(", ")}.` : " No datasets were materialized for this run."),
21490
21639
  void 0,
21491
21640
  "RUN_EXPORT_EMPTY",
21492
21641
  {
@@ -21497,23 +21646,6 @@ function assertDatasetHasExportableRows(input2) {
21497
21646
  }
21498
21647
  );
21499
21648
  }
21500
- function assertDatasetExportAvailable(input2) {
21501
- if (input2.rowsInfo.exportUnavailableReason !== "shared_table_namespace") {
21502
- return;
21503
- }
21504
- throw new DeeplineError(
21505
- input2.rowsInfo.exportUnavailableMessage ?? "Run CSV export is unavailable because multiple Dataset Handles share one physical table.",
21506
- void 0,
21507
- "RUN_EXPORT_UNAVAILABLE",
21508
- {
21509
- runId: input2.status.runId,
21510
- dataset: input2.rowsInfo.source,
21511
- datasetId: input2.rowsInfo.datasetId ?? null,
21512
- tableNamespace: input2.rowsInfo.tableNamespace ?? null,
21513
- reason: input2.rowsInfo.exportUnavailableReason
21514
- }
21515
- );
21516
- }
21517
21649
  async function exportPlayStatusRows(client2, status, outPath, options = {}) {
21518
21650
  if (!outPath) {
21519
21651
  return null;
@@ -21592,7 +21724,6 @@ ${commands.join("\n")}`,
21592
21724
  `Run ${status.runId} did not expose a row-shaped final output to export.`
21593
21725
  );
21594
21726
  }
21595
- assertDatasetExportAvailable({ rowsInfo, status });
21596
21727
  const attempts = Math.max(1, Math.trunc(options.attempts ?? 1));
21597
21728
  const retryDelayMs = Math.max(0, Math.trunc(options.retryDelayMs ?? 0));
21598
21729
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
@@ -21607,6 +21738,9 @@ ${commands.join("\n")}`,
21607
21738
  if (error instanceof DeeplineError && error.code === "RUN_EXPORT_SCOPE_MISMATCH") {
21608
21739
  throw error;
21609
21740
  }
21741
+ if (rowsInfo.currentTable) {
21742
+ throw error;
21743
+ }
21610
21744
  if (!rowsInfo.complete) {
21611
21745
  throw error;
21612
21746
  }
@@ -21620,7 +21754,8 @@ ${commands.join("\n")}`,
21620
21754
  });
21621
21755
  return {
21622
21756
  path: RunDataset.from(guarded2).exportCsv(outPath),
21623
- rowsInfo: guarded2
21757
+ rowsInfo: guarded2,
21758
+ currentTable: fetchedRowsInfo.currentTable === true
21624
21759
  };
21625
21760
  }
21626
21761
  if (rowsInfo.complete) {
@@ -21632,7 +21767,8 @@ ${commands.join("\n")}`,
21632
21767
  });
21633
21768
  return {
21634
21769
  path: RunDataset.from(guarded2).exportCsv(outPath),
21635
- rowsInfo: guarded2
21770
+ rowsInfo: guarded2,
21771
+ currentTable: false
21636
21772
  };
21637
21773
  }
21638
21774
  if (attempt < attempts && retryDelayMs > 0) {
@@ -21667,7 +21803,8 @@ ${commands.join("\n")}`,
21667
21803
  });
21668
21804
  return {
21669
21805
  path: RunDataset.from(guarded).exportCsv(outPath),
21670
- rowsInfo: guarded
21806
+ rowsInfo: guarded,
21807
+ currentTable: false
21671
21808
  };
21672
21809
  }
21673
21810
  function extractActiveRunsFromError(error) {
@@ -24018,6 +24155,11 @@ async function handleRunExport(args) {
24018
24155
  datasetPath
24019
24156
  });
24020
24157
  const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
24158
+ const currentTableNotice = exportResult?.currentTable ? {
24159
+ code: "CURRENT_SHARED_DATASET",
24160
+ message: "This CSV is the current shared dataset and may include writes from another run.",
24161
+ full_run_output_command: `deepline runs get ${status.runId} --full --json`
24162
+ } : null;
24021
24163
  const next = {
24022
24164
  ...buildRunNextCommands(status),
24023
24165
  export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
@@ -24029,6 +24171,7 @@ async function handleRunExport(args) {
24029
24171
  source,
24030
24172
  rowCount: exportResult?.rowsInfo.totalRows ?? null,
24031
24173
  columns: exportResult?.rowsInfo.columns ?? [],
24174
+ ...currentTableNotice ? { notice: currentTableNotice } : {},
24032
24175
  ...metadataOutPath ? { metadata_path: metadataOutPath } : {},
24033
24176
  local: { csv_path: exportResult?.path ?? null },
24034
24177
  next,
@@ -24038,6 +24181,10 @@ async function handleRunExport(args) {
24038
24181
  title: "run export",
24039
24182
  lines: [
24040
24183
  `Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
24184
+ ...currentTableNotice ? [
24185
+ "Current shared dataset: this CSV may include writes from another run.",
24186
+ `This run's full returned output: ${currentTableNotice.full_run_output_command}`
24187
+ ] : [],
24041
24188
  ...source ? [`source=${source}`] : []
24042
24189
  ]
24043
24190
  }
@@ -24495,51 +24642,18 @@ function compactPlaySchema(schema) {
24495
24642
  ).filter((field) => Boolean(field?.name)) : [];
24496
24643
  return fields.length > 0 ? { fields } : schema;
24497
24644
  }
24498
- function playSchemaMetadata(schema, key) {
24499
- if (!schema || typeof schema !== "object" || Array.isArray(schema))
24500
- return null;
24501
- const value = schema[key];
24502
- return value && typeof value === "object" && !Array.isArray(value) ? value : null;
24503
- }
24504
- function playRunCommand(play, options) {
24505
- const target = play.reference || play.name;
24506
- if (options?.csvInput) {
24507
- const inputField = typeof options.csvInput.inputField === "string" && options.csvInput.inputField.trim() ? options.csvInput.inputField.trim() : "csv";
24508
- return `deepline plays run ${target} --input '${JSON.stringify({ [inputField]: "leads.csv" })}' --watch`;
24509
- }
24510
- return `deepline plays run ${target} --input '{...}' --watch`;
24511
- }
24512
- function summarizePlayListItemForCli(play, options) {
24513
- const aliases = play.aliases ?? [];
24514
- const csvInput = playSchemaMetadata(play.inputSchema, "csvInput");
24515
- const rowOutputSchema = playSchemaMetadata(
24516
- play.outputSchema,
24517
- "rowOutputSchema"
24518
- );
24519
- const runCommand2 = playRunCommand(play, { csvInput });
24520
- const cloneEditStarter = buildCloneEditStarter(play);
24645
+ function summarizePlayGrepResult(play) {
24646
+ const reference = formatPlayListReference(play);
24521
24647
  return {
24522
- name: play.name,
24523
- ...play.reference ? { reference: play.reference } : {},
24524
- ...play.displayName ? { displayName: play.displayName } : {},
24525
- pinned: Boolean(play.pinned),
24526
- toolCategories: play.toolCategories ?? [],
24527
- origin: play.origin,
24528
- ownerType: play.ownerType,
24529
- canEdit: play.canEdit,
24530
- canClone: play.canClone,
24531
- aliases,
24532
- inputSchema: options?.compact ? compactPlaySchema(play.inputSchema) : play.inputSchema ?? null,
24533
- outputSchema: options?.compact ? compactPlaySchema(play.outputSchema) : play.outputSchema ?? null,
24534
- ...csvInput ? { csvInput } : {},
24535
- ...rowOutputSchema ? { rowOutputSchema } : {},
24536
- runCommand: runCommand2,
24537
- examples: [runCommand2],
24538
- ...cloneEditStarter ? { cloneEditStarter } : {},
24539
- currentPublishedVersion: play.currentPublishedVersion ?? null,
24540
- isDraftDirty: play.isDraftDirty
24648
+ name: play.displayName?.trim() || play.name,
24649
+ reference,
24650
+ matches: play.matches ?? [],
24651
+ describe: `deepline plays describe ${reference} --json`
24541
24652
  };
24542
24653
  }
24654
+ function formatPlayGrepMatches(matches) {
24655
+ return matches.map((match) => `${match.field}: ${match.terms.join(", ")}`).join("; ");
24656
+ }
24543
24657
  async function handlePlaySearch(args) {
24544
24658
  let options;
24545
24659
  try {
@@ -24598,28 +24712,32 @@ async function handlePlaySearch(args) {
24598
24712
  async function handlePlayGrep(args) {
24599
24713
  const query = args[0]?.trim();
24600
24714
  if (!query) {
24601
- console.error("Usage: deepline plays grep <query> [--compact] [--json]");
24715
+ console.error("Usage: deepline plays grep <query> [--json]");
24602
24716
  return 1;
24603
24717
  }
24604
- const compact = args.includes("--compact");
24605
24718
  const client2 = new DeeplineClient();
24606
- const plays = (await client2.listPlays({ grep: query })).map(
24607
- (play) => summarizePlayListItemForCli(play, { compact })
24719
+ const results = (await client2.listPlays({ grep: query })).map(
24720
+ summarizePlayGrepResult
24608
24721
  );
24609
24722
  if (argsWantJson(args)) {
24610
24723
  printCompactJson({
24611
- plays,
24612
- count: plays.length,
24724
+ plays: results,
24725
+ count: results.length,
24613
24726
  query,
24614
- grep: { engine: "convex_full_text" }
24727
+ grep: { query }
24615
24728
  });
24616
24729
  return 0;
24617
24730
  }
24618
- process.stdout.write(`${plays.length} plays found:
24731
+ process.stdout.write(
24732
+ `${results.length} results for ${JSON.stringify(query)}:
24619
24733
 
24620
- `);
24621
- for (const play of plays) {
24622
- printPlayDescription(play);
24734
+ `
24735
+ );
24736
+ for (const result of results) {
24737
+ console.log(result.name);
24738
+ const matches = formatPlayGrepMatches(result.matches);
24739
+ if (matches) console.log(` Matched: ${matches}`);
24740
+ console.log(` Describe: ${result.describe}`);
24623
24741
  console.log("");
24624
24742
  }
24625
24743
  return 0;
@@ -25455,7 +25573,7 @@ Notes:
25455
25573
  Examples:
25456
25574
  deepline plays search email
25457
25575
  deepline plays search email --all
25458
- deepline plays grep "linkedin to email" --compact --json
25576
+ deepline plays grep "linkedin to email" --json
25459
25577
  deepline plays describe prebuilt/person-linkedin-to-email --json
25460
25578
  `
25461
25579
  ).option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
@@ -25479,13 +25597,11 @@ Notes:
25479
25597
 
25480
25598
  Examples:
25481
25599
  deepline plays grep email --json
25482
- deepline plays grep "company contact" --compact --json
25483
25600
  deepline plays describe prebuilt/company-to-contact --json
25484
25601
  `
25485
- ).option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
25602
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
25486
25603
  process.exitCode = await handlePlayGrep([
25487
25604
  query,
25488
- ...options.compact ? ["--compact"] : [],
25489
25605
  ...options.json ? ["--json"] : []
25490
25606
  ]);
25491
25607
  });
@@ -32146,7 +32262,7 @@ function loadViewerAssets() {
32146
32262
  "viewer"
32147
32263
  )
32148
32264
  ] : [],
32149
- join12(process.cwd(), "apps", "deepline-api", "src", "lib", "cli", "viewer")
32265
+ join12(process.cwd(), "packages", "sdk", "assets", "viewer")
32150
32266
  ];
32151
32267
  for (const root of candidateRoots2) {
32152
32268
  try {
@@ -32431,7 +32547,7 @@ import { readFileSync as readFileSync11, writeFileSync as writeFileSync12 } from
32431
32547
  import { resolve as resolve14 } from "path";
32432
32548
  import { createInterface } from "readline/promises";
32433
32549
 
32434
- // src/monitor-fleet-contract.ts
32550
+ // ../integration-contracts/monitor-fleet-contract.ts
32435
32551
  var MONITOR_FLEET_MAX_MEMBERS = 1e3;
32436
32552
  var MONITOR_FLEET_AUTHORING_CONTRACT_EDITION = 1;
32437
32553
  var SUPPORTED_MONITOR_FLEET_AUTHORING_CONTRACT_EDITIONS = [
@@ -33117,9 +33233,35 @@ function renderMonitorDeployPlan(payload) {
33117
33233
  " Inspect: deepline monitors get <key> --json"
33118
33234
  );
33119
33235
  }
33236
+ const identityConflict = asRecord2(payload.identity_conflict);
33237
+ const identityOwner = identityConflict ? asRecord2(identityConflict.existing_monitor) : null;
33238
+ const identityOwnerKey = identityOwner ? asString(identityOwner.key) : void 0;
33239
+ const identityOwnerStatus = identityOwner ? asString(identityOwner.status) : void 0;
33240
+ if (identityConflict) {
33241
+ if (identityOwnerStatus === "provisioning") {
33242
+ lines.push(
33243
+ "",
33244
+ "An in-progress provider operation owns this upstream identity.",
33245
+ "Do not deploy this key yet. Wait, then rerun this dry run."
33246
+ );
33247
+ } else if (identityOwnerKey) {
33248
+ lines.push(
33249
+ "",
33250
+ `An existing monitor owns this upstream identity: ${identityOwnerKey}.`,
33251
+ `Inspect: deepline monitors get ${identityOwnerKey} --json`,
33252
+ "Do not deploy this key unless that conflict is resolved."
33253
+ );
33254
+ } else {
33255
+ lines.push(
33256
+ "",
33257
+ "An existing monitor owns this upstream identity.",
33258
+ "Do not deploy this key until that conflict is resolved."
33259
+ );
33260
+ }
33261
+ }
33120
33262
  lines.push(
33121
33263
  "",
33122
- valid ? "Deploy for real: re-run this command without --dry-run." : "Fix the definition, then re-run this command."
33264
+ identityConflict ? "Do not deploy for real until this identity conflict clears." : valid ? "Deploy for real: re-run this command without --dry-run." : "Fix the definition, then re-run this command."
33123
33265
  );
33124
33266
  return `${lines.join("\n")}
33125
33267
  `;
@@ -33371,11 +33513,12 @@ async function handleMonitorsDeploy(definition, options) {
33371
33513
  dryRun: true
33372
33514
  });
33373
33515
  const valid = payload2.valid !== false;
33516
+ const hasIdentityConflict = Boolean(asRecord2(payload2)?.identity_conflict);
33374
33517
  printCommandEnvelope(
33375
33518
  { dry_run: true, ...payload2 },
33376
33519
  { json: options.json, text: renderMonitorDeployPlan(payload2) }
33377
33520
  );
33378
- if (!valid) {
33521
+ if (!valid || hasIdentityConflict) {
33379
33522
  process.exitCode = 7;
33380
33523
  }
33381
33524
  return;
@@ -36709,7 +36852,8 @@ function renderSecret(secret) {
36709
36852
  const added = new Date(secret.createdAt).toISOString();
36710
36853
  const updated = new Date(secret.updatedAt).toISOString();
36711
36854
  const lastUsed = secret.lastUsedAt ? `, last used ${new Date(secret.lastUsedAt).toISOString()}` : ", never used";
36712
- return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}, added ${added}${updated !== added ? `, updated ${updated}` : ""}${lastUsed}`;
36855
+ const note = secret.note ? `, note ${JSON.stringify(secret.note)}` : "";
36856
+ return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}${note}, added ${added}${updated !== added ? `, updated ${updated}` : ""}${lastUsed}`;
36713
36857
  }
36714
36858
  async function readHiddenLine(prompt, streams = {}) {
36715
36859
  const inputStream = streams.input ?? input;
@@ -36916,7 +37060,8 @@ async function handleSet2(nameInput, forbidden, options) {
36916
37060
  name,
36917
37061
  value,
36918
37062
  scope,
36919
- ...playName ? { playName } : {}
37063
+ ...playName ? { playName } : {},
37064
+ ...options.note !== void 0 ? { note: options.note } : {}
36920
37065
  }
36921
37066
  );
36922
37067
  const secret = response.secret;
@@ -36939,6 +37084,57 @@ async function handleSet2(nameInput, forbidden, options) {
36939
37084
  { json: options.json }
36940
37085
  );
36941
37086
  }
37087
+ async function handleNote(secretId, noteInput, options) {
37088
+ if (options.clear && noteInput !== void 0) {
37089
+ throw new Error("Pass either a note or --clear, not both.");
37090
+ }
37091
+ if (!options.clear && noteInput === void 0) {
37092
+ throw new Error("Provide a note or use --clear.");
37093
+ }
37094
+ const note = options.clear ? "" : noteInput;
37095
+ if (options.dryRun) {
37096
+ printCommandEnvelope(
37097
+ {
37098
+ ok: true,
37099
+ dryRun: true,
37100
+ secretId,
37101
+ note,
37102
+ render: {
37103
+ sections: [
37104
+ {
37105
+ title: "secret note",
37106
+ lines: [
37107
+ options.clear ? `Would clear the note on secret ${secretId}.` : `Would save a note on secret ${secretId}.`
37108
+ ]
37109
+ }
37110
+ ]
37111
+ }
37112
+ },
37113
+ { json: options.json }
37114
+ );
37115
+ return;
37116
+ }
37117
+ const client2 = new DeeplineClient();
37118
+ const secret = await client2.updateSecretNote(secretId, note);
37119
+ printCommandEnvelope(
37120
+ {
37121
+ ok: true,
37122
+ secret,
37123
+ render: {
37124
+ sections: [
37125
+ {
37126
+ title: "secret note saved",
37127
+ lines: [
37128
+ secret.note ? `${secret.name}: note saved.` : `${secret.name}: note cleared.`,
37129
+ renderSecret(secret)
37130
+ ]
37131
+ }
37132
+ ]
37133
+ }
37134
+ },
37135
+ { json: options.json }
37136
+ );
37137
+ }
36942
37138
  function registerSecretsCommands(program) {
36943
37139
  const secrets = program.command("secrets").description("Manage play secrets without revealing values.").addHelpText(
36944
37140
  "after",
@@ -36946,8 +37142,8 @@ function registerSecretsCommands(program) {
36946
37142
  Notes:
36947
37143
  Secret values are never accepted as command arguments. Use the hidden prompt,
36948
37144
  or one explicit non-argv source: --value-stdin, --from-env NAME, or
36949
- --from-file PATH. Values are never printed. secrets list shows only status,
36950
- added, updated, and last-used metadata.
37145
+ --from-file PATH. Values are never printed. secrets list shows only metadata,
37146
+ including any note you intentionally added.
36951
37147
 
36952
37148
  Examples:
36953
37149
  deepline secrets list
@@ -36957,6 +37153,9 @@ Examples:
36957
37153
  printf %s "$HUBSPOT_TOKEN" | deepline secrets set HUBSPOT_TOKEN --value-stdin
36958
37154
  deepline secrets set HUBSPOT_TOKEN --from-env HUBSPOT_TOKEN
36959
37155
  deepline secrets set HUBSPOT_TOKEN --from-file ./hubspot-token.txt
37156
+ deepline secrets set HUBSPOT_TOKEN --note "Chrome extension \u2014 Avery"
37157
+ deepline secrets note <secret-id> "Chrome extension \u2014 Avery"
37158
+ deepline secrets note <secret-id> --clear
36960
37159
  `
36961
37160
  );
36962
37161
  secrets.command("list").description("List secret metadata only.").option("--json", "Emit JSON output").action(async (options) => {
@@ -36970,11 +37169,19 @@ Examples:
36970
37169
  ).option("--json", "Emit JSON output").action(async (name, options) => {
36971
37170
  await handleCheck(name, options);
36972
37171
  });
36973
- secrets.command("set").description("Set or rotate a secret without exposing its value in argv.").argument("<name>", "Secret name").argument("[forbidden...]", "Do not pass secret values here").option("--json", "Emit JSON output").option("--scope <scope>", "Secret scope: org or play", "org").option("--play <name>", "Play name for play-scoped secrets").option("--value-stdin", "Read the value from piped stdin").option("--from-env <name>", "Read the value from an environment variable").option("--from-file <path>", "Read the value from a file").action(
37172
+ secrets.command("set").description("Set or rotate a secret without exposing its value in argv.").argument("<name>", "Secret name").argument("[forbidden...]", "Do not pass secret values here").option("--json", "Emit JSON output").option("--scope <scope>", "Secret scope: org or play", "org").option("--play <name>", "Play name for play-scoped secrets").option(
37173
+ "--note <note>",
37174
+ "Optional non-sensitive memo (maximum 500 characters)"
37175
+ ).option("--value-stdin", "Read the value from piped stdin").option("--from-env <name>", "Read the value from an environment variable").option("--from-file <path>", "Read the value from a file").action(
36974
37176
  async (name, forbidden, options) => {
36975
37177
  await handleSet2(name, forbidden ?? [], options);
36976
37178
  }
36977
37179
  );
37180
+ secrets.command("note").description("Add, replace, or clear a non-sensitive note on one secret.").argument("<secret-id>", "Secret ID from `deepline secrets list --json`").argument("[note]", "Note text (maximum 500 characters)").option("--clear", "Clear the existing note").option("--dry-run", "Show the note change without saving it").option("--json", "Emit JSON output").action(
37181
+ async (secretId, note, options) => {
37182
+ await handleNote(secretId, note, options);
37183
+ }
37184
+ );
36978
37185
  }
36979
37186
 
36980
37187
  // src/cli/commands/setup.ts