deepline 0.3.134 → 0.3.136

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.134',
203
+ version: '0.3.136',
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: {
@@ -1000,7 +1000,7 @@ export async function runDeployment(
1000
1000
  if (!project) {
1001
1001
  // A directory deploy of a repo-owned play: live now differs from
1002
1002
  // that repository, and a later push from it will replace this.
1003
- return `This play is deployed from ${owner}. This directory deploy made a different revision live, so it is marked drifted from ${owner} until that repository deploys again.`;
1003
+ return `This play is deployed from ${owner}. This directory deploy made a different revision live, so it is marked drifted from ${owner} until that repository deploys again. If you are done with ${owner}, unlink it (deepline git unlink <id>) and this play is released from it.`;
1004
1004
  }
1005
1005
  return `This play was deployed from ${owner} and now deploys from ${project.repoFullName}. Taking it over was allowed because the old deployment target is disabled; re-enabling that target will not give the play back — its deploys will fail on this name instead.`;
1006
1006
  };
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.134",
3071
+ version: "0.3.136",
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
@@ -21189,7 +21189,7 @@ async function runDeployment(params, hooks) {
21189
21189
  const owner = state2?.playProjectRepo;
21190
21190
  if (!owner || owner === project?.repoFullName) return void 0;
21191
21191
  if (!project) {
21192
- return `This play is deployed from ${owner}. This directory deploy made a different revision live, so it is marked drifted from ${owner} until that repository deploys again.`;
21192
+ return `This play is deployed from ${owner}. This directory deploy made a different revision live, so it is marked drifted from ${owner} until that repository deploys again. If you are done with ${owner}, unlink it (deepline git unlink <id>) and this play is released from it.`;
21193
21193
  }
21194
21194
  return `This play was deployed from ${owner} and now deploys from ${project.repoFullName}. Taking it over was allowed because the old deployment target is disabled; re-enabling that target will not give the play back \u2014 its deploys will fail on this name instead.`;
21195
21195
  };
@@ -21812,7 +21812,8 @@ async function handleUnlink(id, options) {
21812
21812
  {
21813
21813
  title: "unlinked",
21814
21814
  lines: [
21815
- `Repository link ${id} removed. Deployments stop immediately and in-flight deploy credentials die; live plays keep running.`
21815
+ `Repository link ${id} removed. Deployments stop immediately and in-flight deploy credentials die; live plays keep running.`,
21816
+ "Plays this repository deployed are released: they keep their live version, stop showing it as their source, and are no longer marked drifted from it."
21816
21817
  ]
21817
21818
  }
21818
21819
  ]
@@ -21978,7 +21979,9 @@ Examples:
21978
21979
  disabled: options.enabled === true ? false : options.disabled === true ? true : void 0
21979
21980
  })
21980
21981
  );
