deepline 0.3.212 → 0.3.214

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 (30) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +137 -32
  2. package/dist/bundling-sources/sdk/src/compat.ts +2 -0
  3. package/dist/bundling-sources/sdk/src/deployment-protection.ts +19 -0
  4. package/dist/bundling-sources/sdk/src/http.ts +3 -7
  5. package/dist/bundling-sources/sdk/src/index.ts +7 -0
  6. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  7. package/dist/bundling-sources/sdk/src/types.ts +25 -0
  8. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +18 -0
  9. package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +1 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +33 -7
  11. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +11 -1
  12. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-heartbeat.ts +3 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +53 -1
  14. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +187 -6
  15. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +67 -37
  16. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +12 -3
  17. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +5 -2
  18. package/dist/bundling-sources/shared_libs/plays/settings-contract.ts +176 -0
  19. package/dist/cli/index.js +572 -92
  20. package/dist/cli/index.mjs +572 -92
  21. package/dist/index.d.mts +191 -3
  22. package/dist/index.d.ts +191 -3
  23. package/dist/index.js +67 -35
  24. package/dist/index.mjs +67 -35
  25. package/dist/install-integrity.json +2 -0
  26. package/dist/release.d.mts +1 -1
  27. package/dist/release.d.ts +1 -1
  28. package/dist/release.js +1 -1
  29. package/dist/release.mjs +1 -1
  30. package/package.json +3 -2
