deepline 0.3.210 → 0.3.211

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
200
200
  // getters keep their established compatibility behavior.
201
201
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
202
202
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
203
- version: '0.3.210',
203
+ version: '0.3.211',
204
204
  updateSummary:
205
205
  'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
206
206
  packageCapabilities: {
@@ -42,6 +42,7 @@ import type {
42
42
  import {
43
43
  buildDaytonaRuntimeWatchdogSource,
44
44
  PLAY_RUNNER_UV_THREADPOOL_SIZE,
45
+ RUNNER_MEMORY_CGROUP_ROOT,
45
46
  RUNTIME_SANDBOX_MEMORY_ABORT_REASON,
46
47
  } from './daytona-runtime-watchdog';
47
48
 
@@ -72,6 +73,9 @@ export type StagedDaytonaPayload = {
72
73
  command: string;
73
74
  outputPath: string;
74
75
  exitCodePath: string;
76
+ oomKillBaselinePath: string;
77
+ runnerPidPath: string;
78
+ runtimeStartedPath: string;
75
79
  runtimeCompletedPath: string;
76
80
  terminationDiagnosticPath: string;
77
81
  progressEventPath: string;
@@ -656,6 +660,7 @@ export async function stageRunnerPayload(input: {
656
660
  const crashPusherLogPath = `${workDir}/deepline-play-crash-terminal-${randomUUID()}.log`;
657
661
  const exitCodePath = `${workDir}/deepline-play-exit-${randomUUID()}.txt`;
658
662
  const oomKillBaselinePath = `${workDir}/deepline-play-oom-kill-${randomUUID()}.txt`;
663
+ const runnerPidPath = `${workDir}/deepline-play-runner-pid-${randomUUID()}.txt`;
659
664
  const runtimeStartedPath = `${workDir}/deepline-play-runtime-started-${randomUUID()}.json`;
660
665
  const runtimeCompletedPath = `${workDir}/deepline-play-runtime-completed-${randomUUID()}.json`;
661
666
  const runtimeLimitMarkerPath = `${workDir}/deepline-play-runtime-limit-${randomUUID()}.txt`;
@@ -691,6 +696,8 @@ export async function stageRunnerPayload(input: {
691
696
  shellQuote(terminationDiagnosticPath),
692
697
  shellQuote(memoryLedgerPath),
693
698
  shellQuote(memoryPressurePath),
699
+ shellQuote(RUNNER_MEMORY_CGROUP_ROOT),
700
+ shellQuote(runnerPidPath),
694
701
  ].join(' ');
695
702
  const runnerCommand = `${nodeMaterializePayloadCommand({
696
703
  envelopePath,
@@ -708,13 +715,16 @@ export async function stageRunnerPayload(input: {
708
715
  // Its own retry diagnostics are kept in a separate log: appending them to
709
716
  // `outputPath` after a near-gateway-sized result could hide that result from
710
717
  // a later bounded-tail recovery read.
711
- const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(crashPusherLogPath)} ${shellQuote(exitCodePath)} ${shellQuote(oomKillBaselinePath)} ${shellQuote(runtimeStartedPath)} ${shellQuote(runtimeCompletedPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(terminationDiagnosticPath)} ${shellQuote(memoryLedgerPath)} ${shellQuote(`${memoryLedgerPath}.tmp`)} ${shellQuote(memoryPressurePath)} ${shellQuote(progressEventPath)} ${shellQuote(`${progressEventPath}.*`)} ${shellQuote(startupDiagnosticPath)}; ( awk '$1 == "oom_kill" { print $2 }' /sys/fs/cgroup/memory.events 2>/dev/null || true ) > ${shellQuote(oomKillBaselinePath)}; ( ${runnerCommand} ) > ${shellQuote(outputPath)} 2>&1; code=$?; printf '%s' "$code" > ${shellQuote(exitCodePath)}; ${runtimeReliabilityEnv}node ${shellQuote(crashPusherPath)} ${shellQuote(configPath)} "$code" ${shellQuote(outputPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(oomKillBaselinePath)} /sys/fs/cgroup/memory.events ${shellQuote(terminationDiagnosticPath)} > ${shellQuote(crashPusherLogPath)} 2>&1 || true; printf 'deepline runner output captured: %s\\n' ${shellQuote(outputPath)}; exit "$code"`;
718
+ const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(crashPusherLogPath)} ${shellQuote(exitCodePath)} ${shellQuote(oomKillBaselinePath)} ${shellQuote(runnerPidPath)} ${shellQuote(runtimeStartedPath)} ${shellQuote(runtimeCompletedPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(terminationDiagnosticPath)} ${shellQuote(memoryLedgerPath)} ${shellQuote(`${memoryLedgerPath}.tmp`)} ${shellQuote(memoryPressurePath)} ${shellQuote(progressEventPath)} ${shellQuote(`${progressEventPath}.*`)} ${shellQuote(startupDiagnosticPath)}; ( awk '$1 == "oom_kill" { print $2 }' /sys/fs/cgroup/memory.events 2>/dev/null || true ) > ${shellQuote(oomKillBaselinePath)}; ( ${runnerCommand} ) > ${shellQuote(outputPath)} 2>&1; code=$?; printf '%s' "$code" > ${shellQuote(exitCodePath)}; ${runtimeReliabilityEnv}node ${shellQuote(crashPusherPath)} ${shellQuote(configPath)} "$code" ${shellQuote(outputPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(oomKillBaselinePath)} /sys/fs/cgroup/memory.events ${shellQuote(terminationDiagnosticPath)} > ${shellQuote(crashPusherLogPath)} 2>&1 || true; printf 'deepline runner output captured: %s\\n' ${shellQuote(outputPath)}; exit "$code"`;
712
719
 
713
720
  return {
714
721
  workDir: input.workDir,
715
722
  command,
716
723
  outputPath,
717
724
  exitCodePath,
725
+ oomKillBaselinePath,
726
+ runnerPidPath,
727
+ runtimeStartedPath,
718
728
  runtimeCompletedPath,
719
729
  terminationDiagnosticPath,
720
730
  progressEventPath,
@@ -126,7 +126,7 @@ export const RUNTIME_SANDBOX_MEMORY_ABORT_REASON =
126
126
  * 1 runnerPath, 2 configPath, 3 runtimeStartedPath, 4 runtimeCompletedPath,
127
127
  * 5 limitMs, 6 startupLimitMs, 7 terminalGraceMs, 8 runtimeLimitMarkerPath,
128
128
  * 9 terminationDiagnosticPath, 10 memoryLedgerPath, 11 memoryPressurePath,
129
- * 12 cgroupRoot.
129
+ * 12 cgroupRoot, 13 runnerPidPath.
130
130
  */
131
131
  export function buildDaytonaRuntimeWatchdogSource(): string {
132
132
  return `
@@ -144,6 +144,7 @@ const terminationDiagnosticPath = process.argv[9] || '';
144
144
  const memoryLedgerPath = process.argv[10] || '';
145
145
  const memoryPressurePath = process.argv[11] || '';
146
146
  const cgroupRoot = process.argv[12] || ${JSON.stringify(RUNNER_MEMORY_CGROUP_ROOT)};
147
+ const runnerPidPath = process.argv[13] || '';
147
148
  const runtimeLimitSeconds = Math.max(1, Math.ceil(limitMs / 1_000));
148
149
  const child = spawn(
149
150
  process.execPath,
@@ -161,6 +162,21 @@ const child = spawn(
161
162
  stdio: 'inherit',
162
163
  },
163
164
  );
165
+ if (runnerPidPath && Number.isSafeInteger(child.pid)) {
166
+ try {
167
+ const rawStat = fs.readFileSync('/proc/' + child.pid + '/stat', 'utf8');
168
+ const close = rawStat.lastIndexOf(')');
169
+ const fields = close >= 0 ? rawStat.slice(close + 1).trim().split(/\\s+/) : [];
170
+ const startTimeTicks = Number.parseInt(fields[19], 10);
171
+ if (Number.isSafeInteger(startTimeTicks) && startTimeTicks >= 0) {
172
+ fs.writeFileSync(
173
+ runnerPidPath,
174
+ JSON.stringify({ pid: child.pid, startTimeTicks }),
175
+ { flag: 'wx' },
176
+ );
177
+ }
178
+ } catch {}
179
+ }
164
180
  let timedOut = false;
165
181
  let startupTimedOut = false;
166
182
  let terminalFlushTimedOut = false;
@@ -46,6 +46,7 @@ import {
46
46
  } from './daytona-session-execution';
47
47
  import { RUNTIME_RELIABILITY_POLICY } from '../../runtime-reliability-policy';
48
48
  import { daytonaSandboxStartAdmission } from './daytona-start-admission';
49
+ import { RUNNER_MEMORY_CGROUP_ROOT } from './daytona-runtime-watchdog';
49
50
 
50
51
  const DAYTONA_COMMAND_RECOVERY_TIMEOUT_MS =
51
52
  RUNTIME_RELIABILITY_POLICY.sandbox.daytonaCommandRecoveryTimeoutMs;
@@ -94,13 +95,37 @@ export type DaytonaCrashDiagnostic = {
94
95
  exitCodeFile: number | null;
95
96
  sessionExitCode: number | null;
96
97
  outputBytes: number | null;
98
+ outputFileAvailable?: boolean | null;
99
+ exitCodeFileAvailable?: boolean | null;
100
+ terminationFileAvailable?: boolean | null;
101
+ runtimeStarted?: boolean | null;
102
+ runtimeCompleted?: boolean | null;
97
103
  tailBytes: number;
98
104
  tailTruncated: boolean;
99
105
  signals: string[];
100
106
  unclassifiedLineCount: number;
101
107
  termination: DaytonaTerminationDiagnostic | null;
108
+ resourceSnapshot?: DaytonaCrashResourceSnapshot | null;
102
109
  collectionFailure: DaytonaLookupFailure | null;
103
110
  };
111
+ export type DaytonaCrashResourceSnapshot = {
112
+ memorySource: 'cgroup_v1' | 'cgroup_v1_nested' | 'cgroup_v2' | null;
113
+ memoryUsageBytes: number | null;
114
+ memoryLimitBytes: number | null;
115
+ memoryUsageRatio: number | null;
116
+ memoryOomCount: number | null;
117
+ memoryOomKillCount: number | null;
118
+ memoryOomKillDelta: number | null;
119
+ memoryOomGroupKillCount: number | null;
120
+ memoryHighCount: number | null;
121
+ memoryMaxCount: number | null;
122
+ cgroupCpuUsageUsecDelta: number | null;
123
+ cgroupCpuSampleWindowMs: number | null;
124
+ runnerPresent: boolean | null;
125
+ runnerState: string | null;
126
+ runnerRssPages: number | null;
127
+ runnerCpuTicksDelta: number | null;
128
+ };
104
129
  export type DaytonaTerminationDiagnostic = {
105
130
  schemaVersion: 1;
106
131
  reason:
@@ -185,6 +210,56 @@ function parseDaytonaTerminationDiagnostic(
185
210
  }
186
211
  return diagnostic;
187
212
  }
213
+
214
+ export function parseDaytonaCrashResourceSnapshot(
215
+ value: unknown,
216
+ ): DaytonaCrashResourceSnapshot | null {
217
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
218
+ const candidate = value as Record<string, unknown>;
219
+ const nonNegativeNumber = (key: string): number | null => {
220
+ const value = candidate[key];
221
+ return typeof value === 'number' &&
222
+ Number.isSafeInteger(value) &&
223
+ value >= 0
224
+ ? value
225
+ : null;
226
+ };
227
+ const ratio = candidate.memoryUsageRatio;
228
+ const source = candidate.memorySource;
229
+ return {
230
+ memorySource:
231
+ source === 'cgroup_v1' ||
232
+ source === 'cgroup_v1_nested' ||
233
+ source === 'cgroup_v2'
234
+ ? source
235
+ : null,
236
+ memoryUsageBytes: nonNegativeNumber('memoryUsageBytes'),
237
+ memoryLimitBytes: nonNegativeNumber('memoryLimitBytes'),
238
+ memoryUsageRatio:
239
+ typeof ratio === 'number' && Number.isFinite(ratio) && ratio >= 0
240
+ ? ratio
241
+ : null,
242
+ memoryOomCount: nonNegativeNumber('memoryOomCount'),
243
+ memoryOomKillCount: nonNegativeNumber('memoryOomKillCount'),
244
+ memoryOomKillDelta: nonNegativeNumber('memoryOomKillDelta'),
245
+ memoryOomGroupKillCount: nonNegativeNumber('memoryOomGroupKillCount'),
246
+ memoryHighCount: nonNegativeNumber('memoryHighCount'),
247
+ memoryMaxCount: nonNegativeNumber('memoryMaxCount'),
248
+ cgroupCpuUsageUsecDelta: nonNegativeNumber('cgroupCpuUsageUsecDelta'),
249
+ cgroupCpuSampleWindowMs: nonNegativeNumber('cgroupCpuSampleWindowMs'),
250
+ runnerPresent:
251
+ typeof candidate.runnerPresent === 'boolean'
252
+ ? candidate.runnerPresent
253
+ : null,
254
+ runnerState:
255
+ typeof candidate.runnerState === 'string' &&
256
+ /^[A-Za-z]$/.test(candidate.runnerState)
257
+ ? candidate.runnerState
258
+ : null,
259
+ runnerRssPages: nonNegativeNumber('runnerRssPages'),
260
+ runnerCpuTicksDelta: nonNegativeNumber('runnerCpuTicksDelta'),
261
+ };
262
+ }
188
263
  type DaytonaUploadAttemptTiming = {
189
264
  attempt: number;
190
265
  sandboxId: string;
@@ -368,6 +443,189 @@ export function extractDaytonaCrashDiagnosticSignals(outputTail: string): {
368
443
  return { signals, unclassifiedLineCount };
369
444
  }
370
445
 
446
+ export function buildDaytonaCrashDiagnosticSnapshotSource(): string {
447
+ return String.raw`
448
+ const fs = require('node:fs');
449
+ (async () => {
450
+ const output = process.argv[1];
451
+ const exit = process.argv[2];
452
+ const max = Number(process.argv[3]);
453
+ const terminationPath = process.argv[4] || '';
454
+ const startedPath = process.argv[5] || '';
455
+ const completedPath = process.argv[6] || '';
456
+ const pidPath = process.argv[7] || '';
457
+ const oomBaselinePath = process.argv[8] || '';
458
+ const cgroupRoot = process.argv[9] || '/sys/fs/cgroup';
459
+ const read = (path) => {
460
+ try { return fs.readFileSync(path, 'utf8'); } catch { return null; }
461
+ };
462
+ const exists = (path) => {
463
+ try { return fs.statSync(path).isFile(); } catch { return false; }
464
+ };
465
+ let outputStat = null;
466
+ try { outputStat = fs.statSync(output); } catch {}
467
+ let tail = Buffer.alloc(0);
468
+ if (outputStat) {
469
+ try {
470
+ const start = Math.max(0, outputStat.size - max);
471
+ const fd = fs.openSync(output, 'r');
472
+ tail = Buffer.alloc(outputStat.size - start);
473
+ fs.readSync(fd, tail, 0, tail.length, start);
474
+ fs.closeSync(fd);
475
+ } catch {}
476
+ }
477
+ const exitRaw = read(exit);
478
+ let exitCode = null;
479
+ if (exitRaw !== null) {
480
+ const value = Number.parseInt(exitRaw.trim(), 10);
481
+ if (Number.isFinite(value)) exitCode = value;
482
+ }
483
+ let termination = null;
484
+ try {
485
+ const value = JSON.parse(read(terminationPath) || 'null');
486
+ if (value && typeof value === 'object') termination = value;
487
+ } catch {}
488
+ const memoryPaths = [
489
+ ['cgroup_v2', cgroupRoot + '/memory.current', cgroupRoot + '/memory.max'],
490
+ ['cgroup_v1', cgroupRoot + '/memory.usage_in_bytes', cgroupRoot + '/memory.limit_in_bytes'],
491
+ ['cgroup_v1_nested', cgroupRoot + '/memory/memory.usage_in_bytes', cgroupRoot + '/memory/memory.limit_in_bytes'],
492
+ ];
493
+ const readNumber = (path) => {
494
+ const raw = read(path);
495
+ if (raw === null || !raw.trim() || raw.trim() === 'max') return null;
496
+ const value = Number.parseInt(raw.trim(), 10);
497
+ return Number.isSafeInteger(value) && value >= 0 ? value : null;
498
+ };
499
+ const readMemory = () => {
500
+ for (const [source, usagePath, limitPath] of memoryPaths) {
501
+ const usage = readNumber(usagePath);
502
+ const limit = readNumber(limitPath);
503
+ if (usage !== null && limit !== null && limit > 0 && limit < 2 ** 50) {
504
+ return {
505
+ memorySource: source,
506
+ memoryUsageBytes: usage,
507
+ memoryLimitBytes: limit,
508
+ memoryUsageRatio: usage / limit,
509
+ };
510
+ }
511
+ }
512
+ return {
513
+ memorySource: null,
514
+ memoryUsageBytes: null,
515
+ memoryLimitBytes: null,
516
+ memoryUsageRatio: null,
517
+ };
518
+ };
519
+ const readEvents = () => {
520
+ const result = {};
521
+ for (const line of (read(cgroupRoot + '/memory.events') || '').split(/\r?\n/)) {
522
+ const match = line.match(/^(oom|oom_kill|oom_group_kill|high|max)\s+(\d+)$/);
523
+ if (match) result[match[1]] = Number.parseInt(match[2], 10);
524
+ }
525
+ return result;
526
+ };
527
+ const readCpu = () => {
528
+ const line = (read(cgroupRoot + '/cpu.stat') || '')
529
+ .split(/\r?\n/)
530
+ .find((entry) => /^usage_usec\s+\d+$/.test(entry));
531
+ return line ? Number.parseInt(line.split(/\s+/)[1], 10) : null;
532
+ };
533
+ const readRunner = () => {
534
+ let identity = null;
535
+ try { identity = JSON.parse(read(pidPath) || 'null'); } catch {}
536
+ const pid = identity && identity.pid;
537
+ const expectedStartTimeTicks = identity && identity.startTimeTicks;
538
+ if (
539
+ !Number.isSafeInteger(pid) ||
540
+ pid < 1 ||
541
+ !Number.isSafeInteger(expectedStartTimeTicks) ||
542
+ expectedStartTimeTicks < 0
543
+ ) return null;
544
+ const rawStat = read('/proc/' + pid + '/stat');
545
+ if (rawStat === null) return { present: false };
546
+ const close = rawStat.lastIndexOf(')');
547
+ if (close < 0) return { present: true };
548
+ const fields = rawStat.slice(close + 1).trim().split(/\s+/);
549
+ const startTimeTicks = Number.parseInt(fields[19], 10);
550
+ if (startTimeTicks !== expectedStartTimeTicks) return null;
551
+ const userTicks = Number.parseInt(fields[11], 10);
552
+ const systemTicks = Number.parseInt(fields[12], 10);
553
+ const rssRaw = (read('/proc/' + pid + '/statm') || '').trim().split(/\s+/)[1];
554
+ const rssPages = Number.parseInt(rssRaw || '', 10);
555
+ return {
556
+ present: true,
557
+ state: fields[0] || null,
558
+ cpuTicks:
559
+ Number.isFinite(userTicks) && Number.isFinite(systemTicks)
560
+ ? userTicks + systemTicks
561
+ : null,
562
+ rssPages: Number.isSafeInteger(rssPages) && rssPages >= 0 ? rssPages : null,
563
+ };
564
+ };
565
+ const beforeCpu = readCpu();
566
+ const beforeRunner = readRunner();
567
+ const sampleStarted = Date.now();
568
+ await new Promise((resolve) => setTimeout(resolve, 200));
569
+ const afterCpu = readCpu();
570
+ const afterRunner = readRunner();
571
+ const sampleWindowMs = Date.now() - sampleStarted;
572
+ const events = readEvents();
573
+ const baseline = readNumber(oomBaselinePath);
574
+ const resourceSnapshot = {
575
+ ...readMemory(),
576
+ memoryOomCount: Number.isSafeInteger(events.oom) ? events.oom : null,
577
+ memoryOomKillCount: Number.isSafeInteger(events.oom_kill) ? events.oom_kill : null,
578
+ memoryOomKillDelta:
579
+ Number.isSafeInteger(events.oom_kill) &&
580
+ baseline !== null &&
581
+ events.oom_kill >= baseline
582
+ ? events.oom_kill - baseline
583
+ : null,
584
+ memoryOomGroupKillCount:
585
+ Number.isSafeInteger(events.oom_group_kill) ? events.oom_group_kill : null,
586
+ memoryHighCount: Number.isSafeInteger(events.high) ? events.high : null,
587
+ memoryMaxCount: Number.isSafeInteger(events.max) ? events.max : null,
588
+ cgroupCpuUsageUsecDelta:
589
+ Number.isSafeInteger(beforeCpu) &&
590
+ Number.isSafeInteger(afterCpu) &&
591
+ afterCpu >= beforeCpu
592
+ ? afterCpu - beforeCpu
593
+ : null,
594
+ cgroupCpuSampleWindowMs: sampleWindowMs,
595
+ runnerPresent: afterRunner ? afterRunner.present : null,
596
+ runnerState:
597
+ afterRunner && typeof afterRunner.state === 'string'
598
+ ? afterRunner.state
599
+ : null,
600
+ runnerRssPages:
601
+ afterRunner && Number.isSafeInteger(afterRunner.rssPages)
602
+ ? afterRunner.rssPages
603
+ : null,
604
+ runnerCpuTicksDelta:
605
+ beforeRunner &&
606
+ afterRunner &&
607
+ Number.isSafeInteger(beforeRunner.cpuTicks) &&
608
+ Number.isSafeInteger(afterRunner.cpuTicks) &&
609
+ afterRunner.cpuTicks >= beforeRunner.cpuTicks
610
+ ? afterRunner.cpuTicks - beforeRunner.cpuTicks
611
+ : null,
612
+ };
613
+ process.stdout.write(JSON.stringify({
614
+ outputBytes: outputStat ? outputStat.size : null,
615
+ outputFileAvailable: Boolean(outputStat),
616
+ exitCodeFileAvailable: exitRaw !== null,
617
+ tail: tail.toString('base64'),
618
+ exitCode,
619
+ terminationFileAvailable: exists(terminationPath),
620
+ termination,
621
+ runtimeStarted: exists(startedPath),
622
+ runtimeCompleted: exists(completedPath),
623
+ resourceSnapshot,
624
+ }));
625
+ })().catch(() => { process.exitCode = 1; });
626
+ `;
627
+ }
628
+
371
629
  /**
372
630
  * Read bounded crash evidence while the failed sandbox still exists. This is
373
631
  * operator telemetry only: it never becomes a run result or customer log.
@@ -378,6 +636,10 @@ export async function readDetachedDaytonaCrashDiagnostic(input: {
378
636
  cmdId: string;
379
637
  outputPath: string;
380
638
  exitCodePath: string;
639
+ oomKillBaselinePath?: string;
640
+ runnerPidPath?: string;
641
+ runtimeStartedPath?: string;
642
+ runtimeCompletedPath?: string;
381
643
  terminationDiagnosticPath?: string;
382
644
  expectedOrganizationId?: string | null;
383
645
  }): Promise<DaytonaCrashDiagnostic> {
@@ -389,11 +651,17 @@ export async function readDetachedDaytonaCrashDiagnostic(input: {
389
651
  exitCodeFile: null,
390
652
  sessionExitCode: null,
391
653
  outputBytes: null,
654
+ outputFileAvailable: null,
655
+ exitCodeFileAvailable: null,
656
+ terminationFileAvailable: null,
657
+ runtimeStarted: null,
658
+ runtimeCompleted: null,
392
659
  tailBytes: 0,
393
660
  tailTruncated: false,
394
661
  signals: [],
395
662
  unclassifiedLineCount: 0,
396
663
  termination: null,
664
+ resourceSnapshot: null,
397
665
  collectionFailure,
398
666
  });
399
667
  try {
@@ -419,10 +687,10 @@ export async function readDetachedDaytonaCrashDiagnostic(input: {
419
687
  };
420
688
  }
421
689
 
422
- const script = `const fs=require('node:fs');const output=process.argv[1];const exit=process.argv[2];const max=Number(process.argv[3]);const terminationPath=process.argv[4]||'';const stat=fs.statSync(output);const start=Math.max(0,stat.size-max);const fd=fs.openSync(output,'r');const tail=Buffer.alloc(stat.size-start);fs.readSync(fd,tail,0,tail.length,start);fs.closeSync(fd);let exitCode=null;try{const value=Number.parseInt(fs.readFileSync(exit,'utf8').trim(),10);if(Number.isFinite(value))exitCode=value}catch{}let termination=null;try{const value=JSON.parse(fs.readFileSync(terminationPath,'utf8'));if(value&&typeof value==='object')termination=value}catch{}process.stdout.write(JSON.stringify({outputBytes:stat.size,tail:tail.toString('base64'),exitCode,termination}));`;
690
+ const script = buildDaytonaCrashDiagnosticSnapshotSource();
423
691
  const [snapshotResult, sessionResult] = await Promise.allSettled([
424
692
  sandbox.process.executeCommand(
425
- `node -e ${shellQuoteDaytonaDiagnostic(script)} ${shellQuoteDaytonaDiagnostic(input.outputPath)} ${shellQuoteDaytonaDiagnostic(input.exitCodePath)} ${DAYTONA_CRASH_DIAGNOSTIC_TAIL_MAX_BYTES} ${shellQuoteDaytonaDiagnostic(input.terminationDiagnosticPath ?? '')}`,
693
+ `node -e ${shellQuoteDaytonaDiagnostic(script)} ${shellQuoteDaytonaDiagnostic(input.outputPath)} ${shellQuoteDaytonaDiagnostic(input.exitCodePath)} ${DAYTONA_CRASH_DIAGNOSTIC_TAIL_MAX_BYTES} ${shellQuoteDaytonaDiagnostic(input.terminationDiagnosticPath ?? '')} ${shellQuoteDaytonaDiagnostic(input.runtimeStartedPath ?? '')} ${shellQuoteDaytonaDiagnostic(input.runtimeCompletedPath ?? '')} ${shellQuoteDaytonaDiagnostic(input.runnerPidPath ?? '')} ${shellQuoteDaytonaDiagnostic(input.oomKillBaselinePath ?? '')} ${shellQuoteDaytonaDiagnostic(RUNNER_MEMORY_CGROUP_ROOT)}`,
426
694
  undefined,
427
695
  {},
428
696
  8,
@@ -434,9 +702,15 @@ export async function readDetachedDaytonaCrashDiagnostic(input: {
434
702
  }
435
703
  const snapshot = JSON.parse(snapshotResult.value.result) as {
436
704
  outputBytes?: unknown;
705
+ outputFileAvailable?: unknown;
706
+ exitCodeFileAvailable?: unknown;
707
+ terminationFileAvailable?: unknown;
708
+ runtimeStarted?: unknown;
709
+ runtimeCompleted?: unknown;
437
710
  tail?: unknown;
438
711
  exitCode?: unknown;
439
712
  termination?: unknown;
713
+ resourceSnapshot?: unknown;
440
714
  };
441
715
  const tailBuffer =
442
716
  typeof snapshot.tail === 'string'
@@ -456,6 +730,9 @@ export async function readDetachedDaytonaCrashDiagnostic(input: {
456
730
  ? sessionResult.value.exitCode
457
731
  : null;
458
732
  const termination = parseDaytonaTerminationDiagnostic(snapshot.termination);
733
+ const resourceSnapshot = parseDaytonaCrashResourceSnapshot(
734
+ snapshot.resourceSnapshot,
735
+ );
459
736
  return {
460
737
  schemaVersion: 1,
461
738
  collectionStatus: 'collected',
@@ -466,6 +743,26 @@ export async function readDetachedDaytonaCrashDiagnostic(input: {
466
743
  : null,
467
744
  sessionExitCode,
468
745
  outputBytes,
746
+ outputFileAvailable:
747
+ typeof snapshot.outputFileAvailable === 'boolean'
748
+ ? snapshot.outputFileAvailable
749
+ : null,
750
+ exitCodeFileAvailable:
751
+ typeof snapshot.exitCodeFileAvailable === 'boolean'
752
+ ? snapshot.exitCodeFileAvailable
753
+ : null,
754
+ terminationFileAvailable:
755
+ typeof snapshot.terminationFileAvailable === 'boolean'
756
+ ? snapshot.terminationFileAvailable
757
+ : null,
758
+ runtimeStarted:
759
+ typeof snapshot.runtimeStarted === 'boolean'
760
+ ? snapshot.runtimeStarted
761
+ : null,
762
+ runtimeCompleted:
763
+ typeof snapshot.runtimeCompleted === 'boolean'
764
+ ? snapshot.runtimeCompleted
765
+ : null,
469
766
  tailBytes: tailBuffer.byteLength,
470
767
  tailTruncated:
471
768
  outputBytes !== null &&
@@ -473,6 +770,7 @@ export async function readDetachedDaytonaCrashDiagnostic(input: {
473
770
  signals,
474
771
  unclassifiedLineCount,
475
772
  termination,
773
+ resourceSnapshot,
476
774
  collectionFailure:
477
775
  sessionResult.status === 'rejected'
478
776
  ? describeDaytonaLookupFailure(sessionResult.reason)
@@ -1418,6 +1716,9 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
1418
1716
  cmdId: start.cmdId,
1419
1717
  outputPath: stagedPayload.outputPath,
1420
1718
  exitCodePath: stagedPayload.exitCodePath,
1719
+ oomKillBaselinePath: stagedPayload.oomKillBaselinePath,
1720
+ runnerPidPath: stagedPayload.runnerPidPath,
1721
+ runtimeStartedPath: stagedPayload.runtimeStartedPath,
1421
1722
  runtimeCompletedPath: stagedPayload.runtimeCompletedPath,
1422
1723
  terminationDiagnosticPath:
1423
1724
  stagedPayload.terminationDiagnosticPath,
@@ -834,6 +834,10 @@ function buildDefaultDeps(absurd: Absurd): AbsurdRuntimeWorkerDeps {
834
834
  cmdId: request.cmdId,
835
835
  outputPath: request.outputPath,
836
836
  exitCodePath: request.exitCodePath,
837
+ oomKillBaselinePath: request.oomKillBaselinePath,
838
+ runnerPidPath: request.runnerPidPath,
839
+ runtimeStartedPath: request.runtimeStartedPath,
840
+ runtimeCompletedPath: request.runtimeCompletedPath,
837
841
  terminationDiagnosticPath: request.terminationDiagnosticPath,
838
842
  expectedOrganizationId: routingDomain,
839
843
  }),
@@ -4057,6 +4061,18 @@ function sandboxCrashDiagnosticRequest(input: {
4057
4061
  cmdId: suspension.cmdId,
4058
4062
  outputPath: suspension.outputPath,
4059
4063
  exitCodePath: suspension.exitCodePath,
4064
+ ...(suspension.oomKillBaselinePath
4065
+ ? { oomKillBaselinePath: suspension.oomKillBaselinePath }
4066
+ : {}),
4067
+ ...(suspension.runnerPidPath
4068
+ ? { runnerPidPath: suspension.runnerPidPath }
4069
+ : {}),
4070
+ ...(suspension.runtimeStartedPath
4071
+ ? { runtimeStartedPath: suspension.runtimeStartedPath }
4072
+ : {}),
4073
+ ...(suspension.runtimeCompletedPath
4074
+ ? { runtimeCompletedPath: suspension.runtimeCompletedPath }
4075
+ : {}),
4060
4076
  ...(suspension.terminationDiagnosticPath
4061
4077
  ? { terminationDiagnosticPath: suspension.terminationDiagnosticPath }
4062
4078
  : {}),
@@ -4371,7 +4387,7 @@ async function resolveDetachedRunnerOutcome(input: {
4371
4387
  runnerAttempt: suspension.runnerAttempt,
4372
4388
  sandboxId: suspension.sandboxId,
4373
4389
  exitCode: inspection.exitCode,
4374
- diagnosis: inspection.diagnosis?.stage,
4390
+ diagnosis: inspection.diagnosis?.stage ?? 'unknown',
4375
4391
  resultStatus: inspection.result.status,
4376
4392
  }),
4377
4393
  );
@@ -4385,7 +4401,7 @@ async function resolveDetachedRunnerOutcome(input: {
4385
4401
  runnerAttempt: suspension.runnerAttempt,
4386
4402
  sandboxId: suspension.sandboxId,
4387
4403
  exitCode: inspection.exitCode,
4388
- diagnosis: inspection.diagnosis?.stage,
4404
+ diagnosis: inspection.diagnosis?.stage ?? 'unknown',
4389
4405
  resultStatus: inspection.result?.status ?? null,
4390
4406
  }),
4391
4407
  );
@@ -6172,6 +6188,20 @@ function parseSandboxCrashDiagnosticRequest(
6172
6188
  ) {
6173
6189
  return null;
6174
6190
  }
6191
+ for (const key of [
6192
+ 'oomKillBaselinePath',
6193
+ 'runnerPidPath',
6194
+ 'runtimeStartedPath',
6195
+ 'runtimeCompletedPath',
6196
+ 'terminationDiagnosticPath',
6197
+ ] as const) {
6198
+ if (
6199
+ candidate[key] !== undefined &&
6200
+ (typeof candidate[key] !== 'string' || !(candidate[key] as string).trim())
6201
+ ) {
6202
+ return null;
6203
+ }
6204
+ }
6175
6205
  return candidate as PostgresSchedulerSandboxCrashDiagnosticRequest;
6176
6206
  }
6177
6207
 
@@ -6184,11 +6214,17 @@ function unavailableSandboxCrashDiagnostic(
6184
6214
  exitCodeFile: null,
6185
6215
  sessionExitCode: null,
6186
6216
  outputBytes: null,
6217
+ outputFileAvailable: null,
6218
+ exitCodeFileAvailable: null,
6219
+ terminationFileAvailable: null,
6220
+ runtimeStarted: null,
6221
+ runtimeCompleted: null,
6187
6222
  tailBytes: 0,
6188
6223
  tailTruncated: false,
6189
6224
  signals: [],
6190
6225
  unclassifiedLineCount: 0,
6191
6226
  termination: null,
6227
+ resourceSnapshot: null,
6192
6228
  collectionFailure: {
6193
6229
  errorName: 'CrashDiagnosticUnavailable',
6194
6230
  errorCode: null,
@@ -392,6 +392,10 @@ export type PostgresSchedulerSandboxCrashDiagnosticRequest = {
392
392
  cmdId: string;
393
393
  outputPath: string;
394
394
  exitCodePath: string;
395
+ oomKillBaselinePath?: string;
396
+ runnerPidPath?: string;
397
+ runtimeStartedPath?: string;
398
+ runtimeCompletedPath?: string;
395
399
  terminationDiagnosticPath?: string;
396
400
  };
397
401
 
@@ -68,6 +68,10 @@ export type PlayExecutionSuspension =
68
68
  * timeout-wake salvage verification. */
69
69
  outputPath: string;
70
70
  exitCodePath: string;
71
+ /** Bounded crash evidence paths for sandbox state at liveness loss. */
72
+ oomKillBaselinePath?: string;
73
+ runnerPidPath?: string;
74
+ runtimeStartedPath?: string;
71
75
  /** Exact customer-code completion fence inside the Daytona sandbox. */
72
76
  runtimeCompletedPath?: string;
73
77
  /** Bounded watchdog-owned cause marker for crash-only diagnostics. */
package/dist/cli/index.js CHANGED
@@ -3051,7 +3051,7 @@ var SDK_RELEASE = {
3051
3051
  // getters keep their established compatibility behavior.
3052
3052
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
3053
3053
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
3054
- version: "0.3.210",
3054
+ version: "0.3.211",
3055
3055
  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.",
3056
3056
  packageCapabilities: {
3057
3057
  updatePreferences: 1
@@ -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.210",
3049
+ version: "0.3.211",
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
package/dist/index.js CHANGED
@@ -864,7 +864,7 @@ var SDK_RELEASE = {
864
864
  // getters keep their established compatibility behavior.
865
865
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
866
866
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
867
- version: "0.3.210",
867
+ version: "0.3.211",
868
868
  updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
869
869
  packageCapabilities: {
870
870
  updatePreferences: 1
package/dist/index.mjs CHANGED
@@ -768,7 +768,7 @@ var SDK_RELEASE = {
768
768
  // getters keep their established compatibility behavior.
769
769
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
770
770
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
771
- version: "0.3.210",
771
+ version: "0.3.211",
772
772
  updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
773
773
  packageCapabilities: {
774
774
  updatePreferences: 1
@@ -149,7 +149,7 @@ type SdkRelease = {
149
149
  supportPolicy: SdkSupportPolicy;
150
150
  };
151
151
  declare const SDK_RELEASE: {
152
- readonly version: "0.3.210";
152
+ readonly version: "0.3.211";
153
153
  readonly updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.";
154
154
  readonly packageCapabilities: {
155
155
  readonly updatePreferences: 1;
package/dist/release.d.ts CHANGED
@@ -149,7 +149,7 @@ type SdkRelease = {
149
149
  supportPolicy: SdkSupportPolicy;
150
150
  };
151
151
  declare const SDK_RELEASE: {
152
- readonly version: "0.3.210";
152
+ readonly version: "0.3.211";
153
153
  readonly updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.";
154
154
  readonly packageCapabilities: {
155
155
  readonly updatePreferences: 1;
package/dist/release.js CHANGED
@@ -74,7 +74,7 @@ var SDK_RELEASE = {
74
74
  // getters keep their established compatibility behavior.
75
75
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
76
76
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
77
- version: "0.3.210",
77
+ version: "0.3.211",
78
78
  updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
79
79
  packageCapabilities: {
80
80
  updatePreferences: 1
package/dist/release.mjs CHANGED
@@ -48,7 +48,7 @@ var SDK_RELEASE = {
48
48
  // getters keep their established compatibility behavior.
49
49
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
50
50
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
51
- version: "0.3.210",
51
+ version: "0.3.211",
52
52
  updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
53
53
  packageCapabilities: {
54
54
  updatePreferences: 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.3.210",
3
+ "version": "0.3.211",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",