deepline 0.3.65 → 0.3.66

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.
@@ -199,7 +199,7 @@ export const SDK_RELEASE = {
199
199
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
200
200
  // getters keep their established compatibility behavior.
201
201
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
202
- version: '0.3.65',
202
+ version: '0.3.66',
203
203
  updateSummary:
204
204
  'Automatic CLI updates are now enabled by default. To opt out, run `deepline settings autoupdate off`; use `deepline settings autoupdate on` to re-enable updates or `deepline settings autoupdate pin <version>` to hold an exact release. This release also adds raw-v2 tool responses at toolResponse.rawV2 while preserving existing toolResponse.raw and declared getters.',
205
205
  packageCapabilities: {
@@ -194,6 +194,10 @@ import {
194
194
  type PlayAuthoringRunScope,
195
195
  type PlayAuthoringRuntimeContext,
196
196
  } from '../plays/authoring-contract';
197
+ import {
198
+ formatCtxFetchHttpFailureDiagnostic,
199
+ tagLogProvenance,
200
+ } from './log-provenance';
197
201
  import {
198
202
  DURABLE_RECEIPT_WAIT_DELAY_MS,
199
203
  DURABLE_RECEIPT_WAIT_MAX_ATTEMPTS,
@@ -451,6 +455,10 @@ const DEFAULT_TOOL_RUNTIME_TIMEOUT_MS = 15 * 60 * 1000 + 30_000;
451
455
  const FETCH_TRANSPORT_MAX_ATTEMPTS =
452
456
  RUNTIME_RELIABILITY_POLICY.egress.fetchMaxAttempts;
453
457
  const FETCH_TRANSPORT_RETRY_DELAY_MS = 100;
458
+ // Diagnostic logs are retained in the context until terminalization. Keep a
459
+ // representative, deduplicated set so row-heavy continued failures cannot turn
460
+ // customer-safe observability into unbounded runner memory or log traffic.
461
+ const MAX_CTX_FETCH_HTTP_FAILURE_DIAGNOSTICS = 16;
454
462
  const CTX_FETCH_HEADERS_TIMEOUT_MS =
455
463
  RUNTIME_RELIABILITY_POLICY.egress.fetchHeadersTimeoutMs;
456
464
  const CTX_FETCH_BODY_TIMEOUT_MS =
@@ -2087,6 +2095,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
2087
2095
  #options: ContextOptions;
2088
2096
  private readonly executionScope: RunExecutionScope;
2089
2097
  private logBuffer: string[] = [];
2098
+ private readonly ctxFetchHttpFailureDiagnosticIdentities = new Set<string>();
2090
2099
  private checkpoint: PlayCheckpoint;
2091
2100
  private readonly durableCallCacheEpochMs: number;
2092
2101
  /**
@@ -10160,6 +10169,58 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
10160
10169
  if (this.#options.verbose) console.log(line);
10161
10170
  }
10162
10171
 
10172
+ /**
10173
+ * Emit a runtime-authored diagnostic through the same durable log path as
10174
+ * ctx.log without changing the customer-authored log wire format.
10175
+ */
10176
+ private runtimeDiagnosticLog(message: string): void {
10177
+ assertNoSecretTaint(message, 'runtime diagnostic log');
10178
+ const line = tagLogProvenance(
10179
+ 'diagnostic',
10180
+ `[${new Date().toISOString()}] ${this.secretRedactor.redactRegisteredSecrets(message)}`,
10181
+ );
10182
+ this.logBuffer.push(line);
10183
+ this.#options.onLog?.(line);
10184
+ if (this.#options.verbose) console.log(line);
10185
+ }
10186
+
10187
+ /** A URL safe to persist in a customer-visible run log (origin only). */
10188
+ private ctxFetchDiagnosticUrl(url: string): string {
10189
+ try {
10190
+ const parsed = new URL(url);
10191
+ return parsed.origin;
10192
+ } catch {
10193
+ // ctx.fetch already parses its URL before this helper is reachable.
10194
+ return '[invalid-url]';
10195
+ }
10196
+ }
10197
+
10198
+ private logCtxFetchHttpFailure(input: {
10199
+ key: string;
10200
+ method: string;
10201
+ url: string;
10202
+ httpStatus: number;
10203
+ }): void {
10204
+ const url = this.ctxFetchDiagnosticUrl(input.url);
10205
+ const identity = `${input.key}\u0000${input.method}\u0000${url}\u0000${input.httpStatus}`;
10206
+ if (
10207
+ this.ctxFetchHttpFailureDiagnosticIdentities.has(identity) ||
10208
+ this.ctxFetchHttpFailureDiagnosticIdentities.size >=
10209
+ MAX_CTX_FETCH_HTTP_FAILURE_DIAGNOSTICS
10210
+ ) {
10211
+ return;
10212
+ }
10213
+ this.ctxFetchHttpFailureDiagnosticIdentities.add(identity);
10214
+ this.runtimeDiagnosticLog(
10215
+ formatCtxFetchHttpFailureDiagnostic({
10216
+ key: input.key,
10217
+ method: input.method,
10218
+ url,
10219
+ http_status: input.httpStatus,
10220
+ }),
10221
+ );
10222
+ }
10223
+
10163
10224
  async sleep(ms: number): Promise<void> {
10164
10225
  this.assertInlineChildContract('suspending_child');
10165
10226
  const delayMs =
@@ -10212,6 +10273,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
10212
10273
 
10213
10274
  const url = input.toString();
10214
10275
  const parsedUrl = new URL(url);
10276
+ const method = (init.method ?? 'GET').toUpperCase();
10215
10277
  const urlContainsResolvedSecret =
10216
10278
  this.secretRedactor.containsRegisteredSecret(url, {
10217
10279
  includeEncoded: true,
@@ -10303,6 +10365,14 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
10303
10365
  staleAfterSeconds: options?.staleAfterSeconds,
10304
10366
  transient: options?.transient === true,
10305
10367
  onRecovered: (output) => {
10368
+ if (!output.ok) {
10369
+ this.logCtxFetchHttpFailure({
10370
+ key: normalizedKey,
10371
+ method,
10372
+ url: output.url || url,
10373
+ httpStatus: output.status,
10374
+ });
10375
+ }
10306
10376
  if (!output.ok && this.currentAuthoringContractEdition >= 5) {
10307
10377
  throw new CtxFetchHttpError(output);
10308
10378
  }
@@ -10314,7 +10384,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
10314
10384
  this.currentAuthoringContractEdition >= 5
10315
10385
  ),
10316
10386
  execute: async ({ retainExternalCallSlot }) => {
10317
- const method = (init.method ?? 'GET').toUpperCase();
10318
10387
  const secretHeaders = await this.resolveSecretAuth(secretAuth);
10319
10388
  const headers: Record<string, string> = {
10320
10389
  ...normalizeFetchHeaders(init.headers),
@@ -10349,6 +10418,15 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
10349
10418
  'output' in existing
10350
10419
  ) {
10351
10420
  this.log(`ctx.fetch(${url}): recovered response from checkpoint`);
10421
+ const checkpointOutput = existing.output as PlayFetchResponse;
10422
+ if (!checkpointOutput.ok) {
10423
+ this.logCtxFetchHttpFailure({
10424
+ key: normalizedKey,
10425
+ method,
10426
+ url: checkpointOutput.url || url,
10427
+ httpStatus: checkpointOutput.status,
10428
+ });
10429
+ }
10352
10430
  if (this.durableDirectToolResultsBackedByReceipts) {
10353
10431
  // The outer durable receipt is the replay authority in hosted
10354
10432
  // runtimes. A legacy checkpoint fetch may seed that receipt
@@ -10356,7 +10434,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
10356
10434
  // cache for the lifetime of a large map.
10357
10435
  delete this.checkpoint.resolvedBoundaries?.[boundaryId];
10358
10436
  }
10359
- return existing.output as PlayFetchResponse;
10437
+ return checkpointOutput;
10360
10438
  }
10361
10439
 
10362
10440
  if (!['GET', 'HEAD', 'OPTIONS'].includes(method)) {
@@ -10496,6 +10574,15 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
10496
10574
  json: this.secretRedactor.redactKnownSecrets(rawJson),
10497
10575
  };
10498
10576
 
10577
+ if (!output.ok) {
10578
+ this.logCtxFetchHttpFailure({
10579
+ key: normalizedKey,
10580
+ method,
10581
+ url: output.url || url,
10582
+ httpStatus: output.status,
10583
+ });
10584
+ }
10585
+
10499
10586
  // Edition 5 adopts normal fetch semantics: a non-2xx response is
10500
10587
  // a failed durable operation. Throw before checkpoint/receipt
10501
10588
  // completion so the failure is never cached. Editions 1–4 retain
@@ -125,6 +125,85 @@ export function tagLogProvenance(
125
125
  return `${PROVENANCE_PREFIX}${provenance}${PROVENANCE_SENTINEL}${line}`;
126
126
  }
127
127
 
128
+ /**
129
+ * A customer-safe record of a `ctx.fetch` response that reached the server but
130
+ * was not successful. Its URL is destination-origin-only; it deliberately
131
+ * omits paths, query strings, request/response bodies, headers, receipt ids,
132
+ * and row identity: all of those can contain customer data or credentials.
133
+ * This one stable shape is shared by the
134
+ * runtime (emission), finalization (terminal warning), and CLI/tests
135
+ * (inspection), rather than each layer trying to infer an HTTP failure from
136
+ * arbitrary user logs.
137
+ */
138
+ export type CtxFetchHttpFailureDiagnostic = {
139
+ key: string;
140
+ method: string;
141
+ url: string;
142
+ http_status: number;
143
+ };
144
+
145
+ /** Guard terminal-transport diagnostics before they reach customer surfaces. */
146
+ export function isCtxFetchHttpFailureDiagnostic(
147
+ value: unknown,
148
+ ): value is CtxFetchHttpFailureDiagnostic {
149
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
150
+ return false;
151
+ }
152
+ const record = value as Record<string, unknown>;
153
+ return (
154
+ typeof record.key === 'string' &&
155
+ typeof record.method === 'string' &&
156
+ typeof record.url === 'string' &&
157
+ typeof record.http_status === 'number' &&
158
+ Number.isInteger(record.http_status)
159
+ );
160
+ }
161
+
162
+ export const CTX_FETCH_HTTP_FAILURE_LOG_PREFIX =
163
+ '[runtime.ctx_fetch_http_failure]';
164
+
165
+ /** Format the canonical durable log line for an observed non-2xx ctx.fetch. */
166
+ export function formatCtxFetchHttpFailureDiagnostic(
167
+ diagnostic: CtxFetchHttpFailureDiagnostic,
168
+ ): string {
169
+ return `${CTX_FETCH_HTTP_FAILURE_LOG_PREFIX} ${JSON.stringify(diagnostic)}`;
170
+ }
171
+
172
+ /**
173
+ * Parse only runtime-authored, canonical ctx.fetch diagnostics. Untagged
174
+ * legacy/user lines are never interpreted as evidence, even if they happen to
175
+ * contain the same words.
176
+ */
177
+ export function parseCtxFetchHttpFailureDiagnostic(
178
+ rawLine: string,
179
+ ): CtxFetchHttpFailureDiagnostic | null {
180
+ const tagged = readProvenanceTag(rawLine);
181
+ if (tagged.provenance !== 'diagnostic') return null;
182
+ const index = tagged.line.indexOf(CTX_FETCH_HTTP_FAILURE_LOG_PREFIX);
183
+ if (index === -1) return null;
184
+ const json = tagged.line
185
+ .slice(index + CTX_FETCH_HTTP_FAILURE_LOG_PREFIX.length)
186
+ .trim();
187
+ try {
188
+ const parsed: unknown = JSON.parse(json);
189
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
190
+ return null;
191
+ }
192
+ const record = parsed as Record<string, unknown>;
193
+ if (!isCtxFetchHttpFailureDiagnostic(record)) {
194
+ return null;
195
+ }
196
+ return {
197
+ key: record.key,
198
+ method: record.method,
199
+ url: record.url,
200
+ http_status: record.http_status,
201
+ };
202
+ } catch {
203
+ return null;
204
+ }
205
+ }
206
+
128
207
  /**
129
208
  * Read a structural provenance tag off a line, if present, and return the tag
130
209
  * plus the original untagged line. Returns `null` provenance when untagged.
@@ -141,9 +220,7 @@ export function readProvenanceTag(line: string): {
141
220
  return { provenance: null, line };
142
221
  }
143
222
  const candidate = line.slice(PROVENANCE_PREFIX.length, end);
144
- const provenance = LOG_PROVENANCE_CLASSES.includes(
145
- candidate as LogProvenance,
146
- )
223
+ const provenance = LOG_PROVENANCE_CLASSES.includes(candidate as LogProvenance)
147
224
  ? (candidate as LogProvenance)
148
225
  : null;
149
226
  return { provenance, line: line.slice(end + 1) };
@@ -17,6 +17,7 @@ import type { PlayRunFailureDetails } from './run-failure';
17
17
  import type { ToolExecutionErrorSchemaVersion } from '../plays/tool-execution-error';
18
18
  import type { ToolResponseContract } from '../plays/tool-response-contract';
19
19
  import type { FixtureBehavior } from './fixture-behavior';
20
+ import type { CtxFetchHttpFailureDiagnostic } from './log-provenance';
20
21
 
21
22
  export type PlayRunnerRateStateBackendConfig =
22
23
  | {
@@ -307,6 +308,8 @@ export type PlayRunnerResult =
307
308
  status: 'completed';
308
309
  output: unknown;
309
310
  outputWarnings?: PlayRunOutputWarning[];
311
+ /** Customer-safe runtime observations that must survive bounded log tails. */
312
+ runtimeDiagnostics?: CtxFetchHttpFailureDiagnostic[];
310
313
  outputRowCount?: number;
311
314
  logs: string[];
312
315
  stats: Record<string, unknown>;
package/dist/cli/index.js CHANGED
@@ -1214,7 +1214,7 @@ var SDK_RELEASE = {
1214
1214
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1215
1215
  // getters keep their established compatibility behavior.
1216
1216
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
1217
- version: "0.3.65",
1217
+ version: "0.3.66",
1218
1218
  updateSummary: "Automatic CLI updates are now enabled by default. To opt out, run `deepline settings autoupdate off`; use `deepline settings autoupdate on` to re-enable updates or `deepline settings autoupdate pin <version>` to hold an exact release. This release also adds raw-v2 tool responses at toolResponse.rawV2 while preserving existing toolResponse.raw and declared getters.",
1219
1219
  packageCapabilities: {
1220
1220
  updatePreferences: 1
@@ -16758,9 +16758,7 @@ function readProvenanceTag(line) {
16758
16758
  return { provenance: null, line };
16759
16759
  }
16760
16760
  const candidate = line.slice(PROVENANCE_PREFIX.length, end);
16761
- const provenance = LOG_PROVENANCE_CLASSES.includes(
16762
- candidate
16763
- ) ? candidate : null;
16761
+ const provenance = LOG_PROVENANCE_CLASSES.includes(candidate) ? candidate : null;
16764
16762
  return { provenance, line: line.slice(end + 1) };
16765
16763
  }
16766
16764
  function classifyLegacyLogLine(line) {
@@ -17094,12 +17092,16 @@ var PLAY_RUN_RESERVED_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
17094
17092
  "--watch",
17095
17093
  "--no-wait",
17096
17094
  "--logs",
17095
+ "--debug",
17097
17096
  "--full",
17098
17097
  "--force",
17099
17098
  "--force-tool-refresh",
17100
17099
  "--open",
17101
17100
  "--debug-map-latency"
17102
17101
  ]);
17102
+ function isBarePlayRunDebugFlag(args, index) {
17103
+ return args[index] === "--debug" && (args[index + 1] === void 0 || args[index + 1].startsWith("--"));
17104
+ }
17103
17105
  async function pathExistsIncludingSymlink(path) {
17104
17106
  try {
17105
17107
  await (0, import_promises6.lstat)(path);
@@ -21057,12 +21059,13 @@ function parsePlayRunOptions(args) {
21057
21059
  const watch = !args.includes("--no-wait");
21058
21060
  let jsonOutput = watch ? args.includes("--json") : argsWantJson(args);
21059
21061
  const fullJson = args.includes("--full");
21060
- const emitLogs = !jsonOutput || args.includes("--logs");
21062
+ const explicitDebugLogs = args.includes("--logs") || args.some((_, index) => isBarePlayRunDebugFlag(args, index));
21063
+ const emitLogs = !jsonOutput || explicitDebugLogs;
21061
21064
  const force = args.includes("--force");
21062
21065
  const forceToolRefresh = args.includes("--force-tool-refresh");
21063
21066
  const open2 = args.includes("--open");
21064
21067
  const debugMapLatency = args.includes("--debug-map-latency");
21065
- const verboseLogs = args.includes("--logs") || debugMapLatency;
21068
+ const verboseLogs = explicitDebugLogs || debugMapLatency;
21066
21069
  let waitTimeoutMs = null;
21067
21070
  let maxConcurrentExternalCalls = null;
21068
21071
  let maxConcurrentRows = null;
@@ -21193,6 +21196,20 @@ function parsePlayRunOptions(args) {
21193
21196
  waitTimeoutMs = parsePositiveInteger3(args[++index], arg);
21194
21197
  continue;
21195
21198
  }
21199
+ if (arg === "--debug" && args[index + 1] && !args[index + 1].startsWith("--")) {
21200
+ input2 ??= {};
21201
+ setDottedInputValue(input2, "debug", parseInputFlagValue(args[++index]));
21202
+ continue;
21203
+ }
21204
+ if (arg.startsWith("--debug=")) {
21205
+ input2 ??= {};
21206
+ setDottedInputValue(
21207
+ input2,
21208
+ "debug",
21209
+ parseInputFlagValue(arg.slice("--debug=".length))
21210
+ );
21211
+ continue;
21212
+ }
21196
21213
  if (PLAY_RUN_RESERVED_BOOLEAN_FLAGS.has(arg)) {
21197
21214
  if (arg === "--watch") {
21198
21215
  continue;
@@ -22451,7 +22468,7 @@ async function handlePlayRun(args, hooks) {
22451
22468
  function parseRunIdPositional(args, usage) {
22452
22469
  for (let index = 0; index < args.length; index += 1) {
22453
22470
  const arg = args[index];
22454
- if (arg === "--json" || arg === "--full" || arg === "--input" || arg === "--logs" || arg === "--compact" || arg === "--log-failed" || arg === "--failed" || arg === "--limit") {
22471
+ if (arg === "--json" || arg === "--full" || arg === "--input" || arg === "--logs" || arg === "--debug" || arg === "--compact" || arg === "--log-failed" || arg === "--failed" || arg === "--limit") {
22455
22472
  if (arg === "--limit" && args[index + 1]) {
22456
22473
  index += 1;
22457
22474
  }
@@ -22599,7 +22616,7 @@ async function handleRunsList(args) {
22599
22616
  return 0;
22600
22617
  }
22601
22618
  async function handleRunTail(args) {
22602
- const usage = "Usage: deepline runs tail <run-id> [--json | --jsonl] [--compact]";
22619
+ const usage = "Usage: deepline runs tail <run-id> [--json | --jsonl] [--compact] [--debug]";
22603
22620
  let runId;
22604
22621
  try {
22605
22622
  runId = parseRunIdPositional(args, usage);
@@ -22615,7 +22632,7 @@ async function handleRunTail(args) {
22615
22632
  );
22616
22633
  return 1;
22617
22634
  }
22618
- if (arg.startsWith("--") && arg !== "--json" && arg !== "--jsonl" && arg !== "--compact") {
22635
+ if (arg.startsWith("--") && arg !== "--json" && arg !== "--jsonl" && arg !== "--compact" && arg !== "--logs" && arg !== "--debug") {
22619
22636
  console.error(`${arg} is not supported by deepline runs tail.`);
22620
22637
  return 1;
22621
22638
  }
@@ -22624,6 +22641,13 @@ async function handleRunTail(args) {
22624
22641
  console.error("--json and --jsonl cannot be used together.");
22625
22642
  return 1;
22626
22643
  }
22644
+ const debug = args.includes("--logs") || args.includes("--debug");
22645
+ if (args.includes("--jsonl") && debug) {
22646
+ console.error(
22647
+ "--debug is redundant with --jsonl: JSON Lines already includes every canonical live event."
22648
+ );
22649
+ return 1;
22650
+ }
22627
22651
  const client2 = new DeeplineClient();
22628
22652
  const jsonLines = args.includes("--jsonl");
22629
22653
  const jsonOutput = !jsonLines && argsWantJson(args);
@@ -22633,7 +22657,8 @@ async function handleRunTail(args) {
22633
22657
  emittedRunnerStarted: false,
22634
22658
  lastProgressSignature: null,
22635
22659
  lastProgressHeartbeatAt: 0,
22636
- lastStatusHeartbeatAt: 0
22660
+ lastStatusHeartbeatAt: 0,
22661
+ verbose: debug
22637
22662
  };
22638
22663
  const status = await client2.runs.tail(runId, {
22639
22664
  onEvent: jsonLines ? (event) => {
@@ -22645,7 +22670,20 @@ async function handleRunTail(args) {
22645
22670
  })}
22646
22671
  `
22647
22672
  );
22648
- } : compact && !jsonOutput ? (event) => {
22673
+ } : compact || debug ? (event) => {
22674
+ if (debug) {
22675
+ for (const line of getLogLinesFromLiveEvent(event)) {
22676
+ const formatted = formatPlayLogLine(
22677
+ line,
22678
+ void 0,
22679
+ compactState
22680
+ );
22681
+ if (formatted) process.stderr.write(`${formatted}
22682
+ `);
22683
+ compactState.lastLogIndex += 1;
22684
+ }
22685
+ }
22686
+ if (!compact || jsonOutput) return;
22649
22687
  const transition = getStepTransitionLineFromLiveEvent(
22650
22688
  event,
22651
22689
  compactState
@@ -22668,7 +22706,7 @@ async function handleRunTail(args) {
22668
22706
  }
22669
22707
  } : void 0,
22670
22708
  // Human mode only: in --json mode emit nothing non-protocol.
22671
- onReconnect: jsonOutput ? void 0 : ({ reason }) => {
22709
+ onReconnect: jsonOutput && !debug ? void 0 : ({ reason }) => {
22672
22710
  process.stderr.write(
22673
22711
  `[runs tail] stream ended without a terminal status; reconnecting to run ${runId} (${reason})
22674
22712
  `
@@ -22684,7 +22722,7 @@ async function handleRunTail(args) {
22684
22722
  return status.status === "failed" ? 1 : 0;
22685
22723
  }
22686
22724
  async function handleRunLogs(args) {
22687
- const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--failed] [--out run.log] [--json]";
22725
+ const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--failed] [--out run.log] [--json] [--debug]";
22688
22726
  let runId;
22689
22727
  try {
22690
22728
  runId = parseRunIdPositional(args, usage);
@@ -22697,12 +22735,20 @@ async function handleRunLogs(args) {
22697
22735
  const failed = args.includes("--failed");
22698
22736
  for (let index = 0; index < args.length; index += 1) {
22699
22737
  const arg = args[index];
22738
+ if (arg === "--debug" || arg === "--logs" || arg === "--json" || arg === "--failed") {
22739
+ continue;
22740
+ }
22700
22741
  if (arg === "--limit" && args[index + 1]) {
22701
22742
  limit = parsePositiveInteger3(args[++index], "--limit");
22702
22743
  continue;
22703
22744
  }
22704
22745
  if (arg === "--out" && args[index + 1]) {
22705
22746
  outPath = (0, import_node_path14.resolve)(args[++index]);
22747
+ continue;
22748
+ }
22749
+ if (arg.startsWith("--")) {
22750
+ console.error(`${arg} is not supported by deepline runs logs.`);
22751
+ return 1;
22706
22752
  }
22707
22753
  }
22708
22754
  if (failed && outPath) {
@@ -24175,9 +24221,9 @@ Examples:
24175
24221
  ).option("--watch", "Compatibility alias; run waits by default").option("--wait", "Compatibility alias; run waits by default").option("--no-wait", "Start the run and return immediately").option(
24176
24222
  "--run-id-file <path>",
24177
24223
  "Atomically write the accepted run id to a new JSON file"
24178
- ).option(
24179
- "--logs",
24180
- "When output is non-interactive, stream play logs to stderr while waiting"
24224
+ ).option("--logs", "Compatibility alias for --debug").option(
24225
+ "--debug [value]",
24226
+ "Stream complete customer-safe runtime logs when passed without a value; otherwise pass input.debug"
24181
24227
  ).option("--tail-timeout-ms <ms>", "Timeout while watching the run stream").option("--force", "Start a fresh run graph").option(
24182
24228
  "--force-tool-refresh",
24183
24229
  "Refresh completed tool receipts; may repeat billed provider calls"
@@ -24226,6 +24272,7 @@ Pass-through input flags:
24226
24272
  ...options.runIdFile ? ["--run-id-file", options.runIdFile] : [],
24227
24273
  ...options.watch || options.wait ? ["--watch"] : [],
24228
24274
  ...options.logs ? ["--logs"] : [],
24275
+ ...options.debug === true ? ["--debug"] : typeof options.debug === "string" ? ["--debug", options.debug] : [],
24229
24276
  ...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
24230
24277
  ...options.force ? ["--force"] : [],
24231
24278
  ...options.forceToolRefresh ? ["--force-tool-refresh"] : [],
@@ -24643,11 +24690,13 @@ Notes:
24643
24690
  logs for persisted log history. In human output, --compact prints deduplicated
24644
24691
  step transitions and progress instead of the full event stream. --json emits
24645
24692
  one terminal package. --jsonl emits canonical live events as JSON Lines and
24646
- ends with the same compact package shape as runs get --json.
24693
+ ends with the same compact package shape as runs get --json. Use --debug
24694
+ (or legacy --logs) to also print customer-safe runtime log lines to stderr.
24647
24695
 
24648
24696
  Examples:
24649
24697
  deepline runs tail play/my-play/run/20260501t000000-000
24650
24698
  deepline runs tail play/my-play/run/20260501t000000-000 --compact
24699
+ deepline runs tail play/my-play/run/20260501t000000-000 --debug
24651
24700
  deepline runs tail play/my-play/run/20260501t000000-000 --jsonl
24652
24701
  `
24653
24702
  ).option("--json", "Emit one terminal JSON package after the run completes").option(
@@ -24656,12 +24705,17 @@ Examples:
24656
24705
  ).option(
24657
24706
  "--compact",
24658
24707
  "Show deduplicated human step transitions and progress"
24708
+ ).option("--logs", "Compatibility alias for --debug").option(
24709
+ "--debug",
24710
+ "Print customer-safe runtime log lines to stderr while tailing"
24659
24711
  ).action(async (runId, options) => {
24660
24712
  process.exitCode = await handleRunTail([
24661
24713
  runId,
24662
24714
  ...options.json ? ["--json"] : [],
24663
24715
  ...options.jsonl ? ["--jsonl"] : [],
24664
- ...options.compact ? ["--compact"] : []
24716
+ ...options.compact ? ["--compact"] : [],
24717
+ ...options.logs ? ["--logs"] : [],
24718
+ ...options.debug ? ["--debug"] : []
24665
24719
  ]);
24666
24720
  });
24667
24721
  runs.command("logs <runId>").description("Fetch persisted logs for a play run.").addHelpText(
@@ -24669,24 +24723,31 @@ Examples:
24669
24723
  `
24670
24724
  Notes:
24671
24725
  Prints a bounded recent log preview by default. Use --out to write the full
24672
- persisted log stream to a local file.
24726
+ persisted log stream to a local file. --debug (or legacy --logs) is accepted
24727
+ for script parity; this command already returns the unfiltered durable stream.
24673
24728
 
24674
24729
  Examples:
24675
24730
  deepline runs logs play/my-play/run/20260501t000000-000
24676
24731
  deepline runs logs play/my-play/run/20260501t000000-000 --limit 500
24677
24732
  deepline runs logs play/my-play/run/20260501t000000-000 --failed --json
24733
+ deepline runs logs play/my-play/run/20260501t000000-000 --debug
24678
24734
  deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
24679
24735
  `
24680
24736
  ).option(
24681
24737
  "--limit <count>",
24682
24738
  "Maximum recent log lines to print without --out",
24683
24739
  "200"
24684
- ).option("--out <path>", "Write the full persisted log stream to a file").option("--failed", "Show the bounded terminal-failure log window").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
24740
+ ).option("--out <path>", "Write the full persisted log stream to a file").option("--failed", "Show the bounded terminal-failure log window").option("--logs", "Compatibility alias for --debug").option(
24741
+ "--debug",
24742
+ "Explicitly request the same persisted log view (no provenance filtering)"
24743
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
24685
24744
  process.exitCode = await handleRunLogs([
24686
24745
  runId,
24687
24746
  ...options.limit ? ["--limit", options.limit] : [],
24688
24747
  ...options.out ? ["--out", options.out] : [],
24689
24748
  ...options.failed ? ["--failed"] : [],
24749
+ ...options.logs ? ["--logs"] : [],
24750
+ ...options.debug ? ["--debug"] : [],
24690
24751
  ...options.json ? ["--json"] : []
24691
24752
  ]);
24692
24753
  });
@@ -1199,7 +1199,7 @@ var SDK_RELEASE = {
1199
1199
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1200
1200
  // getters keep their established compatibility behavior.
1201
1201
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
1202
- version: "0.3.65",
1202
+ version: "0.3.66",
1203
1203
  updateSummary: "Automatic CLI updates are now enabled by default. To opt out, run `deepline settings autoupdate off`; use `deepline settings autoupdate on` to re-enable updates or `deepline settings autoupdate pin <version>` to hold an exact release. This release also adds raw-v2 tool responses at toolResponse.rawV2 while preserving existing toolResponse.raw and declared getters.",
1204
1204
  packageCapabilities: {
1205
1205
  updatePreferences: 1
@@ -16820,9 +16820,7 @@ function readProvenanceTag(line) {
16820
16820
  return { provenance: null, line };
16821
16821
  }
16822
16822
  const candidate = line.slice(PROVENANCE_PREFIX.length, end);
16823
- const provenance = LOG_PROVENANCE_CLASSES.includes(
16824
- candidate
16825
- ) ? candidate : null;
16823
+ const provenance = LOG_PROVENANCE_CLASSES.includes(candidate) ? candidate : null;
16826
16824
  return { provenance, line: line.slice(end + 1) };
16827
16825
  }
16828
16826
  function classifyLegacyLogLine(line) {
@@ -17156,12 +17154,16 @@ var PLAY_RUN_RESERVED_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
17156
17154
  "--watch",
17157
17155
  "--no-wait",
17158
17156
  "--logs",
17157
+ "--debug",
17159
17158
  "--full",
17160
17159
  "--force",
17161
17160
  "--force-tool-refresh",
17162
17161
  "--open",
17163
17162
  "--debug-map-latency"
17164
17163
  ]);
17164
+ function isBarePlayRunDebugFlag(args, index) {
17165
+ return args[index] === "--debug" && (args[index + 1] === void 0 || args[index + 1].startsWith("--"));
17166
+ }
17165
17167
  async function pathExistsIncludingSymlink(path) {
17166
17168
  try {
17167
17169
  await lstat(path);
@@ -21119,12 +21121,13 @@ function parsePlayRunOptions(args) {
21119
21121
  const watch = !args.includes("--no-wait");
21120
21122
  let jsonOutput = watch ? args.includes("--json") : argsWantJson(args);
21121
21123
  const fullJson = args.includes("--full");
21122
- const emitLogs = !jsonOutput || args.includes("--logs");
21124
+ const explicitDebugLogs = args.includes("--logs") || args.some((_, index) => isBarePlayRunDebugFlag(args, index));
21125
+ const emitLogs = !jsonOutput || explicitDebugLogs;
21123
21126
  const force = args.includes("--force");
21124
21127
  const forceToolRefresh = args.includes("--force-tool-refresh");
21125
21128
  const open2 = args.includes("--open");
21126
21129
  const debugMapLatency = args.includes("--debug-map-latency");
21127
- const verboseLogs = args.includes("--logs") || debugMapLatency;
21130
+ const verboseLogs = explicitDebugLogs || debugMapLatency;
21128
21131
  let waitTimeoutMs = null;
21129
21132
  let maxConcurrentExternalCalls = null;
21130
21133
  let maxConcurrentRows = null;
@@ -21255,6 +21258,20 @@ function parsePlayRunOptions(args) {
21255
21258
  waitTimeoutMs = parsePositiveInteger3(args[++index], arg);
21256
21259
  continue;
21257
21260
  }
21261
+ if (arg === "--debug" && args[index + 1] && !args[index + 1].startsWith("--")) {
21262
+ input2 ??= {};
21263
+ setDottedInputValue(input2, "debug", parseInputFlagValue(args[++index]));
21264
+ continue;
21265
+ }
21266
+ if (arg.startsWith("--debug=")) {
21267
+ input2 ??= {};
21268
+ setDottedInputValue(
21269
+ input2,
21270
+ "debug",
21271
+ parseInputFlagValue(arg.slice("--debug=".length))
21272
+ );
21273
+ continue;
21274
+ }
21258
21275
  if (PLAY_RUN_RESERVED_BOOLEAN_FLAGS.has(arg)) {
21259
21276
  if (arg === "--watch") {
21260
21277
  continue;
@@ -22513,7 +22530,7 @@ async function handlePlayRun(args, hooks) {
22513
22530
  function parseRunIdPositional(args, usage) {
22514
22531
  for (let index = 0; index < args.length; index += 1) {
22515
22532
  const arg = args[index];
22516
- if (arg === "--json" || arg === "--full" || arg === "--input" || arg === "--logs" || arg === "--compact" || arg === "--log-failed" || arg === "--failed" || arg === "--limit") {
22533
+ if (arg === "--json" || arg === "--full" || arg === "--input" || arg === "--logs" || arg === "--debug" || arg === "--compact" || arg === "--log-failed" || arg === "--failed" || arg === "--limit") {
22517
22534
  if (arg === "--limit" && args[index + 1]) {
22518
22535
  index += 1;
22519
22536
  }
@@ -22661,7 +22678,7 @@ async function handleRunsList(args) {
22661
22678
  return 0;
22662
22679
  }
22663
22680
  async function handleRunTail(args) {
22664
- const usage = "Usage: deepline runs tail <run-id> [--json | --jsonl] [--compact]";
22681
+ const usage = "Usage: deepline runs tail <run-id> [--json | --jsonl] [--compact] [--debug]";
22665
22682
  let runId;
22666
22683
  try {
22667
22684
  runId = parseRunIdPositional(args, usage);
@@ -22677,7 +22694,7 @@ async function handleRunTail(args) {
22677
22694
  );
22678
22695
  return 1;
22679
22696
  }
22680
- if (arg.startsWith("--") && arg !== "--json" && arg !== "--jsonl" && arg !== "--compact") {
22697
+ if (arg.startsWith("--") && arg !== "--json" && arg !== "--jsonl" && arg !== "--compact" && arg !== "--logs" && arg !== "--debug") {
22681
22698
  console.error(`${arg} is not supported by deepline runs tail.`);
22682
22699
  return 1;
22683
22700
  }
@@ -22686,6 +22703,13 @@ async function handleRunTail(args) {
22686
22703
  console.error("--json and --jsonl cannot be used together.");
22687
22704
  return 1;
22688
22705
  }
22706
+ const debug = args.includes("--logs") || args.includes("--debug");
22707
+ if (args.includes("--jsonl") && debug) {
22708
+ console.error(
22709
+ "--debug is redundant with --jsonl: JSON Lines already includes every canonical live event."
22710
+ );
22711
+ return 1;
22712
+ }
22689
22713
  const client2 = new DeeplineClient();
22690
22714
  const jsonLines = args.includes("--jsonl");
22691
22715
  const jsonOutput = !jsonLines && argsWantJson(args);
@@ -22695,7 +22719,8 @@ async function handleRunTail(args) {
22695
22719
  emittedRunnerStarted: false,
22696
22720
  lastProgressSignature: null,
22697
22721
  lastProgressHeartbeatAt: 0,
22698
- lastStatusHeartbeatAt: 0
22722
+ lastStatusHeartbeatAt: 0,
22723
+ verbose: debug
22699
22724
  };
22700
22725
  const status = await client2.runs.tail(runId, {
22701
22726
  onEvent: jsonLines ? (event) => {
@@ -22707,7 +22732,20 @@ async function handleRunTail(args) {
22707
22732
  })}
22708
22733
  `
22709
22734
  );
22710
- } : compact && !jsonOutput ? (event) => {
22735
+ } : compact || debug ? (event) => {
22736
+ if (debug) {
22737
+ for (const line of getLogLinesFromLiveEvent(event)) {
22738
+ const formatted = formatPlayLogLine(
22739
+ line,
22740
+ void 0,
22741
+ compactState
22742
+ );
22743
+ if (formatted) process.stderr.write(`${formatted}
22744
+ `);
22745
+ compactState.lastLogIndex += 1;
22746
+ }
22747
+ }
22748
+ if (!compact || jsonOutput) return;
22711
22749
  const transition = getStepTransitionLineFromLiveEvent(
22712
22750
  event,
22713
22751
  compactState
@@ -22730,7 +22768,7 @@ async function handleRunTail(args) {
22730
22768
  }
22731
22769
  } : void 0,
22732
22770
  // Human mode only: in --json mode emit nothing non-protocol.
22733
- onReconnect: jsonOutput ? void 0 : ({ reason }) => {
22771
+ onReconnect: jsonOutput && !debug ? void 0 : ({ reason }) => {
22734
22772
  process.stderr.write(
22735
22773
  `[runs tail] stream ended without a terminal status; reconnecting to run ${runId} (${reason})
22736
22774
  `
@@ -22746,7 +22784,7 @@ async function handleRunTail(args) {
22746
22784
  return status.status === "failed" ? 1 : 0;
22747
22785
  }
22748
22786
  async function handleRunLogs(args) {
22749
- const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--failed] [--out run.log] [--json]";
22787
+ const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--failed] [--out run.log] [--json] [--debug]";
22750
22788
  let runId;
22751
22789
  try {
22752
22790
  runId = parseRunIdPositional(args, usage);
@@ -22759,12 +22797,20 @@ async function handleRunLogs(args) {
22759
22797
  const failed = args.includes("--failed");
22760
22798
  for (let index = 0; index < args.length; index += 1) {
22761
22799
  const arg = args[index];
22800
+ if (arg === "--debug" || arg === "--logs" || arg === "--json" || arg === "--failed") {
22801
+ continue;
22802
+ }
22762
22803
  if (arg === "--limit" && args[index + 1]) {
22763
22804
  limit = parsePositiveInteger3(args[++index], "--limit");
22764
22805
  continue;
22765
22806
  }
22766
22807
  if (arg === "--out" && args[index + 1]) {
22767
22808
  outPath = resolve11(args[++index]);
22809
+ continue;
22810
+ }
22811
+ if (arg.startsWith("--")) {
22812
+ console.error(`${arg} is not supported by deepline runs logs.`);
22813
+ return 1;
22768
22814
  }
22769
22815
  }
22770
22816
  if (failed && outPath) {
@@ -24237,9 +24283,9 @@ Examples:
24237
24283
  ).option("--watch", "Compatibility alias; run waits by default").option("--wait", "Compatibility alias; run waits by default").option("--no-wait", "Start the run and return immediately").option(
24238
24284
  "--run-id-file <path>",
24239
24285
  "Atomically write the accepted run id to a new JSON file"
24240
- ).option(
24241
- "--logs",
24242
- "When output is non-interactive, stream play logs to stderr while waiting"
24286
+ ).option("--logs", "Compatibility alias for --debug").option(
24287
+ "--debug [value]",
24288
+ "Stream complete customer-safe runtime logs when passed without a value; otherwise pass input.debug"
24243
24289
  ).option("--tail-timeout-ms <ms>", "Timeout while watching the run stream").option("--force", "Start a fresh run graph").option(
24244
24290
  "--force-tool-refresh",
24245
24291
  "Refresh completed tool receipts; may repeat billed provider calls"
@@ -24288,6 +24334,7 @@ Pass-through input flags:
24288
24334
  ...options.runIdFile ? ["--run-id-file", options.runIdFile] : [],
24289
24335
  ...options.watch || options.wait ? ["--watch"] : [],
24290
24336
  ...options.logs ? ["--logs"] : [],
24337
+ ...options.debug === true ? ["--debug"] : typeof options.debug === "string" ? ["--debug", options.debug] : [],
24291
24338
  ...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
24292
24339
  ...options.force ? ["--force"] : [],
24293
24340
  ...options.forceToolRefresh ? ["--force-tool-refresh"] : [],
@@ -24705,11 +24752,13 @@ Notes:
24705
24752
  logs for persisted log history. In human output, --compact prints deduplicated
24706
24753
  step transitions and progress instead of the full event stream. --json emits
24707
24754
  one terminal package. --jsonl emits canonical live events as JSON Lines and
24708
- ends with the same compact package shape as runs get --json.
24755
+ ends with the same compact package shape as runs get --json. Use --debug
24756
+ (or legacy --logs) to also print customer-safe runtime log lines to stderr.
24709
24757
 
24710
24758
  Examples:
24711
24759
  deepline runs tail play/my-play/run/20260501t000000-000
24712
24760
  deepline runs tail play/my-play/run/20260501t000000-000 --compact
24761
+ deepline runs tail play/my-play/run/20260501t000000-000 --debug
24713
24762
  deepline runs tail play/my-play/run/20260501t000000-000 --jsonl
24714
24763
  `
24715
24764
  ).option("--json", "Emit one terminal JSON package after the run completes").option(
@@ -24718,12 +24767,17 @@ Examples:
24718
24767
  ).option(
24719
24768
  "--compact",
24720
24769
  "Show deduplicated human step transitions and progress"
24770
+ ).option("--logs", "Compatibility alias for --debug").option(
24771
+ "--debug",
24772
+ "Print customer-safe runtime log lines to stderr while tailing"
24721
24773
  ).action(async (runId, options) => {
24722
24774
  process.exitCode = await handleRunTail([
24723
24775
  runId,
24724
24776
  ...options.json ? ["--json"] : [],
24725
24777
  ...options.jsonl ? ["--jsonl"] : [],
24726
- ...options.compact ? ["--compact"] : []
24778
+ ...options.compact ? ["--compact"] : [],
24779
+ ...options.logs ? ["--logs"] : [],
24780
+ ...options.debug ? ["--debug"] : []
24727
24781
  ]);
24728
24782
  });
24729
24783
  runs.command("logs <runId>").description("Fetch persisted logs for a play run.").addHelpText(
@@ -24731,24 +24785,31 @@ Examples:
24731
24785
  `
24732
24786
  Notes:
24733
24787
  Prints a bounded recent log preview by default. Use --out to write the full
24734
- persisted log stream to a local file.
24788
+ persisted log stream to a local file. --debug (or legacy --logs) is accepted
24789
+ for script parity; this command already returns the unfiltered durable stream.
24735
24790
 
24736
24791
  Examples:
24737
24792
  deepline runs logs play/my-play/run/20260501t000000-000
24738
24793
  deepline runs logs play/my-play/run/20260501t000000-000 --limit 500
24739
24794
  deepline runs logs play/my-play/run/20260501t000000-000 --failed --json
24795
+ deepline runs logs play/my-play/run/20260501t000000-000 --debug
24740
24796
  deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
24741
24797
  `
24742
24798
  ).option(
24743
24799
  "--limit <count>",
24744
24800
  "Maximum recent log lines to print without --out",
24745
24801
  "200"
24746
- ).option("--out <path>", "Write the full persisted log stream to a file").option("--failed", "Show the bounded terminal-failure log window").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
24802
+ ).option("--out <path>", "Write the full persisted log stream to a file").option("--failed", "Show the bounded terminal-failure log window").option("--logs", "Compatibility alias for --debug").option(
24803
+ "--debug",
24804
+ "Explicitly request the same persisted log view (no provenance filtering)"
24805
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
24747
24806
  process.exitCode = await handleRunLogs([
24748
24807
  runId,
24749
24808
  ...options.limit ? ["--limit", options.limit] : [],
24750
24809
  ...options.out ? ["--out", options.out] : [],
24751
24810
  ...options.failed ? ["--failed"] : [],
24811
+ ...options.logs ? ["--logs"] : [],
24812
+ ...options.debug ? ["--debug"] : [],
24752
24813
  ...options.json ? ["--json"] : []
24753
24814
  ]);
24754
24815
  });
package/dist/index.js CHANGED
@@ -832,7 +832,7 @@ var SDK_RELEASE = {
832
832
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
833
833
  // getters keep their established compatibility behavior.
834
834
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
835
- version: "0.3.65",
835
+ version: "0.3.66",
836
836
  updateSummary: "Automatic CLI updates are now enabled by default. To opt out, run `deepline settings autoupdate off`; use `deepline settings autoupdate on` to re-enable updates or `deepline settings autoupdate pin <version>` to hold an exact release. This release also adds raw-v2 tool responses at toolResponse.rawV2 while preserving existing toolResponse.raw and declared getters.",
837
837
  packageCapabilities: {
838
838
  updatePreferences: 1
package/dist/index.mjs CHANGED
@@ -744,7 +744,7 @@ var SDK_RELEASE = {
744
744
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
745
745
  // getters keep their established compatibility behavior.
746
746
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
747
- version: "0.3.65",
747
+ version: "0.3.66",
748
748
  updateSummary: "Automatic CLI updates are now enabled by default. To opt out, run `deepline settings autoupdate off`; use `deepline settings autoupdate on` to re-enable updates or `deepline settings autoupdate pin <version>` to hold an exact release. This release also adds raw-v2 tool responses at toolResponse.rawV2 while preserving existing toolResponse.raw and declared getters.",
749
749
  packageCapabilities: {
750
750
  updatePreferences: 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.3.65",
3
+ "version": "0.3.66",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",