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
package/dist/cli/index.js CHANGED
@@ -1297,27 +1297,22 @@ var SDK_RELEASE = {
1297
1297
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1298
1298
  // getters keep their established compatibility behavior.
1299
1299
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
1300
- // 0.3.90 is the first deliberately versioned SDK release for API v3. Play
1301
- // grep hard-cuts to the single Convex full-text index; it does not retain a
1302
- // registry/scanner reader for any SDK/API major.
1303
- version: "0.3.90",
1304
- 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.",
1300
+ // 0.3.90 is the first deliberately versioned SDK release for API v3.
1301
+ version: "0.3.92",
1302
+ 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.",
1305
1303
  packageCapabilities: {
1306
1304
  updatePreferences: 1
1307
1305
  },
1308
1306
  contracts: {
1309
1307
  api: {
1310
1308
  name: "sdk-http-api",
1311
- // API v3 hard-cuts Play grep to the canonical Convex index. API v2 stays
1312
- // admitted for the explicit SDK support window, but it selects neither a
1313
- // registry scanner nor another grep reader: every accepted grep request
1314
- // uses the same indexed query and retired flags fail at the API boundary.
1309
+ // Concise Play grep has the current wire id. Older ids follow the
1310
+ // standard API support window.
1315
1311
  currentMajor: 3,
1316
1312
  supportedMajors: [3, 2],
1317
- // The first wire id is emitted by the current SDK. Remaining ids are
1318
- // accepted only while the API v2 support window is open.
1313
+ // Older ids remain subject to the API support window.
1319
1314
  legacyWireIds: [
1320
- "2026-09-play-grep-convex-index-hard-cutover",
1315
+ "2026-09-play-grep-concise-results",
1321
1316
  "2026-07-admin-cli-local-cutover",
1322
1317
  "2026-07-native-monitor-launch-hard-cutover"
1323
1318
  ]
@@ -5189,9 +5184,19 @@ var DeeplineClient = class {
5189
5184
  targetStatus: () => this.getTargetBillingStatus(),
5190
5185
  autoRecharge: {
5191
5186
  get: () => this.getTargetAutoRecharge(),
5187
+ trigger: (options2) => this.http.post(
5188
+ "/api/v2/billing/auto-recharge/trigger",
5189
+ {},
5190
+ {
5191
+ "Idempotency-Key": requireTargetBillingIdempotencyKey(
5192
+ options2?.idempotencyKey ?? globalThis.crypto.randomUUID()
5193
+ )
5194
+ }
5195
+ ),
5192
5196
  update: (options2) => this.updateTargetAutoRecharge(options2)
5193
5197
  },
5194
5198
  purchaseCredits: (options2) => this.purchaseTargetBillingCredits(options2),
5199
+ recoverCreditPurchase: (options2) => this.recoverTargetBillingCreditPurchase(options2),
5195
5200
  transitionPlan: (options2) => this.transitionTargetBillingPlan(options2),
5196
5201
  portalSession: () => this.createTargetBillingPortalSession()
5197
5202
  };
@@ -5360,6 +5365,14 @@ var DeeplineClient = class {
5360
5365
  if (options.playName !== void 0) params.set("play", options.playName);
5361
5366
  return this.http.get(`/api/v2/secrets?${params.toString()}`);
5362
5367
  }
5368
+ /** Add, replace, or clear the non-sensitive note attached to one secret. */
5369
+ async updateSecretNote(secretId, note) {
5370
+ const response = await this.http.patch(
5371
+ `/api/v2/secrets/${encodeURIComponent(secretId)}`,
5372
+ { note }
5373
+ );
5374
+ return response.secret;
5375
+ }
5363
5376
  // ——————————————————————————————————————————————————————————
5364
5377
  // Tools
5365
5378
  // ——————————————————————————————————————————————————————————
@@ -7553,7 +7566,8 @@ var DeeplineClient = class {
7553
7566
  options.enabled ? {
7554
7567
  enabled: true,
7555
7568
  threshold_credits: options.thresholdCredits,
7556
- refill_to_credits: options.refillToCredits
7569
+ refill_to_credits: options.refillToCredits,
7570
+ ...options.purchaseLimitCents !== void 0 ? { purchase_limit_cents: options.purchaseLimitCents } : {}
7557
7571
  } : { enabled: false },
7558
7572
  { "Idempotency-Key": idempotencyKey }
7559
7573
  );
@@ -7574,6 +7588,39 @@ var DeeplineClient = class {
7574
7588
  { maxRetries: 0, exactUrlOnly: true }
7575
7589
  );
7576
7590
  }
7591
+ /** Recover only the original workspace, credit amount, and purchase key; never charge. */
7592
+ async recoverTargetBillingCreditPurchase(options) {
7593
+ if (typeof options.idempotencyKey !== "string") {
7594
+ throw new DeeplineError(
7595
+ "The original billing idempotencyKey is required.",
7596
+ void 0,
7597
+ "INVALID_BILLING_IDEMPOTENCY_KEY"
7598
+ );
7599
+ }
7600
+ const idempotencyKey = requireTargetBillingIdempotencyKey(
7601
+ options.idempotencyKey
7602
+ );
7603
+ if (!Number.isSafeInteger(options.credits) || options.credits <= 0) {
7604
+ throw new DeeplineError(
7605
+ "credits must be a positive safe integer.",
7606
+ void 0,
7607
+ "INVALID_CREDITS"
7608
+ );
7609
+ }
7610
+ if (typeof options.orgId !== "string" || !options.orgId.trim() || options.orgId !== options.orgId.trim()) {
7611
+ throw new DeeplineError(
7612
+ "The original orgId is required without surrounding whitespace.",
7613
+ void 0,
7614
+ "INVALID_ORG_ID"
7615
+ );
7616
+ }
7617
+ return this.http.post(
7618
+ "/api/v2/billing/credit-purchases/recover",
7619
+ { credits: options.credits, org_id: options.orgId },
7620
+ { "Idempotency-Key": idempotencyKey },
7621
+ { maxRetries: 0, exactUrlOnly: true }
7622
+ );
7623
+ }
7577
7624
  /**
7578
7625
  * Start, change, cancel, or restore a target plan through one idempotent
7579
7626
  * commercial operation.
@@ -10001,6 +10048,17 @@ async function handleBalance(options) {
10001
10048
  const needsCredits = status === "no_billing" || status === "zero_balance" || status === "payment_method_only";
10002
10049
  const recovery = needsCredits ? balanceRecoveryForCredits() : null;
10003
10050
  const lines = [`Balance: ${payload.balance ?? "(unknown)"} credits`];
10051
+ const temporaryHolds = payload.temporary_hold_credits;
10052
+ if (typeof temporaryHolds === "number" && temporaryHolds > 0) {
10053
+ lines.push(
10054
+ `Temporarily reserved: ${temporaryHolds} credits \u2014 not charged; unused credits are released after final usage is calculated.`
10055
+ );
10056
+ } else if (temporaryHolds === null) {
10057
+ lines.push("Temporary reservation status is temporarily unavailable.");
10058
+ }
10059
+ if (payload.temporary_hold_credits_truncated === true) {
10060
+ lines.push("Temporary reservation total may be incomplete.");
10061
+ }
10004
10062
  if (status === "no_billing") {
10005
10063
  lines.push(
10006
10064
  "Billing: No billing account or payment method set up for this workspace."
@@ -10051,7 +10109,7 @@ async function handleUsage(options) {
10051
10109
  `Balance: ${payload.balance ?? "(unknown)"}`,
10052
10110
  `Last 30 days usage: ${last30Usage ?? "(unknown)"}`,
10053
10111
  ...Number.isFinite(temporaryHolds) && temporaryHolds > 0 ? [`Temporary holds: ${temporaryHolds}`] : [],
10054
- `Monthly limit: ${quota.enabled ? quota.monthly_credits_limit ?? "(unknown)" : "off"}`,
10112
+ `Monthly spend guidance: ${quota.enabled ? quota.monthly_credits_limit ?? "(unknown)" : "off"}`,
10055
10113
  ...options.runId && recent.run_id ? [
10056
10114
  `Run spend: ${(payload.run ?? {}).spent_credits ?? "(unknown)"} Deepline Credits`
10057
10115
  ] : [],
@@ -10083,9 +10141,9 @@ async function handleLimit(options) {
10083
10141
  "/api/v2/billing/limit"
10084
10142
  );
10085
10143
  const lines = payload.enabled ? [
10086
- `Monthly limit: ${payload.monthly_credits_limit ?? "(unknown)"}`,
10087
- `Remaining before cap: ${payload.remaining_credits ?? "(unknown)"}`
10088
- ] : ["Monthly limit: off"];
10144
+ `Monthly spend guidance: ${payload.monthly_credits_limit ?? "(unknown)"}`,
10145
+ "Enforcement: advisory; available balance remains the exact admission control."
10146
+ ] : ["Monthly spend guidance: off"];
10089
10147
  printCommandEnvelope(
10090
10148
  {
10091
10149
  ...payload,
@@ -10107,7 +10165,7 @@ async function handleSetLimit(credits, options) {
10107
10165
  sections: [
10108
10166
  {
10109
10167
  title: "billing limit",
10110
- lines: [`Monthly billing limit set to ${credits} credits.`]
10168
+ lines: [`Monthly spend guidance set to ${credits} credits.`]
10111
10169
  }
10112
10170
  ]
10113
10171
  }
@@ -10127,7 +10185,7 @@ async function handleLimitOff(options) {
10127
10185
  sections: [
10128
10186
  {
10129
10187
  title: "billing limit",
10130
- lines: ["Monthly billing limit is now off."]
10188
+ lines: ["Monthly spend guidance is now off."]
10131
10189
  }
10132
10190
  ]
10133
10191
  }
@@ -10263,42 +10321,28 @@ function planPriceText(priceUsd, priceInterval) {
10263
10321
  }
10264
10322
  return `$${priceUsd}${priceInterval ? `/${priceInterval}` : ""}`;
10265
10323
  }
10266
- function planRolloverText(rollover) {
10267
- const mode = rollover?.mode ?? "none";
10268
- if (mode === "none") return "no rollover";
10269
- if (mode === "bounded") {
10270
- return `rollover up to ${rollover?.max_credits ?? "(unknown)"} credits`;
10271
- }
10272
- return `rollover ${mode}`;
10324
+ function targetPlanLine(plan) {
10325
+ 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"}`;
10273
10326
  }
10274
10327
  async function handlePlans(options) {
10275
- const { http } = getAuthedHttpClient();
10276
- const payload = await http.get(
10277
- "/api/v2/billing/catalog/current"
10328
+ const client2 = new DeeplineClient();
10329
+ const payload = await client2.billing.targetPlans();
10330
+ const listedCurrentPlan = payload.plans.find(
10331
+ (plan) => plan.sku === payload.current_plan_sku
10278
10332
  );
10279
- const activePlan = payload.active_plan ?? {};
10280
- const plans = Array.isArray(payload.plans) ? payload.plans : [];
10281
- const meters = Array.isArray(payload.meters) ? payload.meters : Array.isArray(payload.metrics) ? payload.metrics : [];
10333
+ const currentPlan = listedCurrentPlan ?? (await client2.billing.targetStatus()).plan;
10282
10334
  const lines = [
10283
- `Catalog: ${payload.catalog_id ?? "(unknown)"} (version ${payload.catalog_version ?? "(unknown)"})`,
10284
- `Active plan: ${activePlan.public_name ?? "(unknown)"} (${activePlan.plan_version_id ?? "(unknown)"})`,
10285
- `Assigned by: ${activePlan.assigned_by ?? "default"} | subscription: ${activePlan.has_subscription ? "yes" : "no"}`,
10286
- ...plans.length === 0 ? ["Plans: none published"] : [
10287
- "Plans:",
10288
- ...plans.map(
10289
- (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"}`
10290
- )
10291
- ],
10292
- ...meters.length === 0 ? ["Metrics: none"] : [
10293
- "Metrics:",
10294
- ...meters.map(
10295
- (meter) => `${meter.id ?? "(unknown)"} | ${meter.name ?? "(unknown)"}`
10296
- )
10297
- ]
10335
+ `Current plan: ${currentPlan.name} (${currentPlan.sku}) | ${planPriceText(currentPlan.recurring_price_usd, currentPlan.interval)} | ${currentPlan.included_credits ?? "(unknown)"} included credits/month`,
10336
+ `Pending plan: ${payload.pending_plan_sku ?? "none"}`,
10337
+ `Plan changes: ${payload.acquisition_enabled ? "enabled" : "disabled"}`,
10338
+ ...payload.plans.length === 0 ? ["Plans: none available"] : ["Plans:", ...payload.plans.map(targetPlanLine)],
10339
+ "Change plan: deepline billing change-plan <plan_sku> --json"
10298
10340
  ];
10341
+ const legacyPayload = shouldEmitJson(options.json) ? await client2.billing.plans() : null;
10299
10342
  printCommandEnvelope(
10300
10343
  {
10301
- ...payload,
10344
+ ...legacyPayload ?? payload,
10345
+ ...legacyPayload ? { target_billing: payload } : {},
10302
10346
  render: { sections: [{ title: "billing plans", lines }] }
10303
10347
  },
10304
10348
  { json: options.json }
@@ -10673,7 +10717,10 @@ async function handleAutoRechargeStatus(options) {
10673
10717
  const lines = [
10674
10718
  `State: ${state}`,
10675
10719
  ...payload.threshold_credits !== null ? [`Threshold: ${payload.threshold_credits} credits`] : [],
10676
- ...payload.refill_to_credits !== null ? [`Refill balance to: ${payload.refill_to_credits} credits`] : []
10720
+ ...payload.refill_to_credits !== null ? [`Refill balance to: ${payload.refill_to_credits} credits`] : [],
10721
+ ...payload.purchase_limit_cents !== void 0 ? [
10722
+ payload.purchase_limit_cents === null ? "Automatic purchase cap: none" : `Automatic purchase cap: $${(payload.purchase_limit_cents / 100).toFixed(2)} per rolling 30 days`
10723
+ ] : []
10677
10724
  ];
10678
10725
  printCommandEnvelope(
10679
10726
  {
@@ -10687,6 +10734,18 @@ async function handleAutoRechargeStatus(options) {
10687
10734
  async function handleAutoRechargeSet(options) {
10688
10735
  const thresholdCredits = parseTopUpCredits(options.thresholdCredits);
10689
10736
  const refillToCredits = parseTopUpCredits(options.refillToCredits);
10737
+ const rollingLimitCents = options.purchaseLimitCents === void 0 ? void 0 : options.purchaseLimitCents === "none" ? null : Number(options.purchaseLimitCents);
10738
+ if (rollingLimitCents !== void 0 && rollingLimitCents !== null && (!Number.isSafeInteger(rollingLimitCents) || rollingLimitCents <= 0)) {
10739
+ reportBillingFailure(
10740
+ {
10741
+ exitCode: 2,
10742
+ code: "INVALID_AUTO_RECHARGE_CONFIGURATION",
10743
+ message: "--purchase-limit-cents must be a positive whole number of USD cents or none."
10744
+ },
10745
+ options
10746
+ );
10747
+ return;
10748
+ }
10690
10749
  if (thresholdCredits === null || refillToCredits === null || refillToCredits <= thresholdCredits) {
10691
10750
  reportBillingFailure(
10692
10751
  {
@@ -10711,7 +10770,8 @@ async function handleAutoRechargeSet(options) {
10711
10770
  body: {
10712
10771
  enabled: true,
10713
10772
  threshold_credits: thresholdCredits,
10714
- refill_to_credits: refillToCredits
10773
+ refill_to_credits: refillToCredits,
10774
+ ...rollingLimitCents !== void 0 ? { purchase_limit_cents: rollingLimitCents } : {}
10715
10775
  }
10716
10776
  }
10717
10777
  },
@@ -10723,6 +10783,7 @@ async function handleAutoRechargeSet(options) {
10723
10783
  enabled: true,
10724
10784
  thresholdCredits,
10725
10785
  refillToCredits,
10786
+ ...rollingLimitCents !== void 0 ? { purchaseLimitCents: rollingLimitCents } : {},
10726
10787
  idempotencyKey
10727
10788
  });
10728
10789
  printCommandEnvelope(
@@ -10780,6 +10841,60 @@ async function handleBuyCredits(creditsRaw, options) {
10780
10841
  { json: options.json }
10781
10842
  );
10782
10843
  }
10844
+ async function handleTopUpRecover(creditsRaw, options) {
10845
+ const credits = parseTopUpCredits(creditsRaw);
10846
+ if (credits === null) {
10847
+ reportBillingFailure(
10848
+ {
10849
+ exitCode: 2,
10850
+ code: "INVALID_CREDITS",
10851
+ message: "<credits> must be a positive integer."
10852
+ },
10853
+ options
10854
+ );
10855
+ return;
10856
+ }
10857
+ const failure = !options.orgId?.trim() || options.orgId !== options.orgId.trim() ? {
10858
+ code: "INVALID_ORG_ID",
10859
+ message: "--org-id must be the original workspace ID without surrounding whitespace."
10860
+ } : !options.idempotencyKey || options.idempotencyKey.length > 200 || options.idempotencyKey !== options.idempotencyKey.trim() ? {
10861
+ code: "INVALID_BILLING_IDEMPOTENCY_KEY",
10862
+ message: "--idempotency-key must be the original key (1\u2013200 characters without surrounding whitespace)."
10863
+ } : null;
10864
+ if (failure) {
10865
+ reportBillingFailure(
10866
+ {
10867
+ exitCode: 2,
10868
+ ...failure
10869
+ },
10870
+ options
10871
+ );
10872
+ return;
10873
+ }
10874
+ if (options.dryRun) {
10875
+ printCommandEnvelope(
10876
+ {
10877
+ ok: true,
10878
+ dry_run: true,
10879
+ method: "POST",
10880
+ path: "/api/v2/billing/credit-purchases/recover",
10881
+ idempotency_key: options.idempotencyKey,
10882
+ body: { credits, org_id: options.orgId }
10883
+ },
10884
+ { json: options.json }
10885
+ );
10886
+ return;
10887
+ }
10888
+ const payload = await new DeeplineClient().billing.recoverCreditPurchase({
10889
+ credits,
10890
+ orgId: options.orgId,
10891
+ idempotencyKey: options.idempotencyKey
10892
+ });
10893
+ printCommandEnvelope(
10894
+ { ok: true, idempotency_key: options.idempotencyKey, ...payload },
10895
+ { json: options.json }
10896
+ );
10897
+ }
10783
10898
  async function handleTargetPlan(planSku, options) {
10784
10899
  if (planSku !== "payg-v1" && planSku !== "builder-v1" && planSku !== "growth-v1" && planSku !== "growth-canary-v1" && planSku !== "team-v1") {
10785
10900
  reportBillingFailure(
@@ -10897,35 +11012,36 @@ Examples:
10897
11012
  "--cursor <cursor>",
10898
11013
  "Recent-call cursor from the previous response"
10899
11014
  ).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);
10900
- billing.command("limit").description("Show configured monthly limit state.").addHelpText(
11015
+ billing.command("limit").description("Show configured monthly spend guidance.").addHelpText(
10901
11016
  "after",
10902
11017
  `
10903
11018
  Notes:
10904
- Read-only. Shows whether the monthly workspace cap is enabled and how many
10905
- Deepline credits remain before the cap.
11019
+ Read-only. Shows whether monthly workspace spend guidance is enabled.
11020
+ Guidance does not reject funded work; available balance remains exact.
10906
11021
 
10907
11022
  Examples:
10908
11023
  deepline billing limit
10909
11024
  deepline billing limit --json
10910
11025
  `
10911
11026
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLimit);
10912
- billing.command("set-limit").description("Set monthly credit cap.").addHelpText(
11027
+ billing.command("set-limit").description("Set monthly spend guidance.").addHelpText(
10913
11028
  "after",
10914
11029
  `
10915
11030
  Notes:
10916
11031
  Mutates workspace billing settings. The argument is a Deepline credit amount,
10917
- not dollars and not provider credits.
11032
+ not dollars and not provider credits. Guidance is advisory; it does not
11033
+ replace the exact available-balance admission check.
10918
11034
 
10919
11035
  Examples:
10920
11036
  deepline billing set-limit 500
10921
11037
  deepline billing set-limit 500 --json
10922
11038
  `
10923
11039
  ).argument("<credits>", "Monthly credits limit").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleSetLimit);
10924
- billing.command("off").description("Disable monthly credit cap.").addHelpText(
11040
+ billing.command("off").description("Disable monthly spend guidance.").addHelpText(
10925
11041
  "after",
10926
11042
  `
10927
11043
  Notes:
10928
- Mutates workspace billing settings by removing the monthly Deepline credit cap.
11044
+ Mutates workspace billing settings by removing monthly Deepline spend guidance.
10929
11045
 
10930
11046
  Examples:
10931
11047
  deepline billing off
@@ -11023,6 +11139,18 @@ Examples:
11023
11139
  "Stable retry key for the same intended top-up"
11024
11140
  ).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);
11025
11141
  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);
11142
+ billing.command("top-up-recover").description(
11143
+ "Inspect or retire an original top-up intent without starting a payment."
11144
+ ).argument("<credits>", "Original positive integer Deepline credit amount").requiredOption(
11145
+ "--org-id <original-org>",
11146
+ "Original workspace ID (must match the authenticated workspace)"
11147
+ ).requiredOption(
11148
+ "--idempotency-key <original-key>",
11149
+ "Original purchase key; never generates a new key"
11150
+ ).option("--dry-run", "Print the recovery request without changing state").option("--json", "Emit JSON output. Also automatic when stdout is piped").addHelpText(
11151
+ "after",
11152
+ "\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"
11153
+ ).action(handleTopUpRecover);
11026
11154
  billing.command("status").description("Show normalized target billing state.").option("--json", "Emit JSON output").action(handleTargetStatus);
11027
11155
  billing.command("auto-recharge").description("Inspect and manage automatic Deepline credit recharge.").addHelpText(
11028
11156
  "after",
@@ -11043,11 +11171,21 @@ Examples:
11043
11171
  ).requiredOption(
11044
11172
  "--refill-to-credits <credits>",
11045
11173
  "Recharge the balance to this amount"
11174
+ ).option(
11175
+ "--purchase-limit-cents <cents>",
11176
+ "Limit automatic purchases over rolling 30 days (USD cents)"
11046
11177
  ).option("--idempotency-key <key>", "Stable retry key").option("--dry-run", "Print the planned update without applying it").option("--json", "Emit JSON output").action(handleAutoRechargeSet)
11047
11178
  ).addCommand(
11048
11179
  new import_commander.Command("off").description(
11049
11180
  "Disable automatic recharge without clearing saved amounts."
11050
11181
  ).option("--idempotency-key <key>", "Stable retry key").option("--dry-run", "Print the planned update without applying it").option("--json", "Emit JSON output").action(handleAutoRechargeOff)
11182
+ ).addCommand(
11183
+ new import_commander.Command("trigger").description(
11184
+ "Evaluate capped automatic recharge and resume any pending purchase."
11185
+ ).option("--json", "Emit JSON output").action(async (options) => {
11186
+ const result = await new DeeplineClient().billing.autoRecharge.trigger();
11187
+ printCommandEnvelope({ ok: true, ...result }, { json: options.json });
11188
+ })
11051
11189
  );
11052
11190
  billing.command("change-plan").description("Start or change the target billing plan.").argument(
11053
11191
  "<plan_sku>",
@@ -11059,11 +11197,11 @@ Examples:
11059
11197
  "after",
11060
11198
  `
11061
11199
  Notes:
11062
- Read-only. Answers "what plans exist and what am I on": each plan's price,
11063
- monthly grant credits, rollover policy, and whether it is open for
11064
- subscription, plus the catalog's usage metrics. All amounts are Deepline
11065
- credits and Deepline-facing USD, never raw provider spend. Subscribe to a
11066
- listed plan with: deepline billing subscribe <plan_version_id>
11200
+ Read-only. Shows the current target billing plan, pending plan, and every
11201
+ visible plan's recurring price, included credits, purchased-credit price,
11202
+ and current acquisition availability. All amounts are Deepline credits and
11203
+ Deepline-facing USD, never raw provider spend. Change to an available plan
11204
+ with: deepline billing change-plan <plan_sku>
11067
11205
 
11068
11206
  Examples:
11069
11207
  deepline billing plans
@@ -11085,7 +11223,7 @@ Examples:
11085
11223
  deepline billing subscribe runtime-395-2026-07-v1
11086
11224
  deepline billing subscribe runtime-395-2026-07-v1 --no-open --json
11087
11225
  `
11088
- ).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);
11226
+ ).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);
11089
11227
  billing.command("subscription").description("Inspect and manage subscription state for the workspace.").addHelpText(
11090
11228
  "after",
11091
11229
  `
@@ -11344,6 +11482,7 @@ function mergeCanonicalRowsInfo(left, right) {
11344
11482
  ...right.recoveredReturnPaths ?? []
11345
11483
  ])
11346
11484
  ];
11485
+ const currentTable = left.currentTable || right.currentTable;
11347
11486
  return {
11348
11487
  ...fallback,
11349
11488
  ...preferred,
@@ -11357,6 +11496,7 @@ function mergeCanonicalRowsInfo(left, right) {
11357
11496
  tableNamespace: preferred.tableNamespace ?? fallback.tableNamespace,
11358
11497
  ...left.recovered || right.recovered ? { recovered: true } : {},
11359
11498
  ...recoveredReturnPaths2.length ? { recoveredReturnPaths: recoveredReturnPaths2 } : {},
11499
+ ...currentTable ? { currentTable: true } : {},
11360
11500
  ...exportUnavailableReason ? {
11361
11501
  exportUnavailableReason,
11362
11502
  ...unavailableSource?.exportUnavailableMessage ? {
@@ -11417,6 +11557,11 @@ function isSerializedDataset(value) {
11417
11557
  function isPackagedDatasetOutput(value) {
11418
11558
  return isRecord8(value) && value.kind === "dataset" && isRecord8(value.preview) && Array.isArray(value.preview.rows);
11419
11559
  }
11560
+ function hasCurrentTableExport(value) {
11561
+ if (!isRecord8(value) || !isRecord8(value.actions)) return false;
11562
+ const exportCsv = value.actions.exportCsv;
11563
+ return isRecord8(exportCsv) && isRecord8(exportCsv.scope) && exportCsv.scope.kind === "database" && exportCsv.scope.mutability === "current";
11564
+ }
11420
11565
  function recoveredReturnPaths(value) {
11421
11566
  if (!Array.isArray(value)) return [];
11422
11567
  return [
@@ -11523,6 +11668,7 @@ function canonicalRowsInfoFromCandidate(input2) {
11523
11668
  datasetId: typeof candidate.value.datasetId === "string" ? candidate.value.datasetId : null,
11524
11669
  tableNamespace: typeof candidate.value.tableNamespace === "string" ? candidate.value.tableNamespace : null,
11525
11670
  ...candidate.value.recovered === true ? { recovered: true } : {},
11671
+ ...hasCurrentTableExport(candidate.value) ? { currentTable: true } : {},
11526
11672
  ...recoveredReturnPaths(candidate.value.recoveredReturnPaths).length ? {
11527
11673
  recoveredReturnPaths: recoveredReturnPaths(
11528
11674
  candidate.value.recoveredReturnPaths
@@ -20955,11 +21101,15 @@ function formatPackageDatasetActionLines(packaged) {
20955
21101
  ` ${category} dataset ${path}: ${rowCount === null ? "unknown rows" : `${formatInteger(rowCount)} ${rowCount === 1 ? "row" : "rows"}`}`
20956
21102
  );
20957
21103
  }
20958
- const exportCommand = actionToCommand(actions.exportCsv);
21104
+ const exportAction = readRecord(actions.exportCsv);
21105
+ const exportCommand = actionToCommand(exportAction);
21106
+ const exportScope = readRecord(exportAction?.scope);
20959
21107
  const currentQueryCommand = actionToCommand(actions.queryCurrentTable);
20960
21108
  const legacyQueryCommand = actionToCommand(actions.query);
20961
21109
  if (exportCommand) {
20962
- lines.push(` export this run: ${exportCommand}`);
21110
+ lines.push(
21111
+ exportScope?.kind === "database" ? ` export current table (may include other runs): ${exportCommand}` : ` export this run: ${exportCommand}`
21112
+ );
20963
21113
  }
20964
21114
  if (currentQueryCommand) {
20965
21115
  lines.push(` query current table: ${currentQueryCommand}`);
@@ -21368,33 +21518,29 @@ function sqlSafeExportColumnName(id) {
21368
21518
  async function fetchBackingDatasetRows(input2) {
21369
21519
  const playName = extractRunPlayName(input2.status);
21370
21520
  const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
21521
+ const currentTable = input2.rowsInfo.currentTable === true;
21371
21522
  if (!playName || !tableNamespace) {
21372
21523
  return null;
21373
21524
  }
21374
21525
  const sheetRows = [];
21375
21526
  let offset = 0;
21376
- let expectedTotal = input2.rowsInfo.totalRows;
21377
21527
  while (true) {
21378
21528
  const page = await input2.client.runs.exportDatasetRows({
21379
21529
  playName,
21380
21530
  tableNamespace,
21381
- runId: input2.status.runId,
21531
+ ...currentTable ? {} : { runId: input2.status.runId },
21382
21532
  limit: RUN_EXPORT_PAGE_SIZE,
21383
21533
  offset,
21384
21534
  rowMode: "all"
21385
21535
  });
21386
21536
  sheetRows.push(...page.rows);
21387
- const summaryTotal = page.summary?.stats?.total;
21388
- if (typeof summaryTotal === "number" && Number.isFinite(summaryTotal)) {
21389
- expectedTotal = Math.max(expectedTotal, Math.trunc(summaryTotal));
21390
- }
21391
- if (page.rows.length < RUN_EXPORT_PAGE_SIZE || sheetRows.length >= expectedTotal) {
21537
+ if (page.rows.length < RUN_EXPORT_PAGE_SIZE) {
21392
21538
  break;
21393
21539
  }
21394
21540
  offset += page.rows.length;
21395
21541
  }
21396
21542
  const rows = sheetRows.map(exportableSheetRow).filter((row) => Boolean(row));
21397
- if (rows.length < input2.rowsInfo.totalRows) {
21543
+ if (!currentTable && rows.length < input2.rowsInfo.totalRows || currentTable && rows.length === 0 && input2.rowsInfo.totalRows > 0) {
21398
21544
  return null;
21399
21545
  }
21400
21546
  const columns = mergeExportColumns(
@@ -21407,6 +21553,7 @@ async function fetchBackingDatasetRows(input2) {
21407
21553
  columns,
21408
21554
  totalRows: rows.length,
21409
21555
  complete: true,
21556
+ ...currentTable ? { currentTable: true } : {},
21410
21557
  source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
21411
21558
  };
21412
21559
  }
@@ -21431,12 +21578,14 @@ function assertDatasetHasExportableRows(input2) {
21431
21578
  if (input2.rowsInfo.rows.length > 0) {
21432
21579
  return input2.rowsInfo;
21433
21580
  }
21581
+ if (input2.rowsInfo.currentTable === true && input2.rowsInfo.totalRows === 0) {
21582
+ return input2.rowsInfo;
21583
+ }
21434
21584
  const datasetLabel = input2.datasetPath ?? input2.rowsInfo.tableNamespace ?? input2.rowsInfo.source ?? "result.rows";
21435
21585
  const available = input2.availableRows.map((info) => info.tableNamespace ?? info.source).filter((name) => typeof name === "string");
21436
21586
  const runStatus = String(input2.status.status ?? "").toLowerCase();
21437
- const failedBeforePersisting = runStatus !== "completed";
21438
21587
  throw new DeeplineError(
21439
- `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."),
21588
+ `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."),
21440
21589
  void 0,
21441
21590
  "RUN_EXPORT_EMPTY",
21442
21591
  {
@@ -21447,23 +21596,6 @@ function assertDatasetHasExportableRows(input2) {
21447
21596
  }
21448
21597
  );
21449
21598
  }
21450
- function assertDatasetExportAvailable(input2) {
21451
- if (input2.rowsInfo.exportUnavailableReason !== "shared_table_namespace") {
21452
- return;
21453
- }
21454
- throw new DeeplineError(
21455
- input2.rowsInfo.exportUnavailableMessage ?? "Run CSV export is unavailable because multiple Dataset Handles share one physical table.",
21456
- void 0,
21457
- "RUN_EXPORT_UNAVAILABLE",
21458
- {
21459
- runId: input2.status.runId,
21460
- dataset: input2.rowsInfo.source,
21461
- datasetId: input2.rowsInfo.datasetId ?? null,
21462
- tableNamespace: input2.rowsInfo.tableNamespace ?? null,
21463
- reason: input2.rowsInfo.exportUnavailableReason
21464
- }
21465
- );
21466
- }
21467
21599
  async function exportPlayStatusRows(client2, status, outPath, options = {}) {
21468
21600
  if (!outPath) {
21469
21601
  return null;
@@ -21542,7 +21674,6 @@ ${commands.join("\n")}`,
21542
21674
  `Run ${status.runId} did not expose a row-shaped final output to export.`
21543
21675
  );
21544
21676
  }
21545
- assertDatasetExportAvailable({ rowsInfo, status });
21546
21677
  const attempts = Math.max(1, Math.trunc(options.attempts ?? 1));
21547
21678
  const retryDelayMs = Math.max(0, Math.trunc(options.retryDelayMs ?? 0));
21548
21679
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
@@ -21557,6 +21688,9 @@ ${commands.join("\n")}`,
21557
21688
  if (error instanceof DeeplineError && error.code === "RUN_EXPORT_SCOPE_MISMATCH") {
21558
21689
  throw error;
21559
21690
  }
21691
+ if (rowsInfo.currentTable) {
21692
+ throw error;
21693
+ }
21560
21694
  if (!rowsInfo.complete) {
21561
21695
  throw error;
21562
21696
  }
@@ -21570,7 +21704,8 @@ ${commands.join("\n")}`,
21570
21704
  });
21571
21705
  return {
21572
21706
  path: RunDataset.from(guarded2).exportCsv(outPath),
21573
- rowsInfo: guarded2
21707
+ rowsInfo: guarded2,
21708
+ currentTable: fetchedRowsInfo.currentTable === true
21574
21709
  };
21575
21710
  }
21576
21711
  if (rowsInfo.complete) {
@@ -21582,7 +21717,8 @@ ${commands.join("\n")}`,
21582
21717
  });
21583
21718
  return {
21584
21719
  path: RunDataset.from(guarded2).exportCsv(outPath),
21585
- rowsInfo: guarded2
21720
+ rowsInfo: guarded2,
21721
+ currentTable: false
21586
21722
  };
21587
21723
  }
21588
21724
  if (attempt < attempts && retryDelayMs > 0) {
@@ -21617,7 +21753,8 @@ ${commands.join("\n")}`,
21617
21753
  });
21618
21754
  return {
21619
21755
  path: RunDataset.from(guarded).exportCsv(outPath),
21620
- rowsInfo: guarded
21756
+ rowsInfo: guarded,
21757
+ currentTable: false
21621
21758
  };
21622
21759
  }
21623
21760
  function extractActiveRunsFromError(error) {
@@ -23968,6 +24105,11 @@ async function handleRunExport(args) {
23968
24105
  datasetPath
23969
24106
  });
23970
24107
  const source = exportResult?.rowsInfo.source ?? datasetPath ?? null;
24108
+ const currentTableNotice = exportResult?.currentTable ? {
24109
+ code: "CURRENT_SHARED_DATASET",
24110
+ message: "This CSV is the current shared dataset and may include writes from another run.",
24111
+ full_run_output_command: `deepline runs get ${status.runId} --full --json`
24112
+ } : null;
23971
24113
  const next = {
23972
24114
  ...buildRunNextCommands(status),
23973
24115
  export: runExportRetryCommand(status.runId, outPath, datasetPath ?? source)
@@ -23979,6 +24121,7 @@ async function handleRunExport(args) {
23979
24121
  source,
23980
24122
  rowCount: exportResult?.rowsInfo.totalRows ?? null,
23981
24123
  columns: exportResult?.rowsInfo.columns ?? [],
24124
+ ...currentTableNotice ? { notice: currentTableNotice } : {},
23982
24125
  ...metadataOutPath ? { metadata_path: metadataOutPath } : {},
23983
24126
  local: { csv_path: exportResult?.path ?? null },
23984
24127
  next,
@@ -23988,6 +24131,10 @@ async function handleRunExport(args) {
23988
24131
  title: "run export",
23989
24132
  lines: [
23990
24133
  `Exported ${status.runId} to ${exportResult?.path ?? outPath}`,
24134
+ ...currentTableNotice ? [
24135
+ "Current shared dataset: this CSV may include writes from another run.",
24136
+ `This run's full returned output: ${currentTableNotice.full_run_output_command}`
24137
+ ] : [],
23991
24138
  ...source ? [`source=${source}`] : []
23992
24139
  ]
23993
24140
  }
@@ -24445,51 +24592,18 @@ function compactPlaySchema(schema) {
24445
24592
  ).filter((field) => Boolean(field?.name)) : [];
24446
24593
  return fields.length > 0 ? { fields } : schema;
24447
24594
  }
24448
- function playSchemaMetadata(schema, key) {
24449
- if (!schema || typeof schema !== "object" || Array.isArray(schema))
24450
- return null;
24451
- const value = schema[key];
24452
- return value && typeof value === "object" && !Array.isArray(value) ? value : null;
24453
- }
24454
- function playRunCommand(play, options) {
24455
- const target = play.reference || play.name;
24456
- if (options?.csvInput) {
24457
- const inputField = typeof options.csvInput.inputField === "string" && options.csvInput.inputField.trim() ? options.csvInput.inputField.trim() : "csv";
24458
- return `deepline plays run ${target} --input '${JSON.stringify({ [inputField]: "leads.csv" })}' --watch`;
24459
- }
24460
- return `deepline plays run ${target} --input '{...}' --watch`;
24461
- }
24462
- function summarizePlayListItemForCli(play, options) {
24463
- const aliases = play.aliases ?? [];
24464
- const csvInput = playSchemaMetadata(play.inputSchema, "csvInput");
24465
- const rowOutputSchema = playSchemaMetadata(
24466
- play.outputSchema,
24467
- "rowOutputSchema"
24468
- );
24469
- const runCommand2 = playRunCommand(play, { csvInput });
24470
- const cloneEditStarter = buildCloneEditStarter(play);
24595
+ function summarizePlayGrepResult(play) {
24596
+ const reference = formatPlayListReference(play);
24471
24597
  return {
24472
- name: play.name,
24473
- ...play.reference ? { reference: play.reference } : {},
24474
- ...play.displayName ? { displayName: play.displayName } : {},
24475
- pinned: Boolean(play.pinned),
24476
- toolCategories: play.toolCategories ?? [],
24477
- origin: play.origin,
24478
- ownerType: play.ownerType,
24479
- canEdit: play.canEdit,
24480
- canClone: play.canClone,
24481
- aliases,
24482
- inputSchema: options?.compact ? compactPlaySchema(play.inputSchema) : play.inputSchema ?? null,
24483
- outputSchema: options?.compact ? compactPlaySchema(play.outputSchema) : play.outputSchema ?? null,
24484
- ...csvInput ? { csvInput } : {},
24485
- ...rowOutputSchema ? { rowOutputSchema } : {},
24486
- runCommand: runCommand2,
24487
- examples: [runCommand2],
24488
- ...cloneEditStarter ? { cloneEditStarter } : {},
24489
- currentPublishedVersion: play.currentPublishedVersion ?? null,
24490
- isDraftDirty: play.isDraftDirty
24598
+ name: play.displayName?.trim() || play.name,
24599
+ reference,
24600
+ matches: play.matches ?? [],
24601
+ describe: `deepline plays describe ${reference} --json`
24491
24602
  };
24492
24603
  }
24604
+ function formatPlayGrepMatches(matches) {
24605
+ return matches.map((match) => `${match.field}: ${match.terms.join(", ")}`).join("; ");
24606
+ }
24493
24607
  async function handlePlaySearch(args) {
24494
24608
  let options;
24495
24609
  try {
@@ -24548,28 +24662,32 @@ async function handlePlaySearch(args) {
24548
24662
  async function handlePlayGrep(args) {
24549
24663
  const query = args[0]?.trim();
24550
24664
  if (!query) {
24551
- console.error("Usage: deepline plays grep <query> [--compact] [--json]");
24665
+ console.error("Usage: deepline plays grep <query> [--json]");
24552
24666
  return 1;
24553
24667
  }
24554
- const compact = args.includes("--compact");
24555
24668
  const client2 = new DeeplineClient();
24556
- const plays = (await client2.listPlays({ grep: query })).map(
24557
- (play) => summarizePlayListItemForCli(play, { compact })
24669
+ const results = (await client2.listPlays({ grep: query })).map(
24670
+ summarizePlayGrepResult
24558
24671
  );
24559
24672
  if (argsWantJson(args)) {
24560
24673
  printCompactJson({
24561
- plays,
24562
- count: plays.length,
24674
+ plays: results,
24675
+ count: results.length,
24563
24676
  query,
24564
- grep: { engine: "convex_full_text" }
24677
+ grep: { query }
24565
24678
  });
24566
24679
  return 0;
24567
24680
  }
24568
- process.stdout.write(`${plays.length} plays found:
24681
+ process.stdout.write(
24682
+ `${results.length} results for ${JSON.stringify(query)}:
24569
24683
 
24570
- `);
24571
- for (const play of plays) {
24572
- printPlayDescription(play);
24684
+ `
24685
+ );
24686
+ for (const result of results) {
24687
+ console.log(result.name);
24688
+ const matches = formatPlayGrepMatches(result.matches);
24689
+ if (matches) console.log(` Matched: ${matches}`);
24690
+ console.log(` Describe: ${result.describe}`);
24573
24691
  console.log("");
24574
24692
  }
24575
24693
  return 0;
@@ -25405,7 +25523,7 @@ Notes:
25405
25523
  Examples:
25406
25524
  deepline plays search email
25407
25525
  deepline plays search email --all
25408
- deepline plays grep "linkedin to email" --compact --json
25526
+ deepline plays grep "linkedin to email" --json
25409
25527
  deepline plays describe prebuilt/person-linkedin-to-email --json
25410
25528
  `
25411
25529
  ).option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
@@ -25429,13 +25547,11 @@ Notes:
25429
25547
 
25430
25548
  Examples:
25431
25549
  deepline plays grep email --json
25432
- deepline plays grep "company contact" --compact --json
25433
25550
  deepline plays describe prebuilt/company-to-contact --json
25434
25551
  `
25435
- ).option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
25552
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
25436
25553
  process.exitCode = await handlePlayGrep([
25437
25554
  query,
25438
- ...options.compact ? ["--compact"] : [],
25439
25555
  ...options.json ? ["--json"] : []
25440
25556
  ]);
25441
25557
  });
@@ -32089,7 +32205,7 @@ function loadViewerAssets() {
32089
32205
  "viewer"
32090
32206
  )
32091
32207
  ] : [],
32092
- (0, import_node_path16.join)(process.cwd(), "apps", "deepline-api", "src", "lib", "cli", "viewer")
32208
+ (0, import_node_path16.join)(process.cwd(), "packages", "sdk", "assets", "viewer")
32093
32209
  ];
32094
32210
  for (const root of candidateRoots2) {
32095
32211
  try {
@@ -32374,7 +32490,7 @@ var import_node_fs15 = require("fs");
32374
32490
  var import_node_path17 = require("path");
32375
32491
  var import_promises8 = require("readline/promises");
32376
32492
 
32377
- // src/monitor-fleet-contract.ts
32493
+ // ../integration-contracts/monitor-fleet-contract.ts
32378
32494
  var MONITOR_FLEET_MAX_MEMBERS = 1e3;
32379
32495
  var MONITOR_FLEET_AUTHORING_CONTRACT_EDITION = 1;
32380
32496
  var SUPPORTED_MONITOR_FLEET_AUTHORING_CONTRACT_EDITIONS = [
@@ -33060,9 +33176,35 @@ function renderMonitorDeployPlan(payload) {
33060
33176
  " Inspect: deepline monitors get <key> --json"
33061
33177
  );
33062
33178
  }
33179
+ const identityConflict = asRecord2(payload.identity_conflict);
33180
+ const identityOwner = identityConflict ? asRecord2(identityConflict.existing_monitor) : null;
33181
+ const identityOwnerKey = identityOwner ? asString(identityOwner.key) : void 0;
33182
+ const identityOwnerStatus = identityOwner ? asString(identityOwner.status) : void 0;
33183
+ if (identityConflict) {
33184
+ if (identityOwnerStatus === "provisioning") {
33185
+ lines.push(
33186
+ "",
33187
+ "An in-progress provider operation owns this upstream identity.",
33188
+ "Do not deploy this key yet. Wait, then rerun this dry run."
33189
+ );
33190
+ } else if (identityOwnerKey) {
33191
+ lines.push(
33192
+ "",
33193
+ `An existing monitor owns this upstream identity: ${identityOwnerKey}.`,
33194
+ `Inspect: deepline monitors get ${identityOwnerKey} --json`,
33195
+ "Do not deploy this key unless that conflict is resolved."
33196
+ );
33197
+ } else {
33198
+ lines.push(
33199
+ "",
33200
+ "An existing monitor owns this upstream identity.",
33201
+ "Do not deploy this key until that conflict is resolved."
33202
+ );
33203
+ }
33204
+ }
33063
33205
  lines.push(
33064
33206
  "",
33065
- valid ? "Deploy for real: re-run this command without --dry-run." : "Fix the definition, then re-run this command."
33207
+ 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."
33066
33208
  );
33067
33209
  return `${lines.join("\n")}
33068
33210
  `;
@@ -33314,11 +33456,12 @@ async function handleMonitorsDeploy(definition, options) {
33314
33456
  dryRun: true
33315
33457
  });
33316
33458
  const valid = payload2.valid !== false;
33459
+ const hasIdentityConflict = Boolean(asRecord2(payload2)?.identity_conflict);
33317
33460
  printCommandEnvelope(
33318
33461
  { dry_run: true, ...payload2 },
33319
33462
  { json: options.json, text: renderMonitorDeployPlan(payload2) }
33320
33463
  );
33321
- if (!valid) {
33464
+ if (!valid || hasIdentityConflict) {
33322
33465
  process.exitCode = 7;
33323
33466
  }
33324
33467
  return;
@@ -36646,7 +36789,8 @@ function renderSecret(secret) {
36646
36789
  const added = new Date(secret.createdAt).toISOString();
36647
36790
  const updated = new Date(secret.updatedAt).toISOString();
36648
36791
  const lastUsed = secret.lastUsedAt ? `, last used ${new Date(secret.lastUsedAt).toISOString()}` : ", never used";
36649
- return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}, added ${added}${updated !== added ? `, updated ${updated}` : ""}${lastUsed}`;
36792
+ const note = secret.note ? `, note ${JSON.stringify(secret.note)}` : "";
36793
+ return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}${note}, added ${added}${updated !== added ? `, updated ${updated}` : ""}${lastUsed}`;
36650
36794
  }
36651
36795
  async function readHiddenLine(prompt, streams = {}) {
36652
36796
  const inputStream = streams.input ?? import_node_process.stdin;
@@ -36853,7 +36997,8 @@ async function handleSet2(nameInput, forbidden, options) {
36853
36997
  name,
36854
36998
  value,
36855
36999
  scope,
36856
- ...playName ? { playName } : {}
37000
+ ...playName ? { playName } : {},
37001
+ ...options.note !== void 0 ? { note: options.note } : {}
36857
37002
  }
36858
37003
  );
36859
37004
  const secret = response.secret;
@@ -36876,6 +37021,57 @@ async function handleSet2(nameInput, forbidden, options) {
36876
37021
  { json: options.json }
36877
37022
  );
36878
37023
  }
37024
+ async function handleNote(secretId, noteInput, options) {
37025
+ if (options.clear && noteInput !== void 0) {
37026
+ throw new Error("Pass either a note or --clear, not both.");
37027
+ }
37028
+ if (!options.clear && noteInput === void 0) {
37029
+ throw new Error("Provide a note or use --clear.");
37030
+ }
37031
+ const note = options.clear ? "" : noteInput;
37032
+ if (options.dryRun) {
37033
+ printCommandEnvelope(
37034
+ {
37035
+ ok: true,
37036
+ dryRun: true,
37037
+ secretId,
37038
+ note,
37039
+ render: {
37040
+ sections: [
37041
+ {
37042
+ title: "secret note",
37043
+ lines: [
37044
+ options.clear ? `Would clear the note on secret ${secretId}.` : `Would save a note on secret ${secretId}.`
37045
+ ]
37046
+ }
37047
+ ]
37048
+ }
37049
+ },
37050
+ { json: options.json }
37051
+ );
37052
+ return;
37053
+ }
37054
+ const client2 = new DeeplineClient();
37055
+ const secret = await client2.updateSecretNote(secretId, note);
37056
+ printCommandEnvelope(
37057
+ {
37058
+ ok: true,
37059
+ secret,
37060
+ render: {
37061
+ sections: [
37062
+ {
37063
+ title: "secret note saved",
37064
+ lines: [
37065
+ secret.note ? `${secret.name}: note saved.` : `${secret.name}: note cleared.`,
37066
+ renderSecret(secret)
37067
+ ]
37068
+ }
37069
+ ]
37070
+ }
37071
+ },
37072
+ { json: options.json }
37073
+ );
37074
+ }
36879
37075
  function registerSecretsCommands(program) {
36880
37076
  const secrets = program.command("secrets").description("Manage play secrets without revealing values.").addHelpText(
36881
37077
  "after",
@@ -36883,8 +37079,8 @@ function registerSecretsCommands(program) {
36883
37079
  Notes:
36884
37080
  Secret values are never accepted as command arguments. Use the hidden prompt,
36885
37081
  or one explicit non-argv source: --value-stdin, --from-env NAME, or
36886
- --from-file PATH. Values are never printed. secrets list shows only status,
36887
- added, updated, and last-used metadata.
37082
+ --from-file PATH. Values are never printed. secrets list shows only metadata,
37083
+ including any note you intentionally added.
36888
37084
 
36889
37085
  Examples:
36890
37086
  deepline secrets list
@@ -36894,6 +37090,9 @@ Examples:
36894
37090
  printf %s "$HUBSPOT_TOKEN" | deepline secrets set HUBSPOT_TOKEN --value-stdin
36895
37091
  deepline secrets set HUBSPOT_TOKEN --from-env HUBSPOT_TOKEN
36896
37092
  deepline secrets set HUBSPOT_TOKEN --from-file ./hubspot-token.txt
37093
+ deepline secrets set HUBSPOT_TOKEN --note "Chrome extension \u2014 Avery"
37094
+ deepline secrets note <secret-id> "Chrome extension \u2014 Avery"
37095
+ deepline secrets note <secret-id> --clear
36897
37096
  `
36898
37097
  );
36899
37098
  secrets.command("list").description("List secret metadata only.").option("--json", "Emit JSON output").action(async (options) => {
@@ -36907,11 +37106,19 @@ Examples:
36907
37106
  ).option("--json", "Emit JSON output").action(async (name, options) => {
36908
37107
  await handleCheck(name, options);
36909
37108
  });
36910
- 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(
37109
+ 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(
37110
+ "--note <note>",
37111
+ "Optional non-sensitive memo (maximum 500 characters)"
37112
+ ).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(
36911
37113
  async (name, forbidden, options) => {
36912
37114
  await handleSet2(name, forbidden ?? [], options);
36913
37115
  }
36914
37116
  );
37117
+ 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(
37118
+ async (secretId, note, options) => {
37119
+ await handleNote(secretId, note, options);
37120
+ }
37121
+ );
36915
37122
  }
36916
37123
 
36917
37124
  // src/cli/commands/setup.ts