deepline 0.3.174 → 0.3.175

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.
@@ -107,6 +107,7 @@ import type { PlayCompilerManifest } from '../../shared_libs/plays/compiler-mani
107
107
  import type { EnrichCompiledConfig } from './cli/enrich-play-compiler.js';
108
108
  import { RUNTIME_ENVIRONMENT_TOKEN_HEADER } from '../../shared_libs/play-runtime/coordinator-headers.js';
109
109
  import { resolveTheirstackClientTimeoutMs } from '../../shared_libs/integration-contracts/theirstack/execution-policy.js';
110
+ import { resolveWaterfallClientTimeoutMs } from '../../shared_libs/integration-contracts/waterfall/execution-policy.js';
110
111
  import {
111
112
  BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS,
112
113
  usesExtendedBetterContactLauncherBudget,
@@ -724,6 +725,8 @@ function resolveToolExecuteTimeoutMs(
724
725
  input,
725
726
  );
726
727
  if (theirstackTimeoutMs !== null) return theirstackTimeoutMs;
728
+ const waterfallTimeoutMs = resolveWaterfallClientTimeoutMs(normalized);
729
+ if (waterfallTimeoutMs !== null) return waterfallTimeoutMs;
727
730
  if (usesExtendedBetterContactLauncherBudget(normalized)) {
728
731
  return BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS;
729
732
  }
@@ -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.174',
203
+ version: '0.3.175',
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: {
@@ -1,3 +1,4 @@
1
1
  export * from './bettercontact/execution-policy';
2
2
  export * from './theirstack/execution-policy';
3
+ export * from './waterfall/execution-policy';
3
4
  export * from './monitor-input-contract';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Waterfall launcher responses include a bounded launch-and-poll window. The
3
+ * SDK default is only 60 seconds, which can abandon a valid prospector job
4
+ * while the server is still polling it. Keep this budget specific to the
5
+ * launcher instead of widening every integration request.
6
+ */
7
+ export const WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS = 180_000;
8
+
9
+ const WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS = new Set([
10
+ 'prospector',
11
+ 'deepline_native_prospector',
12
+ ]);
13
+
14
+ export function resolveWaterfallClientTimeoutMs(toolId: string): number | null {
15
+ return WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS.has(toolId.trim().toLowerCase())
16
+ ? WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS
17
+ : null;
18
+ }
@@ -2,3 +2,4 @@ export * from './column-names';
2
2
  export * from './contracts';
3
3
  export * from './sheet-contract';
4
4
  export * from './runtime-sheet-storage-contract';
5
+ export * from './runtime-sheet-orm';
@@ -0,0 +1,489 @@
1
+ /**
2
+ * Typed owner for the physical Runtime Sheet table contract.
3
+ *
4
+ * This is intentionally a small ORM seam, not a general SQL builder. It owns
5
+ * the facts that every Runtime Sheet writer needs to agree on: which columns
6
+ * belong to Deepline, what shape they have, how readiness is determined, and
7
+ * which additive/default repairs are safe. Application and worker code supply
8
+ * the query adapter and keep their transport-specific concerns outside this
9
+ * Module.
10
+ */
11
+
12
+ export const RUNTIME_SHEET_VERSION_SEQUENCE = '_deepline_sheet_version_seq';
13
+
14
+ export const RUNTIME_SHEET_CELL_META_COLUMN = {
15
+ name: '_cell_meta',
16
+ dataType: 'jsonb',
17
+ nullable: 'NO',
18
+ defaultSql: "'{}'::jsonb",
19
+ } as const;
20
+
21
+ type RuntimeSheetNullable = 'YES' | 'NO';
22
+
23
+ export type RuntimeSheetColumnContract = {
24
+ name: string;
25
+ sqlType: string;
26
+ dataType: string;
27
+ nullable: RuntimeSheetNullable;
28
+ defaultSql: string | null;
29
+ defaultKind?: 'version_sequence';
30
+ /** A missing column can be added without guessing at customer data. */
31
+ repairable: boolean;
32
+ /** The column must have a default because writers intentionally omit it. */
33
+ requiresDefault: boolean;
34
+ };
35
+
36
+ export type RuntimeSheetColumnState = {
37
+ column_name: string;
38
+ data_type: string;
39
+ is_nullable: string;
40
+ column_default: string | null;
41
+ };
42
+
43
+ export type RuntimeSheetSchemaSnapshot = {
44
+ sequenceExists: boolean;
45
+ columns: ReadonlyMap<string, RuntimeSheetColumnState>;
46
+ };
47
+
48
+ export type RuntimeSheetSchemaReadiness = {
49
+ ready: boolean;
50
+ missingColumns: string[];
51
+ incompatibleColumns: string[];
52
+ missingDefaults: string[];
53
+ sequenceReady: boolean;
54
+ };
55
+
56
+ export type RuntimeSheetOrmQuery = <Row = Record<string, unknown>>(
57
+ sql: string,
58
+ params?: readonly unknown[],
59
+ ) => Promise<{ rows: Row[] }>;
60
+
61
+ export type RuntimeSheetOrm = {
62
+ inspect(): Promise<RuntimeSheetSchemaSnapshot>;
63
+ readiness(
64
+ snapshot?: RuntimeSheetSchemaSnapshot,
65
+ ): Promise<RuntimeSheetSchemaReadiness>;
66
+ repairOwnerMetadata(): Promise<void>;
67
+ isOwnerMetadataConstraintError(error: unknown): boolean;
68
+ };
69
+
70
+ export function isRuntimeSheetOwnerMetadataConstraintError(
71
+ error: unknown,
72
+ input: { table: string },
73
+ ): boolean {
74
+ if (!error || typeof error !== 'object') return false;
75
+ const record = error as Record<string, unknown>;
76
+ if (String(record.code ?? '') !== '23502') return false;
77
+ const table = typeof record.table === 'string' ? record.table : null;
78
+ const message = typeof record.message === 'string' ? record.message : '';
79
+ const tableMatches =
80
+ table === input.table || message.includes(`relation "${input.table}"`);
81
+ const column = readColumnName(error);
82
+ return (
83
+ tableMatches &&
84
+ column !== null &&
85
+ RUNTIME_SHEET_REPAIRABLE_COLUMNS.some(
86
+ (contract) => contract.name === column,
87
+ )
88
+ );
89
+ }
90
+
91
+ const RUNTIME_SHEET_COLUMN_CONTRACTS: readonly RuntimeSheetColumnContract[] = [
92
+ {
93
+ name: '_key',
94
+ sqlType: 'text',
95
+ dataType: 'text',
96
+ nullable: 'NO',
97
+ defaultSql: null,
98
+ repairable: false,
99
+ requiresDefault: false,
100
+ },
101
+ {
102
+ name: '_status',
103
+ sqlType: 'text NOT NULL',
104
+ dataType: 'text',
105
+ nullable: 'NO',
106
+ defaultSql: null,
107
+ repairable: false,
108
+ requiresDefault: false,
109
+ },
110
+ {
111
+ name: '_run_id',
112
+ sqlType: 'text',
113
+ dataType: 'text',
114
+ nullable: 'YES',
115
+ defaultSql: null,
116
+ repairable: true,
117
+ requiresDefault: false,
118
+ },
119
+ {
120
+ name: '_error',
121
+ sqlType: 'text',
122
+ dataType: 'text',
123
+ nullable: 'YES',
124
+ defaultSql: null,
125
+ repairable: true,
126
+ requiresDefault: false,
127
+ },
128
+ {
129
+ name: '_stage',
130
+ sqlType: 'text',
131
+ dataType: 'text',
132
+ nullable: 'YES',
133
+ defaultSql: null,
134
+ repairable: true,
135
+ requiresDefault: false,
136
+ },
137
+ {
138
+ name: '_provider',
139
+ sqlType: 'text',
140
+ dataType: 'text',
141
+ nullable: 'YES',
142
+ defaultSql: null,
143
+ repairable: true,
144
+ requiresDefault: false,
145
+ },
146
+ {
147
+ name: '_input_index',
148
+ sqlType: 'bigint',
149
+ dataType: 'bigint',
150
+ nullable: 'YES',
151
+ defaultSql: null,
152
+ repairable: true,
153
+ requiresDefault: false,
154
+ },
155
+ {
156
+ name: '_attempt_id',
157
+ sqlType: 'text',
158
+ dataType: 'text',
159
+ nullable: 'YES',
160
+ defaultSql: null,
161
+ repairable: true,
162
+ requiresDefault: false,
163
+ },
164
+ {
165
+ name: '_attempt_owner_run_id',
166
+ sqlType: 'text',
167
+ dataType: 'text',
168
+ nullable: 'YES',
169
+ defaultSql: null,
170
+ repairable: true,
171
+ requiresDefault: false,
172
+ },
173
+ {
174
+ name: '_attempt_expires_at',
175
+ sqlType: 'timestamptz',
176
+ dataType: 'timestamp with time zone',
177
+ nullable: 'YES',
178
+ defaultSql: null,
179
+ repairable: true,
180
+ requiresDefault: false,
181
+ },
182
+ {
183
+ name: '_attempt_seq',
184
+ sqlType: 'integer',
185
+ dataType: 'integer',
186
+ nullable: 'YES',
187
+ defaultSql: null,
188
+ repairable: true,
189
+ requiresDefault: false,
190
+ },
191
+ {
192
+ name: '_write_version',
193
+ sqlType: 'bigint NOT NULL DEFAULT 0',
194
+ dataType: 'bigint',
195
+ nullable: 'NO',
196
+ defaultSql: '0',
197
+ repairable: true,
198
+ requiresDefault: true,
199
+ },
200
+ {
201
+ name: '_writer_run_id',
202
+ sqlType: 'text',
203
+ dataType: 'text',
204
+ nullable: 'YES',
205
+ defaultSql: null,
206
+ repairable: true,
207
+ requiresDefault: false,
208
+ },
209
+ {
210
+ name: '_created_at',
211
+ sqlType: 'timestamptz NOT NULL DEFAULT now()',
212
+ dataType: 'timestamp with time zone',
213
+ nullable: 'NO',
214
+ defaultSql: 'now()',
215
+ repairable: true,
216
+ requiresDefault: true,
217
+ },
218
+ {
219
+ name: '_updated_at',
220
+ sqlType: 'timestamptz NOT NULL DEFAULT now()',
221
+ dataType: 'timestamp with time zone',
222
+ nullable: 'NO',
223
+ defaultSql: 'now()',
224
+ repairable: true,
225
+ requiresDefault: true,
226
+ },
227
+ {
228
+ name: '_version',
229
+ sqlType: 'bigint NOT NULL',
230
+ dataType: 'bigint',
231
+ nullable: 'NO',
232
+ defaultSql: null,
233
+ defaultKind: 'version_sequence',
234
+ repairable: true,
235
+ requiresDefault: true,
236
+ },
237
+ {
238
+ ...RUNTIME_SHEET_CELL_META_COLUMN,
239
+ sqlType: `jsonb NOT NULL DEFAULT ${RUNTIME_SHEET_CELL_META_COLUMN.defaultSql}`,
240
+ repairable: true,
241
+ requiresDefault: true,
242
+ },
243
+ ];
244
+
245
+ export const RUNTIME_SHEET_ATTEMPT_COLUMNS =
246
+ RUNTIME_SHEET_COLUMN_CONTRACTS.filter((column) =>
247
+ column.name.startsWith('_attempt_'),
248
+ ).map((column) => column.name);
249
+
250
+ export const RUNTIME_SHEET_WRITE_VERSION_COLUMNS =
251
+ RUNTIME_SHEET_COLUMN_CONTRACTS.filter(
252
+ (column) =>
253
+ column.name === '_write_version' || column.name === '_writer_run_id',
254
+ ).map((column) => column.name);
255
+
256
+ export const RUNTIME_SHEET_TIMESTAMP_COLUMNS =
257
+ RUNTIME_SHEET_COLUMN_CONTRACTS.filter(
258
+ (column) => column.name === '_created_at' || column.name === '_updated_at',
259
+ ).map((column) => column.name);
260
+
261
+ export const RUNTIME_SHEET_SYSTEM_COLUMNS = new Set(
262
+ RUNTIME_SHEET_COLUMN_CONTRACTS.map((column) => column.name),
263
+ );
264
+
265
+ const RUNTIME_SHEET_REPAIRABLE_COLUMNS = RUNTIME_SHEET_COLUMN_CONTRACTS.filter(
266
+ (column) => column.repairable,
267
+ );
268
+
269
+ export function runtimeSheetColumnContracts(): readonly RuntimeSheetColumnContract[] {
270
+ return RUNTIME_SHEET_COLUMN_CONTRACTS;
271
+ }
272
+
273
+ export function runtimeSheetRepairableColumnContracts(): readonly RuntimeSheetColumnContract[] {
274
+ return RUNTIME_SHEET_REPAIRABLE_COLUMNS;
275
+ }
276
+
277
+ export function isRuntimeSheetSystemColumn(columnName: string): boolean {
278
+ return RUNTIME_SHEET_SYSTEM_COLUMNS.has(columnName);
279
+ }
280
+
281
+ /**
282
+ * SQL projection for adapters that already have a larger relation-readiness
283
+ * query. The expected rows are generated from the contract, so adding an
284
+ * owner column expands this projection automatically instead of requiring a
285
+ * new field-specific boolean in every adapter.
286
+ */
287
+ export function runtimeSheetOwnerColumnsReadinessSql(input: {
288
+ schemaParam: string;
289
+ tableParam: string;
290
+ }): string {
291
+ const expectedRows = RUNTIME_SHEET_COLUMN_CONTRACTS.map(
292
+ (column) =>
293
+ `(${quoteLiteral(column.name)}, ${quoteLiteral(column.dataType)}, ${quoteLiteral(column.nullable)}, ${column.requiresDefault ? 'TRUE' : 'FALSE'})`,
294
+ ).join(',\n ');
295
+ return `(
296
+ SELECT count(*) = ${RUNTIME_SHEET_COLUMN_CONTRACTS.length}
297
+ FROM information_schema.columns AS actual
298
+ JOIN (VALUES
299
+ ${expectedRows}
300
+ ) AS expected(column_name, data_type, is_nullable, requires_default)
301
+ ON expected.column_name = actual.column_name
302
+ WHERE actual.table_schema = ${input.schemaParam}
303
+ AND actual.table_name = ${input.tableParam}
304
+ AND actual.data_type = expected.data_type
305
+ AND actual.is_nullable = expected.is_nullable
306
+ AND (NOT expected.requires_default OR actual.column_default IS NOT NULL)
307
+ )`;
308
+ }
309
+
310
+ export function isRuntimeSheetColumnReady(
311
+ contract: RuntimeSheetColumnContract,
312
+ state: RuntimeSheetColumnState | undefined,
313
+ ): boolean {
314
+ return (
315
+ state?.data_type === contract.dataType &&
316
+ state.is_nullable === contract.nullable &&
317
+ (!contract.requiresDefault || state.column_default != null)
318
+ );
319
+ }
320
+
321
+ export function evaluateRuntimeSheetSchema(
322
+ snapshot: RuntimeSheetSchemaSnapshot,
323
+ ): RuntimeSheetSchemaReadiness {
324
+ const missingColumns: string[] = [];
325
+ const incompatibleColumns: string[] = [];
326
+ const missingDefaults: string[] = [];
327
+
328
+ for (const contract of RUNTIME_SHEET_COLUMN_CONTRACTS) {
329
+ const state = snapshot.columns.get(contract.name);
330
+ if (!state) {
331
+ missingColumns.push(contract.name);
332
+ continue;
333
+ }
334
+ if (
335
+ state.data_type !== contract.dataType ||
336
+ state.is_nullable !== contract.nullable
337
+ ) {
338
+ incompatibleColumns.push(contract.name);
339
+ continue;
340
+ }
341
+ if (contract.requiresDefault && state.column_default == null) {
342
+ missingDefaults.push(contract.name);
343
+ }
344
+ }
345
+
346
+ const sequenceReady = snapshot.sequenceExists;
347
+ return {
348
+ ready:
349
+ missingColumns.length === 0 &&
350
+ incompatibleColumns.length === 0 &&
351
+ missingDefaults.length === 0 &&
352
+ sequenceReady,
353
+ missingColumns,
354
+ incompatibleColumns,
355
+ missingDefaults,
356
+ sequenceReady,
357
+ };
358
+ }
359
+
360
+ function quoteIdentifier(identifier: string): string {
361
+ return `"${identifier.replace(/"/g, '""')}"`;
362
+ }
363
+
364
+ function quoteLiteral(value: string): string {
365
+ return `'${value.replace(/'/g, "''")}'`;
366
+ }
367
+
368
+ function relation(schema: string, table: string): string {
369
+ return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;
370
+ }
371
+
372
+ function versionDefaultSql(schema: string): string {
373
+ return `nextval(${quoteLiteral(`${schema}.${RUNTIME_SHEET_VERSION_SEQUENCE}`)}::regclass)`;
374
+ }
375
+
376
+ function columnDefaultSql(
377
+ column: RuntimeSheetColumnContract,
378
+ schema: string,
379
+ ): string | null {
380
+ if (column.defaultKind === 'version_sequence') {
381
+ return versionDefaultSql(schema);
382
+ }
383
+ return column.defaultSql;
384
+ }
385
+
386
+ function readColumnName(error: unknown): string | null {
387
+ if (!error || typeof error !== 'object') return null;
388
+ const record = error as Record<string, unknown>;
389
+ if (typeof record.column === 'string') return record.column;
390
+ if (typeof record.message !== 'string') return null;
391
+ return /column ['"]([^'"]+)['"]/i.exec(record.message)?.[1] ?? null;
392
+ }
393
+
394
+ export function createRuntimeSheetOrm(input: {
395
+ schema: string;
396
+ table: string;
397
+ query: RuntimeSheetOrmQuery;
398
+ }): RuntimeSheetOrm {
399
+ const tableReference = relation(input.schema, input.table);
400
+ const versionSequenceReference = `${input.schema}.${RUNTIME_SHEET_VERSION_SEQUENCE}`;
401
+
402
+ async function inspect(): Promise<RuntimeSheetSchemaSnapshot> {
403
+ const [columns, sequence] = await Promise.all([
404
+ input.query<RuntimeSheetColumnState>(
405
+ `
406
+ SELECT column_name, data_type, is_nullable, column_default
407
+ FROM information_schema.columns
408
+ WHERE table_schema = $1
409
+ AND table_name = $2
410
+ AND column_name = ANY($3::text[])
411
+ `,
412
+ [input.schema, input.table, [...RUNTIME_SHEET_SYSTEM_COLUMNS]],
413
+ ),
414
+ input.query<{ exists: boolean }>(
415
+ 'SELECT to_regclass($1) IS NOT NULL AS exists',
416
+ [versionSequenceReference],
417
+ ),
418
+ ]);
419
+ return {
420
+ sequenceExists: sequence.rows[0]?.exists === true,
421
+ columns: new Map(columns.rows.map((row) => [row.column_name, row])),
422
+ };
423
+ }
424
+
425
+ async function readiness(
426
+ snapshot?: RuntimeSheetSchemaSnapshot,
427
+ ): Promise<RuntimeSheetSchemaReadiness> {
428
+ return evaluateRuntimeSheetSchema(snapshot ?? (await inspect()));
429
+ }
430
+
431
+ async function repairOwnerMetadata(): Promise<void> {
432
+ await input.query(`
433
+ ALTER TABLE ${tableReference}
434
+ ${RUNTIME_SHEET_REPAIRABLE_COLUMNS.map(
435
+ (column) =>
436
+ `ADD COLUMN IF NOT EXISTS ${quoteIdentifier(column.name)} ${column.dataType}`,
437
+ ).join(',\n ')}
438
+ `);
439
+
440
+ const defaultedColumns = RUNTIME_SHEET_REPAIRABLE_COLUMNS.filter(
441
+ (column) => column.requiresDefault,
442
+ );
443
+ await input.query(`
444
+ ALTER TABLE ${tableReference}
445
+ ${defaultedColumns
446
+ .map(
447
+ (column) =>
448
+ `ALTER COLUMN ${quoteIdentifier(column.name)} SET DEFAULT ${columnDefaultSql(column, input.schema)}`,
449
+ )
450
+ .join(',\n ')}
451
+ `);
452
+
453
+ for (const column of defaultedColumns) {
454
+ const defaultSql = columnDefaultSql(column, input.schema);
455
+ if (defaultSql === null) continue;
456
+ await input.query(`
457
+ UPDATE ${tableReference}
458
+ SET ${quoteIdentifier(column.name)} = ${defaultSql}
459
+ WHERE ${quoteIdentifier(column.name)} IS NULL
460
+ `);
461
+ }
462
+
463
+ const nonNullableColumns = RUNTIME_SHEET_REPAIRABLE_COLUMNS.filter(
464
+ (column) => column.nullable === 'NO',
465
+ );
466
+ await input.query(`
467
+ ALTER TABLE ${tableReference}
468
+ ${nonNullableColumns
469
+ .map(
470
+ (column) =>
471
+ `ALTER COLUMN ${quoteIdentifier(column.name)} SET NOT NULL`,
472
+ )
473
+ .join(',\n ')}
474
+ `);
475
+ }
476
+
477
+ function isOwnerMetadataConstraintError(error: unknown): boolean {
478
+ return isRuntimeSheetOwnerMetadataConstraintError(error, {
479
+ table: input.table,
480
+ });
481
+ }
482
+
483
+ return {
484
+ inspect,
485
+ readiness,
486
+ repairOwnerMetadata,
487
+ isOwnerMetadataConstraintError,
488
+ };
489
+ }
@@ -1,16 +1,7 @@
1
- /**
2
- * Canonical contract for the runtime sheet cell-provenance column.
3
- *
4
- * Runtime sheet writers intentionally omit this column and rely on the
5
- * database default. Keep the type, nullability, and default in one Module so
6
- * table creation, readiness probes, migrations, and diagnostics cannot drift.
7
- */
8
- export const RUNTIME_SHEET_CELL_META_COLUMN = {
9
- name: '_cell_meta',
10
- dataType: 'jsonb',
11
- nullable: 'NO',
12
- defaultSql: "'{}'::jsonb",
13
- } as const;
1
+ /** Compatibility seam for callers that used the cell-meta-only contract. */
2
+ import { RUNTIME_SHEET_CELL_META_COLUMN } from './runtime-sheet-orm';
3
+
4
+ export { RUNTIME_SHEET_CELL_META_COLUMN } from './runtime-sheet-orm';
14
5
 
15
6
  export type RuntimeSheetCellMetaColumnState = {
16
7
  data_type: string;
@@ -25,6 +25,13 @@ import {
25
25
  type PhysicalSheetColumnProjection,
26
26
  } from '../play-data-plane/sheet-contract';
27
27
  import { RUNTIME_SHEET_CELL_META_COLUMN } from '../play-data-plane/runtime-sheet-storage-contract';
28
+ import {
29
+ createRuntimeSheetOrm,
30
+ isRuntimeSheetOwnerMetadataConstraintError,
31
+ RUNTIME_SHEET_ATTEMPT_COLUMNS,
32
+ RUNTIME_SHEET_TIMESTAMP_COLUMNS,
33
+ RUNTIME_SHEET_VERSION_SEQUENCE,
34
+ } from '../play-data-plane/runtime-sheet-orm';
28
35
  import type {
29
36
  CreateDbSessionResponse,
30
37
  DbLogicalTable,
@@ -316,13 +323,6 @@ const APPEND_KEY_SUFFIX_LENGTH = 12;
316
323
  // 60-min alignment fixed. A shorter TTL only causes periodic re-mints (cheap;
317
324
  // the tenant runtime role is long-lived), not run failures.
318
325
  const RUNTIME_DB_SESSION_TTL_SECONDS = 10 * 60;
319
- const RUNTIME_SHEET_ATTEMPT_COLUMNS = [
320
- '_attempt_id',
321
- '_attempt_owner_run_id',
322
- '_attempt_seq',
323
- '_attempt_expires_at',
324
- ] as const;
325
- const RUNTIME_SHEET_TIMESTAMP_COLUMNS = ['_created_at', '_updated_at'] as const;
326
326
  const RUNTIME_SHEET_ENSURE_CACHE_TTL_MS = 10 * 60_000;
327
327
  const RUNTIME_SHEET_READY_AFTER_ENSURE_RETRY_DELAYS_MS = [
328
328
  100, 250, 500, 1_000, 2_000,
@@ -519,6 +519,7 @@ type RuntimeApiActionRequest =
519
519
  tableNamespace: string;
520
520
  sheetContract?: PlaySheetContract | null;
521
521
  userEmail?: string | null;
522
+ forceRepair?: boolean;
522
523
  }
523
524
  | {
524
525
  action: 'create_db_session';
@@ -1135,62 +1136,21 @@ async function isRuntimeSheetSchemaReady(
1135
1136
  FROM ${sheetTable(session)}
1136
1137
  LIMIT 0`,
1137
1138
  );
1138
- const attemptColumns = await client.query<Record<string, unknown>>(
1139
- `
1140
- SELECT count(*)::int AS present_count
1141
- FROM information_schema.columns
1142
- WHERE table_schema = $1
1143
- AND table_name = $2
1144
- AND column_name = ANY($3::text[])
1145
- `,
1146
- [
1147
- session.postgres.schema,
1148
- session.postgres.sheetTable,
1149
- [...RUNTIME_SHEET_ATTEMPT_COLUMNS],
1150
- ],
1151
- );
1152
- const timestampColumns = await client.query<Record<string, unknown>>(
1153
- `
1154
- SELECT count(*)::int AS ready_count
1155
- FROM information_schema.columns
1156
- WHERE table_schema = $1
1157
- AND table_name = $2
1158
- AND column_name = ANY($3::text[])
1159
- AND data_type = 'timestamp with time zone'
1160
- AND is_nullable = 'NO'
1161
- AND column_default IS NOT NULL
1162
- `,
1163
- [
1164
- session.postgres.schema,
1165
- session.postgres.sheetTable,
1166
- [...RUNTIME_SHEET_TIMESTAMP_COLUMNS],
1167
- ],
1168
- );
1169
- const cellMetaColumn = await client.query<Record<string, unknown>>(
1170
- `
1171
- SELECT count(*)::int AS ready_count
1172
- FROM information_schema.columns
1173
- WHERE table_schema = $1
1174
- AND table_name = $2
1175
- AND column_name = $3
1176
- AND data_type = $4
1177
- AND is_nullable = 'NO'
1178
- AND column_default IS NOT NULL
1179
- `,
1180
- [
1181
- session.postgres.schema,
1182
- session.postgres.sheetTable,
1183
- RUNTIME_SHEET_CELL_META_COLUMN.name,
1184
- RUNTIME_SHEET_CELL_META_COLUMN.dataType,
1185
- ],
1186
- );
1187
- return (
1188
- Number(attemptColumns.rows[0]?.present_count ?? 0) ===
1189
- RUNTIME_SHEET_ATTEMPT_COLUMNS.length &&
1190
- Number(timestampColumns.rows[0]?.ready_count ?? 0) ===
1191
- RUNTIME_SHEET_TIMESTAMP_COLUMNS.length &&
1192
- Number(cellMetaColumn.rows[0]?.ready_count ?? 0) === 1
1193
- );
1139
+ const orm = createRuntimeSheetOrm({
1140
+ schema: session.postgres.schema,
1141
+ table: session.postgres.sheetTable,
1142
+ query: async <Row = Record<string, unknown>>(
1143
+ sql: string,
1144
+ params?: readonly unknown[],
1145
+ ): Promise<{ rows: Row[] }> => {
1146
+ const result = await client.query<Row & Record<string, unknown>>(
1147
+ sql,
1148
+ params === undefined ? undefined : [...params],
1149
+ );
1150
+ return { rows: result.rows as Row[] };
1151
+ },
1152
+ });
1153
+ return (await orm.readiness()).ready;
1194
1154
  };
1195
1155
  try {
1196
1156
  if (isRuntimeOneShotQueryFactoryRegistered()) {
@@ -1250,15 +1210,31 @@ async function readRuntimeSheetSchemaDiagnostic(
1250
1210
  `${quoteIdentifier(session.postgres.schema)}.${quoteIdentifier(session.postgres.sheetTable)}`,
1251
1211
  ],
1252
1212
  );
1213
+ const orm = createRuntimeSheetOrm({
1214
+ schema: session.postgres.schema,
1215
+ table: session.postgres.sheetTable,
1216
+ query: async <Row = Record<string, unknown>>(
1217
+ sql: string,
1218
+ params?: readonly unknown[],
1219
+ ): Promise<{ rows: Row[] }> => {
1220
+ const result = await client.query<Row & Record<string, unknown>>(
1221
+ sql,
1222
+ params === undefined ? undefined : [...params],
1223
+ );
1224
+ return { rows: result.rows as Row[] };
1225
+ },
1226
+ });
1227
+ const ownerSchema = await orm.inspect();
1228
+ const ownerReadiness = await orm.readiness(ownerSchema);
1253
1229
  const visible = new Set(visibleColumns.rows.map((row) => row.column_name));
1254
1230
  const timestampColumns = new Map(
1255
- visibleColumns.rows
1256
- .filter((row) =>
1257
- RUNTIME_SHEET_TIMESTAMP_COLUMNS.includes(
1258
- row.column_name as (typeof RUNTIME_SHEET_TIMESTAMP_COLUMNS)[number],
1259
- ),
1260
- )
1261
- .map((row) => [row.column_name, row]),
1231
+ [...ownerSchema.columns.entries()].filter(([column]) =>
1232
+ RUNTIME_SHEET_TIMESTAMP_COLUMNS.includes(column),
1233
+ ),
1234
+ );
1235
+ const versionColumn = ownerSchema.columns.get('_version');
1236
+ const cellMetaColumn = ownerSchema.columns.get(
1237
+ RUNTIME_SHEET_CELL_META_COLUMN.name,
1262
1238
  );
1263
1239
  return {
1264
1240
  schema: session.postgres.schema,
@@ -1268,6 +1244,16 @@ async function readRuntimeSheetSchemaDiagnostic(
1268
1244
  canSelect: privileges.rows[0]?.can_select ?? null,
1269
1245
  canInsert: privileges.rows[0]?.can_insert ?? null,
1270
1246
  canUpdate: privileges.rows[0]?.can_update ?? null,
1247
+ ownerSchemaReady: ownerReadiness.ready,
1248
+ ownerSchemaMissingColumns: ownerReadiness.missingColumns,
1249
+ ownerSchemaIncompatibleColumns: ownerReadiness.incompatibleColumns,
1250
+ ownerSchemaMissingDefaults: ownerReadiness.missingDefaults,
1251
+ versionSequenceExists: ownerSchema.sequenceExists,
1252
+ versionColumnState: {
1253
+ dataType: versionColumn?.data_type ?? null,
1254
+ isNullable: versionColumn?.is_nullable ?? null,
1255
+ hasDefault: versionColumn?.column_default != null,
1256
+ },
1271
1257
  visibleColumnCount: visible.size,
1272
1258
  missingAttemptColumns: RUNTIME_SHEET_ATTEMPT_COLUMNS.filter(
1273
1259
  (column) => !visible.has(column),
@@ -1282,14 +1268,10 @@ async function readRuntimeSheetSchemaDiagnostic(
1282
1268
  };
1283
1269
  }),
1284
1270
  cellMetaColumnState: (() => {
1285
- const state = visibleColumns.rows.find(
1286
- (column) =>
1287
- column.column_name === RUNTIME_SHEET_CELL_META_COLUMN.name,
1288
- );
1289
1271
  return {
1290
- dataType: state?.data_type ?? null,
1291
- isNullable: state?.is_nullable ?? null,
1292
- hasDefault: state?.column_default != null,
1272
+ dataType: cellMetaColumn?.data_type ?? null,
1273
+ isNullable: cellMetaColumn?.is_nullable ?? null,
1274
+ hasDefault: cellMetaColumn?.column_default != null,
1293
1275
  };
1294
1276
  })(),
1295
1277
  };
@@ -2483,6 +2465,7 @@ async function withRuntimeSheetProvisioningRetry<T>(
2483
2465
  playName: string;
2484
2466
  tableNamespace: string;
2485
2467
  sheetContract: PlaySheetContract;
2468
+ session: RuntimePostgresSession;
2486
2469
  timings?: RuntimeSheetTiming[];
2487
2470
  },
2488
2471
  operation: () => Promise<T>,
@@ -2505,12 +2488,33 @@ async function withRuntimeSheetProvisioningRetry<T>(
2505
2488
  });
2506
2489
  if (isMissingRelationError(error)) {
2507
2490
  const ensureStartedAt = Date.now();
2508
- await ensureRuntimeSheet(context, input);
2491
+ await ensureRuntimeSheet(context, {
2492
+ playName: input.playName,
2493
+ tableNamespace: input.tableNamespace,
2494
+ sheetContract: input.sheetContract,
2495
+ });
2509
2496
  input.timings?.push({
2510
2497
  phase: 'ensure_sheet_after_provisioning_error',
2511
2498
  ms: Date.now() - ensureStartedAt,
2512
2499
  retried: true,
2513
2500
  });
2501
+ } else if (
2502
+ isRuntimeSheetOwnerMetadataConstraintError(error, {
2503
+ table: input.session.postgres.sheetTable,
2504
+ })
2505
+ ) {
2506
+ const ensureStartedAt = Date.now();
2507
+ await ensureRuntimeSheet(context, {
2508
+ playName: input.playName,
2509
+ tableNamespace: input.tableNamespace,
2510
+ sheetContract: input.sheetContract,
2511
+ forceRepair: true,
2512
+ });
2513
+ input.timings?.push({
2514
+ phase: 'force_repair_sheet_after_metadata_constraint_error',
2515
+ ms: Date.now() - ensureStartedAt,
2516
+ retried: true,
2517
+ });
2514
2518
  } else if (isPostgresPermissionDeniedError(error)) {
2515
2519
  const repairStartedAt = Date.now();
2516
2520
  await repairRuntimeStorageGrants(context, {
@@ -2551,7 +2555,7 @@ async function withRuntimeSheetQueryClient<T>(
2551
2555
  const totalStartedAt = Date.now();
2552
2556
  const result = await withRuntimeSheetProvisioningRetry(
2553
2557
  context,
2554
- input,
2558
+ { ...input, session },
2555
2559
  async () => {
2556
2560
  if (
2557
2561
  !input.transactional &&
@@ -2865,12 +2869,10 @@ async function withRuntimeWorkReceiptClient<T>(
2865
2869
  throw new Error('Runtime work receipt query failed after retries.');
2866
2870
  }
2867
2871
 
2868
- const PLAY_INTERNAL_SHEET_VERSION_SEQUENCE = '_deepline_sheet_version_seq';
2869
-
2870
2872
  function nextRuntimeSheetVersionExpression(
2871
2873
  session: RuntimePostgresSession,
2872
2874
  ): string {
2873
- return `nextval(${quoteLiteral(`${session.postgres.schema}.${PLAY_INTERNAL_SHEET_VERSION_SEQUENCE}`)}::regclass)`;
2875
+ return `nextval(${quoteLiteral(`${session.postgres.schema}.${RUNTIME_SHEET_VERSION_SEQUENCE}`)}::regclass)`;
2874
2876
  }
2875
2877
 
2876
2878
  function missingOutputCellSql(
@@ -3476,6 +3478,23 @@ async function writeRuntimeRows(
3476
3478
  });
3477
3479
  }
3478
3480
 
3481
+ async function writeRuntimeRowsWithProvisioningRetry(
3482
+ context: RuntimeApiContext,
3483
+ session: RuntimePostgresSession,
3484
+ input: Parameters<typeof writeRuntimeRows>[1],
3485
+ ): Promise<RowsWriteResponse> {
3486
+ return await withRuntimeSheetProvisioningRetry(
3487
+ context,
3488
+ {
3489
+ playName: session.playName,
3490
+ tableNamespace: input.tableNamespace,
3491
+ sheetContract: input.sheetContract,
3492
+ session,
3493
+ },
3494
+ () => writeRuntimeRows(session, input),
3495
+ );
3496
+ }
3497
+
3479
3498
  export async function resolveRuntimeReferencedPlay(
3480
3499
  context: RuntimeApiContext,
3481
3500
  playRef: string,
@@ -3509,6 +3528,7 @@ export async function ensureRuntimeSheet(
3509
3528
  playName: string;
3510
3529
  tableNamespace: string;
3511
3530
  sheetContract: PlaySheetContract;
3531
+ forceRepair?: boolean;
3512
3532
  },
3513
3533
  ): Promise<void> {
3514
3534
  const request = {
@@ -3516,6 +3536,7 @@ export async function ensureRuntimeSheet(
3516
3536
  ...input,
3517
3537
  runId: context.runId ?? null,
3518
3538
  userEmail: normalizeRuntimeUserEmail(context.userEmail),
3539
+ ...(input.forceRepair === true ? { forceRepair: true } : {}),
3519
3540
  };
3520
3541
  try {
3521
3542
  await postRuntimeApi<{ ok: true }>(context, request);
@@ -9124,18 +9145,22 @@ export async function upsertRuntimeRows(
9124
9145
  },
9125
9146
  );
9126
9147
  return rowsWriteResponseSchema.parse(
9127
- await writeRuntimeRows(requireRuntimePostgresSession(session), {
9128
- tableNamespace: input.tableNamespace,
9129
- rows: input.rows,
9130
- runId: input.runId,
9131
- sheetContract: input.sheetContract,
9132
- idempotencyKey: createHash('sha1')
9133
- .update(
9134
- `${input.playName}:${input.tableNamespace}:${input.runId}:${JSON.stringify(input.rows)}`,
9135
- )
9136
- .digest('hex'),
9137
- mode: 'upsert',
9138
- }),
9148
+ await writeRuntimeRowsWithProvisioningRetry(
9149
+ context,
9150
+ requireRuntimePostgresSession(session),
9151
+ {
9152
+ tableNamespace: input.tableNamespace,
9153
+ rows: input.rows,
9154
+ runId: input.runId,
9155
+ sheetContract: input.sheetContract,
9156
+ idempotencyKey: createHash('sha1')
9157
+ .update(
9158
+ `${input.playName}:${input.tableNamespace}:${input.runId}:${JSON.stringify(input.rows)}`,
9159
+ )
9160
+ .digest('hex'),
9161
+ mode: 'upsert',
9162
+ },
9163
+ ),
9139
9164
  );
9140
9165
  }
9141
9166
 
@@ -9170,14 +9195,18 @@ export async function appendRuntimeRows(
9170
9195
  },
9171
9196
  );
9172
9197
  return rowsWriteResponseSchema.parse(
9173
- await writeRuntimeRows(requireRuntimePostgresSession(session), {
9174
- tableNamespace: input.tableNamespace,
9175
- rows: input.rows,
9176
- runId: input.runId,
9177
- sheetContract: input.sheetContract,
9178
- idempotencyKey: input.idempotencyKey,
9179
- mode: 'append',
9180
- }),
9198
+ await writeRuntimeRowsWithProvisioningRetry(
9199
+ context,
9200
+ requireRuntimePostgresSession(session),
9201
+ {
9202
+ tableNamespace: input.tableNamespace,
9203
+ rows: input.rows,
9204
+ runId: input.runId,
9205
+ sheetContract: input.sheetContract,
9206
+ idempotencyKey: input.idempotencyKey,
9207
+ mode: 'append',
9208
+ },
9209
+ ),
9181
9210
  );
9182
9211
  }
9183
9212
 
@@ -9212,14 +9241,18 @@ export async function replaceRuntimeRows(
9212
9241
  },
9213
9242
  );
9214
9243
  return rowsWriteResponseSchema.parse(
9215
- await writeRuntimeRows(requireRuntimePostgresSession(session), {
9216
- tableNamespace: input.tableNamespace,
9217
- rows: input.rows,
9218
- runId: input.runId,
9219
- sheetContract: input.sheetContract,
9220
- idempotencyKey: input.idempotencyKey,
9221
- mode: 'replace',
9222
- }),
9244
+ await writeRuntimeRowsWithProvisioningRetry(
9245
+ context,
9246
+ requireRuntimePostgresSession(session),
9247
+ {
9248
+ tableNamespace: input.tableNamespace,
9249
+ rows: input.rows,
9250
+ runId: input.runId,
9251
+ sheetContract: input.sheetContract,
9252
+ idempotencyKey: input.idempotencyKey,
9253
+ mode: 'replace',
9254
+ },
9255
+ ),
9223
9256
  );
9224
9257
  }
9225
9258
 
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.174",
3054
+ version: "0.3.175",
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
@@ -6425,6 +6425,16 @@ function resolveTheirstackClientTimeoutMs(endpointId, payload) {
6425
6425
  return usesExtendedTheirstackJobSearchBudget(endpointId, payload) ? THEIRSTACK_SLOW_JOB_SEARCH_CLIENT_TIMEOUT_MS : null;
6426
6426
  }
6427
6427
 
6428
+ // ../integration-contracts/waterfall/execution-policy.ts
6429
+ var WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS = 18e4;
6430
+ var WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS = /* @__PURE__ */ new Set([
6431
+ "prospector",
6432
+ "deepline_native_prospector"
6433
+ ]);
6434
+ function resolveWaterfallClientTimeoutMs(toolId) {
6435
+ return WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS.has(toolId.trim().toLowerCase()) ? WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS : null;
6436
+ }
6437
+
6428
6438
  // ../integration-contracts/bettercontact/execution-policy.ts
6429
6439
  var BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS = 12e4;
6430
6440
  var BETTERCONTACT_LAUNCHER_TOOL_IDS = /* @__PURE__ */ new Set([
@@ -6835,6 +6845,8 @@ function resolveToolExecuteTimeoutMs(toolId, input2) {
6835
6845
  input2
6836
6846
  );
6837
6847
  if (theirstackTimeoutMs !== null) return theirstackTimeoutMs;
6848
+ const waterfallTimeoutMs = resolveWaterfallClientTimeoutMs(normalized);
6849
+ if (waterfallTimeoutMs !== null) return waterfallTimeoutMs;
6838
6850
  if (usesExtendedBetterContactLauncherBudget(normalized)) {
6839
6851
  return BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS;
6840
6852
  }
@@ -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.174",
3049
+ version: "0.3.175",
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
@@ -6420,6 +6420,16 @@ function resolveTheirstackClientTimeoutMs(endpointId, payload) {
6420
6420
  return usesExtendedTheirstackJobSearchBudget(endpointId, payload) ? THEIRSTACK_SLOW_JOB_SEARCH_CLIENT_TIMEOUT_MS : null;
6421
6421
  }
6422
6422
 
6423
+ // ../integration-contracts/waterfall/execution-policy.ts
6424
+ var WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS = 18e4;
6425
+ var WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS = /* @__PURE__ */ new Set([
6426
+ "prospector",
6427
+ "deepline_native_prospector"
6428
+ ]);
6429
+ function resolveWaterfallClientTimeoutMs(toolId) {
6430
+ return WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS.has(toolId.trim().toLowerCase()) ? WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS : null;
6431
+ }
6432
+
6423
6433
  // ../integration-contracts/bettercontact/execution-policy.ts
6424
6434
  var BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS = 12e4;
6425
6435
  var BETTERCONTACT_LAUNCHER_TOOL_IDS = /* @__PURE__ */ new Set([
@@ -6830,6 +6840,8 @@ function resolveToolExecuteTimeoutMs(toolId, input2) {
6830
6840
  input2
6831
6841
  );
6832
6842
  if (theirstackTimeoutMs !== null) return theirstackTimeoutMs;
6843
+ const waterfallTimeoutMs = resolveWaterfallClientTimeoutMs(normalized);
6844
+ if (waterfallTimeoutMs !== null) return waterfallTimeoutMs;
6833
6845
  if (usesExtendedBetterContactLauncherBudget(normalized)) {
6834
6846
  return BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS;
6835
6847
  }
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.174",
867
+ version: "0.3.175",
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
@@ -4095,6 +4095,16 @@ function resolveTheirstackClientTimeoutMs(endpointId, payload) {
4095
4095
  return usesExtendedTheirstackJobSearchBudget(endpointId, payload) ? THEIRSTACK_SLOW_JOB_SEARCH_CLIENT_TIMEOUT_MS : null;
4096
4096
  }
4097
4097
 
4098
+ // ../integration-contracts/waterfall/execution-policy.ts
4099
+ var WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS = 18e4;
4100
+ var WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS = /* @__PURE__ */ new Set([
4101
+ "prospector",
4102
+ "deepline_native_prospector"
4103
+ ]);
4104
+ function resolveWaterfallClientTimeoutMs(toolId) {
4105
+ return WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS.has(toolId.trim().toLowerCase()) ? WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS : null;
4106
+ }
4107
+
4098
4108
  // ../integration-contracts/bettercontact/execution-policy.ts
4099
4109
  var BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS = 12e4;
4100
4110
  var BETTERCONTACT_LAUNCHER_TOOL_IDS = /* @__PURE__ */ new Set([
@@ -4505,6 +4515,8 @@ function resolveToolExecuteTimeoutMs(toolId, input) {
4505
4515
  input
4506
4516
  );
4507
4517
  if (theirstackTimeoutMs !== null) return theirstackTimeoutMs;
4518
+ const waterfallTimeoutMs = resolveWaterfallClientTimeoutMs(normalized);
4519
+ if (waterfallTimeoutMs !== null) return waterfallTimeoutMs;
4508
4520
  if (usesExtendedBetterContactLauncherBudget(normalized)) {
4509
4521
  return BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS;
4510
4522
  }
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.174",
771
+ version: "0.3.175",
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
@@ -3999,6 +3999,16 @@ function resolveTheirstackClientTimeoutMs(endpointId, payload) {
3999
3999
  return usesExtendedTheirstackJobSearchBudget(endpointId, payload) ? THEIRSTACK_SLOW_JOB_SEARCH_CLIENT_TIMEOUT_MS : null;
4000
4000
  }
4001
4001
 
4002
+ // ../integration-contracts/waterfall/execution-policy.ts
4003
+ var WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS = 18e4;
4004
+ var WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS = /* @__PURE__ */ new Set([
4005
+ "prospector",
4006
+ "deepline_native_prospector"
4007
+ ]);
4008
+ function resolveWaterfallClientTimeoutMs(toolId) {
4009
+ return WATERFALL_PROSPECTOR_LAUNCHER_TOOL_IDS.has(toolId.trim().toLowerCase()) ? WATERFALL_PROSPECTOR_CLIENT_TIMEOUT_MS : null;
4010
+ }
4011
+
4002
4012
  // ../integration-contracts/bettercontact/execution-policy.ts
4003
4013
  var BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS = 12e4;
4004
4014
  var BETTERCONTACT_LAUNCHER_TOOL_IDS = /* @__PURE__ */ new Set([
@@ -4409,6 +4419,8 @@ function resolveToolExecuteTimeoutMs(toolId, input) {
4409
4419
  input
4410
4420
  );
4411
4421
  if (theirstackTimeoutMs !== null) return theirstackTimeoutMs;
4422
+ const waterfallTimeoutMs = resolveWaterfallClientTimeoutMs(normalized);
4423
+ if (waterfallTimeoutMs !== null) return waterfallTimeoutMs;
4412
4424
  if (usesExtendedBetterContactLauncherBudget(normalized)) {
4413
4425
  return BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS;
4414
4426
  }
@@ -32,6 +32,7 @@
32
32
  "dist/bundling-sources/shared_libs/integration-contracts/monitor-input-contract.ts",
33
33
  "dist/bundling-sources/shared_libs/integration-contracts/README.md",
34
34
  "dist/bundling-sources/shared_libs/integration-contracts/theirstack/execution-policy.ts",
35
+ "dist/bundling-sources/shared_libs/integration-contracts/waterfall/execution-policy.ts",
35
36
  "dist/bundling-sources/shared_libs/monitors/analytics-install-guides.ts",
36
37
  "dist/bundling-sources/shared_libs/monitors/analytics-public.ts",
37
38
  "dist/bundling-sources/shared_libs/monitors/billing/charges.ts",
@@ -114,6 +115,7 @@
114
115
  "dist/bundling-sources/shared_libs/play-data-plane/index.ts",
115
116
  "dist/bundling-sources/shared_libs/play-data-plane/neon-constants.ts",
116
117
  "dist/bundling-sources/shared_libs/play-data-plane/r2.ts",
118
+ "dist/bundling-sources/shared_libs/play-data-plane/runtime-sheet-orm.ts",
117
119
  "dist/bundling-sources/shared_libs/play-data-plane/runtime-sheet-storage-contract.ts",
118
120
  "dist/bundling-sources/shared_libs/play-data-plane/sheet-contract.ts",
119
121
  "dist/bundling-sources/shared_libs/play-runtime/activity-observation.ts",
@@ -149,7 +149,7 @@ type SdkRelease = {
149
149
  supportPolicy: SdkSupportPolicy;
150
150
  };
151
151
  declare const SDK_RELEASE: {
152
- readonly version: "0.3.174";
152
+ readonly version: "0.3.175";
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.174";
152
+ readonly version: "0.3.175";
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.174",
77
+ version: "0.3.175",
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.174",
51
+ version: "0.3.175",
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.174",
3
+ "version": "0.3.175",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",