deepline 0.3.135 → 0.3.137

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.
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
200
200
  // getters keep their established compatibility behavior.
201
201
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
202
202
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
203
- version: '0.3.135',
203
+ version: '0.3.137',
204
204
  updateSummary:
205
205
  '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.',
206
206
  packageCapabilities: {
@@ -200,6 +200,11 @@ export const QUEUE_ITEM_STATES = [
200
200
 
201
201
  export type QueueItemState = (typeof QUEUE_ITEM_STATES)[number];
202
202
 
203
+ /** Operator disposition is an overlay on native source state. Retiring an
204
+ * item removes it from active operational views without pretending the owner
205
+ * completed, deleted, or replayed the source row. */
206
+ export type QueueItemDisposition = 'active' | 'retired';
207
+
203
208
  export type QueueItemAction =
204
209
  | 'archive'
205
210
  | 'quarantine'
@@ -207,6 +212,7 @@ export type QueueItemAction =
207
212
  | 'hold'
208
213
  | 'resume'
209
214
  | 'cancel'
215
+ | 'retire'
210
216
  | 'update';
211
217
 
212
218
  export const QUEUE_ITEM_ACTIONS = [
@@ -216,6 +222,7 @@ export const QUEUE_ITEM_ACTIONS = [
216
222
  'hold',
217
223
  'resume',
218
224
  'cancel',
225
+ 'retire',
219
226
  'update',
220
227
  ] as const satisfies readonly QueueItemAction[];
221
228
 
@@ -262,6 +269,8 @@ export type QueueItem = {
262
269
  readonly revision: string;
263
270
  readonly observedAt: string;
264
271
  readonly state: QueueItemState;
272
+ /** Additive operator overlay; older connectors may omit it. */
273
+ readonly disposition?: QueueItemDisposition;
265
274
  readonly nativeState: string;
266
275
  readonly lastError?: QueueItemLastError;
267
276
  readonly actions: readonly ActionAvailability[];
@@ -269,6 +278,8 @@ export type QueueItem = {
269
278
  readonly createdAt?: string;
270
279
  readonly updatedAt?: string;
271
280
  readonly summary?: string;
281
+ readonly retiredAt?: string;
282
+ readonly retirementReason?: string;
272
283
  };
273
284
 
274
285
  /** Keep old DLQ verbs working at the boundary while exposing a smaller,
@@ -424,8 +435,9 @@ export type QueueItemConnectorContext = {
424
435
 
425
436
  /**
426
437
  * Owner implementation port. The connector owns native reads, state mapping,
427
- * lease/CAS checks, and outcome verification. The shared control service only
428
- * authenticates, validates, journals idempotency, and returns this result.
438
+ * lease/CAS checks, and outcome verification. `retire` is the one shared
439
+ * disposition action: connectors fence the source revision, while the shared
440
+ * control plane records an overlay and never mutates the owner row.
429
441
  */
430
442
  export type QueueItemConnector = {
431
443
  readonly id: string;
package/dist/cli/index.js CHANGED
@@ -3068,7 +3068,7 @@ var SDK_RELEASE = {
3068
3068
  // getters keep their established compatibility behavior.
3069
3069
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
3070
3070
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
3071
- version: "0.3.135",
3071
+ version: "0.3.137",
3072
3072
  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.",
3073
3073
  packageCapabilities: {
3074
3074
  updatePreferences: 1
@@ -24717,6 +24717,22 @@ function formatPlayErrorForDisplay(status, error) {
24717
24717
  }
24718
24718
  return error;
24719
24719
  }
24720
+ function structuredErrorsForStatus(status) {
24721
+ const directErrors = getRecordField(status, "errors");
24722
+ if (Array.isArray(directErrors)) {
24723
+ const records = directErrors.filter(
24724
+ (entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
24725
+ );
24726
+ if (records.length > 0) return records;
24727
+ }
24728
+ const resultErrors = getRecordField(
24729
+ getRecordField(status, "result"),
24730
+ "errors"
24731
+ );
24732
+ return Array.isArray(resultErrors) ? resultErrors.filter(
24733
+ (entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
24734
+ ) : [];
24735
+ }
24720
24736
  function isGenericInternalServerError(error) {
24721
24737
  if (!error) return false;
24722
24738
  return /^(?:internalservererror|internal server error|http 500|500)$/i.test(
@@ -24725,16 +24741,21 @@ function isGenericInternalServerError(error) {
24725
24741
  }
24726
24742
  function selectRunErrorForDisplay(status) {
24727
24743
  const progressError = getStringField(status.progress, "error");
24744
+ const structuredErrors = structuredErrorsForStatus(status);
24745
+ const structuredMessage = structuredErrors.map((entry) => getStringField(entry, "message")).find((message) => Boolean(message));
24746
+ const structuredRuntimeLimit = structuredErrors.some(
24747
+ (entry) => getStringField(entry, "code") === "RUNTIME_LIMIT_EXCEEDED"
24748
+ );
24749
+ if (structuredMessage && (structuredRuntimeLimit || !progressError && getPlayRunPackage(status) === null)) {
24750
+ return structuredMessage;
24751
+ }
24728
24752
  if (!isGenericInternalServerError(progressError)) {
24729
24753
  return progressError;
24730
24754
  }
24731
- const directErrors = getRecordField(status, "errors");
24732
- if (Array.isArray(directErrors)) {
24733
- for (const entry of directErrors) {
24734
- const message = getStringField(entry, "message");
24735
- if (message && !isGenericInternalServerError(message)) {
24736
- return message;
24737
- }
24755
+ for (const entry of structuredErrors) {
24756
+ const message = getStringField(entry, "message");
24757
+ if (message && !isGenericInternalServerError(message)) {
24758
+ return message;
24738
24759
  }
24739
24760
  }
24740
24761
  const directError = getStringField(status, "error");
@@ -24792,11 +24813,9 @@ function normalizeStepsForEnvelope(status) {
24792
24813
  return [];
24793
24814
  }
24794
24815
  function normalizeErrorsForEnvelope(status, error) {
24795
- const directErrors = getRecordField(status, "errors");
24796
- if (Array.isArray(directErrors)) {
24797
- return directErrors.filter(
24798
- (entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
24799
- ).map((entry) => {
24816
+ const structuredErrors = structuredErrorsForStatus(status);
24817
+ if (structuredErrors.length > 0) {
24818
+ return structuredErrors.map((entry) => {
24800
24819
  const message2 = typeof entry.message === "string" && entry.message.trim() ? entry.message : error;
24801
24820
  const billing2 = getObjectField(entry, "billing");
24802
24821
  if (!isInsufficientCreditsBilling(billing2) || !message2) {
@@ -25144,8 +25163,9 @@ function packageReturnedDatasetIdentity(packaged) {
25144
25163
  }
25145
25164
  return { datasetIds, paths };
25146
25165
  }
25147
- function formatPackageDatasetActionLines(packaged) {
25166
+ function formatPackageDatasetActionLines(packaged, options) {
25148
25167
  const returned = packageReturnedDatasetIdentity(packaged);
25168
+ const includeSummary = options?.includeSummary ?? true;
25149
25169
  const lines = [];
25150
25170
  for (const dataset of packageDatasetRecords(packaged)) {
25151
25171
  const path = typeof dataset.path === "string" && dataset.path.trim() ? dataset.path.trim() : "dataset";
@@ -25154,14 +25174,16 @@ function formatPackageDatasetActionLines(packaged) {
25154
25174
  const category = isReturned ? "returned" : dataset.recovered === true ? "recovered" : "persisted";
25155
25175
  const rowCount = typeof dataset.rowCount === "number" && Number.isFinite(dataset.rowCount) ? Math.max(0, Math.trunc(dataset.rowCount)) : null;
25156
25176
  const actions = readRecord(dataset.actions) ?? {};
25157
- if (category === "recovered" && Object.keys(actions).length === 0) {
25158
- lines.push(
25159
- ` dataset ${path}: available, ${rowCount === null ? "persisted" : formatInteger(rowCount)} rows persisted; re-running reuses completed work`
25160
- );
25161
- } else {
25162
- lines.push(
25163
- ` ${category} dataset ${path}: ${rowCount === null ? "unknown rows" : `${formatInteger(rowCount)} ${rowCount === 1 ? "row" : "rows"}`}`
25164
- );
25177
+ if (includeSummary) {
25178
+ if (category === "recovered" && Object.keys(actions).length === 0) {
25179
+ lines.push(
25180
+ ` dataset ${path}: available, ${rowCount === null ? "persisted" : formatInteger(rowCount)} rows persisted; re-running reuses completed work`
25181
+ );
25182
+ } else {
25183
+ lines.push(
25184
+ ` ${category} dataset ${path}: ${rowCount === null ? "unknown rows" : `${formatInteger(rowCount)} ${rowCount === 1 ? "row" : "rows"}`}`
25185
+ );
25186
+ }
25165
25187
  }
25166
25188
  const exportAction = readRecord(actions.exportCsv);
25167
25189
  const exportCommand = actionToCommand(exportAction);
@@ -25187,6 +25209,52 @@ function formatPackageDatasetActionLines(packaged) {
25187
25209
  }
25188
25210
  return lines;
25189
25211
  }
25212
+ function packageSavedRowCount(packaged) {
25213
+ const rowCounts = packageDatasetRecords(packaged).map((dataset) => dataset.rowCount).filter(
25214
+ (rowCount) => typeof rowCount === "number" && Number.isFinite(rowCount)
25215
+ ).map((rowCount) => Math.max(0, Math.trunc(rowCount)));
25216
+ if (rowCounts.length === 0) return null;
25217
+ return rowCounts.reduce((total, rowCount) => total + rowCount, 0);
25218
+ }
25219
+ function runtimeLimitWindowLabel(runtimeLimitFailure) {
25220
+ const message = getStringField(runtimeLimitFailure, "message") ?? "";
25221
+ const configuredSeconds = /\bconfigured\s+(\d+)\s+second(?:s)?\s+runtime limit\b/i.exec(message)?.[1];
25222
+ if (configuredSeconds) {
25223
+ const seconds = Number(configuredSeconds);
25224
+ if (Number.isSafeInteger(seconds) && seconds > 0) {
25225
+ if (seconds % 3600 === 0) return `${seconds / 3600}-hour`;
25226
+ if (seconds % 60 === 0) return `${seconds / 60}-minute`;
25227
+ return `${seconds}-second`;
25228
+ }
25229
+ }
25230
+ const match = /\b(\d+)\s+(hour|hours|minute|minutes|second|seconds)\b/i.exec(
25231
+ message
25232
+ );
25233
+ if (!match) return "30-minute";
25234
+ const unit = match[2].toLowerCase().replace(/s$/, "");
25235
+ return `${match[1]}-${unit}`;
25236
+ }
25237
+ function runtimeLimitCheckpointLines(packaged, runId, runtimeLimitFailure) {
25238
+ const savedRows = packageSavedRowCount(packaged);
25239
+ const lines = [
25240
+ `\u2713 progress saved ${runId}`,
25241
+ "",
25242
+ `The Play reached its ${runtimeLimitWindowLabel(runtimeLimitFailure)} runtime window.`
25243
+ ];
25244
+ if (savedRows === null) {
25245
+ lines.push("Progress completed before the runtime window closed.");
25246
+ } else {
25247
+ lines.push(
25248
+ `${formatInteger(savedRows)} ${savedRows === 1 ? "row was" : "rows were"} saved successfully.`
25249
+ );
25250
+ }
25251
+ lines.push(
25252
+ "",
25253
+ "Run the same Play again to continue where you left off.",
25254
+ "Completed work will be reused automatically."
25255
+ );
25256
+ return lines;
25257
+ }
25190
25258
  function formatInlinePackageValue(value) {
25191
25259
  const compacted = compactReturnValue(value);
25192
25260
  const json2 = JSON.stringify(compacted);
@@ -25298,24 +25366,20 @@ function buildRunPackageTextLines(packaged) {
25298
25366
  const runId = typeof run.id === "string" ? run.id : "unknown";
25299
25367
  const status = typeof run.status === "string" ? run.status : "unknown";
25300
25368
  const playName = typeof run.playName === "string" ? run.playName : null;
25301
- const lines = [
25369
+ const runtimeLimitFailure = readRecordArray(packaged.errors).find(
25370
+ (entry) => entry.code === "RUNTIME_LIMIT_EXCEEDED"
25371
+ );
25372
+ const isRuntimeTimeout = status === "failed" && (runtimeLimitFailure !== void 0 || typeof run.error === "string" && /RUNTIME_LIMIT_EXCEEDED/.test(run.error));
25373
+ const isRuntimeLimitCheckpoint = isRuntimeTimeout;
25374
+ const checkpointFailure = runtimeLimitFailure ?? (typeof run.error === "string" ? { message: run.error } : { message: "The Play reached its runtime limit and was stopped." });
25375
+ const lines = isRuntimeLimitCheckpoint ? runtimeLimitCheckpointLines(packaged, runId, checkpointFailure) : [
25302
25376
  `${status === "completed" ? "\u2713" : status === "failed" ? "\u2717" : "\u2022"} ${status} ${runId}`
25303
25377
  ];
25304
- const isRuntimeTimeout = status === "failed" && (readRecordArray(packaged.errors).some(
25305
- (error) => error.code === "RUNTIME_LIMIT_EXCEEDED"
25306
- ) || typeof run.error === "string" && /RUNTIME_LIMIT_EXCEEDED/.test(run.error));
25307
- if (isRuntimeTimeout) {
25308
- lines.push(" RUNTIME_LIMIT_EXCEEDED: the Play stopped before returning.");
25309
- lines.push(
25310
- " Inspect the dataset catalog below and export saved data before rerunning unfinished work."
25311
- );
25312
- lines.push(
25313
- " Adjust runtime.timeout in the Play (maximum 4h), remove the override for the 30-minute default, or use fewer rows."
25314
- );
25315
- }
25316
25378
  const runError = typeof run.error === "string" && run.error.trim() ? run.error.trim() : null;
25317
- if (runError && (status === "failed" || status === "cancelled")) {
25318
- lines.push(` error: ${truncateErrorForDisplay(runError, runId)}`);
25379
+ const structuredRuntimeLimitMessage = typeof runtimeLimitFailure?.message === "string" && runtimeLimitFailure.message.trim() ? `${typeof runtimeLimitFailure.code === "string" ? runtimeLimitFailure.code : "RUNTIME_LIMIT_EXCEEDED"}: ${runtimeLimitFailure.message.trim()}` : null;
25380
+ const displayRunError = structuredRuntimeLimitMessage ?? runError;
25381
+ if (!isRuntimeLimitCheckpoint && displayRunError && (status === "failed" || status === "cancelled")) {
25382
+ lines.push(` error: ${truncateErrorForDisplay(displayRunError, runId)}`);
25319
25383
  const stackFrames = authoredPackageStackFrames(packaged);
25320
25384
  if (stackFrames.length > 0) {
25321
25385
  lines.push(" stack:");
@@ -25352,12 +25416,18 @@ function buildRunPackageTextLines(packaged) {
25352
25416
  failedLogAssociation === "retained_before_truncation" ? ` retained logs: ${failedLogNext.logs}` : ` retry failed logs: ${failedLogNext.logs}`
25353
25417
  );
25354
25418
  }
25355
- if (playName) {
25419
+ if (playName && !isRuntimeLimitCheckpoint) {
25356
25420
  lines.push(` play: ${playName}`);
25357
25421
  }
25358
- lines.push(...buildRunActivityTextLines(run));
25422
+ if (!isRuntimeLimitCheckpoint) {
25423
+ lines.push(...buildRunActivityTextLines(run));
25424
+ }
25359
25425
  lines.push(...formatPackageValueOutputLines(packaged));
25360
- lines.push(...formatPackageDatasetActionLines(packaged));
25426
+ lines.push(
25427
+ ...formatPackageDatasetActionLines(packaged, {
25428
+ includeSummary: !isRuntimeLimitCheckpoint
25429
+ })
25430
+ );
25361
25431
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
25362
25432
  const billingCommand = actionToCommand(next.billing);
25363
25433
  const logsCommand = actionToCommand(next.logs);
@@ -25365,7 +25435,7 @@ function buildRunPackageTextLines(packaged) {
25365
25435
  const costState = status === "completed" || status === "failed" || status === "cancelled" ? "settles asynchronously \u2014 run the billing command below for totals" : "pending";
25366
25436
  lines.push(` cost: ${costState}`);
25367
25437
  }
25368
- for (const step of readRecordArray(packaged.steps).slice(0, 8)) {
25438
+ for (const step of isRuntimeLimitCheckpoint ? [] : readRecordArray(packaged.steps).slice(0, 8)) {
25369
25439
  const id = typeof step.id === "string" ? step.id : "step";
25370
25440
  const kind = typeof step.kind === "string" ? step.kind : "step";
25371
25441
  const stepStatus = typeof step.status === "string" ? step.status : status;
@@ -25398,10 +25468,8 @@ function buildRunPackageTextLines(packaged) {
25398
25468
  if (legacyExportCommand) {
25399
25469
  lines.push(` export CSV: ${legacyExportCommand}`);
25400
25470
  }
25401
- if (runAgainCommand) {
25402
- lines.push(
25403
- isRuntimeTimeout ? " run again after adjusting the deadline or batch (compatible completed work may be reused):" : " run again (completed work is reused):"
25404
- );
25471
+ if (runAgainCommand && !isRuntimeLimitCheckpoint) {
25472
+ lines.push(" run again (completed work is reused):");
25405
25473
  lines.push(` ${runAgainCommand}`);
25406
25474
  }
25407
25475
  return lines;
@@ -3063,7 +3063,7 @@ var SDK_RELEASE = {
3063
3063
  // getters keep their established compatibility behavior.
3064
3064
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
3065
3065
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
3066
- version: "0.3.135",
3066
+ version: "0.3.137",
3067
3067
  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.",
3068
3068
  packageCapabilities: {
3069
3069
  updatePreferences: 1
@@ -24789,6 +24789,22 @@ function formatPlayErrorForDisplay(status, error) {
24789
24789
  }
24790
24790
  return error;
24791
24791
  }
24792
+ function structuredErrorsForStatus(status) {
24793
+ const directErrors = getRecordField(status, "errors");
24794
+ if (Array.isArray(directErrors)) {
24795
+ const records = directErrors.filter(
24796
+ (entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
24797
+ );
24798
+ if (records.length > 0) return records;
24799
+ }
24800
+ const resultErrors = getRecordField(
24801
+ getRecordField(status, "result"),
24802
+ "errors"
24803
+ );
24804
+ return Array.isArray(resultErrors) ? resultErrors.filter(
24805
+ (entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
24806
+ ) : [];
24807
+ }
24792
24808
  function isGenericInternalServerError(error) {
24793
24809
  if (!error) return false;
24794
24810
  return /^(?:internalservererror|internal server error|http 500|500)$/i.test(
@@ -24797,16 +24813,21 @@ function isGenericInternalServerError(error) {
24797
24813
  }
24798
24814
  function selectRunErrorForDisplay(status) {
24799
24815
  const progressError = getStringField(status.progress, "error");
24816
+ const structuredErrors = structuredErrorsForStatus(status);
24817
+ const structuredMessage = structuredErrors.map((entry) => getStringField(entry, "message")).find((message) => Boolean(message));
24818
+ const structuredRuntimeLimit = structuredErrors.some(
24819
+ (entry) => getStringField(entry, "code") === "RUNTIME_LIMIT_EXCEEDED"
24820
+ );
24821
+ if (structuredMessage && (structuredRuntimeLimit || !progressError && getPlayRunPackage(status) === null)) {
24822
+ return structuredMessage;
24823
+ }
24800
24824
  if (!isGenericInternalServerError(progressError)) {
24801
24825
  return progressError;
24802
24826
  }
24803
- const directErrors = getRecordField(status, "errors");
24804
- if (Array.isArray(directErrors)) {
24805
- for (const entry of directErrors) {
24806
- const message = getStringField(entry, "message");
24807
- if (message && !isGenericInternalServerError(message)) {
24808
- return message;
24809
- }
24827
+ for (const entry of structuredErrors) {
24828
+ const message = getStringField(entry, "message");
24829
+ if (message && !isGenericInternalServerError(message)) {
24830
+ return message;
24810
24831
  }
24811
24832
  }
24812
24833
  const directError = getStringField(status, "error");
@@ -24864,11 +24885,9 @@ function normalizeStepsForEnvelope(status) {
24864
24885
  return [];
24865
24886
  }
24866
24887
  function normalizeErrorsForEnvelope(status, error) {
24867
- const directErrors = getRecordField(status, "errors");
24868
- if (Array.isArray(directErrors)) {
24869
- return directErrors.filter(
24870
- (entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
24871
- ).map((entry) => {
24888
+ const structuredErrors = structuredErrorsForStatus(status);
24889
+ if (structuredErrors.length > 0) {
24890
+ return structuredErrors.map((entry) => {
24872
24891
  const message2 = typeof entry.message === "string" && entry.message.trim() ? entry.message : error;
24873
24892
  const billing2 = getObjectField(entry, "billing");
24874
24893
  if (!isInsufficientCreditsBilling(billing2) || !message2) {
@@ -25216,8 +25235,9 @@ function packageReturnedDatasetIdentity(packaged) {
25216
25235
  }
25217
25236
  return { datasetIds, paths };
25218
25237
  }
25219
- function formatPackageDatasetActionLines(packaged) {
25238
+ function formatPackageDatasetActionLines(packaged, options) {
25220
25239
  const returned = packageReturnedDatasetIdentity(packaged);
25240
+ const includeSummary = options?.includeSummary ?? true;
25221
25241
  const lines = [];
25222
25242
  for (const dataset of packageDatasetRecords(packaged)) {
25223
25243
  const path = typeof dataset.path === "string" && dataset.path.trim() ? dataset.path.trim() : "dataset";
@@ -25226,14 +25246,16 @@ function formatPackageDatasetActionLines(packaged) {
25226
25246
  const category = isReturned ? "returned" : dataset.recovered === true ? "recovered" : "persisted";
25227
25247
  const rowCount = typeof dataset.rowCount === "number" && Number.isFinite(dataset.rowCount) ? Math.max(0, Math.trunc(dataset.rowCount)) : null;
25228
25248
  const actions = readRecord(dataset.actions) ?? {};
25229
- if (category === "recovered" && Object.keys(actions).length === 0) {
25230
- lines.push(
25231
- ` dataset ${path}: available, ${rowCount === null ? "persisted" : formatInteger(rowCount)} rows persisted; re-running reuses completed work`
25232
- );
25233
- } else {
25234
- lines.push(
25235
- ` ${category} dataset ${path}: ${rowCount === null ? "unknown rows" : `${formatInteger(rowCount)} ${rowCount === 1 ? "row" : "rows"}`}`
25236
- );
25249
+ if (includeSummary) {
25250
+ if (category === "recovered" && Object.keys(actions).length === 0) {
25251
+ lines.push(
25252
+ ` dataset ${path}: available, ${rowCount === null ? "persisted" : formatInteger(rowCount)} rows persisted; re-running reuses completed work`
25253
+ );
25254
+ } else {
25255
+ lines.push(
25256
+ ` ${category} dataset ${path}: ${rowCount === null ? "unknown rows" : `${formatInteger(rowCount)} ${rowCount === 1 ? "row" : "rows"}`}`
25257
+ );
25258
+ }
25237
25259
  }
25238
25260
  const exportAction = readRecord(actions.exportCsv);
25239
25261
  const exportCommand = actionToCommand(exportAction);
@@ -25259,6 +25281,52 @@ function formatPackageDatasetActionLines(packaged) {
25259
25281
  }
25260
25282
  return lines;
25261
25283
  }
25284
+ function packageSavedRowCount(packaged) {
25285
+ const rowCounts = packageDatasetRecords(packaged).map((dataset) => dataset.rowCount).filter(
25286
+ (rowCount) => typeof rowCount === "number" && Number.isFinite(rowCount)
25287
+ ).map((rowCount) => Math.max(0, Math.trunc(rowCount)));
25288
+ if (rowCounts.length === 0) return null;
25289
+ return rowCounts.reduce((total, rowCount) => total + rowCount, 0);
25290
+ }
25291
+ function runtimeLimitWindowLabel(runtimeLimitFailure) {
25292
+ const message = getStringField(runtimeLimitFailure, "message") ?? "";
25293
+ const configuredSeconds = /\bconfigured\s+(\d+)\s+second(?:s)?\s+runtime limit\b/i.exec(message)?.[1];
25294
+ if (configuredSeconds) {
25295
+ const seconds = Number(configuredSeconds);
25296
+ if (Number.isSafeInteger(seconds) && seconds > 0) {
25297
+ if (seconds % 3600 === 0) return `${seconds / 3600}-hour`;
25298
+ if (seconds % 60 === 0) return `${seconds / 60}-minute`;
25299
+ return `${seconds}-second`;
25300
+ }
25301
+ }
25302
+ const match = /\b(\d+)\s+(hour|hours|minute|minutes|second|seconds)\b/i.exec(
25303
+ message
25304
+ );
25305
+ if (!match) return "30-minute";
25306
+ const unit = match[2].toLowerCase().replace(/s$/, "");
25307
+ return `${match[1]}-${unit}`;
25308
+ }
25309
+ function runtimeLimitCheckpointLines(packaged, runId, runtimeLimitFailure) {
25310
+ const savedRows = packageSavedRowCount(packaged);
25311
+ const lines = [
25312
+ `\u2713 progress saved ${runId}`,
25313
+ "",
25314
+ `The Play reached its ${runtimeLimitWindowLabel(runtimeLimitFailure)} runtime window.`
25315
+ ];
25316
+ if (savedRows === null) {
25317
+ lines.push("Progress completed before the runtime window closed.");
25318
+ } else {
25319
+ lines.push(
25320
+ `${formatInteger(savedRows)} ${savedRows === 1 ? "row was" : "rows were"} saved successfully.`
25321
+ );
25322
+ }
25323
+ lines.push(
25324
+ "",
25325
+ "Run the same Play again to continue where you left off.",
25326
+ "Completed work will be reused automatically."
25327
+ );
25328
+ return lines;
25329
+ }
25262
25330
  function formatInlinePackageValue(value) {
25263
25331
  const compacted = compactReturnValue(value);
25264
25332
  const json2 = JSON.stringify(compacted);
@@ -25370,24 +25438,20 @@ function buildRunPackageTextLines(packaged) {
25370
25438
  const runId = typeof run.id === "string" ? run.id : "unknown";
25371
25439
  const status = typeof run.status === "string" ? run.status : "unknown";
25372
25440
  const playName = typeof run.playName === "string" ? run.playName : null;
25373
- const lines = [
25441
+ const runtimeLimitFailure = readRecordArray(packaged.errors).find(
25442
+ (entry) => entry.code === "RUNTIME_LIMIT_EXCEEDED"
25443
+ );
25444
+ const isRuntimeTimeout = status === "failed" && (runtimeLimitFailure !== void 0 || typeof run.error === "string" && /RUNTIME_LIMIT_EXCEEDED/.test(run.error));
25445
+ const isRuntimeLimitCheckpoint = isRuntimeTimeout;
25446
+ const checkpointFailure = runtimeLimitFailure ?? (typeof run.error === "string" ? { message: run.error } : { message: "The Play reached its runtime limit and was stopped." });
25447
+ const lines = isRuntimeLimitCheckpoint ? runtimeLimitCheckpointLines(packaged, runId, checkpointFailure) : [
25374
25448
  `${status === "completed" ? "\u2713" : status === "failed" ? "\u2717" : "\u2022"} ${status} ${runId}`
25375
25449
  ];
25376
- const isRuntimeTimeout = status === "failed" && (readRecordArray(packaged.errors).some(
25377
- (error) => error.code === "RUNTIME_LIMIT_EXCEEDED"
25378
- ) || typeof run.error === "string" && /RUNTIME_LIMIT_EXCEEDED/.test(run.error));
25379
- if (isRuntimeTimeout) {
25380
- lines.push(" RUNTIME_LIMIT_EXCEEDED: the Play stopped before returning.");
25381
- lines.push(
25382
- " Inspect the dataset catalog below and export saved data before rerunning unfinished work."
25383
- );
25384
- lines.push(
25385
- " Adjust runtime.timeout in the Play (maximum 4h), remove the override for the 30-minute default, or use fewer rows."
25386
- );
25387
- }
25388
25450
  const runError = typeof run.error === "string" && run.error.trim() ? run.error.trim() : null;
25389
- if (runError && (status === "failed" || status === "cancelled")) {
25390
- lines.push(` error: ${truncateErrorForDisplay(runError, runId)}`);
25451
+ const structuredRuntimeLimitMessage = typeof runtimeLimitFailure?.message === "string" && runtimeLimitFailure.message.trim() ? `${typeof runtimeLimitFailure.code === "string" ? runtimeLimitFailure.code : "RUNTIME_LIMIT_EXCEEDED"}: ${runtimeLimitFailure.message.trim()}` : null;
25452
+ const displayRunError = structuredRuntimeLimitMessage ?? runError;
25453
+ if (!isRuntimeLimitCheckpoint && displayRunError && (status === "failed" || status === "cancelled")) {
25454
+ lines.push(` error: ${truncateErrorForDisplay(displayRunError, runId)}`);
25391
25455
  const stackFrames = authoredPackageStackFrames(packaged);
25392
25456
  if (stackFrames.length > 0) {
25393
25457
  lines.push(" stack:");
@@ -25424,12 +25488,18 @@ function buildRunPackageTextLines(packaged) {
25424
25488
  failedLogAssociation === "retained_before_truncation" ? ` retained logs: ${failedLogNext.logs}` : ` retry failed logs: ${failedLogNext.logs}`
25425
25489
  );
25426
25490
  }
25427
- if (playName) {
25491
+ if (playName && !isRuntimeLimitCheckpoint) {
25428
25492
  lines.push(` play: ${playName}`);
25429
25493
  }
25430
- lines.push(...buildRunActivityTextLines(run));
25494
+ if (!isRuntimeLimitCheckpoint) {
25495
+ lines.push(...buildRunActivityTextLines(run));
25496
+ }
25431
25497
  lines.push(...formatPackageValueOutputLines(packaged));
25432
- lines.push(...formatPackageDatasetActionLines(packaged));
25498
+ lines.push(
25499
+ ...formatPackageDatasetActionLines(packaged, {
25500
+ includeSummary: !isRuntimeLimitCheckpoint
25501
+ })
25502
+ );
25433
25503
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
25434
25504
  const billingCommand = actionToCommand(next.billing);
25435
25505
  const logsCommand = actionToCommand(next.logs);
@@ -25437,7 +25507,7 @@ function buildRunPackageTextLines(packaged) {
25437
25507
  const costState = status === "completed" || status === "failed" || status === "cancelled" ? "settles asynchronously \u2014 run the billing command below for totals" : "pending";
25438
25508
  lines.push(` cost: ${costState}`);
25439
25509
  }
25440
- for (const step of readRecordArray(packaged.steps).slice(0, 8)) {
25510
+ for (const step of isRuntimeLimitCheckpoint ? [] : readRecordArray(packaged.steps).slice(0, 8)) {
25441
25511
  const id = typeof step.id === "string" ? step.id : "step";
25442
25512
  const kind = typeof step.kind === "string" ? step.kind : "step";
25443
25513
  const stepStatus = typeof step.status === "string" ? step.status : status;
@@ -25470,10 +25540,8 @@ function buildRunPackageTextLines(packaged) {
25470
25540
  if (legacyExportCommand) {
25471
25541
  lines.push(` export CSV: ${legacyExportCommand}`);
25472
25542
  }
25473
- if (runAgainCommand) {
25474
- lines.push(
25475
- isRuntimeTimeout ? " run again after adjusting the deadline or batch (compatible completed work may be reused):" : " run again (completed work is reused):"
25476
- );
25543
+ if (runAgainCommand && !isRuntimeLimitCheckpoint) {
25544
+ lines.push(" run again (completed work is reused):");
25477
25545
  lines.push(` ${runAgainCommand}`);
25478
25546
  }
25479
25547
  return lines;
package/dist/index.js CHANGED
@@ -864,7 +864,7 @@ var SDK_RELEASE = {
864
864
  // getters keep their established compatibility behavior.
865
865
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
866
866
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
867
- version: "0.3.135",
867
+ version: "0.3.137",
868
868
  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.",
869
869
  packageCapabilities: {
870
870
  updatePreferences: 1
package/dist/index.mjs CHANGED
@@ -768,7 +768,7 @@ var SDK_RELEASE = {
768
768
  // getters keep their established compatibility behavior.
769
769
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
770
770
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
771
- version: "0.3.135",
771
+ version: "0.3.137",
772
772
  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.",
773
773
  packageCapabilities: {
774
774
  updatePreferences: 1
@@ -149,7 +149,7 @@ type SdkRelease = {
149
149
  supportPolicy: SdkSupportPolicy;
150
150
  };
151
151
  declare const SDK_RELEASE: {
152
- readonly version: "0.3.135";
152
+ readonly version: "0.3.137";
153
153
  readonly 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.";
154
154
  readonly packageCapabilities: {
155
155
  readonly updatePreferences: 1;
package/dist/release.d.ts CHANGED
@@ -149,7 +149,7 @@ type SdkRelease = {
149
149
  supportPolicy: SdkSupportPolicy;
150
150
  };
151
151
  declare const SDK_RELEASE: {
152
- readonly version: "0.3.135";
152
+ readonly version: "0.3.137";
153
153
  readonly 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.";
154
154
  readonly packageCapabilities: {
155
155
  readonly updatePreferences: 1;
package/dist/release.js CHANGED
@@ -74,7 +74,7 @@ var SDK_RELEASE = {
74
74
  // getters keep their established compatibility behavior.
75
75
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
76
76
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
77
- version: "0.3.135",
77
+ version: "0.3.137",
78
78
  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.",
79
79
  packageCapabilities: {
80
80
  updatePreferences: 1
package/dist/release.mjs CHANGED
@@ -48,7 +48,7 @@ var SDK_RELEASE = {
48
48
  // getters keep their established compatibility behavior.
49
49
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
50
50
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
51
- version: "0.3.135",
51
+ version: "0.3.137",
52
52
  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.",
53
53
  packageCapabilities: {
54
54
  updatePreferences: 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.3.135",
3
+ "version": "0.3.137",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",