@@ -3046,7 +3046,7 @@ var SDK_RELEASE = {
3046
3046
  // getters keep their established compatibility behavior.
3047
3047
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
3048
3048
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
3049
- version: "0.3.212",
3049
+ version: "0.3.214",
3050
3050
  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.",
3051
3051
  packageCapabilities: {
3052
3052
  updatePreferences: 1
@@ -3367,6 +3367,22 @@ function writeSdkSkillsLocalVersion(baseUrl, version, agents) {
3367
3367
  return complete;
3368
3368
  }
3369
3369
 
3370
+ // src/deployment-protection.ts
3371
+ function deploymentProtectionHeaders() {
3372
+ const token = typeof process !== "undefined" ? process.env?.VERCEL_PROTECTION_BYPASS_TOKEN : void 0;
3373
+ return token ? { "x-vercel-protection-bypass": token } : {};
3374
+ }
3375
+ var fetchWithDeploymentProtection = (input2, init) => {
3376
+ const headers = new Headers(
3377
+ input2 instanceof Request ? input2.headers : void 0
3378
+ );
3379
+ new Headers(init?.headers).forEach((value, name) => headers.set(name, value));
3380
+ for (const [name, value] of Object.entries(deploymentProtectionHeaders())) {
3381
+ headers.set(name, value);
3382
+ }
3383
+ return fetch(input2, { ...init, headers });
3384
+ };
3385
+
3370
3386
  // ../play-runtime/coordinator-headers.ts
3371
3387
  var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
3372
3388
  var COORDINATOR_URL_OVERRIDE_HEADER = "x-deepline-coordinator-url";
@@ -3749,16 +3765,13 @@ var HttpClient = class {
3749
3765
  "X-Deepline-SDK-Version": SDK_VERSION,
3750
3766
  "X-Deepline-API-Contract": SDK_API_CONTRACT,
3751
3767
  "X-Deepline-Run-Result-Shape": "canonical",
3752
- ...extra
3768
+ ...extra,
3769
+ ...deploymentProtectionHeaders()
3753
3770
  };
3754
3771
  const skillsVersion = this.readSkillsVersionHeader();
3755
3772
  if (skillsVersion) {
3756
3773
  headers["X-Deepline-Skills-Version"] = skillsVersion;
3757
3774
  }
3758
- const bypassToken = typeof process !== "undefined" ? process.env?.VERCEL_PROTECTION_BYPASS_TOKEN : void 0;
3759
- if (bypassToken) {
3760
- headers["x-vercel-protection-bypass"] = bypassToken;
3761
- }
3762
3775
  const playArtifactR2Prefix = typeof process !== "undefined" ? process.env?.DEEPLINE_PLAY_ARTIFACT_R2_PREFIX : void 0;
3763
3776
  if (playArtifactR2Prefix) {
3764
3777
  headers["x-deepline-play-artifact-r2-prefix"] = playArtifactR2Prefix;
@@ -4887,13 +4900,13 @@ function previewValue(value, input2) {
4887
4900
  ([, descriptor]) => descriptor.enumerable
4888
4901
  );
4889
4902
  const selected = entries.slice(0, DOCFLOW_NODE_IO_LIMITS.maxObjectFields);
4890
- const fields = {};
4903
+ const fields2 = {};
4891
4904
  for (const [key, descriptor] of selected) {
4892
4905
  const safeKey = truncateUtf8(
4893
4906
  ledgerSafeDocflowPreviewKey(input2.redactor.redactString(key)),
4894
4907
  DOCFLOW_NODE_IO_LIMITS.maxStringBytes
4895
4908
  );
4896
- fields[safeKey] = "value" in descriptor ? previewValue(descriptor.value, {
4909
+ fields2[safeKey] = "value" in descriptor ? previewValue(descriptor.value, {
4897
4910
  ...input2,
4898
4911
  depth: input2.depth + 1,
4899
4912
  key
@@ -4901,7 +4914,7 @@ function previewValue(value, input2) {
4901
4914
  }
4902
4915
  return {
4903
4916
  kind: "object",
4904
- fields,
4917
+ fields: fields2,
4905
4918
  totalFields: entries.length,
4906
4919
  ...entries.length > selected.length ? { truncated: true } : {}
4907
4920
  };
@@ -5010,20 +5023,20 @@ function normalizePreview(value, depth) {
5010
5023
  };
5011
5024
  }
5012
5025
  if (value.kind === "object" && isRecord3(value.fields)) {
5013
- const fields = {};
5026
+ const fields2 = {};
5014
5027
  for (const [key, field] of Object.entries(value.fields).slice(
5015
5028
  0,
5016
5029
  DOCFLOW_NODE_IO_LIMITS.maxObjectFields
5017
5030
  )) {
5018
5031
  const normalized = normalizePreview(field, depth + 1);
5019
- if (normalized) fields[ledgerSafeDocflowPreviewKey(key)] = normalized;
5032
+ if (normalized) fields2[ledgerSafeDocflowPreviewKey(key)] = normalized;
5020
5033
  }
5021
- const totalFields = typeof value.totalFields === "number" && Number.isFinite(value.totalFields) ? Math.max(Object.keys(fields).length, Math.floor(value.totalFields)) : Object.keys(fields).length;
5034
+ const totalFields = typeof value.totalFields === "number" && Number.isFinite(value.totalFields) ? Math.max(Object.keys(fields2).length, Math.floor(value.totalFields)) : Object.keys(fields2).length;
5022
5035
  return {
5023
5036
  kind: "object",
5024
- fields,
5037
+ fields: fields2,
5025
5038
  totalFields,
5026
- ...value.truncated === true || totalFields > Object.keys(fields).length ? { truncated: true } : {}
5039
+ ...value.truncated === true || totalFields > Object.keys(fields2).length ? { truncated: true } : {}
5027
5040
  };
5028
5041
  }
5029
5042
  return null;
@@ -7035,10 +7048,19 @@ function normalizePlayStatus(raw) {
7035
7048
  );
7036
7049
  }
7037
7050
  const runId = typeof raw.runId === "string" ? raw.runId : typeof raw.workflowId === "string" ? raw.workflowId : packageRun?.id ?? "";
7051
+ const legacyOverview = runPackage?.overview ?? raw.overview;
7052
+ const runStatus = runPackage?.runStatus ?? raw.runStatus;
7038
7053
  return {
7039
7054
  ...raw,
7040
7055
  runId,
7041
- ...runPackage ? { package: runPackage, outputs: runPackage.outputs } : {},
7056
+ ...isRecord7(legacyOverview) ? {
7057
+ overview: legacyOverview
7058
+ } : {},
7059
+ ...isRecord7(runStatus) ? { runStatus } : {},
7060
+ ...runPackage ? {
7061
+ package: runPackage,
7062
+ outputs: runPackage.outputs
7063
+ } : {},
7042
7064
  status
7043
7065
  };
7044
7066
  }
@@ -7220,18 +7242,6 @@ function playRunResultFromStatus(status, startedAt, fallbackRunId) {
7220
7242
  error: status.progress?.error ?? (status.status !== "completed" ? status.status : void 0)
7221
7243
  };
7222
7244
  }
7223
- function playRunStatusFromState(state) {
7224
- return {
7225
- runId: state.runId,
7226
- status: state.status,
7227
- progress: {
7228
- status: state.status,
7229
- logs: state.logs,
7230
- ...state.error ? { error: state.error } : {}
7231
- },
7232
- ..."result" in state ? { result: state.result } : {}
7233
- };
7234
- }
7235
7245
  var DeeplineClient = class _DeeplineClient {
7236
7246
  http;
7237
7247
  config;
@@ -7374,14 +7384,14 @@ var DeeplineClient = class _DeeplineClient {
7374
7384
  }
7375
7385
  compactSchema(schema) {
7376
7386
  if (!schema) return null;
7377
- const fields = Array.isArray(schema.fields) ? schema.fields.map(
7387
+ const fields2 = Array.isArray(schema.fields) ? schema.fields.map(
7378
7388
  (field) => field && typeof field === "object" ? {
7379
7389
  name: String(field.name ?? ""),
7380
7390
  type: field.type ?? void 0,
7381
7391
  required: field.required ?? void 0
7382
7392
  } : null
7383
7393
  ).filter((field) => Boolean(field?.name)) : [];
7384
- return fields.length > 0 ? { fields } : schema;
7394
+ return fields2.length > 0 ? { fields: fields2 } : schema;
7385
7395
  }
7386
7396
  schemaMetadata(schema, key) {
7387
7397
  if (!isRecord7(schema)) return null;
@@ -7568,6 +7578,12 @@ var DeeplineClient = class _DeeplineClient {
7568
7578
  options.includeSearchDebug ? "true" : "false"
7569
7579
  );
7570
7580
  params.set("search_mode", options.searchMode ?? "v2");
7581
+ if (options.limit !== void 0) {
7582
+ params.set("limit", String(options.limit));
7583
+ }
7584
+ if (options.offset !== void 0) {
7585
+ params.set("offset", String(options.offset));
7586
+ }
7571
7587
  if (options.categories?.trim()) {
7572
7588
  params.set("categories", options.categories.trim());
7573
7589
  }
@@ -8629,9 +8645,18 @@ var DeeplineClient = class _DeeplineClient {
8629
8645
  }
8630
8646
  const query = params.size > 0 ? `?${params.toString()}` : "";
8631
8647
  const response = await this.http.get(
8632
- `/api/v2/runs/${encodeURIComponent(runId)}${query}`
8648
+ `/api/v2/runs/${encodeURIComponent(runId)}${query}`,
8649
+ { headers: { "x-deepline-run-status": "1" } }
8633
8650
  );
8651
+ const responseRunStatus = isPlayRunPackage(response) ? response.runStatus : isPlayRunPackage(response.package) ? response.package.runStatus : response.runStatus;
8652
+ const responseOverview = isPlayRunPackage(response) ? response.overview : isPlayRunPackage(response.package) ? response.package.overview : response.overview;
8634
8653
  const status = normalizePlayStatus(response);
8654
+ if (isRecord7(responseRunStatus)) {
8655
+ status.runStatus = responseRunStatus;
8656
+ }
8657
+ if (isRecord7(responseOverview)) {
8658
+ status.overview = responseOverview;
8659
+ }
8635
8660
  if (options?.failedLogs !== true || status.status !== "failed") {
8636
8661
  return status;
8637
8662
  }
@@ -8672,7 +8697,10 @@ var DeeplineClient = class _DeeplineClient {
8672
8697
  }
8673
8698
  };
8674
8699
  }
8675
- /** Read only the bounded scalar projection; does not hydrate the run package. */
8700
+ /** Fetch only the legacy scalar lifecycle status for a run.
8701
+ *
8702
+ * @deprecated Use `client.runs.get(runId)` for the canonical run read.
8703
+ */
8676
8704
  async getRunLifecycleStatus(runId) {
8677
8705
  const response = await this.http.get(
8678
8706
  `/api/v2/runs/${encodeURIComponent(runId)}/status`
@@ -8848,9 +8876,7 @@ var DeeplineClient = class _DeeplineClient {
8848
8876
  if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
8849
8877
  continue;
8850
8878
  }
8851
- return await this.getRunStatus(status.runId || runId).catch(
8852
- () => state.latest ?? playRunStatusFromState(state)
8853
- );
8879
+ return await this.getRunStatus(status.runId || runId);
8854
8880
  }
8855
8881
  if (options?.signal?.aborted) {
8856
8882
  throw new DeeplineError("Run observation aborted.", void 0, "ABORTED");
@@ -8901,6 +8927,7 @@ var DeeplineClient = class _DeeplineClient {
8901
8927
  for (; ; ) {
8902
8928
  const connectedAt = Date.now();
8903
8929
  let sawEvent = false;
8930
+ let terminalRunId = null;
8904
8931
  let endedReason = "stream window ended before a terminal event";
8905
8932
  try {
8906
8933
  for await (const event of this.streamPlayRunEvents(runId, {
@@ -8913,9 +8940,8 @@ var DeeplineClient = class _DeeplineClient {
8913
8940
  if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
8914
8941
  continue;
8915
8942
  }
8916
- return await this.getRunStatus(status.runId || runId).catch(
8917
- () => state.latest ?? playRunStatusFromState(state)
8918
- );
8943
+ terminalRunId = status.runId || runId;
8944
+ break;
8919
8945
  }
8920
8946
  } catch (error) {
8921
8947
  if (options?.signal?.aborted || !isTransientPlayStreamError(error)) {
@@ -8923,15 +8949,11 @@ var DeeplineClient = class _DeeplineClient {
8923
8949
  }
8924
8950
  endedReason = error instanceof Error ? error.message : String(error);
8925
8951
  }
8926
- let refreshed = null;
8927
- try {
8928
- refreshed = await this.getRunStatus(runId);
8929
- } catch (error) {
8930
- if (!isTransientPlayStreamError(error)) {
8931
- throw error;
8932
- }
8952
+ if (terminalRunId) {
8953
+ return await this.getRunStatus(terminalRunId);
8933
8954
  }
8934
- if (refreshed && TERMINAL_PLAY_STATUSES.has(refreshed.status)) {
8955
+ const refreshed = await this.getRunStatus(runId);
8956
+ if (TERMINAL_PLAY_STATUSES.has(refreshed.status)) {
8935
8957
  return refreshed;
8936
8958
  }
8937
8959
  if (sawEvent || Date.now() - connectedAt >= STREAM_HEALTHY_CONNECTION_MS) {
@@ -9220,6 +9242,26 @@ var DeeplineClient = class _DeeplineClient {
9220
9242
  hasMore: Boolean(response.pagination?.hasMore ?? response.hasMore)
9221
9243
  };
9222
9244
  }
9245
+ /** Read definition-level settings, independently of code revisions. */
9246
+ async getPlaySettings(playName) {
9247
+ return this.http.get(
9248
+ `/api/v2/plays/${encodeURIComponent(playName)}/settings`
9249
+ );
9250
+ }
9251
+ /** Retry-safe field patch; omitted fields retain their current value. */
9252
+ async updatePlaySettings(playName, patch) {
9253
+ return this.http.patch(
9254
+ `/api/v2/plays/${encodeURIComponent(playName)}/settings`,
9255
+ patch
9256
+ );
9257
+ }
9258
+ /** List one bounded page of existing Play locations; continue with cursor. */
9259
+ async listPlaySettingsPaths(options = {}) {
9260
+ const query = new URLSearchParams();
9261
+ for (const [key, value] of Object.entries(options))
9262
+ if (value !== void 0) query.set(key, String(value));
9263
+ return this.http.get(`/api/v2/plays/settings/paths?${query}`);
9264
+ }
9223
9265
  /** Set whether an org-owned Play sorts before unpinned Plays. */
9224
9266
  async setPlayPinned(playName, pinned) {
9225
9267
  return this.http.post(`/api/v2/plays/${encodeURIComponent(playName)}/pin`, {
@@ -10837,6 +10879,7 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
10837
10879
  const response = await fetch(url, {
10838
10880
  method: "GET",
10839
10881
  headers: {
10882
+ ...deploymentProtectionHeaders(),
10840
10883
  "User-Agent": `deepline-ts-sdk/${SDK_VERSION}`,
10841
10884
  "X-Deepline-SDK-Version": SDK_VERSION,
10842
10885
  "X-Deepline-API-Major": String(SDK_API_MAJOR),
@@ -11713,8 +11756,8 @@ function resolvePendingAuthClaimForResume(baseUrl, requestedScope) {
11713
11756
  const claim = readPendingAuthClaim(baseUrl, requestedScope);
11714
11757
  return { claim, scope: claim?.scope ?? requestedScope };
11715
11758
  }
11716
- const folder = readPendingAuthClaim(baseUrl, "folder");
11717
- if (folder) return { claim: folder, scope: folder.scope };
11759
+ const folder2 = readPendingAuthClaim(baseUrl, "folder");
11760
+ if (folder2) return { claim: folder2, scope: folder2.scope };
11718
11761
  const global = readPendingAuthClaim(baseUrl, "global");
11719
11762
  return { claim: global, scope: global?.scope ?? "global" };
11720
11763
  }
@@ -15917,6 +15960,332 @@ import { homedir as homedir6, tmpdir as tmpdir5 } from "os";
15917
15960
  import { basename as basename4, dirname as dirname11, extname as extname3, join as join14, resolve as resolve13 } from "path";
15918
15961
  import { Option as Option2 } from "commander";
15919
15962
 
15963
+ // ../plays/settings-contract.ts
15964
+ import { z } from "zod";
15965
+ function formatPlaySettingsError(error) {
15966
+ if (error instanceof z.ZodError)
15967
+ return [...new Set(error.issues.map((issue) => issue.message))].join(" ");
15968
+ return error instanceof Error ? error.message : String(error);
15969
+ }
15970
+ var PLAY_LOCATION_ROOTS = [
15971
+ {
15972
+ value: "person",
15973
+ label: "Personal",
15974
+ description: "The creator\u2019s personal root, displayed as their name followed by \u201C\u2019s team\u201D."
15975
+ },
15976
+ {
15977
+ value: "team",
15978
+ label: "Team library",
15979
+ description: "The shared team library. Publishing moves personal locations here, keeping their folders."
15980
+ }
15981
+ ];
15982
+ var folder = z.string().min(1).max(128).refine(
15983
+ (value) => value === value.trim() && value !== "." && value !== ".." && !/[\\/\u0000-\u001f\u007f]/u.test(value),
15984
+ "Folder names must be trimmed, cannot be . or .., and cannot contain slashes or control characters."
15985
+ );
15986
+ var playPathSchema = z.union([
15987
+ z.null(),
15988
+ z.object({
15989
+ root: z.enum(["person", "team"]),
15990
+ folders: z.array(folder).max(16).default([])
15991
+ }).strict()
15992
+ ]).transform(
15993
+ (path) => path?.root === "person" && path.folders.length === 0 ? null : path
15994
+ );
15995
+ function parsePlayPath(value) {
15996
+ const [root, ...parts] = value.split("/");
15997
+ if (!PLAY_LOCATION_ROOTS.some((option) => option.value === root)) {
15998
+ throw new Error(
15999
+ "Path must start with person or team. Example: person/Research/ICP."
16000
+ );
16001
+ }
16002
+ let folders;
16003
+ try {
16004
+ folders = parts.map(decodeURIComponent);
16005
+ } catch {
16006
+ throw new Error(
16007
+ "Path contains an invalid percent escape. Encode a literal % as %25."
16008
+ );
16009
+ }
16010
+ return playPathSchema.parse({ root, folders });
16011
+ }
16012
+ function formatPlayPath(path) {
16013
+ return path === null ? "person" : [path.root, ...path.folders.map(encodeURIComponent)].join("/");
16014
+ }
16015
+ function personalPlayRootLabel(ownerName) {
16016
+ const name = ownerName?.trim();
16017
+ return name ? `${name.split(/\s+/)[0]}\u2019s team` : "Personal";
16018
+ }
16019
+ function displayPlayPath(path, ownerName) {
16020
+ return [
16021
+ path?.root === "team" ? "Team library" : personalPlayRootLabel(ownerName),
16022
+ ...path?.folders ?? []
16023
+ ].join(" / ");
16024
+ }
16025
+ var PLAY_SETTING_FIELDS = {
16026
+ path: {
16027
+ schema: playPathSchema.default(null).describe(
16028
+ "Play location. Null means the creator\u2019s personal root. Publishing moves it into Team library, preserving folders."
16029
+ ),
16030
+ label: "Location",
16031
+ description: "Organize this Play in the creator\u2019s personal root or Team library. Publishing moves it to Team library and keeps its folders. Workspace sharing permissions apply in both roots.",
16032
+ get defaultValue() {
16033
+ return this.schema.parse(void 0);
16034
+ },
16035
+ cli: {
16036
+ valueSyntax: "person[/folder/\u2026] | team[/folder/\u2026] | null",
16037
+ examples: [
16038
+ "person",
16039
+ "person/Research/ICP",
16040
+ "team",
16041
+ "team/Research",
16042
+ "null"
16043
+ ],
16044
+ parse: (value) => value === "null" ? null : parsePlayPath(value),
16045
+ format: formatPlayPath
16046
+ },
16047
+ ui: { control: "play-location-picker" }
16048
+ }
16049
+ };
16050
+ var playSettingsSchema = z.object(
16051
+ Object.fromEntries(
16052
+ Object.entries(PLAY_SETTING_FIELDS).map(([key, field]) => [
16053
+ key,
16054
+ field.schema
16055
+ ])
16056
+ )
16057
+ ).passthrough();
16058
+ var playSettingsPatchSchema = z.object(
16059
+ Object.fromEntries(
16060
+ Object.entries(PLAY_SETTING_FIELDS).map(([key, field]) => [
16061
+ key,
16062
+ field.schema.unwrap().optional()
16063
+ ])
16064
+ )
16065
+ ).strict().refine(
16066
+ (patch) => Object.keys(patch).length > 0,
16067
+ "Supply at least one setting."
16068
+ );
16069
+ function parsePlaySettings(value) {
16070
+ return playSettingsSchema.parse(value);
16071
+ }
16072
+ var DEFAULT_PLAY_SETTINGS = parsePlaySettings({});
16073
+
16074
+ // src/cli/commands/plays-settings.ts
16075
+ var fields = Object.entries(PLAY_SETTING_FIELDS);
16076
+ var help = `
16077
+ Settings live on the Play definition. Edits preserve code revisions.
16078
+ New Plays start at person (the creator\u2019s personal root, e.g. Chirag\u2019s team).
16079
+ Publishing moves a Play into team and keeps its folders. Workspace sharing
16080
+ permissions apply in both roots. Folder paths are independent of your cwd.
16081
+
16082
+ Setting names and values:
16083
+ ${fields.map(([key, field]) => ` ${key}: ${field.schema.description}
16084
+ Values: ${field.cli.valueSyntax}
16085
+ Default: ${JSON.stringify(field.defaultValue)} (${field.cli.format(field.defaultValue)})`).join("\n")}
16086
+
16087
+ Roots:
16088
+ ${PLAY_LOCATION_ROOTS.map((root) => ` ${root.value}: ${root.description}`).join("\n")}
16089
+
16090
+ Examples:
16091
+ deepline plays settings describe --name path --json
16092
+ deepline plays settings get --play company-research --json
16093
+ deepline plays settings get --play company-research --name path
16094
+ deepline plays settings set --play company-research --name path --value person/Research/ICP
16095
+ deepline plays settings set --play company-research --name path --value team/Research
16096
+ deepline plays settings reset --play company-research --name path
16097
+ deepline plays settings paths --root team --json
16098
+
16099
+ Quote values containing spaces. Use percent escapes for literal % characters.
16100
+ `;
16101
+ function resolveField(key, command) {
16102
+ const entry = fields.find(([name]) => name === key);
16103
+ if (!entry)
16104
+ command.error(
16105
+ `Unknown --name ${JSON.stringify(key)}. Available settings: ${fields.map(([name]) => name).join(", ")}. Run deepline plays settings describe.`,
16106
+ { exitCode: 2 }
16107
+ );
16108
+ return entry[1];
16109
+ }
16110
+ function printSettings(result, json2, name) {
16111
+ const selected = fields.filter(([key]) => !name || key === name);
16112
+ printCommandEnvelope(
16113
+ {
16114
+ ...result,
16115
+ settings: Object.fromEntries(
16116
+ selected.map(([key]) => [
16117
+ key,
16118
+ result.settings[key]
16119
+ ])
16120
+ ),
16121
+ render: {
16122
+ sections: [
16123
+ {
16124
+ title: "Play settings",
16125
+ lines: selected.map(
16126
+ ([key, field]) => `${field.label}: ${key === "path" ? displayPlayPath(result.settings.path, result.ownerName) : field.cli.format(result.settings[key])} (${field.cli.format(result.settings[key])})`
16127
+ )
16128
+ }
16129
+ ]
16130
+ }
16131
+ },
16132
+ { json: json2 }
16133
+ );
16134
+ }
16135
+ function registerPlaySettingsCommands(plays) {
16136
+ const settings = plays.command("settings").description("Read and change Play settings by name and value.").exitOverride((error) => {
16137
+ if (error.exitCode !== 0) error.exitCode = 2;
16138
+ throw error;
16139
+ }).addHelpText("after", help);
16140
+ settings.command("describe").usage("[--name <setting>] [options]").description(
16141
+ "List setting names, values, examples and defaults; no authentication required."
16142
+ ).option(
16143
+ "--name <setting>",
16144
+ `Describe one setting. Available: ${fields.map(([key]) => key).join(", ")}`
16145
+ ).option("--json", "Emit JSON; automatic when piped").addHelpText("after", help).action((options, command) => {
16146
+ if (options.name !== void 0) resolveField(options.name, command);
16147
+ const descriptions = fields.filter(([name]) => !options.name || options.name === name).map(([name, field]) => ({
16148
+ key: name,
16149
+ label: field.label,
16150
+ description: field.schema.description ?? field.description,
16151
+ default: field.defaultValue,
16152
+ defaultText: field.cli.format(field.defaultValue),
16153
+ valueSyntax: field.cli.valueSyntax,
16154
+ examples: field.cli.examples
16155
+ }));
16156
+ printCommandEnvelope(
16157
+ {
16158
+ fields: descriptions,
16159
+ render: {
16160
+ sections: descriptions.map((field) => ({
16161
+ title: field.key,
16162
+ lines: [
16163
+ field.description,
16164
+ `Values: ${field.valueSyntax}`,
16165
+ `Default: ${JSON.stringify(field.default)} (${field.defaultText})`,
16166
+ `Examples: ${field.examples.join(", ")}`
16167
+ ]
16168
+ }))
16169
+ }
16170
+ },
16171
+ { json: options.json }
16172
+ );
16173
+ });
16174
+ settings.command("get").usage("--play <play> [--name <setting>] [options]").description("Read all settings, or one setting selected with --name.").requiredOption("--play <play>", "Play to read").option(
16175
+ "--name <setting>",
16176
+ `Read one setting. Available: ${fields.map(([key]) => key).join(", ")}`
16177
+ ).option("--json", "Emit JSON; automatic when piped").addHelpText("after", help).action(
16178
+ async (options, command) => {
16179
+ if (options.name !== void 0) resolveField(options.name, command);
16180
+ printSettings(
16181
+ await new DeeplineClient().getPlaySettings(options.play),
16182
+ options.json,
16183
+ options.name
16184
+ );
16185
+ }
16186
+ );
16187
+ const set = settings.command("set").usage("--play <play> --name <setting> --value <value> [options]").requiredOption("--play <play>", "Play to update").requiredOption(
16188
+ "--name <setting>",
16189
+ `Setting name. Available: ${fields.map(([key]) => key).join(", ")}`
16190
+ ).requiredOption(
16191
+ "--value <value>",
16192
+ "New value; see settings describe --name <setting>"
16193
+ ).description("Set one setting without creating or publishing a revision.");
16194
+ const reset = settings.command("reset").usage("--play <play> --name <setting> [options]").requiredOption("--play <play>", "Play to update").requiredOption(
16195
+ "--name <setting>",
16196
+ `Setting name. Available: ${fields.map(([key]) => key).join(", ")}`
16197
+ ).description("Reset one setting to its schema default.");
16198
+ const change = async (command, play, key, value, options, resetting) => {
16199
+ const field = resolveField(key, command);
16200
+ let patch;
16201
+ try {
16202
+ patch = playSettingsPatchSchema.parse({
16203
+ [key]: resetting ? field.defaultValue : field.cli.parse(value)
16204
+ });
16205
+ } catch (error) {
16206
+ command.error(
16207
+ `Invalid --value for --name ${key}: ${formatPlaySettingsError(error)} Values: ${field.cli.valueSyntax}.`,
16208
+ { exitCode: 2 }
16209
+ );
16210
+ }
16211
+ if (options.dryRun) {
16212
+ printCommandEnvelope(
16213
+ {
16214
+ dryRun: true,
16215
+ play,
16216
+ patch,
16217
+ render: {
16218
+ sections: [
16219
+ {
16220
+ title: "Planned settings patch",
16221
+ lines: Object.entries(patch).map(
16222
+ ([name, setting]) => `${name}: ${JSON.stringify(setting)}`
16223
+ )
16224
+ }
16225
+ ]
16226
+ }
16227
+ },
16228
+ { json: options.json }
16229
+ );
16230
+ return;
16231
+ }
16232
+ printSettings(
16233
+ await new DeeplineClient().updatePlaySettings(play, patch),
16234
+ options.json
16235
+ );
16236
+ };
16237
+ for (const [command, resetting] of [
16238
+ [set, false],
16239
+ [reset, true]
16240
+ ])
16241
+ command.option("--dry-run", "Show the patch without changing settings").option("--json", "Emit JSON; automatic when piped").addHelpText("after", help).action(
16242
+ (options) => change(
16243
+ command,
16244
+ options.play,
16245
+ options.name,
16246
+ options.value,
16247
+ options,
16248
+ resetting
16249
+ )
16250
+ );
16251
+ settings.command("paths").description("List existing locations (one bounded page).").option("--root <person|team>", "Filter by root").option("--limit <n>", "Plays to inspect, 1\u2013100", "50").option("--cursor <cursor>", "Continue from a previous page").option("--json", "Emit JSON; automatic when piped").addHelpText("after", help).action(
16252
+ async (options, command) => {
16253
+ const limit = Number(options.limit);
16254
+ if (options.root !== void 0 && options.root !== "person" && options.root !== "team" || !Number.isInteger(limit) || limit < 1 || limit > 100)
16255
+ command.error(
16256
+ "--root must be person or team; --limit must be 1\u2013100.",
16257
+ { exitCode: 2 }
16258
+ );
16259
+ const page = await new DeeplineClient().listPlaySettingsPaths({
16260
+ root: options.root,
16261
+ limit,
16262
+ cursor: options.cursor
16263
+ });
16264
+ const nextCommand = page.hasMore ? `deepline plays settings paths --cursor '${page.cursor}'${options.root ? ` --root ${options.root}` : ""} --json` : null;
16265
+ printCommandEnvelope(
16266
+ {
16267
+ ...page,
16268
+ nextCommand,
16269
+ render: {
16270
+ sections: [
16271
+ {
16272
+ title: "Play locations",
16273
+ lines: [
16274
+ ...page.paths.map(
16275
+ (item) => `${displayPlayPath(item.path, item.ownerName)} (${formatPlayPath(item.path)}) \u2014 ${item.playName}`
16276
+ ),
16277
+ ...nextCommand ? [`More: ${nextCommand}`] : []
16278
+ ]
16279
+ }
16280
+ ]
16281
+ }
16282
+ },
16283
+ { json: options.json }
16284
+ );
16285
+ }
16286
+ );
16287
+ }
16288
+
15920
16289
  // src/cli/commands/play.ts
15921
16290
  import { createHash as createHash4, randomUUID as randomUUID4 } from "crypto";
15922
16291
  import {
@@ -16560,8 +16929,8 @@ function readCsvHeaderFields(csvPath, sample) {
16560
16929
  skip_empty_lines: false
16561
16930
  });
16562
16931
  const firstRecord = Array.isArray(records) ? records[0] : null;
16563
- const fields = Array.isArray(firstRecord) ? firstRecord.map((field) => String(field ?? "").trim()).filter(Boolean) : [];
16564
- const uniqueFields = [...new Set(fields)];
16932
+ const fields2 = Array.isArray(firstRecord) ? firstRecord.map((field) => String(field ?? "").trim()).filter(Boolean) : [];
16933
+ const uniqueFields = [...new Set(fields2)];
16565
16934
  if (uniqueFields.length === 0) {
16566
16935
  throw new PlayBootstrapUsageError(
16567
16936
  `Could not read a header row from --from csv:${csvPath}.`
@@ -17650,6 +18019,45 @@ Examples:
17650
18019
  });
17651
18020
  }
17652
18021
 
18022
+ // src/cli/commands/plays/run-history.ts
18023
+ async function handleRunsHistory(options) {
18024
+ const query = new URLSearchParams();
18025
+ if (options.cursor) query.set("cursor", options.cursor);
18026
+ if (options.org) query.set("orgId", options.org);
18027
+ if (options.limit !== void 0) {
18028
+ const limit = Number(options.limit);
18029
+ if (!/^\d+$/.test(options.limit) || !Number.isSafeInteger(limit) || limit < 1) {
18030
+ throw new Error("--limit must be a positive integer.");
18031
+ }
18032
+ query.set("limit", String(limit));
18033
+ }
18034
+ const search = query.toString();
18035
+ const page = await new HttpClient(resolveConfig()).get(
18036
+ `/api/v2/dashboard/runs-history${search ? `?${search}` : ""}`
18037
+ );
18038
+ const lines = page.runs.map(
18039
+ (run) => `${run.workflowName} \xB7 ${run.status} \xB7 ${run.runId}`
18040
+ );
18041
+ if (lines.length === 0) lines.push("No runs found on this page.");
18042
+ if (page.hasMore) lines.push(`Next cursor: ${page.nextCursor}`);
18043
+ printCommandEnvelope(
18044
+ { ...page, render: { sections: [{ title: "Run history", lines }] } },
18045
+ options.json ? { json: true } : {}
18046
+ );
18047
+ }
18048
+ function registerRunHistoryCommand(runs) {
18049
+ runs.command("history").description("Page workspace run history.").option(
18050
+ "--cursor <cursor>",
18051
+ "Opaque nextCursor returned by the previous page"
18052
+ ).option("--limit <count>", "Maximum runs on this page").option(
18053
+ "--org <id>",
18054
+ "Workspace ID (must match the authenticated workspace)"
18055
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").addHelpText(
18056
+ "after",
18057
+ "\nUse the opaque --cursor returned by the previous page to continue.\n\nExample:\n deepline runs history --limit 100 --json\n"
18058
+ ).action(handleRunsHistory);
18059
+ }
18060
+
17653
18061
  // src/plays/bundle-play-file.ts
17654
18062
  import { tmpdir as tmpdir3 } from "os";
17655
18063
  import { dirname as dirname9, join as join9, resolve as resolve10 } from "path";
@@ -20554,7 +20962,7 @@ function recordCliTrace(event) {
20554
20962
  process.stderr.write(`[cli-trace] ${JSON.stringify(payload)}
20555
20963
  `);
20556
20964
  }
20557
- async function traceCliSpan(phase, fields, run) {
20965
+ async function traceCliSpan(phase, fields2, run) {
20558
20966
  if (!isCliTraceEnabled()) {
20559
20967
  return run();
20560
20968
  }
@@ -20565,7 +20973,7 @@ async function traceCliSpan(phase, fields, run) {
20565
20973
  phase,
20566
20974
  ms: Date.now() - startedAt,
20567
20975
  ok: true,
20568
- ...fields
20976
+ ...fields2
20569
20977
  });
20570
20978
  return result;
20571
20979
  } catch (error) {
@@ -20574,7 +20982,7 @@ async function traceCliSpan(phase, fields, run) {
20574
20982
  ms: Date.now() - startedAt,
20575
20983
  ok: false,
20576
20984
  error: error instanceof Error ? error.message : String(error),
20577
- ...fields
20985
+ ...fields2
20578
20986
  });
20579
20987
  throw error;
20580
20988
  }
@@ -22418,6 +22826,7 @@ async function handlePlaysDeploy(directory, options) {
22418
22826
  },
22419
22827
  {
22420
22828
  bundle: bundleDeployPlayFile,
22829
+ fetchImpl: fetchWithDeploymentProtection,
22421
22830
  // The plays are already here: "opening" the source is naming it.
22422
22831
  openSource: async () => ({
22423
22832
  open: async () => ({ repoRoot: root })
@@ -23129,7 +23538,7 @@ async function writePlayRunIdFile(destination, runId, options = {}) {
23129
23538
  await removeRunIdTempFile(tempPath);
23130
23539
  }
23131
23540
  }
23132
- function traceCliSync(phase, fields, run) {
23541
+ function traceCliSync(phase, fields2, run) {
23133
23542
  const startedAt = Date.now();
23134
23543
  try {
23135
23544
  const result = run();
@@ -23137,7 +23546,7 @@ function traceCliSync(phase, fields, run) {
23137
23546
  phase,
23138
23547
  ms: Date.now() - startedAt,
23139
23548
  ok: true,
23140
- ...fields
23549
+ ...fields2
23141
23550
  });
23142
23551
  return result;
23143
23552
  } catch (error) {
@@ -23146,7 +23555,7 @@ function traceCliSync(phase, fields, run) {
23146
23555
  ms: Date.now() - startedAt,
23147
23556
  ok: false,
23148
23557
  error: error instanceof Error ? error.message : String(error),
23149
- ...fields
23558
+ ...fields2
23150
23559
  });
23151
23560
  throw error;
23152
23561
  }
@@ -24470,7 +24879,8 @@ function formatProgressCounts(input2) {
24470
24879
  Math.min(100, Math.round(completed / total * 100))
24471
24880
  );
24472
24881
  const failed = typeof input2.failed === "number" && Number.isFinite(input2.failed) && input2.failed > 0 ? `, failed ${formatInteger(input2.failed)}` : "";
24473
- return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
24882
+ const completedLabel = typeof input2.failed === "number" ? "successful " : "";
24883
+ return `${completedLabel}${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
24474
24884
  }
24475
24885
  function formatProgressMessageSuffix(input2) {
24476
24886
  const message = typeof input2.message === "string" ? input2.message.trim() : "";
@@ -25356,8 +25766,8 @@ function formatPlayLogLine(rawLine, status, state) {
25356
25766
  if (!logLevelReaches("info", state.logLevel ?? "info")) {
25357
25767
  return null;
25358
25768
  }
25359
- const [, rows, fields, namespace, cached, pending] = mapStart;
25360
- return `${prefix}map ${sourceLabelForNamespace(namespace)}: ${formatInteger(Number(rows))} rows, ${fields} fields, ${formatInteger(Number(cached))} cached, ${formatInteger(Number(pending))} pending`;
25769
+ const [, rows, fields2, namespace, cached, pending] = mapStart;
25770
+ return `${prefix}map ${sourceLabelForNamespace(namespace)}: ${formatInteger(Number(rows))} rows, ${fields2} fields, ${formatInteger(Number(cached))} cached, ${formatInteger(Number(pending))} pending`;
25361
25771
  }
25362
25772
  const mapDone = message.match(
25363
25773
  /^Map completed: (\d+) results \((\d+) executed, (\d+) already satisfied\)$/
@@ -26411,6 +26821,54 @@ function buildRunActivityTextLines(run) {
26411
26821
  if (observedAt) lines.push(` observed: ${observedAt}`);
26412
26822
  return lines;
26413
26823
  }
26824
+ function formatObservedRunCounter(value) {
26825
+ const counter = readRecord(value);
26826
+ const count = counter?.value;
26827
+ if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) {
26828
+ return "unknown";
26829
+ }
26830
+ return counter?.confirmed === true ? formatInteger(count) : `${formatInteger(count)} observed`;
26831
+ }
26832
+ function buildRunStatusEvidenceTextLines(packaged) {
26833
+ const evidence = readRecord(packaged.runStatus);
26834
+ if (!evidence || evidence.available !== true) return [];
26835
+ const calls = readRecord(evidence.calls);
26836
+ const lines = [];
26837
+ if (calls) {
26838
+ lines.push(
26839
+ ` calls: ${formatObservedRunCounter(calls.logicalCalls)} logical, ${formatObservedRunCounter(calls.toolDispatches)} tool dispatches, ${formatObservedRunCounter(calls.provider429s)} provider 429s`
26840
+ );
26841
+ }
26842
+ const source = readRecord(evidence.source);
26843
+ if (source?.aligned === false) {
26844
+ lines.push(
26845
+ ` consistency: run snapshot event ${String(source.runSnapshotLedgerNextSeq)} and progress event ${String(source.ledgerNextSeq)} differ; retry this read to align them`
26846
+ );
26847
+ }
26848
+ const focus = readRecord(evidence.focusStep);
26849
+ const rows = readRecord(focus?.rows);
26850
+ if (focus) {
26851
+ const id = typeof focus.id === "string" && focus.id.trim() ? focus.id.trim() : "unknown step";
26852
+ const label = typeof focus.label === "string" && focus.label.trim() ? ` (${focus.label.trim()})` : "";
26853
+ const state = typeof focus.status === "string" && focus.status.trim() ? `: ${focus.status.trim()}` : "";
26854
+ const rowCounts = rows ? `; rows ${formatObservedRunCounter({ value: rows.succeeded, confirmed: true })} succeeded, ${formatObservedRunCounter({ value: rows.failed, confirmed: true })} failed, ${formatObservedRunCounter({ value: rows.total, confirmed: true })} total` : "";
26855
+ lines.push(` current step: ${id}${label}${state}${rowCounts}`);
26856
+ }
26857
+ return lines;
26858
+ }
26859
+ function buildRecentRunLogTextLines(packaged) {
26860
+ const logs = readRecord(packaged.logs);
26861
+ const tail = Array.isArray(logs?.tail) ? logs.tail.filter((line) => typeof line === "string") : [];
26862
+ if (tail.length === 0) return [];
26863
+ const visible = tail.slice(-5);
26864
+ const total = typeof logs?.totalCount === "number" && Number.isFinite(logs.totalCount) ? ` of ${formatInteger(logs.totalCount)}` : "";
26865
+ const lines = [` recent logs: showing ${visible.length}${total}`];
26866
+ lines.push(...visible.map((line) => ` ${line}`));
26867
+ if (logs?.truncated === true) {
26868
+ lines.push(" older log lines were truncated by the retention cap");
26869
+ }
26870
+ return lines;
26871
+ }
26414
26872
  function buildRunPackageTextLines(packaged) {
26415
26873
  const run = readRunPackageRun(packaged);
26416
26874
  const runId = typeof run.id === "string" ? run.id : "unknown";
@@ -26480,6 +26938,8 @@ function buildRunPackageTextLines(packaged) {
26480
26938
  if (!isRuntimeLimitCheckpoint) {
26481
26939
  lines.push(...buildRunActivityTextLines(run));
26482
26940
  }
26941
+ lines.push(...buildRunStatusEvidenceTextLines(packaged));
26942
+ lines.push(...buildRecentRunLogTextLines(packaged));
26483
26943
  lines.push(...formatPackageValueOutputLines(packaged));
26484
26944
  lines.push(
26485
26945
  ...formatPackageDatasetActionLines(packaged, {
@@ -26487,12 +26947,7 @@ function buildRunPackageTextLines(packaged) {
26487
26947
  })
26488
26948
  );
26489
26949
  const next = packaged.next && typeof packaged.next === "object" && !Array.isArray(packaged.next) ? packaged.next : {};
26490
- const billingCommand = actionToCommand(next.billing);
26491
26950
  const logsCommand = actionToCommand(next.logs);
26492
- if (billingCommand) {
26493
- const costState = status === "completed" || status === "failed" || status === "cancelled" ? "settles asynchronously \u2014 run the billing command below for totals" : "pending";
26494
- lines.push(` cost: ${costState}`);
26495
- }
26496
26951
  for (const step of isRuntimeLimitCheckpoint ? [] : readRecordArray(packaged.steps).slice(0, 8)) {
26497
26952
  const id = typeof step.id === "string" ? step.id : "step";
26498
26953
  const kind = typeof step.kind === "string" ? step.kind : "step";
@@ -26522,7 +26977,6 @@ function buildRunPackageTextLines(packaged) {
26522
26977
  ` ${isRuntimeTimeout ? "full run details" : "full result"}: ${fullResultCommand}`
26523
26978
  );
26524
26979
  if (logsCommand) lines.push(` logs: ${logsCommand}`);
26525
- if (billingCommand) lines.push(` billing: ${billingCommand}`);
26526
26980
  if (legacyExportCommand) {
26527
26981
  lines.push(` export CSV: ${legacyExportCommand}`);
26528
26982
  }
@@ -28950,11 +29404,23 @@ async function handleRunLifecycleStatus(args) {
28950
29404
  console.log(
28951
29405
  `Map-step work (summed, not unique rows): completed ${formatCount(status.mapStepWork.completed)} / ${formatCount(status.mapStepWork.total)}, failed ${formatCount(status.mapStepWork.failed)}`
28952
29406
  );
29407
+ if (status.activity) {
29408
+ const { activity } = status;
29409
+ const reason = activity.reason ? ` (${activity.reason})` : "";
29410
+ const nextDate = typeof activity.nextAt === "number" ? new Date(activity.nextAt) : null;
29411
+ const next = nextDate && Number.isFinite(nextDate.getTime()) ? `; next at ${nextDate.toISOString()}` : "";
29412
+ console.log(`Activity: ${activity.kind}${reason}${next}`);
29413
+ }
28953
29414
  if (status.lifecycle.status === "waiting") {
28954
29415
  console.log(
28955
29416
  status.wait.confirmed && status.wait.kind ? `Waiting: ${status.wait.kind}` : "Waiting reason: unknown"
28956
29417
  );
28957
29418
  }
29419
+ if (status.calls) {
29420
+ console.log(
29421
+ `Calls: ${formatCount(status.calls.logicalCalls)} logical, ${formatCount(status.calls.providerRequests)} provider requests, ${formatCount(status.calls.provider429s)} provider 429s`
29422
+ );
29423
+ }
28958
29424
  return 0;
28959
29425
  }
28960
29426
  async function handleRunsRerun(args) {
@@ -30105,8 +30571,8 @@ function printPlayDescription(play) {
30105
30571
  }
30106
30572
  }
30107
30573
  function inputFieldNames(schema) {
30108
- const fields = Array.isArray(schema?.fields) ? schema.fields : [];
30109
- return fields.map(
30574
+ const fields2 = Array.isArray(schema?.fields) ? schema.fields : [];
30575
+ return fields2.map(
30110
30576
  (field) => field && typeof field === "object" ? String(field.name ?? "").trim() : ""
30111
30577
  ).filter(Boolean);
30112
30578
  }
@@ -30123,9 +30589,9 @@ function printCompactPlaySearchResult(play) {
30123
30589
  if (aliases) {
30124
30590
  console.log(` Aliases: ${aliases}`);
30125
30591
  }
30126
- const fields = inputFieldNames(play.inputSchema);
30127
- if (fields.length > 0) {
30128
- console.log(` Inputs: ${fields.join(", ")}`);
30592
+ const fields2 = inputFieldNames(play.inputSchema);
30593
+ if (fields2.length > 0) {
30594
+ console.log(` Inputs: ${fields2.join(", ")}`);
30129
30595
  } else if (play.inputSchema) {
30130
30596
  console.log(" Inputs: see describe");
30131
30597
  }
@@ -30134,14 +30600,14 @@ function printCompactPlaySearchResult(play) {
30134
30600
  }
30135
30601
  function compactPlaySchema(schema) {
30136
30602
  if (!schema) return null;
30137
- const fields = Array.isArray(schema.fields) ? schema.fields.map(
30603
+ const fields2 = Array.isArray(schema.fields) ? schema.fields.map(
30138
30604
  (field) => field && typeof field === "object" ? {
30139
30605
  name: String(field.name ?? ""),
30140
30606
  type: field.type ?? void 0,
30141
30607
  required: field.required ?? void 0
30142
30608
  } : null
30143
30609
  ).filter((field) => Boolean(field?.name)) : [];
30144
- return fields.length > 0 ? { fields } : schema;
30610
+ return fields2.length > 0 ? { fields: fields2 } : schema;
30145
30611
  }
30146
30612
  function summarizePlayGrepResult(play) {
30147
30613
  const reference = formatPlayListReference(play);
@@ -30770,6 +31236,8 @@ Concepts:
30770
31236
  Installed npm and repo-local CLIs can run saved/prebuilt plays by name or
30771
31237
  bundle local .play.ts files for development workflows.
30772
31238
  Running a local file does not make it live; use publish or set-live for that.
31239
+ plays settings organizes a Play independently of code revisions.
31240
+ New Plays start at person; publishing moves them to team, preserving folders.
30773
31241
 
30774
31242
  Authoring:
30775
31243
  Use normal TypeScript interpolation for human-facing strings:
@@ -30975,6 +31443,7 @@ Pass-through input flags:
30975
31443
  process.exitCode = exitCode;
30976
31444
  });
30977
31445
  registerPlayBootstrapCommand(play);
31446
+ registerPlaySettingsCommands(play);
30978
31447
  play.command("get <target>").description(
30979
31448
  "Fetch full play details or materialize a saved source bundle."
30980
31449
  ).addHelpText(
@@ -31243,6 +31712,8 @@ Notes:
31243
31712
  plays check to refuse publishing bytes that changed after validation.
31244
31713
  --dry-run bundles only and prints the exact artifact that would be published.
31245
31714
  Running a local file with plays run does not publish it.
31715
+ Publishing moves personal locations into Team library, preserving folders.
31716
+ Change location with: deepline plays settings set --play <play> --name path --value team/Research
31246
31717
 
31247
31718
  Examples:
31248
31719
  deepline plays set-live my-play --latest --json
@@ -31386,7 +31857,10 @@ Examples:
31386
31857
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
31387
31858
  `
31388
31859
  );
31389
- runs.command("status <runId>").description("Read bounded lifecycle and confirmed work counts for a run.").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
31860
+ registerRunHistoryCommand(runs);
31861
+ runs.command("status <runId>").description(
31862
+ "Legacy scalar-only read. Use runs get for canonical status, progress, logs, and results."
31863
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
31390
31864
  process.exitCode = await handleRunLifecycleStatus([
31391
31865
  runId,
31392
31866
  ...options.json ? ["--json"] : []
@@ -34992,9 +35466,9 @@ function readEnrichRunStatus(status) {
34992
35466
  return null;
34993
35467
  }
34994
35468
  function firstCollectedStringField(value, key) {
34995
- const fields = /* @__PURE__ */ new Set();
34996
- collectStringFields(value, key, fields);
34997
- return fields.values().next().value ?? null;
35469
+ const fields2 = /* @__PURE__ */ new Set();
35470
+ collectStringFields(value, key, fields2);
35471
+ return fields2.values().next().value ?? null;
34998
35472
  }
34999
35473
  function emitPlainRunFailure(status) {
35000
35474
  const runId = extractRunId(status) ?? firstCollectedStringField(status, "runId");
@@ -47791,7 +48265,7 @@ function requireCatalogEvent(settings, eventType) {
47791
48265
  }
47792
48266
  return event;
47793
48267
  }
47794
- async function printSettings(options) {
48268
+ async function printSettings2(options) {
47795
48269
  const settings = await new DeeplineClient().getNotificationSettings();
47796
48270
  const slack = slackDestination(settings);
47797
48271
  const destinationId = typeof slack?._id === "string" ? slack._id : void 0;
@@ -47918,7 +48392,7 @@ Slack is the delivery integration. This command group only manages product
47918
48392
  notifications; there is no general integrations CLI.
47919
48393
  `
47920
48394
  );
47921
- notifications.command("get").description("Show destination, subscriptions, and DLQ health.").option("--json", "Emit JSON output").action(printSettings);
48395
+ notifications.command("get").description("Show destination, subscriptions, and DLQ health.").option("--json", "Emit JSON output").action(printSettings2);
47922
48396
  notifications.command("connect").description("Start the OAuth connection required by a destination.").argument("<destination>", "Destination kind (currently slack)").option("--open", "Open the Slack authorization URL in a browser").option("--dry-run", "Describe the mutation without starting OAuth").option("--json", "Emit JSON output").action(
47923
48397
  async (destination, options) => {
47924
48398
  if (destination !== "slack")
@@ -49356,6 +49830,8 @@ async function searchTools(queryInput, options = {}) {
49356
49830
  query,
49357
49831
  categories: options.categories,
49358
49832
  searchTerms: options.searchTerms,
49833
+ limit: options.limit,
49834
+ offset: options.offset,
49359
49835
  searchMode: options.searchMode,
49360
49836
  includeSearchDebug: options.includeSearchDebug
49361
49837
  });
@@ -49586,13 +50062,15 @@ Notes:
49586
50062
  that can be passed to deepline tools describe or deepline tools execute.
49587
50063
  Provide a query, or omit it only when --categories and/or --search_terms is
49588
50064
  supplied. Providing neither is a usage error. Both filters accept
49589
- comma-separated values. Use a provider name in the query; --prefix is not a
49590
- supported option.
50065
+ comma-separated values. Use --limit and --offset to page through ranked
50066
+ results (limit 1-50, offset is zero-based); JSON includes next_offset.
50067
+ Use a provider name in the query; --prefix is not a supported option.
49591
50068
  The grep alias is the same ranked retrieval surface with a more literal name
49592
50069
  for agents that are filtering a registry rather than choosing a workflow.
49593
50070
 
49594
50071
  Examples:
49595
- deepline tools search email
50072
+ deepline tools search email --limit 10 --json
50073
+ deepline tools search email --limit 10 --offset 10 --json
49596
50074
  deepline tools search --categories company_search --search_terms "investors,funding"
49597
50075
  deepline tools grep "company enrichment" --categories enrichment --json
49598
50076
  deepline tools search verifier --search-mode v2 --json
@@ -49603,10 +50081,12 @@ Examples:
49603
50081
  ).option(
49604
50082
  "--search_terms <terms>",
49605
50083
  "Comma-separated structured search terms; may be used without a query"
49606
- ).option("--search-terms <terms>", "Alias for --search_terms").option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
50084
+ ).option("--search-terms <terms>", "Alias for --search_terms").option("--limit <count>", "Maximum ranked results to return (1-50)").option("--offset <count>", "Zero-based ranked result offset").option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
49607
50085
  process.exitCode = await searchTools(query, {
49608
50086
  json: options.json,
49609
50087
  compact: options.compact,
50088
+ limit: options.limit !== void 0 ? Number.parseInt(options.limit, 10) : void 0,
50089
+ offset: options.offset !== void 0 ? Number.parseInt(options.offset, 10) : void 0,
49610
50090
  categories: options.categories,
49611
50091
  searchTerms: options.searchTerms ?? options.search_terms,
49612
50092
  searchMode: options.searchMode === "v1" || options.searchMode === "v2" ? options.searchMode : void 0,
@@ -50009,8 +50489,8 @@ function printMonitorTypeFilters(tool) {
50009
50489
  }
50010
50490
  function printMonitorTypeFilterExamples(tool) {
50011
50491
  const documentation = recordField2(tool, "documentation");
50012
- const fields = recordField2(documentation, "fields");
50013
- const examples = Object.entries(fields).flatMap(([name, rawField]) => {
50492
+ const fields2 = recordField2(documentation, "fields");
50493
+ const examples = Object.entries(fields2).flatMap(([name, rawField]) => {
50014
50494
  const grammar = recordField2(isRecord12(rawField) ? rawField : {}, "grammar");
50015
50495
  const example = stringField2(grammar, "example");
50016
50496
  const values = [
@@ -50365,9 +50845,9 @@ function sampleValueForField(field) {
50365
50845
  if (type === "object") return {};
50366
50846
  return "...";
50367
50847
  }
50368
- function samplePayloadForInputFields(fields) {
50848
+ function samplePayloadForInputFields(fields2) {
50369
50849
  return Object.fromEntries(
50370
- fields.slice(0, 4).flatMap((field) => {
50850
+ fields2.slice(0, 4).flatMap((field) => {
50371
50851
  if (!isRecord12(field)) return [];
50372
50852
  const name = stringField2(field, "name");
50373
50853
  if (!name) return [];
@@ -50498,8 +50978,8 @@ function formatListedToolCost(tool) {
50498
50978
  }
50499
50979
  function toolInputFieldsForDisplay(inputSchema) {
50500
50980
  if (Array.isArray(inputSchema.fields)) {
50501
- const fields = inputSchema.fields.filter(isRecord12);
50502
- if (!isRecord12(inputSchema.jsonSchema)) return fields;
50981
+ const fields2 = inputSchema.fields.filter(isRecord12);
50982
+ if (!isRecord12(inputSchema.jsonSchema)) return fields2;
50503
50983
  const jsonSchemaFields = new Map(
50504
50984
  recursiveToolInputFieldsForDisplay({
50505
50985
  jsonSchema: inputSchema.jsonSchema
@@ -50507,7 +50987,7 @@ function toolInputFieldsForDisplay(inputSchema) {
50507
50987
  (field) => typeof field.name === "string" ? [[field.name, field]] : []
50508
50988
  )
50509
50989
  );
50510
- return fields.map((field) => {
50990
+ return fields2.map((field) => {
50511
50991
  const jsonSchemaField = typeof field.name === "string" ? jsonSchemaFields.get(field.name) : void 0;
50512
50992
  const minItems = typeof field.minItems === "number" ? field.minItems : jsonSchemaField?.minItems;
50513
50993
  const maxItems = typeof field.maxItems === "number" ? field.maxItems : jsonSchemaField?.maxItems;
@@ -50604,7 +51084,7 @@ function publicToolInputSchemaForDescribe(inputSchema) {
50604
51084
  }
50605
51085
  function recursiveToolInputFieldsForDisplay(inputSchema) {
50606
51086
  const root = canonicalToolJsonSchema(inputSchema);
50607
- const fields = /* @__PURE__ */ new Map();
51087
+ const fields2 = /* @__PURE__ */ new Map();
50608
51088
  const schemasById = /* @__PURE__ */ new Map();
50609
51089
  const collectSchemaIds = (value) => {
50610
51090
  if (Array.isArray(value)) {
@@ -50632,9 +51112,9 @@ function recursiveToolInputFieldsForDisplay(inputSchema) {
50632
51112
  const addField = (field) => {
50633
51113
  const name = typeof field.name === "string" ? field.name : "";
50634
51114
  if (!name) return;
50635
- const existing = fields.get(name);
51115
+ const existing = fields2.get(name);
50636
51116
  if (!existing || existing.type === "unknown") {
50637
- fields.set(name, field);
51117
+ fields2.set(name, field);
50638
51118
  }
50639
51119
  };
50640
51120
  const visit = (unresolvedSchema, path, required, activeRefs = /* @__PURE__ */ new Set()) => {
@@ -50682,7 +51162,7 @@ function recursiveToolInputFieldsForDisplay(inputSchema) {
50682
51162
  }
50683
51163
  };
50684
51164
  visit(root, "", false);
50685
- return fields.size ? [...fields.values()] : toolInputFieldsForDisplay(inputSchema);
51165
+ return fields2.size ? [...fields2.values()] : toolInputFieldsForDisplay(inputSchema);
50686
51166
  }
50687
51167
  function inputFieldJsonForDescribe(field) {
50688
51168
  const publicItems = isRecord12(field.items) ? publicToolInputSchemaForDescribe({ items: field.items }).items : void 0;