deepline 0.3.9 → 0.3.10

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.
@@ -192,7 +192,7 @@ export const SDK_RELEASE = {
192
192
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
193
193
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
194
194
  // getters keep their established compatibility behavior.
195
- version: '0.3.9',
195
+ version: '0.3.10',
196
196
  updateSummary:
197
197
  'New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.',
198
198
  contracts: {
@@ -68,6 +68,7 @@ export type StagedDaytonaPayload = {
68
68
  runtimeCompletedPath: string;
69
69
  terminationDiagnosticPath: string;
70
70
  progressEventPath: string;
71
+ startupDiagnosticPath: string;
71
72
  };
72
73
 
73
74
  export type RemoteRunnerPayloadSandbox = {
@@ -573,6 +574,7 @@ export async function stageRunnerPayload(input: {
573
574
  const runtimeLimitMarkerPath = `${workDir}/deepline-play-runtime-limit-${randomUUID()}.txt`;
574
575
  const terminationDiagnosticPath = `${workDir}/deepline-play-termination-${randomUUID()}.json`;
575
576
  const progressEventPath = `${workDir}/deepline-play-progress-${randomUUID()}.jsonl`;
577
+ const startupDiagnosticPath = `${workDir}/deepline-play-startup-${randomUUID()}.json`;
576
578
  const runnerTraceEnv =
577
579
  process.env.DEEPLINE_RUNTIME_RECEIPT_TRACE === '1'
578
580
  ? 'DEEPLINE_RUNTIME_RECEIPT_TRACE=1 '
@@ -598,7 +600,7 @@ export async function stageRunnerPayload(input: {
598
600
  artifactCodePath,
599
601
  artifactSourceMapPath,
600
602
  crashPusherPath,
601
- })} && DEEPLINE_PLAY_RUNNER_RUNTIME_STARTED_PATH=${shellQuote(runtimeStartedPath)} DEEPLINE_PLAY_RUNNER_RUNTIME_COMPLETED_PATH=${shellQuote(runtimeCompletedPath)} DEEPLINE_PLAY_RUNNER_PROGRESS_EVENT_PATH=${shellQuote(progressEventPath)} DEEPLINE_PLAY_RUNNER_STDOUT_EVENT_MODE=compact ${runnerTraceEnv}${watchedRunnerCommand}`;
603
+ })} && DEEPLINE_PLAY_RUNNER_RUNTIME_STARTED_PATH=${shellQuote(runtimeStartedPath)} DEEPLINE_PLAY_RUNNER_RUNTIME_COMPLETED_PATH=${shellQuote(runtimeCompletedPath)} DEEPLINE_PLAY_RUNNER_PROGRESS_EVENT_PATH=${shellQuote(progressEventPath)} DEEPLINE_PLAY_RUNNER_STARTUP_DIAGNOSTIC_PATH=${shellQuote(startupDiagnosticPath)} DEEPLINE_PLAY_RUNNER_STDOUT_EVENT_MODE=compact ${runnerTraceEnv}${watchedRunnerCommand}`;
602
604
  // Crash-containment epilogue: runs UNCONDITIONALLY after the runner exits and
603
605
  // pushes the parsed (or synthesized) terminal to the gateway so the parked
604
606
  // worker wakes within seconds of ANY runner death — process.exit abuse, OOM
@@ -607,7 +609,7 @@ export async function stageRunnerPayload(input: {
607
609
  // Its own retry diagnostics are kept in a separate log: appending them to
608
610
  // `outputPath` after a near-gateway-sized result could hide that result from
609
611
  // a later bounded-tail recovery read.
610
- const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(crashPusherLogPath)} ${shellQuote(exitCodePath)} ${shellQuote(oomKillBaselinePath)} ${shellQuote(runtimeStartedPath)} ${shellQuote(runtimeCompletedPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(terminationDiagnosticPath)} ${shellQuote(progressEventPath)} ${shellQuote(`${progressEventPath}.*`)}; ( 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)}; 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"`;
612
+ const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(crashPusherLogPath)} ${shellQuote(exitCodePath)} ${shellQuote(oomKillBaselinePath)} ${shellQuote(runtimeStartedPath)} ${shellQuote(runtimeCompletedPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(terminationDiagnosticPath)} ${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)}; 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"`;
611
613
 
612
614
  return {
613
615
  workDir: input.workDir,
@@ -617,6 +619,7 @@ export async function stageRunnerPayload(input: {
617
619
  runtimeCompletedPath,
618
620
  terminationDiagnosticPath,
619
621
  progressEventPath,
622
+ startupDiagnosticPath,
620
623
  };
621
624
  }
622
625
 
@@ -13,9 +13,88 @@ export type DetachedDaytonaStartupDiagnostic = {
13
13
  node: number;
14
14
  states: Record<string, number>;
15
15
  } | null;
16
+ runnerStartup: {
17
+ phase: 'booted' | 'heartbeat_transport';
18
+ outcome?:
19
+ | 'ok'
20
+ | 'terminal'
21
+ | 'redirect'
22
+ | 'gateway_4xx'
23
+ | 'gateway_5xx'
24
+ | 'protocol_error'
25
+ | 'timeout'
26
+ | 'network_error';
27
+ status?: number;
28
+ errorCode?: string;
29
+ transportAttemptId?: string;
30
+ } | null;
16
31
  errors: string[];
17
32
  };
18
33
 
34
+ function parseRunnerStartupDiagnostic(
35
+ value: Buffer,
36
+ ): DetachedDaytonaStartupDiagnostic['runnerStartup'] {
37
+ try {
38
+ const parsed = JSON.parse(value.toString('utf-8')) as Record<
39
+ string,
40
+ unknown
41
+ >;
42
+ if (
43
+ parsed.schemaVersion !== 1 ||
44
+ (parsed.phase !== 'booted' && parsed.phase !== 'heartbeat_transport')
45
+ ) {
46
+ return null;
47
+ }
48
+ if (parsed.phase === 'booted') return { phase: 'booted' };
49
+ const event = parsed.event;
50
+ if (!event || typeof event !== 'object') return null;
51
+ const record = event as Record<string, unknown>;
52
+ const allowedOutcomes = new Set([
53
+ 'ok',
54
+ 'terminal',
55
+ 'redirect',
56
+ 'gateway_4xx',
57
+ 'gateway_5xx',
58
+ 'protocol_error',
59
+ 'timeout',
60
+ 'network_error',
61
+ ]);
62
+ if (
63
+ typeof record.outcome !== 'string' ||
64
+ !allowedOutcomes.has(record.outcome)
65
+ )
66
+ return null;
67
+ const diagnostic: NonNullable<
68
+ DetachedDaytonaStartupDiagnostic['runnerStartup']
69
+ > = {
70
+ phase: 'heartbeat_transport',
71
+ outcome: record.outcome as NonNullable<
72
+ DetachedDaytonaStartupDiagnostic['runnerStartup']
73
+ >['outcome'],
74
+ };
75
+ if (
76
+ typeof record.status === 'number' &&
77
+ Number.isSafeInteger(record.status) &&
78
+ record.status >= 100 &&
79
+ record.status <= 599
80
+ )
81
+ diagnostic.status = record.status;
82
+ if (
83
+ typeof record.errorCode === 'string' &&
84
+ /^[A-Za-z0-9_]{1,64}$/.test(record.errorCode)
85
+ )
86
+ diagnostic.errorCode = record.errorCode;
87
+ if (
88
+ typeof record.transportAttemptId === 'string' &&
89
+ /^[a-f0-9-]{36}$/i.test(record.transportAttemptId)
90
+ )
91
+ diagnostic.transportAttemptId = record.transportAttemptId;
92
+ return diagnostic;
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+
19
98
  function summarizeProcesses(value: unknown): {
20
99
  total: number;
21
100
  node: number;
@@ -50,6 +129,7 @@ export async function inspectDetachedDaytonaStartup(input: {
50
129
  sessionId: string;
51
130
  cmdId: string;
52
131
  exitCodePath: string;
132
+ startupDiagnosticPath?: string;
53
133
  }): Promise<DetachedDaytonaStartupDiagnostic> {
54
134
  const errors: string[] = [];
55
135
  const diagnostic: DetachedDaytonaStartupDiagnostic = {
@@ -61,6 +141,7 @@ export async function inspectDetachedDaytonaStartup(input: {
61
141
  sessionCommandCount: null,
62
142
  exitCodeFile: null,
63
143
  processSummary: null,
144
+ runnerStartup: null,
64
145
  errors,
65
146
  };
66
147
 
@@ -87,6 +168,18 @@ export async function inspectDetachedDaytonaStartup(input: {
87
168
  diagnostic.exitCodeFile = Number.isFinite(value) ? value : null;
88
169
  })
89
170
  .catch(() => errors.push('exit_code_file_unavailable')),
171
+ ...(input.startupDiagnosticPath
172
+ ? [
173
+ input.sandbox.fs
174
+ .downloadFile(input.startupDiagnosticPath, 5)
175
+ .then((file) => {
176
+ diagnostic.runnerStartup = parseRunnerStartupDiagnostic(file);
177
+ if (!diagnostic.runnerStartup)
178
+ errors.push('startup_diagnostic_invalid');
179
+ })
180
+ .catch(() => errors.push('startup_diagnostic_unavailable')),
181
+ ]
182
+ : []),
90
183
  input.sandbox.process
91
184
  .executeCommand('ps -eo stat=,comm=', undefined, {}, 5)
92
185
  .then((result) => {
@@ -130,6 +223,7 @@ export type DetachedDaytonaRunnerSupervisor = {
130
223
  start(input: {
131
224
  command: string;
132
225
  exitCodePath: string;
226
+ startupDiagnosticPath?: string;
133
227
  }): Promise<Extract<DetachedDaytonaRunnerState, { phase: 'ready' }>>;
134
228
  };
135
229
 
@@ -283,7 +377,7 @@ export function prepareDetachedDaytonaRunner(input: {
283
377
  let started = false;
284
378
 
285
379
  return {
286
- async start({ command, exitCodePath }) {
380
+ async start({ command, exitCodePath, startupDiagnosticPath }) {
287
381
  if (started) {
288
382
  throw new Error(
289
383
  `Detached Daytona runner session ${input.sessionId} was already started.`,
@@ -319,6 +413,7 @@ export function prepareDetachedDaytonaRunner(input: {
319
413
  sessionId: state.sessionId,
320
414
  cmdId: state.cmdId,
321
415
  exitCodePath,
416
+ startupDiagnosticPath,
322
417
  readiness: input.readiness,
323
418
  baselineHeartbeatAt: state.baselineHeartbeatAt,
324
419
  }),
@@ -342,6 +437,7 @@ export async function confirmDetachedDaytonaRunnerReady(input: {
342
437
  sessionId: string;
343
438
  cmdId: string;
344
439
  exitCodePath: string;
440
+ startupDiagnosticPath?: string;
345
441
  readiness: DetachedRunnerReadinessPort;
346
442
  baselineHeartbeatAt: string | null;
347
443
  timeoutMs?: number;
@@ -385,6 +481,7 @@ export async function confirmDetachedDaytonaRunnerReady(input: {
385
481
  sessionId: input.sessionId,
386
482
  cmdId: input.cmdId,
387
483
  exitCodePath: input.exitCodePath,
484
+ startupDiagnosticPath: input.startupDiagnosticPath,
388
485
  });
389
486
  diagnostic.schedulerReadinessObserved = false;
390
487
  diagnostic.schedulerReadinessResponses = schedulerReadinessResponses;
@@ -1292,6 +1292,7 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
1292
1292
  start = await detachedRunner.start({
1293
1293
  command: stagedPayload.command,
1294
1294
  exitCodePath: stagedPayload.exitCodePath,
1295
+ startupDiagnosticPath: stagedPayload.startupDiagnosticPath,
1295
1296
  });
1296
1297
  } catch (error) {
1297
1298
  if (
package/dist/cli/index.js CHANGED
@@ -1047,7 +1047,7 @@ var SDK_RELEASE = {
1047
1047
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
1048
1048
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1049
1049
  // getters keep their established compatibility behavior.
1050
- version: "0.3.9",
1050
+ version: "0.3.10",
1051
1051
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
1052
1052
  contracts: {
1053
1053
  api: {
@@ -1033,7 +1033,7 @@ var SDK_RELEASE = {
1033
1033
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
1034
1034
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1035
1035
  // getters keep their established compatibility behavior.
1036
- version: "0.3.9",
1036
+ version: "0.3.10",
1037
1037
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
1038
1038
  contracts: {
1039
1039
  api: {
package/dist/index.js CHANGED
@@ -783,7 +783,7 @@ var SDK_RELEASE = {
783
783
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
784
784
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
785
785
  // getters keep their established compatibility behavior.
786
- version: "0.3.9",
786
+ version: "0.3.10",
787
787
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
788
788
  contracts: {
789
789
  api: {
package/dist/index.mjs CHANGED
@@ -706,7 +706,7 @@ var SDK_RELEASE = {
706
706
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
707
707
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
708
708
  // getters keep their established compatibility behavior.
709
- version: "0.3.9",
709
+ version: "0.3.10",
710
710
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
711
711
  contracts: {
712
712
  api: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.3.9",
3
+ "version": "0.3.10",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",