deepline 0.3.115 → 0.3.117

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 (28) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +356 -12
  2. package/dist/bundling-sources/sdk/src/index.ts +12 -1
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/shared_libs/monitors/billing/state.ts +36 -6
  5. package/dist/bundling-sources/shared_libs/monitors/billing/types.ts +0 -1
  6. package/dist/bundling-sources/shared_libs/monitors/deactivation-reasons.ts +6 -3
  7. package/dist/bundling-sources/shared_libs/monitors/fleets/verdict.ts +52 -15
  8. package/dist/bundling-sources/shared_libs/monitors/monitor-job-state.ts +44 -0
  9. package/dist/bundling-sources/shared_libs/monitors/package.json +2 -0
  10. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +76 -3
  11. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-state.ts +81 -6
  12. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-status.ts +26 -10
  13. package/dist/bundling-sources/shared_libs/observability/queue-health.ts +128 -0
  14. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +18 -0
  15. package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +1 -0
  16. package/dist/bundling-sources/shared_libs/plays/share/static-pipeline-summary.ts +2 -2
  17. package/dist/cli/index.js +413 -68
  18. package/dist/cli/index.mjs +413 -68
  19. package/dist/index.d.mts +155 -13
  20. package/dist/index.d.ts +155 -13
  21. package/dist/index.js +137 -2
  22. package/dist/index.mjs +134 -2
  23. package/dist/install-integrity.json +1 -0
  24. package/dist/release.d.mts +1 -1
  25. package/dist/release.d.ts +1 -1
  26. package/dist/release.js +1 -1
  27. package/dist/release.mjs +1 -1
  28. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -1298,7 +1298,7 @@ var SDK_RELEASE = {
1298
1298
  // getters keep their established compatibility behavior.
1299
1299
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
1300
1300
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
1301
- version: "0.3.115",
1301
+ version: "0.3.117",
1302
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.",
1303
1303
  packageCapabilities: {
1304
1304
  updatePreferences: 1
@@ -5222,6 +5222,7 @@ var DeeplineClient = class {
5222
5222
  available: (toolIdOrOptions, options2) => this.getMonitorsAvailable(toolIdOrOptions, options2),
5223
5223
  check: (definition) => this.checkMonitor(definition),
5224
5224
  deploy: (definition, options2) => this.deployMonitor(definition, options2),
5225
+ sync: (definition, options2) => options2?.dryRun ? this.deployMonitor(definition, { dryRun: true }) : this.syncScalarMonitor(definition, options2),
5225
5226
  list: (options2) => this.listMonitors(options2),
5226
5227
  get: (key) => this.getMonitor(key),
5227
5228
  test: (key, payload, options2) => this.testMonitorWebhook(key, payload, options2),
@@ -5230,6 +5231,18 @@ var DeeplineClient = class {
5230
5231
  update: (key, patch) => this.updateMonitor(key, patch),
5231
5232
  delete: (key, options2) => this.deleteMonitor(key, options2),
5232
5233
  reactivate: (key, options2) => this.reactivateMonitor(key, options2),
5234
+ start: (key, options2) => options2?.dryRun ? this.submitMonitorBatch({
5235
+ kind: "reactivate",
5236
+ scope: { kind: "keys", monitorKeys: [key] },
5237
+ dryRun: true,
5238
+ idempotencyKey: options2.idempotencyKey ?? this.monitorJobIdempotencyKey(`start-${key}`)
5239
+ }) : this.submitScalarMonitorLifecycle(key, "start", options2),
5240
+ stop: (key, options2) => options2?.dryRun ? this.submitMonitorBatch({
5241
+ kind: "deactivate",
5242
+ scope: { kind: "keys", monitorKeys: [key] },
5243
+ dryRun: true,
5244
+ idempotencyKey: options2.idempotencyKey ?? this.monitorJobIdempotencyKey(`stop-${key}`)
5245
+ }) : this.submitScalarMonitorLifecycle(key, "stop", options2),
5233
5246
  audit: (options2) => this.auditMonitors(options2),
5234
5247
  repair: (options2) => this.repairMonitors(options2),
5235
5248
  health: (options2) => this.readMonitorsHealth(options2),
@@ -5238,6 +5251,12 @@ var DeeplineClient = class {
5238
5251
  submit: (options2) => this.submitMonitorBatch(options2),
5239
5252
  get: (operationId, options2) => this.getMonitorBatch(operationId, options2)
5240
5253
  },
5254
+ batches: {
5255
+ sync: (batchId, definitions, options2) => this.syncNamedMonitorBatch(batchId, definitions, options2),
5256
+ start: (batchId, options2) => this.startNamedMonitorBatch(batchId, options2),
5257
+ stop: (batchId, options2) => this.stopNamedMonitorBatch(batchId, options2),
5258
+ get: (batchId) => this.getNamedMonitorBatch(batchId)
5259
+ },
5241
5260
  jobs: {
5242
5261
  get: (jobId) => this.getMonitorJob(jobId),
5243
5262
  logs: (jobId, options2) => this.getMonitorJobLogs(jobId, options2),
@@ -5251,6 +5270,8 @@ var DeeplineClient = class {
5251
5270
  list: () => this.listMonitorFleets(),
5252
5271
  deactivate: (fleetId, options2) => this.deactivateMonitorFleet(fleetId, options2),
5253
5272
  reactivate: (fleetId, options2) => this.reactivateMonitorFleet(fleetId, options2),
5273
+ start: (fleetId, options2) => this.reactivateMonitorFleet(fleetId, options2),
5274
+ stop: (fleetId, options2) => this.deactivateMonitorFleet(fleetId, options2),
5254
5275
  waitForConvergence: (fleetId, options2) => this.waitForMonitorFleetConvergence(fleetId, options2)
5255
5276
  }
5256
5277
  };
@@ -7901,7 +7922,8 @@ var DeeplineClient = class {
7901
7922
  /** List deployed monitors. Prefer `client.monitors.list(...)`. */
7902
7923
  async listMonitors(options) {
7903
7924
  const params = new URLSearchParams();
7904
- if (options?.status) params.set("status", options.status);
7925
+ if (options?.state) params.set("state", options.state);
7926
+ else if (options?.status) params.set("status", options.status);
7905
7927
  if (options?.limit !== void 0)
7906
7928
  params.set("limit", String(options.limit));
7907
7929
  if (options?.cursor) params.set("cursor", options.cursor);
@@ -8040,6 +8062,92 @@ var DeeplineClient = class {
8040
8062
  }
8041
8063
  );
8042
8064
  }
8065
+ namedMonitorBatchPath(batchId) {
8066
+ return `/api/v2/monitors/batches/${encodeURIComponent(batchId)}`;
8067
+ }
8068
+ async syncNamedMonitorBatch(batchId, definitions, options) {
8069
+ return this.http.request(
8070
+ this.namedMonitorBatchPath(batchId),
8071
+ {
8072
+ method: "PUT",
8073
+ body: {
8074
+ version: 1,
8075
+ kind: "batch",
8076
+ monitors: definitions,
8077
+ ...options?.expectedGeneration === void 0 ? {} : { expected_generation: options.expectedGeneration }
8078
+ },
8079
+ headers: this.monitorJobHeaders(
8080
+ `batch-sync-${batchId}`,
8081
+ options?.idempotencyKey
8082
+ ),
8083
+ maxRetries: 0,
8084
+ exactUrlOnly: true
8085
+ }
8086
+ );
8087
+ }
8088
+ async startNamedMonitorBatch(batchId, options) {
8089
+ return this.http.request(
8090
+ `${this.namedMonitorBatchPath(batchId)}/start`,
8091
+ {
8092
+ method: "POST",
8093
+ body: {},
8094
+ headers: this.monitorJobHeaders(
8095
+ `batch-start-${batchId}`,
8096
+ options?.idempotencyKey
8097
+ ),
8098
+ maxRetries: 0,
8099
+ exactUrlOnly: true
8100
+ }
8101
+ );
8102
+ }
8103
+ async stopNamedMonitorBatch(batchId, options) {
8104
+ return this.http.request(
8105
+ this.namedMonitorBatchPath(batchId),
8106
+ {
8107
+ method: "DELETE",
8108
+ body: {},
8109
+ headers: this.monitorJobHeaders(
8110
+ `batch-stop-${batchId}`,
8111
+ options?.idempotencyKey
8112
+ ),
8113
+ maxRetries: 0,
8114
+ exactUrlOnly: true
8115
+ }
8116
+ );
8117
+ }
8118
+ async getNamedMonitorBatch(batchId) {
8119
+ return this.http.request(
8120
+ this.namedMonitorBatchPath(batchId),
8121
+ { method: "GET" }
8122
+ );
8123
+ }
8124
+ async submitScalarMonitorLifecycle(monitorKey, action, options) {
8125
+ return this.http.request(
8126
+ `/api/v2/monitors/deployed/${encodeURIComponent(monitorKey)}/${action}`,
8127
+ {
8128
+ method: "POST",
8129
+ body: {},
8130
+ headers: this.monitorJobHeaders(
8131
+ `${action}-${monitorKey}`,
8132
+ options?.idempotencyKey
8133
+ ),
8134
+ maxRetries: 0,
8135
+ exactUrlOnly: true
8136
+ }
8137
+ );
8138
+ }
8139
+ async syncScalarMonitor(definition, options) {
8140
+ return this.http.request("/api/v2/monitors/sync", {
8141
+ method: "POST",
8142
+ body: definition,
8143
+ headers: this.monitorJobHeaders(
8144
+ `sync-${definition.key}`,
8145
+ options?.idempotencyKey
8146
+ ),
8147
+ maxRetries: 0,
8148
+ exactUrlOnly: true
8149
+ });
8150
+ }
8043
8151
  async getMonitorJob(jobId) {
8044
8152
  return this.http.request(
8045
8153
  `/api/v2/monitors/jobs/${encodeURIComponent(jobId)}`,
@@ -33626,6 +33734,40 @@ function asRecord2(value) {
33626
33734
  function asString(value) {
33627
33735
  return typeof value === "string" && value.trim() ? value : void 0;
33628
33736
  }
33737
+ var MONITOR_STATES = /* @__PURE__ */ new Set([
33738
+ "active",
33739
+ "billing_suspended",
33740
+ "disabled"
33741
+ ]);
33742
+ function customerMonitorState(value) {
33743
+ if (typeof value === "string" && MONITOR_STATES.has(value)) {
33744
+ return value;
33745
+ }
33746
+ return void 0;
33747
+ }
33748
+ function readMonitorState(record3) {
33749
+ const state = customerMonitorState(record3.state);
33750
+ if (state) return state;
33751
+ const legacyStatus = asString(record3.status);
33752
+ if (legacyStatus === "active") return "active";
33753
+ if (legacyStatus === "billing_suspended") return "billing_suspended";
33754
+ if (legacyStatus === "disabled") return "disabled";
33755
+ if (legacyStatus === "inactive") return "disabled";
33756
+ if (typeof record3.active === "boolean") {
33757
+ return record3.active ? "active" : "disabled";
33758
+ }
33759
+ return void 0;
33760
+ }
33761
+ function monitorStateFilter(value) {
33762
+ if (value === "all") return "all";
33763
+ return customerMonitorState(value);
33764
+ }
33765
+ function monitorStateFilterLabel(value, fallback = "active") {
33766
+ const canonical = monitorStateFilter(value);
33767
+ if (canonical) return canonical;
33768
+ if (value === "inactive") return "disabled";
33769
+ return fallback;
33770
+ }
33629
33771
  function asFiniteNumber(value) {
33630
33772
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
33631
33773
  }
@@ -33716,14 +33858,14 @@ function renderMonitorDeployCompletion(payload) {
33716
33858
  if (!key || streams.length === 0) return void 0;
33717
33859
  const toolId = tool ?? (monitor ? asString(monitor.tool) : void 0) ?? "<tool>";
33718
33860
  const name = monitor ? asString(monitor.name) : void 0;
33719
- const status = monitor ? asString(monitor.status) : void 0;
33861
+ const state = monitor ? readMonitorState(monitor) : void 0;
33720
33862
  const pricingLine = monitorPricingLine(monitor?.pricing ?? payload.pricing);
33721
33863
  const eventStreams = streams.filter((stream) => stream.isEvent);
33722
33864
  const matched = eventStreams.filter((stream) => stream.matchesPayload);
33723
33865
  const shown = matched.length ? matched : eventStreams.length ? eventStreams : streams;
33724
33866
  const primary = shown[0];
33725
33867
  const lines = [
33726
- `\u2713 Deployed monitor "${key}"${name ? ` (${name})` : ""} \u2014 tool ${toolId}${status ? `, status ${status}` : ""}`,
33868
+ `\u2713 Deployed monitor "${key}"${name ? ` (${name})` : ""} \u2014 tool ${toolId}${state ? `, status ${state}` : ""}`,
33727
33869
  "",
33728
33870
  "Output \u2192 Customer DB:"
33729
33871
  ];
@@ -33824,10 +33966,10 @@ function renderMonitorDeployPlan(payload) {
33824
33966
  const key = candidate ? asString(candidate.key) : void 0;
33825
33967
  if (!candidate || !key) return [];
33826
33968
  const name = asString(candidate.name);
33827
- const status = asString(candidate.status);
33969
+ const state = readMonitorState(candidate);
33828
33970
  const covers = asString(candidate.covers);
33829
33971
  return [
33830
- ` ${key}${name ? ` (${name})` : ""}${status ? ` \u2014 ${status}` : ""}${covers ? `; covers ${covers}` : ""}`
33972
+ ` ${key}${name ? ` (${name})` : ""}${state ? ` \u2014 ${state}` : ""}${covers ? `; covers ${covers}` : ""}`
33831
33973
  ];
33832
33974
  });
33833
33975
  if (candidateLines.length > 0) {
@@ -34006,7 +34148,7 @@ async function handleMonitorsAvailable(toolId, options) {
34006
34148
  text: tool ? void 0 : renderAvailableToolsText(payload)
34007
34149
  });
34008
34150
  }
34009
- function renderDeployedListText(payload, requestedStatus) {
34151
+ function renderDeployedListText(payload, requestedStatus, filterKind = "status") {
34010
34152
  const monitors = Array.isArray(payload.monitors) ? payload.monitors : null;
34011
34153
  if (!monitors) return void 0;
34012
34154
  const total = asFiniteNumber(payload.total);
@@ -34016,7 +34158,7 @@ function renderDeployedListText(payload, requestedStatus) {
34016
34158
  const entry = asRecord2(raw);
34017
34159
  const key = entry ? asString(entry.key) ?? asString(entry.monitor_key) : void 0;
34018
34160
  if (!entry || !key) continue;
34019
- const status = asString(entry.status);
34161
+ const state = readMonitorState(entry);
34020
34162
  const tool = asString(entry.tool);
34021
34163
  const monitorType = asString(entry.type);
34022
34164
  const name = asString(entry.name);
@@ -34027,7 +34169,7 @@ function renderDeployedListText(payload, requestedStatus) {
34027
34169
  const lastReceivedEvent = asString(entry.last_received_event);
34028
34170
  const boundPlays = Array.isArray(entry.bound_plays) ? entry.bound_plays.length : void 0;
34029
34171
  lines.push(
34030
- ` ${key}${status ? ` ${status}` : ""}${tool ? ` ${tool}` : ""}${name ? ` (${name})` : ""}`
34172
+ ` ${key}${state ? ` ${state}` : ""}${tool ? ` ${tool}` : ""}${name ? ` (${name})` : ""}`
34031
34173
  );
34032
34174
  if (outputTable || monitorType || webhookState || executionType || boundPlays !== void 0) {
34033
34175
  lines.push(
@@ -34049,30 +34191,38 @@ function renderDeployedListText(payload, requestedStatus) {
34049
34191
  const playName = asString(play?.name) ?? "unnamed Play";
34050
34192
  const health = asRecord2(play?.consumer_health);
34051
34193
  const healthRequested = Boolean(play && "consumer_health" in play);
34052
- const state = healthRequested ? asString(health?.last_run_status) ?? "no delivery yet" : "health not requested";
34194
+ const state2 = healthRequested ? asString(health?.last_run_status) ?? "no delivery yet" : "health not requested";
34053
34195
  const lastError = asString(health?.last_error);
34054
34196
  lines.push(
34055
- ` consumer: ${playName} \u2014 ${state}${lastError ? ` (${lastError})` : ""}`
34197
+ ` consumer: ${playName} \u2014 ${state2}${lastError ? ` (${lastError})` : ""}`
34056
34198
  );
34057
34199
  }
34058
34200
  }
34059
34201
  }
34060
- const applied = asString(payload.status_filter_applied) ?? requestedStatus ?? "active";
34202
+ const applied = monitorStateFilterLabel(
34203
+ payload.state_filter_applied ?? payload.status_filter_applied,
34204
+ monitorStateFilterLabel(requestedStatus)
34205
+ );
34061
34206
  lines.push(
34062
- `Status filter: ${applied}${requestedStatus === void 0 && applied === "active" ? " (default)" : ""} \u2014 use --status all to include inactive monitors.`
34207
+ `State filter: ${applied}${requestedStatus === void 0 && applied === "active" ? " (default)" : ""} \u2014 use --state all to include all monitors.`
34063
34208
  );
34064
- const summary = Array.isArray(payload.status_summary) ? payload.status_summary.flatMap((raw) => {
34209
+ const rawSummary = Array.isArray(payload.state_summary) ? payload.state_summary : Array.isArray(payload.status_summary) ? payload.status_summary : [];
34210
+ const summary = rawSummary.flatMap((raw) => {
34065
34211
  const item = asRecord2(raw);
34066
- const status = item ? asString(item.status) : void 0;
34212
+ const state = item ? readMonitorState(item) : void 0;
34067
34213
  const count = item ? asFiniteNumber(item.count) : void 0;
34068
- return status && count !== void 0 ? [`${status}: ${count}`] : [];
34069
- }).join(" ") : "";
34070
- if (summary) lines.push(`All monitor states: ${summary}`);
34214
+ return state && count !== void 0 ? [`${state}: ${count}`] : [];
34215
+ }).join(" ");
34216
+ if (summary) {
34217
+ lines.push(
34218
+ `${payload.state_summary_scope === "filter_total" ? "Matching monitors" : "Current page states"}: ${summary}`
34219
+ );
34220
+ }
34071
34221
  if (payload.has_more === true || payload.is_truncated === true) {
34072
34222
  const nextCursor = asString(payload.next_cursor);
34073
34223
  lines.push(
34074
34224
  total !== void 0 ? `List truncated \u2014 showing ${monitors.length} of ${total}. Before concluding "no matching monitor exists," page the full registry:` : 'List truncated. Before concluding "no matching monitor exists," page the full registry:',
34075
- nextCursor ? ` deepline monitors list${requestedStatus ? ` --status ${requestedStatus}` : ""} --cursor ${nextCursor}` : " raise --limit above the reported total."
34225
+ nextCursor ? ` deepline monitors list${requestedStatus ? ` --${filterKind} ${filterKind === "state" ? monitorStateFilterLabel(requestedStatus) : requestedStatus}` : ""} --cursor ${nextCursor}` : " raise --limit above the reported total."
34076
34226
  );
34077
34227
  }
34078
34228
  if (monitors.length > 0) {
@@ -34082,12 +34232,19 @@ function renderDeployedListText(payload, requestedStatus) {
34082
34232
  `;
34083
34233
  }
34084
34234
  async function handleMonitorsList(options) {
34235
+ const state = options.state ? monitorStateFilter(options.state) : void 0;
34236
+ if (options.state !== void 0 && !state) {
34237
+ throw new MonitorsUsageError(
34238
+ `--state must be active, billing_suspended, disabled, or all; received ${options.state}.`
34239
+ );
34240
+ }
34085
34241
  if (options.compact) {
34086
34242
  process.stderr.write(
34087
34243
  "`--compact` is deprecated and now does nothing; returning the complete monitor records.\n"
34088
34244
  );
34089
34245
  }
34090
34246
  const payload = await new DeeplineClient().monitors.list({
34247
+ ...state ? { state } : {},
34091
34248
  ...options.status ? { status: options.status } : {},
34092
34249
  ...options.limit ? { limit: options.limit } : {},
34093
34250
  ...options.cursor ? { cursor: options.cursor } : {},
@@ -34095,7 +34252,11 @@ async function handleMonitorsList(options) {
34095
34252
  });
34096
34253
  printCommandEnvelope(payload, {
34097
34254
  json: options.json,
34098
- text: renderDeployedListText(payload, options.status)
34255
+ text: renderDeployedListText(
34256
+ payload,
34257
+ options.state ?? options.status,
34258
+ options.state !== void 0 ? "state" : "status"
34259
+ )
34099
34260
  });
34100
34261
  }
34101
34262
  async function handleMonitorsCheck(definition, options) {
@@ -34140,6 +34301,40 @@ async function handleMonitorsDeploy(definition, options) {
34140
34301
  text: renderMonitorDeployCompletion(payload)
34141
34302
  });
34142
34303
  }
34304
+ async function handleMonitorsSync(definition, options) {
34305
+ const body = resolveMonitorJsonBody({
34306
+ positional: definition,
34307
+ file: options.file,
34308
+ argLabel: "<definition>",
34309
+ command: "deepline monitors sync"
34310
+ });
34311
+ const payload = await new DeeplineClient().monitors.sync(body, {
34312
+ ...options.dryRun ? { dryRun: true } : {},
34313
+ idempotencyKey: options.idempotencyKey ?? monitorJobIdempotencyKey("scalar-sync", void 0)
34314
+ });
34315
+ if (options.dryRun) {
34316
+ const plan = payload;
34317
+ printCommandEnvelope(
34318
+ { dry_run: true, ...plan },
34319
+ { json: options.json, text: renderMonitorDeployPlan(plan) }
34320
+ );
34321
+ return;
34322
+ }
34323
+ printCommandEnvelope(payload, {
34324
+ json: options.json,
34325
+ text: renderMonitorJob(payload)
34326
+ });
34327
+ }
34328
+ async function handleScalarMonitorLifecycle(action, key, options) {
34329
+ const payload = await new DeeplineClient().monitors[action](key, {
34330
+ ...options.dryRun ? { dryRun: true } : {},
34331
+ idempotencyKey: options.idempotencyKey ?? monitorJobIdempotencyKey(`${action}-${key}`, void 0)
34332
+ });
34333
+ printCommandEnvelope(payload, {
34334
+ json: options.json,
34335
+ text: options.dryRun ? void 0 : renderMonitorJob(payload)
34336
+ });
34337
+ }
34143
34338
  function fleetIntegerOption(raw, flag) {
34144
34339
  if (raw === void 0) return void 0;
34145
34340
  const value = Number(raw);
@@ -34193,7 +34388,7 @@ function renderMonitorJob(payload) {
34193
34388
  ];
34194
34389
  if (counts) {
34195
34390
  lines.push(
34196
- `Counts: requested ${asFiniteNumber(counts.requested) ?? 0}, created ${asFiniteNumber(counts.created) ?? 0}, unchanged ${asFiniteNumber(counts.unchanged) ?? 0}, verified ${asFiniteNumber(counts.verified) ?? 0}, failed ${asFiniteNumber(counts.failed) ?? 0}`
34391
+ `Counts: requested ${asFiniteNumber(counts.requested) ?? 0}, created ${asFiniteNumber(counts.created) ?? 0}, updated ${asFiniteNumber(counts.updated) ?? 0}, removed ${asFiniteNumber(counts.removed) ?? 0}, unchanged ${asFiniteNumber(counts.unchanged) ?? 0}, verified ${asFiniteNumber(counts.verified) ?? 0}, failed ${asFiniteNumber(counts.failed) ?? 0}`
34197
34392
  );
34198
34393
  }
34199
34394
  if (reconciliation) {
@@ -34233,6 +34428,93 @@ async function handleMonitorJobBatchDeploy(options, idempotencyKey) {
34233
34428
  { json: options.json, text: renderMonitorJob(payload) }
34234
34429
  );
34235
34430
  }
34431
+ function namedBatchIdempotencyKey(batchId, intent, supplied) {
34432
+ return supplied?.trim() || `monitor-batch-${intent}-${batchId}-${(0, import_node_crypto8.randomUUID)()}`;
34433
+ }
34434
+ async function handleNamedMonitorBatchSync(batchId, options) {
34435
+ if (!options.file) {
34436
+ throw new MonitorsUsageError(
34437
+ "monitors batches sync requires --file <batch.json>."
34438
+ );
34439
+ }
34440
+ const lint = lintMonitorBatchInput(
34441
+ readMonitorDefinitionsJsonFile(options.file)
34442
+ );
34443
+ if (!lint.normalized) {
34444
+ throw new MonitorsUsageError(
34445
+ lint.issues.filter((issue) => issue.severity === "error").map((issue) => `${issue.path || "batch"}: ${issue.message}`).join("; ")
34446
+ );
34447
+ }
34448
+ const parsedGeneration = options.expectedGeneration === void 0 ? void 0 : Number(options.expectedGeneration);
34449
+ if (parsedGeneration !== void 0 && (!Number.isSafeInteger(parsedGeneration) || parsedGeneration < 0)) {
34450
+ throw new MonitorsUsageError(
34451
+ "--expected-generation must be a non-negative integer."
34452
+ );
34453
+ }
34454
+ if (options.dryRun) {
34455
+ printCommandEnvelope(
34456
+ {
34457
+ ok: true,
34458
+ dry_run: true,
34459
+ batch: { id: batchId, desired_count: lint.normalized.monitors.length },
34460
+ issues: lint.issues,
34461
+ next: `deepline monitors batches sync ${batchId} --file ${options.file} --idempotency-key <stable-key> --json`
34462
+ },
34463
+ { json: options.json }
34464
+ );
34465
+ return;
34466
+ }
34467
+ const idempotencyKey = namedBatchIdempotencyKey(
34468
+ batchId,
34469
+ "sync",
34470
+ options.idempotencyKey
34471
+ );
34472
+ const payload = await new DeeplineClient().monitors.batches.sync(
34473
+ batchId,
34474
+ lint.normalized.monitors,
34475
+ {
34476
+ idempotencyKey,
34477
+ ...parsedGeneration === void 0 ? {} : { expectedGeneration: parsedGeneration }
34478
+ }
34479
+ );
34480
+ printCommandEnvelope(
34481
+ { ...payload, idempotency_key: idempotencyKey },
34482
+ { json: options.json, text: renderMonitorJob(payload) }
34483
+ );
34484
+ }
34485
+ async function handleNamedMonitorBatchLifecycle(batchId, intent, options) {
34486
+ if (options.dryRun) {
34487
+ printCommandEnvelope(
34488
+ {
34489
+ ok: true,
34490
+ dry_run: true,
34491
+ batch: { id: batchId, intent },
34492
+ next: `deepline monitors batches ${intent} ${batchId} --idempotency-key <stable-key> --json`
34493
+ },
34494
+ { json: options.json }
34495
+ );
34496
+ return;
34497
+ }
34498
+ const idempotencyKey = namedBatchIdempotencyKey(
34499
+ batchId,
34500
+ intent,
34501
+ options.idempotencyKey
34502
+ );
34503
+ const payload = await new DeeplineClient().monitors.batches[intent](batchId, {
34504
+ idempotencyKey
34505
+ });
34506
+ printCommandEnvelope(
34507
+ { ...payload, idempotency_key: idempotencyKey },
34508
+ { json: options.json, text: renderMonitorJob(payload) }
34509
+ );
34510
+ }
34511
+ async function handleNamedMonitorBatchGet(batchId, options) {
34512
+ const payload = await new DeeplineClient().monitors.batches.get(batchId);
34513
+ printCommandEnvelope(payload, {
34514
+ json: options.json,
34515
+ text: renderMonitorJob(payload)
34516
+ });
34517
+ }
34236
34518
  async function handleMonitorBatchLint(options) {
34237
34519
  if (!options.file) {
34238
34520
  throw new MonitorsUsageError(
@@ -34482,9 +34764,10 @@ function renderFleetSync(payload, input2) {
34482
34764
  }
34483
34765
  function renderFleetGet(payload) {
34484
34766
  const id = asString(payload.id) ?? "unknown";
34485
- const status = fleetStatus(payload) ?? "unknown";
34767
+ const state = readMonitorState(payload) ?? "unknown";
34768
+ const status = fleetStatus(payload);
34486
34769
  const lines = [
34487
- `Fleet ${id} \u2014 ${status}`,
34770
+ `Fleet ${id} \u2014 state ${state}`,
34488
34771
  ` monitors ${asFiniteNumber(payload.live) ?? 0} live / ${asFiniteNumber(payload.expected) ?? 0} expected`,
34489
34772
  ` counts ${fleetCountsLine(payload)}`,
34490
34773
  ` generation ${asFiniteNumber(payload.generation) ?? "unknown"} \xB7 converged generation ${asFiniteNumber(payload.converged_generation) ?? "none"}`
@@ -34563,8 +34846,8 @@ function renderFleetList(payload) {
34563
34846
  (max, fleet) => Math.max(max, (asString(fleet.id) ?? "").length),
34564
34847
  0
34565
34848
  );
34566
- const statusWidth = fleets.reduce(
34567
- (max, fleet) => Math.max(max, (fleetStatus(fleet) ?? "unknown").length),
34849
+ const stateWidth = fleets.reduce(
34850
+ (max, fleet) => Math.max(max, (readMonitorState(fleet) ?? "unknown").length),
34568
34851
  0
34569
34852
  );
34570
34853
  const lines = [`Fleets (${fleets.length})`];
@@ -34575,7 +34858,7 @@ function renderFleetList(payload) {
34575
34858
  counts.failed ? `failed ${counts.failed}` : ""
34576
34859
  ].filter(Boolean);
34577
34860
  lines.push(
34578
- ` ${(asString(fleet.id) ?? "-").padEnd(idWidth)} ${(fleetStatus(fleet) ?? "unknown").padEnd(statusWidth)} ${asFiniteNumber(fleet.live) ?? 0}/${asFiniteNumber(fleet.expected) ?? 0}${trouble.length ? ` ${trouble.join(" \xB7 ")}` : ""}`
34861
+ ` ${(asString(fleet.id) ?? "-").padEnd(idWidth)} ${(readMonitorState(fleet) ?? "unknown").padEnd(stateWidth)} ${asFiniteNumber(fleet.live) ?? 0}/${asFiniteNumber(fleet.expected) ?? 0}${trouble.length ? ` ${trouble.join(" \xB7 ")}` : ""}`
34579
34862
  );
34580
34863
  }
34581
34864
  return `${lines.join("\n")}
@@ -34916,7 +35199,7 @@ async function handleMonitorFleetsReactivate(fleetId, options, idempotencyKey) {
34916
35199
  if (!options.wait) {
34917
35200
  printCommandEnvelope(accepted, {
34918
35201
  json: options.json,
34919
- text: `Fleet ${fleetId} \u2014 ${asString(payload.status) ?? "billing_reactivating"}
35202
+ text: `Fleet ${fleetId} \u2014 ${readMonitorState(payload) ? `state ${readMonitorState(payload)}` : "reactivation accepted"}
34920
35203
  idempotency key ${idempotencyKey}
34921
35204
  `
34922
35205
  });
@@ -35034,7 +35317,7 @@ Preview the blast radius first:
35034
35317
  });
35035
35318
  return;
35036
35319
  }
35037
- const acceptedText = `Fleet ${fleetId} \u2014 ${asString(payload.status) ?? "deactivating"}
35320
+ const acceptedText = `Fleet ${fleetId} \u2014 ${readMonitorState(payload) ? `state ${readMonitorState(payload)}` : "deactivation accepted"}
35038
35321
  idempotency key ${idempotencyKey}
35039
35322
  ` + (fleetServerNext(payload) ? `Next: ${fleetServerNext(payload)}
35040
35323
  ` : "");
@@ -35108,7 +35391,7 @@ function renderMonitorGet(payload) {
35108
35391
  const key = asString(payload.key);
35109
35392
  const tool = asString(payload.tool);
35110
35393
  if (!key || !tool) return void 0;
35111
- const status = asString(payload.status);
35394
+ const state = readMonitorState(payload);
35112
35395
  const monitorType = asString(payload.type);
35113
35396
  const hasLastReceivedEvent = "last_received_event" in payload;
35114
35397
  const lastReceivedEvent = asString(payload.last_received_event);
@@ -35128,7 +35411,7 @@ function renderMonitorGet(payload) {
35128
35411
  `Monitor: ${key}`,
35129
35412
  `Tool: ${tool}`,
35130
35413
  ...monitorType ? [`Type: ${monitorType}`] : [],
35131
- ...status ? [`Status: ${status}`] : [],
35414
+ ...state ? [`Status: ${state}`] : [],
35132
35415
  ...hasLastReceivedEvent ? [`Latest inbound event: ${lastReceivedEvent ?? "never"}`] : [],
35133
35416
  ...pricingLine ? [`Pricing: ${pricingLine}`] : [],
35134
35417
  ...nextRenewalAt ? [`Next renewal: ${nextRenewalAt}`] : []
@@ -35565,27 +35848,15 @@ function monitorBatchScope(options, kind) {
35565
35848
  function monitorBatchIdempotencyKey(kind, value) {
35566
35849
  return value?.trim() || `monitor-batch-${kind}-${(0, import_node_crypto8.randomUUID)()}`;
35567
35850
  }
35568
- function legacyDryRunManifest(raw) {
35569
- let parsed;
35851
+ function isCanonicalBatchJsonDocument(raw) {
35570
35852
  try {
35571
- parsed = JSON.parse(raw);
35853
+ const parsed = JSON.parse(raw);
35854
+ if (Array.isArray(parsed)) return true;
35855
+ const input2 = asRecord2(parsed);
35856
+ return input2 !== null && (input2.kind === "batch" || Object.prototype.hasOwnProperty.call(input2, "monitors") || Object.prototype.hasOwnProperty.call(input2, "version"));
35572
35857
  } catch {
35573
- return raw;
35574
- }
35575
- const object = asRecord2(parsed);
35576
- if (object && asString(object.key) && asString(object.tool)) {
35577
- return raw;
35578
- }
35579
- const isBatchDocument = Array.isArray(parsed) || object !== null && (Object.prototype.hasOwnProperty.call(object, "monitors") || object.kind === "batch");
35580
- if (!isBatchDocument) return raw;
35581
- const lint = lintMonitorBatchInput(parsed);
35582
- if (!lint.normalized) {
35583
- throw new MonitorsUsageError(
35584
- lint.issues.filter((issue) => issue.severity === "error").map((issue) => `${issue.path || "batch"}: ${issue.message}`).join("; ")
35585
- );
35858
+ return false;
35586
35859
  }
35587
- return `${lint.normalized.monitors.map((monitor) => JSON.stringify(monitor)).join("\n")}
35588
- `;
35589
35860
  }
35590
35861
  async function handleMonitorBatchDeploy(options) {
35591
35862
  if (!options.file?.trim()) {
@@ -35609,8 +35880,10 @@ async function handleMonitorBatchDeploy(options) {
35609
35880
  if (!manifestNdjson.trim()) {
35610
35881
  throw new MonitorsUsageError("Monitor batch manifest is empty.");
35611
35882
  }
35612
- if (options.dryRun === true) {
35613
- manifestNdjson = legacyDryRunManifest(manifestNdjson);
35883
+ if (isCanonicalBatchJsonDocument(manifestNdjson)) {
35884
+ throw new MonitorsUsageError(
35885
+ "Canonical Batch JSON cannot use --dry-run or --yes; those flags select the retained legacy NDJSON operation. Run `deepline monitors batch lint --file <batch.json> --json`, then submit the Monitor Job with `deepline monitors batch deploy --file <batch.json> --idempotency-key <key> --json`."
35886
+ );
35614
35887
  }
35615
35888
  const idempotencyKey = monitorBatchIdempotencyKey(
35616
35889
  "deploy",
@@ -35812,7 +36085,7 @@ Examples:
35812
36085
  ).requiredOption(
35813
36086
  "--file <path>",
35814
36087
  'Batch JSON ({"version":1,"kind":"batch","monitors":[...]}), or legacy NDJSON with --yes/--dry-run'
35815
- ).option("--dry-run", "Use the retained legacy batch-operation plan").option("--yes", "Use the retained legacy NDJSON batch operation").option(
36088
+ ).option("--dry-run", "Preview a retained legacy NDJSON batch operation").option("--yes", "Confirm a retained legacy NDJSON batch operation").option(
35816
36089
  "--idempotency-key <key>",
35817
36090
  "Stable retry key (generated when omitted)"
35818
36091
  )
@@ -35879,6 +36152,46 @@ Examples:
35879
36152
  withJsonOption(
35880
36153
  batch.command("get <operation-id>").description("Read batch progress and one bounded evidence page.").option("--cursor <cursor>", "Read the next retained evidence page")
35881
36154
  ).action(monitorsAction(handleMonitorBatchGet));
36155
+ const namedBatches = monitors.command("batches").description(
36156
+ "Manage stable named Batches whose omitted members are stopped."
36157
+ );
36158
+ withJsonOption(namedBatches);
36159
+ withJsonOption(
36160
+ namedBatches.command("sync <batch-id>").description(
36161
+ "Publish the complete desired member set and return one Monitor Job."
36162
+ ).requiredOption(
36163
+ "--file <path>",
36164
+ "Canonical Batch JSON file, or - for stdin"
36165
+ ).option(
36166
+ "--dry-run",
36167
+ "Validate and show the desired count without publishing"
36168
+ ).option("--expected-generation <n>", "Reject a stale concurrent update").option("--idempotency-key <key>", "Stable retry key")
36169
+ ).action(monitorsAction(handleNamedMonitorBatchSync));
36170
+ withJsonOption(
36171
+ namedBatches.command("start <batch-id>").description("Reapply the retained member set through one Monitor Job.").option(
36172
+ "--dry-run",
36173
+ "Show the retained-intent operation without publishing"
36174
+ ).option("--idempotency-key <key>", "Stable retry key")
36175
+ ).action(
36176
+ monitorsAction(
36177
+ (batchId, options) => handleNamedMonitorBatchLifecycle(batchId, "start", options)
36178
+ )
36179
+ );
36180
+ withJsonOption(
36181
+ namedBatches.command("stop <batch-id>").description(
36182
+ "Publish an empty desired set while retaining members for start."
36183
+ ).option(
36184
+ "--dry-run",
36185
+ "Show the retained-intent operation without publishing"
36186
+ ).option("--idempotency-key <key>", "Stable retry key")
36187
+ ).action(
36188
+ monitorsAction(
36189
+ (batchId, options) => handleNamedMonitorBatchLifecycle(batchId, "stop", options)
36190
+ )
36191
+ );
36192
+ withJsonOption(
36193
+ namedBatches.command("get <batch-id>").description("Read named Batch intent and its latest Monitor Job.")
36194
+ ).action(monitorsAction(handleNamedMonitorBatchGet));
35882
36195
  withJsonOption(
35883
36196
  monitors.command("status").description("Check whether you have access to Deepline monitors.").addHelpText(
35884
36197
  "after",
@@ -35930,9 +36243,11 @@ Examples:
35930
36243
  "after",
35931
36244
  `
35932
36245
  Notes:
35933
- Read-only. A monitor state is active or inactive; provider disagreement is
35934
- reported separately by audit/health. The output echoes the state filter that
35935
- was applied. The response reports
36246
+ Read-only. A monitor has one of three customer states: active,
36247
+ billing_suspended, or disabled. Provisioning, cleanup, retries, and failures
36248
+ are reported by Monitor Jobs; provider disagreement is reported separately by
36249
+ audit/health. The output echoes the canonical state filter that was applied.
36250
+ The legacy --status flag remains accepted for installed clients. The response reports
35936
36251
  total (the true registry count, not the page size), returned, has_more, and
35937
36252
  next_cursor. When has_more is true, page with --cursor <next_cursor> until it
35938
36253
  is false \u2014 a "no matching
@@ -35944,13 +36259,18 @@ Notes:
35944
36259
 
35945
36260
  Examples:
35946
36261
  deepline monitors list
36262
+ deepline monitors list --state billing_suspended --json
36263
+ deepline monitors list --state all --json
35947
36264
  deepline monitors list --status all --json
35948
36265
  deepline monitors list --status all --cursor <next_cursor> --json
35949
36266
  deepline monitors list --include-consumers --limit 20 --json
35950
36267
  `
36268
+ ).option(
36269
+ "--state <state>",
36270
+ "Filter by customer state: active (default), billing_suspended, disabled, or all"
35951
36271
  ).option(
35952
36272
  "--status <status>",
35953
- "Filter by monitor state: active (default), inactive, or all"
36273
+ "Deprecated compatibility filter; use --state (active, billing_suspended, disabled, or all)"
35954
36274
  ).option("--limit <n>", "Limit the number of deployed monitors returned").option(
35955
36275
  "--cursor <cursor>",
35956
36276
  "Page past a truncated result using the next_cursor from a prior list response"
@@ -36048,13 +36368,10 @@ Notes:
36048
36368
  no separate repair command or retry queue: rerun the same deploy/update.
36049
36369
  Scheduled reconciliation can also finish that exact saved cleanup; it never
36050
36370
  creates another monitor.
36051
- For TamRadar, deliberately changing payload.updates_since on an initial or
36052
- active definition is an explicit historical replay request. A disabled
36053
- monitor cannot stage this change; Deepline rejects that update. Filter-only
36054
- deploys and ordinary reactivation omit the field and start the provider
36055
- resource at creation instead.
36056
- New Hire and Promotion source dates use calendar-month precision upstream,
36057
- so Deepline rejects current-month updates_since values for those radar types.
36371
+ For TamRadar, deliberately changing payload.updates_since is an explicit
36372
+ historical replay request, including when redeploying a disabled monitor.
36373
+ Deepline preserves that selected boundary; filter-only deploys and ordinary
36374
+ reactivation start from a fresh future-only source boundary instead.
36058
36375
  Operational controls are Deepline-managed. A monitor writes rows; downstream
36059
36376
  automation belongs in a Play with sqlListeners.
36060
36377
 
@@ -36071,6 +36388,17 @@ Examples:
36071
36388
  "Validate and show the deploy plan (cost, reuse candidates) without deploying"
36072
36389
  )
36073
36390
  ).action(monitorsAction(handleMonitorsDeploy));
36391
+ withJsonOption(
36392
+ monitors.command("sync [definition]").description(
36393
+ "Publish one complete desired monitor definition and return a Monitor Job."
36394
+ ).option(
36395
+ "-f, --file <path>",
36396
+ "Read definition JSON from a file, or - for stdin"
36397
+ ).option(
36398
+ "--dry-run",
36399
+ "Validate and show the deploy plan without publishing"
36400
+ ).option("--idempotency-key <key>", "Stable retry key")
36401
+ ).action(monitorsAction(handleMonitorsSync));
36074
36402
  withJsonOption(
36075
36403
  monitors.command("update <key> [patch]").description("Update a deployed monitor by its public key.").addHelpText(
36076
36404
  "after",
@@ -36086,9 +36414,7 @@ For TamRadar, changing payload.updates_since on an initial or active definition
36086
36414
  is an explicit historical replay request. Deepline passes that requested boundary upstream, but previously
36087
36415
  delivered canonical findings are deduplicated before dispatch and billing; only
36088
36416
  previously unseen historical findings are chargeable. Filter-only updates,
36089
- repair, and reactivation instead omit the field and start the provider resource
36090
- at creation. New Hire and Promotion source dates use calendar-month precision,
36091
- so current-month updates_since values are rejected for those radar types.
36417
+ repair, and reactivation instead use a fresh future-only source boundary.
36092
36418
 
36093
36419
  Examples:
36094
36420
  deepline monitors update my-monitor '{"name":"Interested replies"}' --json
@@ -36141,6 +36467,22 @@ Examples:
36141
36467
  `
36142
36468
  ).option("--dry-run", "Show the reactivation cost without reactivating")
36143
36469
  ).action(monitorsAction(handleMonitorsReactivate));
36470
+ withJsonOption(
36471
+ monitors.command("start <key>").description("Apply the retained definition for a stopped monitor.").option("--dry-run", "Show the start plan without changing anything").option("--idempotency-key <key>", "Stable retry key")
36472
+ ).action(
36473
+ monitorsAction(
36474
+ (key, options) => handleScalarMonitorLifecycle("start", key, options)
36475
+ )
36476
+ );
36477
+ withJsonOption(
36478
+ monitors.command("stop <key>").description(
36479
+ "Stop a monitor upstream while retaining its definition for `start`."
36480
+ ).option("--dry-run", "Show the stop plan without changing anything").option("--idempotency-key <key>", "Stable retry key")
36481
+ ).action(
36482
+ monitorsAction(
36483
+ (key, options) => handleScalarMonitorLifecycle("stop", key, options)
36484
+ )
36485
+ );
36144
36486
  const jobs = monitors.command("jobs").description("Read, wait for, inspect, or cancel Monitor Jobs.");
36145
36487
  withJsonOption(jobs);
36146
36488
  withJsonOption(
@@ -36320,7 +36662,7 @@ Examples:
36320
36662
  )
36321
36663
  ).action(monitorsAction(handleMonitorFleetsGet));
36322
36664
  withJsonOption(
36323
- fleets.command("deactivate <fleet-id>").description("Deactivate a fleet and the monitors it owns.").addHelpText(
36665
+ fleets.command("deactivate <fleet-id>").alias("stop").description("Deactivate a fleet and the monitors it owns.").addHelpText(
36324
36666
  "after",
36325
36667
  `
36326
36668
  Notes:
@@ -36359,7 +36701,7 @@ Examples:
36359
36701
  }
36360
36702
  });
36361
36703
  withJsonOption(
36362
- fleets.command("reactivate <fleet-id>").description(
36704
+ fleets.command("reactivate <fleet-id>").alias("start").description(
36363
36705
  "Explicitly recreate a fleet after a credit-triggered suspension."
36364
36706
  ).addHelpText(
36365
36707
  "after",
@@ -36394,8 +36736,11 @@ Example:
36394
36736
  });
36395
36737
  const deployed = withJsonOption(
36396
36738
  monitors.command("deployed", { hidden: true }).description("Alias of `monitors list` (plus get/update/delete aliases).").option(
36739
+ "--state <state>",
36740
+ "Filter by customer state: active (default), billing_suspended, disabled, or all"
36741
+ ).option(
36397
36742
  "--status <status>",
36398
- "Filter by monitor state: active (default), inactive, or all"
36743
+ "Deprecated compatibility filter; use --state (active, billing_suspended, disabled, or all)"
36399
36744
  ).option("--limit <n>", "Limit the number of deployed monitors returned").option(
36400
36745
  "--cursor <cursor>",
36401
36746
  "Page past a truncated result using the next_cursor from a prior list response"