21981
- git.command("unlink").description("Unlink a repository (live plays keep running).").argument("<id>", "Repository link id").option("--json", "Emit JSON output").action(
21982
+ git.command("unlink").description(
21983
+ "Unlink a repository (live plays keep running, and are released from it)."
21984
+ ).argument("<id>", "Repository link id").option("--json", "Emit JSON output").action(
21982
21985
  async (id, options) => handleUnlink(id, options)
21983
21986
  );
21984
21987
  git.command("deployments").description("Deployment history; pass an id for one deployment.").argument("[id]", "Deployment id (omit to list)").option("--repo <id>", "Filter to one repository link").option("--limit <n>", "Max rows (default 50)").option("--json", "Emit JSON output").action(
@@ -24714,6 +24717,22 @@ function formatPlayErrorForDisplay(status, error) {
24714
24717
  }
24715
24718
  return error;
24716
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
+ }
24717
24736
  function isGenericInternalServerError(error) {
24718
24737
  if (!error) return false;
24719
24738
  return /^(?:internalservererror|internal server error|http 500|500)$/i.test(
@@ -24722,16 +24741,21 @@ function isGenericInternalServerError(error) {
24722
24741
  }
24723
24742
  function selectRunErrorForDisplay(status) {
24724
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
+ }
24725
24752
  if (!isGenericInternalServerError(progressError)) {
24726
24753
  return progressError;
24727
24754
  }
24728
- const directErrors = getRecordField(status, "errors");
24729
- if (Array.isArray(directErrors)) {
24730
- for (const entry of directErrors) {
24731
- const message = getStringField(entry, "message");
24732
- if (message && !isGenericInternalServerError(message)) {
24733
- return message;
24734
- }
24755
+ for (const entry of structuredErrors) {
24756
+ const message = getStringField(entry, "message");
24757
+ if (message && !isGenericInternalServerError(message)) {
24758
+ return message;
24735
24759
  }
24736
24760
  }
24737
24761
  const directError = getStringField(status, "error");
@@ -24789,11 +24813,9 @@ function normalizeStepsForEnvelope(status) {
24789
24813
  return [];
24790
24814
  }
24791
24815
  function normalizeErrorsForEnvelope(status, error) {
24792
- const directErrors = getRecordField(status, "errors");
24793
- if (Array.isArray(directErrors)) {
24794
- return directErrors.filter(
24795
- (entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
24796
- ).map((entry) => {
24816
+ const structuredErrors = structuredErrorsForStatus(status);
24817
+ if (structuredErrors.length > 0) {
24818
+ return structuredErrors.map((entry) => {
24797
24819
  const message2 = typeof entry.message === "string" && entry.message.trim() ? entry.message : error;
24798
24820
  const billing2 = getObjectField(entry, "billing");
24799
24821
  if (!isInsufficientCreditsBilling(billing2) || !message2) {
@@ -25141,8 +25163,9 @@ function packageReturnedDatasetIdentity(packaged) {
25141
25163
  }
25142
25164
  return { datasetIds, paths };
25143
25165
  }
25144
- function formatPackageDatasetActionLines(packaged) {
25166
+ function formatPackageDatasetActionLines(packaged, options) {
25145
25167
  const returned = packageReturnedDatasetIdentity(packaged);
25168
+ const includeSummary = options?.includeSummary ?? true;
25146
25169
  const lines = [];
25147
25170
  for (const dataset of packageDatasetRecords(packaged)) {
25148
25171
  const path = typeof dataset.path === "string" && dataset.path.trim() ? dataset.path.trim() : "dataset";
@@ -25151,14 +25174,16 @@ function formatPackageDatasetActionLines(packaged) {
25151
25174
  const category = isReturned ? "returned" : dataset.recovered === true ? "recovered" : "persisted";
25152
25175
  const rowCount = typeof dataset.rowCount === "number" && Number.isFinite(dataset.rowCount) ? Math.max(0, Math.trunc(dataset.rowCount)) : null;
25153
25176
  const actions = readRecord(dataset.actions) ?? {};
25154
- if (category === "recovered" && Object.keys(actions).length === 0) {
25155
- lines.push(
25156
- ` dataset ${path}: available, ${rowCount === null ? "persisted" : formatInteger(rowCount)} rows persisted; re-running reuses completed work`
25157
- );
25158
- } else {
25159
- lines.push(
25160
- ` ${category} dataset ${path}: ${rowCount === null ? "unknown rows" : `${formatInteger(rowCount)} ${rowCount === 1 ? "row" : "rows"}`}`
25161
- );
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
+ }
25162
25187
  }
25163
25188
  const exportAction = readRecord(actions.exportCsv);
25164
25189
  const exportCommand = actionToCommand(exportAction);
@@ -25184,6 +25209,52 @@ function formatPackageDatasetActionLines(packaged) {
25184
25209
  }
25185
25210
  return lines;
25186
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
+ }
25187
25258
  function formatInlinePackageValue(value) {
25188
25259
  const compacted = compactReturnValue(value);
25189
25260
  const json2 = JSON.stringify(compacted);
@@ -25295,24 +25366,20 @@ function buildRunPackageTextLines(packaged) {
25295
25366
  const runId = typeof run.id === "string" ? run.id : "unknown";
25296
25367
  const status = typeof run.status === "string" ? run.status : "unknown";
25297
25368
  const playName = typeof run.playName === "string" ? run.playName : null;
25298
- 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) : [
25299
25376
  `${status === "completed" ? "\u2713" : status === "failed" ? "\u2717" : "\u2022"} ${status} ${runId}`
25300
25377
  ];
25301
- const isRuntimeTimeout = status === "failed" && (readRecordArray(packaged.errors).some(
25302
- (error) => error.code === "RUNTIME_LIMIT_EXCEEDED"
25303
- ) || typeof run.error === "string" && /RUNTIME_LIMIT_EXCEEDED/.test(run.error));
25304
- if (isRuntimeTimeout) {
25305
- lines.push(" RUNTIME_LIMIT_EXCEEDED: the Play stopped before returning.");
25306
- lines.push(
25307
- " Inspect the dataset catalog below and export saved data before rerunning unfinished work."
25308
- );
25309
- lines.push(
25310
- " Adjust runtime.timeout in the Play (maximum 4h), remove the override for the 30-minute default, or use fewer rows."
25311
- );
25312
- }
25313
25378
  const runError = typeof run.error === "string" && run.error.trim() ? run.error.trim() : null;
25314
- if (runError && (status === "failed" || status === "cancelled")) {
25315
- 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)}`);
25316
25383
  const stackFrames = authoredPackageStackFrames(packaged);
25317
25384
  if (stackFrames.length > 0) {
25318
25385
  lines.push(" stack:");
@@ -25349,12 +25416,18 @@ function buildRunPackageTextLines(packaged) {
25349
25416
  failedLogAssociation === "retained_before_truncation" ? ` retained logs: ${failedLogNext.logs}` : ` retry failed logs: ${failedLogNext.logs}`
25350
25417
  );
25351
25418
  }
25352
- if (playName) {
25419
+ if (playName && !isRuntimeLimitCheckpoint) {
25353
25420
  lines.push(` play: ${playName}`);
25354
25421
  }
25355
- lines.push(...buildRunActivityTextLines(run));
25422
+ if (!isRuntimeLimitCheckpoint) {
25423
+ lines.push(...buildRunActivityTextLines(run));
25424
+ }
25356
25425
  lines.push(...formatPackageValueOutputLines(packaged));
25357
- lines.push(...formatPackageDatasetActionLines(packaged));
25426
+ lines.push(
25427
+ ...formatPackageDatasetActionLines(packaged, {
25428
+ includeSummary: !isRuntimeLimitCheckpoint
25429
+ })
25430
+ );
25358
25431
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
25359
25432
  const billingCommand = actionToCommand(next.billing);
25360
25433
  const logsCommand = actionToCommand(next.logs);
@@ -25362,7 +25435,7 @@ function buildRunPackageTextLines(packaged) {
25362
25435
  const costState = status === "completed" || status === "failed" || status === "cancelled" ? "settles asynchronously \u2014 run the billing command below for totals" : "pending";
25363
25436
  lines.push(` cost: ${costState}`);
25364
25437
  }
25365
- for (const step of readRecordArray(packaged.steps).slice(0, 8)) {
25438
+ for (const step of isRuntimeLimitCheckpoint ? [] : readRecordArray(packaged.steps).slice(0, 8)) {
25366
25439
  const id = typeof step.id === "string" ? step.id : "step";
25367
25440
  const kind = typeof step.kind === "string" ? step.kind : "step";
25368
25441
  const stepStatus = typeof step.status === "string" ? step.status : status;
@@ -25395,10 +25468,8 @@ function buildRunPackageTextLines(packaged) {
25395
25468
  if (legacyExportCommand) {
25396
25469
  lines.push(` export CSV: ${legacyExportCommand}`);
25397
25470
  }
25398
- if (runAgainCommand) {
25399
- lines.push(
25400
- isRuntimeTimeout ? " run again after adjusting the deadline or batch (compatible completed work may be reused):" : " run again (completed work is reused):"
25401
- );
25471
+ if (runAgainCommand && !isRuntimeLimitCheckpoint) {
25472
+ lines.push(" run again (completed work is reused):");
25402
25473
  lines.push(` ${runAgainCommand}`);
25403
25474
  }
25404
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.134",
3066
+ version: "0.3.136",
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
@@ -21261,7 +21261,7 @@ async function runDeployment(params, hooks) {
21261
21261
  const owner = state2?.playProjectRepo;
21262
21262
  if (!owner || owner === project?.repoFullName) return void 0;
21263
21263
  if (!project) {
21264
- return `This play is deployed from ${owner}. This directory deploy made a different revision live, so it is marked drifted from ${owner} until that repository deploys again.`;
21264
+ return `This play is deployed from ${owner}. This directory deploy made a different revision live, so it is marked drifted from ${owner} until that repository deploys again. If you are done with ${owner}, unlink it (deepline git unlink <id>) and this play is released from it.`;
21265
21265
  }
21266
21266
  return `This play was deployed from ${owner} and now deploys from ${project.repoFullName}. Taking it over was allowed because the old deployment target is disabled; re-enabling that target will not give the play back \u2014 its deploys will fail on this name instead.`;
21267
21267
  };
@@ -21884,7 +21884,8 @@ async function handleUnlink(id, options) {
21884
21884
  {
21885
21885
  title: "unlinked",
21886
21886
  lines: [
21887
- `Repository link ${id} removed. Deployments stop immediately and in-flight deploy credentials die; live plays keep running.`
21887
+ `Repository link ${id} removed. Deployments stop immediately and in-flight deploy credentials die; live plays keep running.`,
21888
+ "Plays this repository deployed are released: they keep their live version, stop showing it as their source, and are no longer marked drifted from it."
21888
21889
  ]
21889
21890
  }
21890
21891
  ]
@@ -22050,7 +22051,9 @@ Examples:
22050
22051
  disabled: options.enabled === true ? false : options.disabled === true ? true : void 0
22051
22052
  })
22052
22053
  );
22053
- git.command("unlink").description("Unlink a repository (live plays keep running).").argument("<id>", "Repository link id").option("--json", "Emit JSON output").action(
22054
+ git.command("unlink").description(
22055
+ "Unlink a repository (live plays keep running, and are released from it)."
22056
+ ).argument("<id>", "Repository link id").option("--json", "Emit JSON output").action(
22054
22057
  async (id, options) => handleUnlink(id, options)
22055
22058
  );
22056
22059
  git.command("deployments").description("Deployment history; pass an id for one deployment.").argument("[id]", "Deployment id (omit to list)").option("--repo <id>", "Filter to one repository link").option("--limit <n>", "Max rows (default 50)").option("--json", "Emit JSON output").action(
@@ -24786,6 +24789,22 @@ function formatPlayErrorForDisplay(status, error) {
24786
24789
  }
24787
24790
  return error;
24788
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
+ }
24789
24808
  function isGenericInternalServerError(error) {
24790
24809
  if (!error) return false;
24791
24810
  return /^(?:internalservererror|internal server error|http 500|500)$/i.test(
@@ -24794,16 +24813,21 @@ function isGenericInternalServerError(error) {
24794
24813
  }
24795
24814
  function selectRunErrorForDisplay(status) {
24796
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
+ }
24797
24824
  if (!isGenericInternalServerError(progressError)) {
24798
24825
  return progressError;
24799
24826
  }
24800
- const directErrors = getRecordField(status, "errors");
24801
- if (Array.isArray(directErrors)) {
24802
- for (const entry of directErrors) {
24803
- const message = getStringField(entry, "message");
24804
- if (message && !isGenericInternalServerError(message)) {
24805
- return message;
24806
- }
24827
+ for (const entry of structuredErrors) {
24828
+ const message = getStringField(entry, "message");
24829
+ if (message && !isGenericInternalServerError(message)) {
24830
+ return message;
24807
24831
  }
24808
24832
  }
24809
24833
  const directError = getStringField(status, "error");
@@ -24861,11 +24885,9 @@ function normalizeStepsForEnvelope(status) {
24861
24885
  return [];
24862
24886
  }
24863
24887
  function normalizeErrorsForEnvelope(status, error) {
24864
- const directErrors = getRecordField(status, "errors");
24865
- if (Array.isArray(directErrors)) {
24866
- return directErrors.filter(
24867
- (entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)
24868
- ).map((entry) => {
24888
+ const structuredErrors = structuredErrorsForStatus(status);
24889
+ if (structuredErrors.length > 0) {
24890
+ return structuredErrors.map((entry) => {
24869
24891
  const message2 = typeof entry.message === "string" && entry.message.trim() ? entry.message : error;
24870
24892
  const billing2 = getObjectField(entry, "billing");
24871
24893
  if (!isInsufficientCreditsBilling(billing2) || !message2) {
@@ -25213,8 +25235,9 @@ function packageReturnedDatasetIdentity(packaged) {
25213
25235
  }
25214
25236
  return { datasetIds, paths };
25215
25237
  }
25216
- function formatPackageDatasetActionLines(packaged) {
25238
+ function formatPackageDatasetActionLines(packaged, options) {
25217
25239
  const returned = packageReturnedDatasetIdentity(packaged);
25240
+ const includeSummary = options?.includeSummary ?? true;
25218
25241
  const lines = [];
25219
25242
  for (const dataset of packageDatasetRecords(packaged)) {
25220
25243
  const path = typeof dataset.path === "string" && dataset.path.trim() ? dataset.path.trim() : "dataset";
@@ -25223,14 +25246,16 @@ function formatPackageDatasetActionLines(packaged) {
25223
25246
  const category = isReturned ? "returned" : dataset.recovered === true ? "recovered" : "persisted";
25224
25247
  const rowCount = typeof dataset.rowCount === "number" && Number.isFinite(dataset.rowCount) ? Math.max(0, Math.trunc(dataset.rowCount)) : null;
25225
25248
  const actions = readRecord(dataset.actions) ?? {};
25226
- if (category === "recovered" && Object.keys(actions).length === 0) {
25227
- lines.push(
25228
- ` dataset ${path}: available, ${rowCount === null ? "persisted" : formatInteger(rowCount)} rows persisted; re-running reuses completed work`
25229
- );
25230
- } else {
25231
- lines.push(
25232
- ` ${category} dataset ${path}: ${rowCount === null ? "unknown rows" : `${formatInteger(rowCount)} ${rowCount === 1 ? "row" : "rows"}`}`
25233
- );
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
+ }
25234
25259
  }
25235
25260
  const exportAction = readRecord(actions.exportCsv);
25236
25261
  const exportCommand = actionToCommand(exportAction);
@@ -25256,6 +25281,52 @@ function formatPackageDatasetActionLines(packaged) {
25256
25281
  }
25257
25282
  return lines;
25258
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
+ }
25259
25330
  function formatInlinePackageValue(value) {
25260
25331
  const compacted = compactReturnValue(value);
25261
25332
  const json2 = JSON.stringify(compacted);
@@ -25367,24 +25438,20 @@ function buildRunPackageTextLines(packaged) {
25367
25438
  const runId = typeof run.id === "string" ? run.id : "unknown";
25368
25439
  const status = typeof run.status === "string" ? run.status : "unknown";
25369
25440
  const playName = typeof run.playName === "string" ? run.playName : null;
25370
- 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) : [
25371
25448
  `${status === "completed" ? "\u2713" : status === "failed" ? "\u2717" : "\u2022"} ${status} ${runId}`
25372
25449
  ];
25373
- const isRuntimeTimeout = status === "failed" && (readRecordArray(packaged.errors).some(
25374
- (error) => error.code === "RUNTIME_LIMIT_EXCEEDED"
25375
- ) || typeof run.error === "string" && /RUNTIME_LIMIT_EXCEEDED/.test(run.error));
25376
- if (isRuntimeTimeout) {
25377
- lines.push(" RUNTIME_LIMIT_EXCEEDED: the Play stopped before returning.");
25378
- lines.push(
25379
- " Inspect the dataset catalog below and export saved data before rerunning unfinished work."
25380
- );
25381
- lines.push(
25382
- " Adjust runtime.timeout in the Play (maximum 4h), remove the override for the 30-minute default, or use fewer rows."
25383
- );
25384
- }
25385
25450
  const runError = typeof run.error === "string" && run.error.trim() ? run.error.trim() : null;
25386
- if (runError && (status === "failed" || status === "cancelled")) {
25387
- 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)}`);
25388
25455
  const stackFrames = authoredPackageStackFrames(packaged);
25389
25456
  if (stackFrames.length > 0) {
25390
25457
  lines.push(" stack:");
@@ -25421,12 +25488,18 @@ function buildRunPackageTextLines(packaged) {
25421
25488
  failedLogAssociation === "retained_before_truncation" ? ` retained logs: ${failedLogNext.logs}` : ` retry failed logs: ${failedLogNext.logs}`
25422
25489
  );
25423
25490
  }
25424
- if (playName) {
25491
+ if (playName && !isRuntimeLimitCheckpoint) {
25425
25492
  lines.push(` play: ${playName}`);
25426
25493
  }
25427
- lines.push(...buildRunActivityTextLines(run));
25494
+ if (!isRuntimeLimitCheckpoint) {
25495
+ lines.push(...buildRunActivityTextLines(run));
25496
+ }
25428
25497
  lines.push(...formatPackageValueOutputLines(packaged));
25429
- lines.push(...formatPackageDatasetActionLines(packaged));
25498
+ lines.push(
25499
+ ...formatPackageDatasetActionLines(packaged, {
25500
+ includeSummary: !isRuntimeLimitCheckpoint
25501
+ })
25502
+ );
25430
25503
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
25431
25504
  const billingCommand = actionToCommand(next.billing);
25432
25505
  const logsCommand = actionToCommand(next.logs);
@@ -25434,7 +25507,7 @@ function buildRunPackageTextLines(packaged) {
25434
25507
  const costState = status === "completed" || status === "failed" || status === "cancelled" ? "settles asynchronously \u2014 run the billing command below for totals" : "pending";
25435
25508
  lines.push(` cost: ${costState}`);
25436
25509
  }
25437
- for (const step of readRecordArray(packaged.steps).slice(0, 8)) {
25510
+ for (const step of isRuntimeLimitCheckpoint ? [] : readRecordArray(packaged.steps).slice(0, 8)) {
25438
25511
  const id = typeof step.id === "string" ? step.id : "step";
25439
25512
  const kind = typeof step.kind === "string" ? step.kind : "step";
25440
25513
  const stepStatus = typeof step.status === "string" ? step.status : status;
@@ -25467,10 +25540,8 @@ function buildRunPackageTextLines(packaged) {
25467
25540
  if (legacyExportCommand) {
25468
25541
  lines.push(` export CSV: ${legacyExportCommand}`);
25469
25542
  }
25470
- if (runAgainCommand) {
25471
- lines.push(
25472
- isRuntimeTimeout ? " run again after adjusting the deadline or batch (compatible completed work may be reused):" : " run again (completed work is reused):"
25473
- );
25543
+ if (runAgainCommand && !isRuntimeLimitCheckpoint) {
25544
+ lines.push(" run again (completed work is reused):");
25474
25545
  lines.push(` ${runAgainCommand}`);
25475
25546
  }
25476
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.134",
867
+ version: "0.3.136",
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.134",
771
+ version: "0.3.136",
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.134";
152
+ readonly version: "0.3.136";
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.134";
152
+ readonly version: "0.3.136";
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.134",
77
+ version: "0.3.136",
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.134",
51
+ version: "0.3.136",
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.134",
3
+ "version": "0.3.136",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",