deepline 0.3.88 → 0.3.89

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 (121) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +534 -4
  2. package/dist/bundling-sources/sdk/src/config.ts +77 -0
  3. package/dist/bundling-sources/sdk/src/http.ts +76 -30
  4. package/dist/bundling-sources/sdk/src/index.ts +6 -0
  5. package/dist/bundling-sources/sdk/src/monitor-fleet-contract.ts +1 -1
  6. package/dist/bundling-sources/sdk/src/play.ts +15 -1
  7. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +2 -2
  8. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  9. package/dist/bundling-sources/sdk/src/types.ts +83 -4
  10. package/dist/bundling-sources/shared_libs/integration-contracts/AGENTS.md +9 -0
  11. package/dist/bundling-sources/shared_libs/integration-contracts/README.md +3 -0
  12. package/dist/bundling-sources/shared_libs/integration-contracts/index.ts +2 -0
  13. package/dist/bundling-sources/shared_libs/monitors/analytics-install-guides.ts +77 -0
  14. package/dist/bundling-sources/shared_libs/monitors/billing/charges.ts +125 -0
  15. package/dist/bundling-sources/shared_libs/monitors/billing/policy-builders.ts +686 -0
  16. package/dist/bundling-sources/shared_libs/monitors/billing/pricing.ts +54 -0
  17. package/dist/bundling-sources/shared_libs/monitors/billing/public-pricing.ts +72 -0
  18. package/dist/bundling-sources/shared_libs/monitors/billing/session.ts +45 -0
  19. package/dist/bundling-sources/shared_libs/monitors/billing/state.ts +454 -0
  20. package/dist/bundling-sources/shared_libs/monitors/billing/tamradar.ts +260 -0
  21. package/dist/bundling-sources/shared_libs/monitors/billing/types.ts +215 -0
  22. package/dist/bundling-sources/shared_libs/monitors/callback-security.ts +333 -0
  23. package/dist/bundling-sources/shared_libs/monitors/cursor-page.ts +42 -0
  24. package/dist/bundling-sources/shared_libs/monitors/deactivation-reasons.ts +16 -0
  25. package/dist/bundling-sources/shared_libs/monitors/framework-managed-payload-fields.ts +71 -0
  26. package/dist/bundling-sources/shared_libs/monitors/generated/provider-monitor-callback-admission-targets.ts +16 -0
  27. package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +267 -0
  28. package/dist/bundling-sources/shared_libs/monitors/inbound-publish-key.ts +39 -0
  29. package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +82 -0
  30. package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +473 -0
  31. package/dist/bundling-sources/shared_libs/monitors/org-monitor-limits.ts +1 -1
  32. package/dist/bundling-sources/shared_libs/monitors/package.json +29 -0
  33. package/dist/bundling-sources/shared_libs/monitors/provider-callback-verification.ts +1125 -0
  34. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +263 -0
  35. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-capability.ts +964 -0
  36. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-consumer-health.ts +56 -0
  37. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-errors.ts +131 -0
  38. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-identity-claims.ts +535 -0
  39. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-legacy-aliases.ts +16 -0
  40. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-priority-execution.ts +56 -0
  41. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-public-aliases.ts +28 -0
  42. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-runtime-read-eligibility.ts +38 -0
  43. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-state.ts +122 -0
  44. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-status.ts +10 -0
  45. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-upstream-identity.ts +112 -0
  46. package/dist/bundling-sources/shared_libs/monitors/provider-webhook-monitor-runtime.ts +300 -0
  47. package/dist/bundling-sources/shared_libs/monitors/quickstart-prompts.ts +22 -0
  48. package/dist/bundling-sources/shared_libs/monitors/snitcher-install-validation.ts +93 -0
  49. package/dist/bundling-sources/shared_libs/monitors/snitcher-ip2company.ts +332 -0
  50. package/dist/bundling-sources/shared_libs/monitors/snitcher-radar.ts +221 -0
  51. package/dist/bundling-sources/shared_libs/monitors/starter-templates.ts +105 -0
  52. package/dist/bundling-sources/shared_libs/monitors/tracking-provider-guidance.ts +73 -0
  53. package/dist/bundling-sources/shared_libs/monitors/tracking-provider-integrations.ts +81 -0
  54. package/dist/bundling-sources/shared_libs/monitors/tsconfig.json +10 -0
  55. package/dist/bundling-sources/shared_libs/play-runtime/activity-observation.ts +6 -11
  56. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +90 -12
  57. package/dist/bundling-sources/shared_libs/play-runtime/async-play-invocation.ts +78 -0
  58. package/dist/bundling-sources/shared_libs/play-runtime/checkpoint-boundaries.ts +70 -0
  59. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +407 -53
  60. package/dist/bundling-sources/shared_libs/play-runtime/coordinator-headers.ts +1 -32
  61. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +57 -0
  62. package/dist/bundling-sources/shared_libs/play-runtime/default-batch-strategies.ts +20 -1
  63. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +6 -0
  64. package/dist/bundling-sources/shared_libs/play-runtime/execution-protocol.ts +7 -1
  65. package/dist/bundling-sources/shared_libs/play-runtime/lane-retirement-gate.ts +189 -0
  66. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +28 -0
  67. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +2 -0
  68. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +23 -0
  69. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +1 -1
  70. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +18 -4
  71. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-start-admission.ts +68 -0
  72. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +2 -0
  73. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +1 -0
  74. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +10 -8
  75. package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +20 -0
  76. package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +6 -0
  77. package/dist/bundling-sources/shared_libs/play-runtime/runtime-env.ts +6 -0
  78. package/dist/bundling-sources/shared_libs/play-runtime/runtime-scheduler-topology.ts +24 -0
  79. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +30 -1
  80. package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +1 -1
  81. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +1 -1
  82. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +6 -3
  83. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +454 -17
  84. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +19 -4
  85. package/dist/bundling-sources/shared_libs/plays/contracts.ts +6 -14
  86. package/dist/bundling-sources/shared_libs/plays/core.ts +11 -6
  87. package/dist/bundling-sources/shared_libs/plays/docflow-binding-owner.ts +16 -11
  88. package/dist/bundling-sources/shared_libs/plays/email-status.ts +1 -1
  89. package/dist/bundling-sources/shared_libs/plays/resolve-static-pipeline.ts +1 -1
  90. package/dist/bundling-sources/shared_libs/plays/slug.ts +115 -0
  91. package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +44 -14
  92. package/dist/bundling-sources/shared_libs/plays/tool-category-descriptions.ts +2 -2
  93. package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +877 -0
  94. package/dist/bundling-sources/shared_libs/product-notifications/configuration-draft.ts +456 -0
  95. package/dist/bundling-sources/shared_libs/product-notifications/configuration.ts +560 -0
  96. package/dist/bundling-sources/shared_libs/product-notifications/content.ts +28 -0
  97. package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +59 -0
  98. package/dist/bundling-sources/shared_libs/product-notifications/email.ts +246 -0
  99. package/dist/bundling-sources/shared_libs/product-notifications/evaluation.ts +280 -0
  100. package/dist/bundling-sources/shared_libs/product-notifications/events.ts +433 -0
  101. package/dist/bundling-sources/shared_libs/product-notifications/legacy-slack.ts +80 -0
  102. package/dist/bundling-sources/shared_libs/product-notifications/workspace.ts +38 -0
  103. package/dist/bundling-sources/shared_libs/runtime-env.ts +6 -0
  104. package/dist/bundling-sources/shared_libs/security/header-safe-env.ts +28 -0
  105. package/dist/bundling-sources/shared_libs/security/internal-actor.ts +50 -0
  106. package/dist/bundling-sources/shared_libs/security/secret-redaction.ts +267 -0
  107. package/dist/cli/index.js +1070 -193
  108. package/dist/cli/index.mjs +1057 -180
  109. package/dist/{compiler-manifest-Dbov16F7.d.mts → compiler-manifest-DsLbQaew.d.mts} +132 -8
  110. package/dist/{compiler-manifest-Dbov16F7.d.ts → compiler-manifest-DsLbQaew.d.ts} +132 -8
  111. package/dist/index.d.mts +834 -12
  112. package/dist/index.d.ts +834 -12
  113. package/dist/index.js +469 -40
  114. package/dist/index.mjs +469 -40
  115. package/dist/install-integrity.json +65 -4
  116. package/dist/plays/bundle-play-file.d.mts +8 -3
  117. package/dist/plays/bundle-play-file.d.ts +8 -3
  118. package/dist/plays/bundle-play-file.mjs +100 -20
  119. package/package.json +3 -1
  120. /package/dist/bundling-sources/shared_libs/{integrations/bettercontact-execution-policy.ts → integration-contracts/bettercontact/execution-policy.ts} +0 -0
  121. /package/dist/bundling-sources/shared_libs/{integrations/theirstack-execution-policy.ts → integration-contracts/theirstack/execution-policy.ts} +0 -0
@@ -37,6 +37,13 @@ import { resolveConfig } from './config.js';
37
37
  import { DeeplineError } from './errors.js';
38
38
  import { HttpClient } from './http.js';
39
39
  import { PRODUCT_NOTIFICATION_SLACK_OAUTH_SCOPES } from '../../shared_libs/product-notifications/contract.js';
40
+ import { normalizeProductNotificationEmail } from '../../shared_libs/product-notifications/configuration.js';
41
+ import {
42
+ type ProductNotificationConfigurationChange,
43
+ type EffectiveProductNotificationDestination,
44
+ type EffectiveProductNotificationGroup,
45
+ type ProductNotificationGroupDraft,
46
+ } from '../../shared_libs/product-notifications/configuration.js';
40
47
  import {
41
48
  STREAM_HEALTHY_CONNECTION_MS,
42
49
  isTransientPlayStreamError,
@@ -60,6 +67,7 @@ import type {
60
67
  PlayLiveEvent,
61
68
  PlayListItem,
62
69
  ProductNotificationSettings,
70
+ ProductNotificationConfigurationResponse,
63
71
  PlayDescription,
64
72
  StopPlayRunResult,
65
73
  StopAllPlayRunsResult,
@@ -88,11 +96,11 @@ import type { PlayStagedFileRef } from './plays/local-file-discovery.js';
88
96
  import type { PlayCompilerManifest } from '../../shared_libs/plays/compiler-manifest.js';
89
97
  import type { EnrichCompiledConfig } from './cli/enrich-play-compiler.js';
90
98
  import { RUNTIME_ENVIRONMENT_TOKEN_HEADER } from '../../shared_libs/play-runtime/coordinator-headers.js';
91
- import { resolveTheirstackClientTimeoutMs } from '../../shared_libs/integrations/theirstack-execution-policy.js';
99
+ import { resolveTheirstackClientTimeoutMs } from '../../shared_libs/integration-contracts/theirstack/execution-policy.js';
92
100
  import {
93
101
  BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS,
94
102
  usesExtendedBetterContactLauncherBudget,
95
- } from '../../shared_libs/integrations/bettercontact-execution-policy.js';
103
+ } from '../../shared_libs/integration-contracts/bettercontact/execution-policy.js';
96
104
  import {
97
105
  normalizePlayRuntimeEnvironment,
98
106
  normalizePlayRuntimeNamespace,
@@ -124,6 +132,76 @@ export type UpdateNotificationInput =
124
132
  | { enabled: boolean }
125
133
  | ({ name: string; eventTypes: string[] } & SlackNotificationTarget);
126
134
 
135
+ export type CreateNotificationGroupInput = {
136
+ name: string;
137
+ targets: string[];
138
+ legacyEvents?: string[];
139
+ dryRun?: boolean;
140
+ };
141
+
142
+ export type CreateNotificationGroupResult =
143
+ | {
144
+ mode: 'dry_run';
145
+ compatibilityMode: boolean;
146
+ name: string;
147
+ targets: string[];
148
+ legacyEvents: string[];
149
+ }
150
+ | { mode: 'legacy'; notification: unknown }
151
+ | {
152
+ mode: 'native';
153
+ groupKey: string;
154
+ targets: string[];
155
+ group: EffectiveProductNotificationGroup;
156
+ destinations: EffectiveProductNotificationDestination[];
157
+ };
158
+
159
+ type ParsedNotificationGroupTarget =
160
+ | { kind: 'email'; email: string }
161
+ | { kind: 'slack'; channel: string }
162
+ | { kind: 'slack'; memberId: string };
163
+
164
+ const MAX_NOTIFICATION_GROUP_CREATE_TARGETS = 50;
165
+
166
+ function parseNotificationGroupTarget(
167
+ value: string,
168
+ ): ParsedNotificationGroupTarget {
169
+ const normalized = value.trim();
170
+ if (normalized.toLowerCase().startsWith('email:')) {
171
+ const email = normalizeProductNotificationEmail(normalized.slice(6));
172
+ if (!email) {
173
+ throw new Error(
174
+ `Invalid email notification target "${value}". Use --to email:name@example.com.`,
175
+ );
176
+ }
177
+ return { kind: 'email', email };
178
+ }
179
+ const slack = /^slack:(.+)$/i.exec(normalized)?.[1]?.trim();
180
+ if (!slack) {
181
+ const provider = normalized.split(':', 1)[0] || normalized;
182
+ throw new Error(
183
+ `Unsupported notification destination "${provider}". Use email: or slack:.`,
184
+ );
185
+ }
186
+ const member = /^member:([UW][A-Z0-9]{8,})$/i.exec(slack);
187
+ if (member?.[1]) {
188
+ return { kind: 'slack', memberId: member[1].toUpperCase() };
189
+ }
190
+ if (slack.toLowerCase().startsWith('member:')) {
191
+ throw new Error(
192
+ 'Slack member IDs must look like slack:member:U0123456789.',
193
+ );
194
+ }
195
+ if (!slack.replace(/^#/, '').trim()) {
196
+ throw new Error('Use --to slack:#channel.');
197
+ }
198
+ return { kind: 'slack', channel: slack };
199
+ }
200
+
201
+ function notificationObjectKey(kind: 'group' | 'destination') {
202
+ return `${kind}.${globalThis.crypto.randomUUID()}`;
203
+ }
204
+
127
205
  const TERMINAL_PLAY_STATUSES = new Set(['completed', 'failed', 'cancelled']);
128
206
  const INCLUDE_TOOL_METADATA_HEADER = 'x-deepline-include-tool-metadata';
129
207
  const EXECUTE_RESPONSE_CONTRACT_HEADER = 'x-deepline-execute-response-contract';
@@ -645,6 +723,14 @@ export type PlaySecretMetadata = {
645
723
  lastUsedAt?: number;
646
724
  };
647
725
 
726
+ export type PlaySecretCheck = {
727
+ ok: boolean;
728
+ name: string;
729
+ playName: string | null;
730
+ reason: 'active' | 'missing' | 'disabled' | 'empty' | 'invalid_version';
731
+ secret: PlaySecretMetadata | null;
732
+ };
733
+
648
734
  /**
649
735
  * Public runs namespace exposed as `client.runs`.
650
736
  *
@@ -930,6 +1016,62 @@ export type MonitorFleetWaitOptions = {
930
1016
  until?: 'converged' | 'deactivated';
931
1017
  };
932
1018
 
1019
+ /** A durable monitor batch can name a small key set, a query target, or one Fleet. */
1020
+ export type MonitorBatchScope =
1021
+ | { kind: 'keys'; monitorKeys: string[] }
1022
+ | {
1023
+ kind: 'target';
1024
+ target: 'all' | 'all-active' | 'billing-suspended' | 'needs-repair';
1025
+ }
1026
+ | { kind: 'fleet'; fleetId: string };
1027
+
1028
+ export type MonitorBatchExistingSubmitOptions = {
1029
+ kind: 'audit' | 'deactivate' | 'reactivate' | 'repair';
1030
+ scope: MonitorBatchScope;
1031
+ dryRun?: boolean;
1032
+ /** Required for deactivate; it is the declared reason shown by health/UI. */
1033
+ deactivationReason?: string;
1034
+ /** Stable retry key. Reusing it joins the original durable operation. */
1035
+ idempotencyKey: string;
1036
+ };
1037
+
1038
+ /** Complete definitions, one JSON object per line; uploaded as bounded shards. */
1039
+ export type MonitorBatchDeploySubmitOptions = {
1040
+ kind: 'deploy';
1041
+ manifestNdjson: string;
1042
+ dryRun?: boolean;
1043
+ /** Stable retry key. Reusing it joins the same content-addressed manifest. */
1044
+ idempotencyKey: string;
1045
+ };
1046
+
1047
+ export type MonitorBatchSubmitOptions =
1048
+ | MonitorBatchExistingSubmitOptions
1049
+ | MonitorBatchDeploySubmitOptions;
1050
+
1051
+ export type MonitorBatchOperationResult = {
1052
+ ok?: boolean;
1053
+ rejoined?: boolean;
1054
+ operation: {
1055
+ runId: string;
1056
+ kind: 'audit' | 'deactivate' | 'reactivate' | 'deploy' | 'repair';
1057
+ state: 'running' | 'retry_scheduled' | 'completed' | 'failed';
1058
+ dryRun: boolean;
1059
+ scope: unknown;
1060
+ submittedAt: number;
1061
+ updatedAt: number;
1062
+ deactivationReason?: string;
1063
+ nextAttemptAt?: number;
1064
+ completedAt?: number;
1065
+ summary?: Record<string, unknown>;
1066
+ lastError?: string;
1067
+ };
1068
+ results?: {
1069
+ page: Array<Record<string, unknown>>;
1070
+ isDone: boolean;
1071
+ continueCursor: string;
1072
+ };
1073
+ };
1074
+
933
1075
  export type MonitorFleetsNamespace = {
934
1076
  /**
935
1077
  * Create, update, or re-plan a fleet. Pass a definition to admit new source
@@ -963,6 +1105,16 @@ export type MonitorFleetsNamespace = {
963
1105
  ) => Promise<MonitorFleetResult>;
964
1106
  };
965
1107
 
1108
+ export type MonitorBatchNamespace = {
1109
+ submit: (
1110
+ options: MonitorBatchSubmitOptions,
1111
+ ) => Promise<MonitorBatchOperationResult>;
1112
+ get: (
1113
+ operationId: string,
1114
+ options?: { cursor?: string | null },
1115
+ ) => Promise<MonitorBatchOperationResult>;
1116
+ };
1117
+
966
1118
  /**
967
1119
  * Delivery and convergence health for a scope, from
968
1120
  * `GET /api/v2/monitors/health`.
@@ -977,6 +1129,16 @@ export type MonitorsHealth = {
977
1129
  scanned: number;
978
1130
  /** True when the scope was larger than one bounded read; counts are partial. */
979
1131
  truncated: boolean;
1132
+ /**
1133
+ * A durable whole-scope snapshot is rebuilding. Counts remain intentionally
1134
+ * partial until it completes; older servers omit this additive field.
1135
+ */
1136
+ refresh?: {
1137
+ state: 'running' | 'completed';
1138
+ started_at: number;
1139
+ updated_at: number;
1140
+ completed_at: number | null;
1141
+ };
980
1142
  desired: { active: number; inactive: number; unset: number };
981
1143
  observed: {
982
1144
  active: number;
@@ -1003,6 +1165,15 @@ export type MonitorsHealth = {
1003
1165
  observed_at: number | null;
1004
1166
  provider_resource_id: string | null;
1005
1167
  }>;
1168
+ /** Bounded current durable monitor work, if the server supports it. */
1169
+ batch_operations?: Array<{
1170
+ run_id: string;
1171
+ kind: 'audit' | 'deactivate' | 'reactivate' | 'repair' | 'deploy';
1172
+ state: 'running' | 'retry_scheduled';
1173
+ updated_at: number;
1174
+ next_attempt_at?: number;
1175
+ summary?: Record<string, unknown>;
1176
+ }>;
1006
1177
  };
1007
1178
 
1008
1179
  /** One bounded audit pass, from `POST /api/v2/monitors/audit`. */
@@ -1137,6 +1308,8 @@ export type MonitorsNamespace = {
1137
1308
  }) => Promise<MonitorsRepairResult>;
1138
1309
  /** Delivery and convergence health for the workspace or one fleet. */
1139
1310
  health: (options?: { fleetId?: string }) => Promise<MonitorsHealth>;
1311
+ /** Durable bulk audit/deactivation/reactivation/repair with retained progress. */
1312
+ batch: MonitorBatchNamespace;
1140
1313
  /** Define, reconcile, and control table-backed monitor fleets. */
1141
1314
  fleets: MonitorFleetsNamespace;
1142
1315
  };
@@ -1293,7 +1466,12 @@ export type TargetBillingMutationResult = {
1293
1466
  export type TargetBillingPlanTransitionOptions =
1294
1467
  | {
1295
1468
  action: 'start_or_change';
1296
- targetPlanSku: 'payg-v1' | 'builder-v1' | 'team-v1';
1469
+ targetPlanSku:
1470
+ | 'payg-v1'
1471
+ | 'builder-v1'
1472
+ | 'growth-v1'
1473
+ | 'growth-canary-v1'
1474
+ | 'team-v1';
1297
1475
  idempotencyKey: string;
1298
1476
  }
1299
1477
  | {
@@ -1379,7 +1557,12 @@ export type WorkspaceCreateResult = {
1379
1557
  org_name: string;
1380
1558
  org_slug: string;
1381
1559
  plan_sku: 'payg-v1';
1382
- rate_policy_ref: 'payg-rates-v2';
1560
+ /**
1561
+ * The PAYG rate policy the workspace was provisioned onto, taken from the
1562
+ * catalog revision its operation pinned: v4 bound payg-rates-v2, v5 binds
1563
+ * the flat payg-rates-v3.
1564
+ */
1565
+ rate_policy_ref: 'payg-rates-v2' | 'payg-rates-v3';
1383
1566
  operation: {
1384
1567
  id: string;
1385
1568
  state: 'completed';
@@ -2059,6 +2242,11 @@ export class DeeplineClient {
2059
2242
  audit: (options) => this.auditMonitors(options),
2060
2243
  repair: (options) => this.repairMonitors(options),
2061
2244
  health: (options) => this.readMonitorsHealth(options),
2245
+ batch: {
2246
+ submit: (options) => this.submitMonitorBatch(options),
2247
+ get: (operationId, options) =>
2248
+ this.getMonitorBatch(operationId, options),
2249
+ },
2062
2250
  fleets: {
2063
2251
  sync: (definitionOrId, options) =>
2064
2252
  this.syncMonitorFleet(definitionOrId, options),
@@ -2271,6 +2459,20 @@ export class DeeplineClient {
2271
2459
  );
2272
2460
  }
2273
2461
 
2462
+ /** Check effective scope and active-version health without reading the value.
2463
+ * Without playName, checks the organization-scoped secret only. With a Play
2464
+ * name, an active Play secret takes precedence; a deleted/disabled Play
2465
+ * secret falls back to the organization-scoped secret.
2466
+ */
2467
+ async inspectSecret(
2468
+ name: string,
2469
+ options: { playName?: string } = {},
2470
+ ): Promise<PlaySecretCheck> {
2471
+ const params = new URLSearchParams({ name: name.trim().toUpperCase() });
2472
+ if (options.playName !== undefined) params.set('play', options.playName);
2473
+ return this.http.get(`/api/v2/secrets?${params.toString()}`);
2474
+ }
2475
+
2274
2476
  // ——————————————————————————————————————————————————————————
2275
2477
  // Tools
2276
2478
  // ——————————————————————————————————————————————————————————
@@ -2376,6 +2578,10 @@ export class DeeplineClient {
2376
2578
  `/api/v2/integrations/${encodeURIComponent(toolId)}/get`,
2377
2579
  {
2378
2580
  method: 'GET',
2581
+ // Tool metadata is a read-only catalog lookup. Keep the metadata
2582
+ // header while opting into the same transient edge-response retries as
2583
+ // other GET catalog methods such as searchTools().
2584
+ retryApiErrors: true,
2379
2585
  headers: {
2380
2586
  'x-deepline-tool-meta-only': '1',
2381
2587
  },
@@ -4342,6 +4548,244 @@ export class DeeplineClient {
4342
4548
  return this.http.get('/api/v2/notifications');
4343
4549
  }
4344
4550
 
4551
+ /** Read the group-based product-notification configuration and rule catalog. */
4552
+ async getNotificationConfiguration(): Promise<ProductNotificationConfigurationResponse> {
4553
+ return this.http.get('/api/v2/notifications/configuration');
4554
+ }
4555
+
4556
+ /** Atomically apply one retry-safe desired configuration change. */
4557
+ async changeNotificationConfiguration(
4558
+ expectedWorkspaceVersion: number,
4559
+ change: ProductNotificationConfigurationChange,
4560
+ ): Promise<Pick<ProductNotificationConfigurationResponse, 'configuration'>> {
4561
+ return this.http.put('/api/v2/notifications/configuration', {
4562
+ expectedWorkspaceVersion,
4563
+ change,
4564
+ });
4565
+ }
4566
+
4567
+ /** Create one notification group and its destinations as a retry-safe unit. */
4568
+ async createNotificationGroup(
4569
+ input: CreateNotificationGroupInput,
4570
+ ): Promise<CreateNotificationGroupResult> {
4571
+ const name = input.name.trim().replace(/\s+/g, ' ');
4572
+ if (!name) throw new Error('Notification group name is required.');
4573
+ if (
4574
+ input.targets.length < 1 ||
4575
+ input.targets.length > MAX_NOTIFICATION_GROUP_CREATE_TARGETS
4576
+ ) {
4577
+ throw new Error(
4578
+ `Choose between 1 and ${MAX_NOTIFICATION_GROUP_CREATE_TARGETS} notification targets.`,
4579
+ );
4580
+ }
4581
+
4582
+ const targets = input.targets.map(parseNotificationGroupTarget);
4583
+ const legacyEvents = input.legacyEvents ?? [];
4584
+ const legacyTarget =
4585
+ targets.length === 1 &&
4586
+ targets[0]?.kind === 'slack' &&
4587
+ legacyEvents.length > 0
4588
+ ? targets[0]
4589
+ : null;
4590
+ if (legacyEvents.length > 0 && !legacyTarget) {
4591
+ throw new Error(
4592
+ '--for is supported only by the legacy one-Slack-target form. Create the group first, then add rules in notification configuration.',
4593
+ );
4594
+ }
4595
+
4596
+ if (!legacyTarget && name.toLowerCase() === 'default') {
4597
+ throw new Error(
4598
+ 'Default is reserved for the workspace default notification group.',
4599
+ );
4600
+ }
4601
+
4602
+ const normalizedTargets = targets.map((target) =>
4603
+ target.kind === 'email'
4604
+ ? `email:${target.email}`
4605
+ : 'memberId' in target
4606
+ ? `slack:member:${target.memberId}`
4607
+ : `slack:${target.channel}`,
4608
+ );
4609
+ if (input.dryRun) {
4610
+ return {
4611
+ mode: 'dry_run' as const,
4612
+ compatibilityMode: legacyTarget !== null,
4613
+ name: legacyTarget ? input.name : name,
4614
+ targets: normalizedTargets,
4615
+ legacyEvents,
4616
+ };
4617
+ }
4618
+
4619
+ if (legacyTarget) {
4620
+ const notification = await this.createNotification({
4621
+ name: input.name,
4622
+ provider: 'slack',
4623
+ ...('channel' in legacyTarget
4624
+ ? { channel: legacyTarget.channel }
4625
+ : { memberId: legacyTarget.memberId }),
4626
+ eventTypes: legacyEvents,
4627
+ });
4628
+ return { mode: 'legacy' as const, notification };
4629
+ }
4630
+
4631
+ const current = await this.getNotificationConfiguration();
4632
+ const existingGroup = current.configuration.groups.find(
4633
+ (candidate) => candidate.name.toLowerCase() === name.toLowerCase(),
4634
+ );
4635
+ const groupKey = existingGroup?.groupKey ?? notificationObjectKey('group');
4636
+ const group: EffectiveProductNotificationGroup = existingGroup ?? {
4637
+ groupKey,
4638
+ name,
4639
+ enabled: true,
4640
+ deliveryTiming: { mode: 'immediate' },
4641
+ source: 'workspace',
4642
+ configMode: 'custom',
4643
+ version: 0,
4644
+ };
4645
+ const destinations = current.configuration.destinations.filter(
4646
+ (destination) => destination.groupKey === groupKey,
4647
+ );
4648
+
4649
+ const emails = [
4650
+ ...new Set(
4651
+ targets.flatMap((target) =>
4652
+ target.kind === 'email' ? [target.email] : [],
4653
+ ),
4654
+ ),
4655
+ ].sort();
4656
+ const existingEmails = new Set(
4657
+ destinations.flatMap((destination) =>
4658
+ destination.settings.kind === 'email_addresses'
4659
+ ? destination.settings.to
4660
+ : [],
4661
+ ),
4662
+ );
4663
+ const newEmails = emails.filter((email) => !existingEmails.has(email));
4664
+ if (newEmails.length > 0) {
4665
+ destinations.push({
4666
+ destinationKey: notificationObjectKey('destination'),
4667
+ groupKey,
4668
+ name: 'Email recipients',
4669
+ enabled: true,
4670
+ source: 'workspace',
4671
+ configMode: 'custom',
4672
+ version: 0,
4673
+ status: 'active',
4674
+ settings: { kind: 'email_addresses', to: newEmails },
4675
+ });
4676
+ }
4677
+
4678
+ const slackTargets = new Map<
4679
+ string,
4680
+ Extract<ParsedNotificationGroupTarget, { kind: 'slack' }>
4681
+ >();
4682
+ for (const target of targets) {
4683
+ if (target.kind !== 'slack') continue;
4684
+ const targetKey =
4685
+ 'memberId' in target
4686
+ ? `member:${target.memberId}`
4687
+ : `channel:${target.channel.replace(/^#/, '').toLowerCase()}`;
4688
+ slackTargets.set(targetKey, target);
4689
+ }
4690
+ const connectionId = current.slackConnection.connectionId;
4691
+ if (slackTargets.size > 0 && !connectionId) {
4692
+ throw new Error(
4693
+ 'Slack is not connected to this workspace. Connect it in Dashboard → Integrations, then retry.',
4694
+ );
4695
+ }
4696
+ const resolvedSlackTargets = await Promise.all(
4697
+ [...slackTargets.values()].map(async (target) => {
4698
+ if ('memberId' in target) {
4699
+ return {
4700
+ targetKind: 'member' as const,
4701
+ targetId: target.memberId,
4702
+ targetName: target.memberId,
4703
+ };
4704
+ }
4705
+ const channel = target.channel;
4706
+ const requested = channel.replace(/^#/, '');
4707
+ const response = await this.listNotificationChannels(channel);
4708
+ const matches = response.channels.filter(
4709
+ (candidate) =>
4710
+ candidate.id === requested ||
4711
+ candidate.name.toLowerCase() === requested.toLowerCase(),
4712
+ );
4713
+ if (matches.length !== 1) {
4714
+ throw new Error(
4715
+ matches.length === 0
4716
+ ? `Slack channel ${channel} was not found or is not visible to the Deepline app.`
4717
+ : `Slack channel ${channel} is ambiguous. Use its channel ID.`,
4718
+ );
4719
+ }
4720
+ return {
4721
+ targetKind: 'channel' as const,
4722
+ targetId: matches[0]!.id,
4723
+ targetName: matches[0]!.name,
4724
+ };
4725
+ }),
4726
+ );
4727
+ const uniqueSlackTargets = new Map(
4728
+ resolvedSlackTargets.map((target) => [
4729
+ `${target.targetKind}:${target.targetId}`,
4730
+ target,
4731
+ ]),
4732
+ );
4733
+ for (const target of uniqueSlackTargets.values()) {
4734
+ if (
4735
+ destinations.some(
4736
+ (destination) =>
4737
+ destination.settings.kind === 'slack' &&
4738
+ destination.settings.targetKind === target.targetKind &&
4739
+ destination.settings.targetId === target.targetId,
4740
+ )
4741
+ ) {
4742
+ continue;
4743
+ }
4744
+ destinations.push({
4745
+ destinationKey: notificationObjectKey('destination'),
4746
+ groupKey,
4747
+ name: `${target.targetKind === 'channel' ? '#' : '@'}${target.targetName}`,
4748
+ enabled: true,
4749
+ source: 'workspace',
4750
+ configMode: 'custom',
4751
+ version: 0,
4752
+ status: 'pending_verification',
4753
+ settings: {
4754
+ kind: 'slack',
4755
+ ...target,
4756
+ oauthConnectionId: connectionId!,
4757
+ },
4758
+ });
4759
+ }
4760
+
4761
+ const draft: ProductNotificationGroupDraft = {
4762
+ group,
4763
+ destinations,
4764
+ rules: current.configuration.rules.filter(
4765
+ (rule) => rule.groupKey === groupKey,
4766
+ ),
4767
+ };
4768
+ const result = await this.changeNotificationConfiguration(
4769
+ current.configuration.workspaceVersion,
4770
+ { kind: 'save_group', draft },
4771
+ );
4772
+ const storedGroup = result.configuration.groups.find(
4773
+ (candidate) => candidate.groupKey === groupKey,
4774
+ );
4775
+ if (!storedGroup) {
4776
+ throw new Error('Notification group creation returned no saved group.');
4777
+ }
4778
+ return {
4779
+ mode: 'native' as const,
4780
+ groupKey,
4781
+ targets: normalizedTargets,
4782
+ group: storedGroup,
4783
+ destinations: result.configuration.destinations.filter(
4784
+ (destination) => destination.groupKey === groupKey,
4785
+ ),
4786
+ };
4787
+ }
4788
+
4345
4789
  /** List Slack channels available to an already-connected Slack integration. */
4346
4790
  async listNotificationChannels(query?: string): Promise<{
4347
4791
  identity: { teamId: string; teamName?: string };
@@ -5049,6 +5493,92 @@ export class DeeplineClient {
5049
5493
  );
5050
5494
  }
5051
5495
 
5496
+ /** Submit durable monitor work; transport retries use the same idempotency key. */
5497
+ async submitMonitorBatch(
5498
+ options: MonitorBatchSubmitOptions,
5499
+ ): Promise<MonitorBatchOperationResult> {
5500
+ const idempotencyKey = options.idempotencyKey.trim();
5501
+ if (!idempotencyKey) {
5502
+ throw new DeeplineError(
5503
+ 'Monitor batch idempotencyKey is required.',
5504
+ undefined,
5505
+ 'INVALID_MONITOR_BATCH_IDEMPOTENCY_KEY',
5506
+ );
5507
+ }
5508
+ if (options.kind === 'deploy') {
5509
+ if (!options.manifestNdjson.trim()) {
5510
+ throw new DeeplineError(
5511
+ 'Monitor batch deploy requires a non-empty NDJSON manifest.',
5512
+ undefined,
5513
+ 'INVALID_MONITOR_BATCH_MANIFEST',
5514
+ );
5515
+ }
5516
+ return this.http.request<MonitorBatchOperationResult>(
5517
+ '/api/v2/monitors/batch',
5518
+ {
5519
+ method: 'POST',
5520
+ body: {
5521
+ kind: 'deploy',
5522
+ manifest_ndjson: options.manifestNdjson,
5523
+ dry_run: options.dryRun === true,
5524
+ idempotency_key: idempotencyKey,
5525
+ },
5526
+ headers: { 'Idempotency-Key': idempotencyKey },
5527
+ maxRetries: 0,
5528
+ exactUrlOnly: true,
5529
+ },
5530
+ );
5531
+ }
5532
+ const scope =
5533
+ options.scope.kind === 'keys'
5534
+ ? { kind: 'keys', monitor_keys: options.scope.monitorKeys }
5535
+ : options.scope.kind === 'fleet'
5536
+ ? { kind: 'fleet', fleet_id: options.scope.fleetId }
5537
+ : { kind: 'target', target: options.scope.target };
5538
+ return this.http.request<MonitorBatchOperationResult>(
5539
+ '/api/v2/monitors/batch',
5540
+ {
5541
+ method: 'POST',
5542
+ body: {
5543
+ kind: options.kind,
5544
+ scope,
5545
+ dry_run: options.dryRun === true,
5546
+ idempotency_key: idempotencyKey,
5547
+ ...(options.deactivationReason === undefined
5548
+ ? {}
5549
+ : { deactivation_reason: options.deactivationReason }),
5550
+ },
5551
+ headers: { 'Idempotency-Key': idempotencyKey },
5552
+ // Durable submission is itself idempotent, but an ambiguous local retry
5553
+ // must retain the exact key and never turn a CLI attempt into two runs.
5554
+ maxRetries: 0,
5555
+ exactUrlOnly: true,
5556
+ },
5557
+ );
5558
+ }
5559
+
5560
+ /** Get durable batch progress and a bounded retained evidence page. */
5561
+ async getMonitorBatch(
5562
+ operationId: string,
5563
+ options?: { cursor?: string | null },
5564
+ ): Promise<MonitorBatchOperationResult> {
5565
+ const runId = operationId.trim();
5566
+ if (!runId) {
5567
+ throw new DeeplineError(
5568
+ 'Monitor batch operation id is required.',
5569
+ undefined,
5570
+ 'INVALID_MONITOR_BATCH_OPERATION_ID',
5571
+ );
5572
+ }
5573
+ const params = new URLSearchParams();
5574
+ if (options?.cursor) params.set('cursor', options.cursor);
5575
+ const suffix = params.size > 0 ? `?${params}` : '';
5576
+ return this.http.request<MonitorBatchOperationResult>(
5577
+ `/api/v2/monitors/batch/${encodeURIComponent(runId)}${suffix}`,
5578
+ { method: 'GET' },
5579
+ );
5580
+ }
5581
+
5052
5582
  /**
5053
5583
  * The deployable monitor tools catalog. Pass a tool id (positional or
5054
5584
  * `{ tool }`) to describe one tool's full payload/stream contract, or no tool