deepline 0.3.113 → 0.3.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +3 -1
  2. package/dist/bundling-sources/sdk/src/compat.ts +167 -11
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/sdk/src/skills-version.ts +27 -1
  5. package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +6 -2
  6. package/dist/bundling-sources/shared_libs/observability/dlq.ts +942 -0
  7. package/dist/bundling-sources/shared_libs/observability/queue-health.ts +361 -6
  8. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +24 -24
  9. package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +2 -0
  10. package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +29 -1
  11. package/dist/bundling-sources/shared_libs/play-runtime/admission-transport-policy.ts +91 -0
  12. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +2 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/direct-admission-deadline.ts +34 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +1 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +325 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/play-admission-outcome.ts +134 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +13 -0
  18. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/index.ts +4 -1
  19. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +13 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/play-webhook-admission-probe.ts +32 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/play-webhook-identity.ts +28 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +7 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-cron-fire-task.ts +100 -0
  24. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +313 -0
  25. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +111 -3
  26. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +16 -0
  27. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +67 -8
  28. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +1734 -147
  29. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +74 -13
  30. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-queue-health.ts +245 -81
  31. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/submit-admission.ts +79 -15
  32. package/dist/bundling-sources/shared_libs/play-runtime/webhook-receipt-retry.ts +21 -21
  33. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +4 -1
  34. package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +64 -0
  35. package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +1 -1
  36. package/dist/bundling-sources/shared_libs/product-notifications/events.ts +20 -1
  37. package/dist/bundling-sources/shared_libs/security/receipt-admission-token.ts +224 -0
  38. package/dist/cli/index.js +574 -114
  39. package/dist/cli/index.mjs +592 -133
  40. package/dist/index.d.mts +54 -1
  41. package/dist/index.d.ts +54 -1
  42. package/dist/index.js +8 -3
  43. package/dist/index.mjs +8 -3
  44. package/dist/install-integrity.json +8 -0
  45. package/dist/plays/bundle-play-file.mjs +1 -1
  46. package/dist/release.d.mts +1 -1
  47. package/dist/release.d.ts +1 -1
  48. package/dist/release.js +1 -1
  49. package/dist/release.mjs +1 -1
  50. package/package.json +1 -1
@@ -558,6 +558,8 @@ function resolveToolExecuteTimeoutMs(
558
558
  normalized === 'deeplineagent_deeplineagent' ||
559
559
  normalized === 'ai_inference' ||
560
560
  normalized === 'deeplineagent_ai_inference' ||
561
+ normalized === 'ai_evaluate' ||
562
+ normalized === 'deeplineagent_ai_evaluate' ||
561
563
  normalized === 'aiinference'
562
564
  ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS
563
565
  : undefined;
@@ -2782,7 +2784,7 @@ export class DeeplineClient {
2782
2784
  * maximum and contains Deepline credits only.
2783
2785
  */
2784
2786
  async quoteInferenceTool(
2785
- toolId: 'ai_inference' | 'deeplineagent',
2787
+ toolId: 'ai_evaluate' | 'ai_inference' | 'deeplineagent',
2786
2788
  payload: Record<string, unknown>,
2787
2789
  ): Promise<InferenceQuote> {
2788
2790
  return this.http.post<InferenceQuote>(
@@ -62,7 +62,28 @@ export type SdkCompatibilitySkillsUpdate = {
62
62
  };
63
63
 
64
64
  const CHECK_TIMEOUT_MS = 2_000;
65
- export const SDK_COMPATIBILITY_CACHE_TTL_MS = 5 * 60 * 1000;
65
+ /**
66
+ * A cached clean policy younger than this is trusted outright: the command
67
+ * runs without a live request. Policy floors move on a release cadence; the
68
+ * one control designed to move in minutes, a forced rollback, is delayed by
69
+ * at most this window and only for commands run within it. The live check
70
+ * is best-effort already (a network failure runs the command with no policy),
71
+ * so trusting a fresh clean answer is strictly stronger than that path.
72
+ */
73
+ export const SDK_COMPATIBILITY_TRUST_MS = 10 * 60 * 1000;
74
+ /**
75
+ * A cached entry older than the trust window but younger than this still
76
+ * qualifies for the short live budget and for the offline fallback.
77
+ */
78
+ export const SDK_COMPATIBILITY_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
79
+ /**
80
+ * Blocking budget for the live compatibility check when a fresh, clean policy
81
+ * for the same command is already cached. The live check still runs and still
82
+ * wins whenever the server answers inside this window; on a slow or proxied
83
+ * network the command proceeds on the cached policy instead of waiting the
84
+ * full timeout. Blocking policies never use this budget.
85
+ */
86
+ export const SDK_COMPATIBILITY_FAST_DEADLINE_MS = 400;
66
87
 
67
88
  type CompatCacheFile = {
68
89
  entries?: Record<
@@ -118,11 +139,83 @@ function legacyCompatibilityCacheKey(
118
139
  });
119
140
  }
120
141
 
142
+ /**
143
+ * A cached policy is "clean" when it carries no blocking or mutating control:
144
+ * proceeding on it can at most delay an advisory notice, never bypass a
145
+ * required update, a server-directed auto-update, or a CLI-family rollback.
146
+ */
147
+ export function isCleanCompatibilityPolicy(
148
+ response: SdkCompatibilityResponse | null,
149
+ ): boolean {
150
+ if (!response) return false;
151
+ // `ok` is the server's own "this is a policy" marker (426 otherwise); a
152
+ // proxy error body or other junk JSON never earns the trusted tiers.
153
+ return (
154
+ response.ok === true &&
155
+ response.update_required !== true &&
156
+ response.status !== 'unsupported' &&
157
+ !response.auto_update?.should_auto_update &&
158
+ !response.cli_family
159
+ );
160
+ }
161
+
162
+ /**
163
+ * The cached response for this exact command, only when it is inside the
164
+ * cache TTL and clean. Used to decide whether the live check may run with the
165
+ * short deadline instead of its full timeout.
166
+ */
167
+ export function readFreshCleanCompatibility(
168
+ baseUrl: string,
169
+ command: string | null | undefined,
170
+ skillsVersion: string | null | undefined,
171
+ ): SdkCompatibilityResponse | null {
172
+ const cached = readCachedCompatibility(baseUrl, command, skillsVersion);
173
+ return isCleanCompatibilityPolicy(cached) ? cached : null;
174
+ }
175
+
176
+ /**
177
+ * The cached response for this exact command when it is clean and younger
178
+ * than the trust window: the command may run on it without a live request.
179
+ */
180
+ export function readTrustedCleanCompatibility(
181
+ baseUrl: string,
182
+ command: string | null | undefined,
183
+ skillsVersion: string | null | undefined,
184
+ now = Date.now(),
185
+ ): SdkCompatibilityResponse | null {
186
+ const entry = readCachedCompatibilityEntry(baseUrl, command, skillsVersion);
187
+ if (!entry || !isSavedWithin(entry.savedAt, SDK_COMPATIBILITY_TRUST_MS, now))
188
+ return null;
189
+ return isCleanCompatibilityPolicy(entry.response) ? entry.response : null;
190
+ }
191
+
192
+ /**
193
+ * A cache entry is usable only when its age is a real, non-negative number
194
+ * inside the window. A missing timestamp (NaN) or a future one (after a clock
195
+ * correction) would otherwise pass a plain `age > window` check forever.
196
+ */
197
+ function isSavedWithin(savedAt: unknown, windowMs: number, now: number) {
198
+ if (typeof savedAt !== 'number') return false;
199
+ const age = now - savedAt;
200
+ return Number.isFinite(age) && age >= 0 && age <= windowMs;
201
+ }
202
+
121
203
  function readCachedCompatibility(
122
204
  baseUrl: string,
123
205
  command: string | null | undefined,
124
206
  skillsVersion: string | null | undefined,
125
207
  ): SdkCompatibilityResponse | null {
208
+ return (
209
+ readCachedCompatibilityEntry(baseUrl, command, skillsVersion)?.response ??
210
+ null
211
+ );
212
+ }
213
+
214
+ function readCachedCompatibilityEntry(
215
+ baseUrl: string,
216
+ command: string | null | undefined,
217
+ skillsVersion: string | null | undefined,
218
+ ): { savedAt: number; response: SdkCompatibilityResponse } | null {
126
219
  try {
127
220
  const path = sdkCompatibilityCachePath(baseUrl);
128
221
  const legacyPath = legacySdkCompatibilityCachePath();
@@ -141,15 +234,50 @@ function readCachedCompatibility(
141
234
  (useLegacyCache
142
235
  ? parsed.entries?.[legacyCompatibilityCacheKey(baseUrl, command)]
143
236
  : undefined);
144
- if (!entry || Date.now() - entry.savedAt > SDK_COMPATIBILITY_CACHE_TTL_MS) {
237
+ if (
238
+ !entry ||
239
+ !isSavedWithin(entry.savedAt, SDK_COMPATIBILITY_CACHE_TTL_MS, Date.now())
240
+ ) {
145
241
  return null;
146
242
  }
147
- return entry.response;
243
+ return entry;
148
244
  } catch {
149
245
  return null;
150
246
  }
151
247
  }
152
248
 
249
+ /**
250
+ * Drop one cached entry so the next check for this command runs with the full
251
+ * budget. Used after a short-deadline check fell back to the cache: the
252
+ * command proceeds on the cached clean policy once, but a blocking policy the
253
+ * server may have published meanwhile is enforced on the very next command
254
+ * instead of after the cache TTL.
255
+ */
256
+ function invalidateCachedCompatibility(
257
+ baseUrl: string,
258
+ command: string | null | undefined,
259
+ skillsVersion: string | null | undefined,
260
+ ): void {
261
+ try {
262
+ // Mirror the reader: an upgraded client may still be served from the
263
+ // legacy cache file until the host-scoped one is first written.
264
+ const path = sdkCompatibilityCachePath(baseUrl);
265
+ const legacyPath = legacySdkCompatibilityCachePath();
266
+ const cachePath =
267
+ !existsSync(path) && existsSync(legacyPath) ? legacyPath : path;
268
+ if (!existsSync(cachePath)) return;
269
+ const existing = JSON.parse(
270
+ readFileSync(cachePath, 'utf8'),
271
+ ) as CompatCacheFile;
272
+ const entries = existing.entries ?? {};
273
+ delete entries[compatibilityCacheKey(baseUrl, command, skillsVersion)];
274
+ delete entries[legacyCompatibilityCacheKey(baseUrl, command)];
275
+ writeFileSync(cachePath, `${JSON.stringify({ entries }, null, 2)}\n`);
276
+ } catch {
277
+ // A cache that cannot be edited simply expires on its own TTL.
278
+ }
279
+ }
280
+
153
281
  function writeCachedCompatibility(
154
282
  baseUrl: string,
155
283
  command: string | null | undefined,
@@ -176,7 +304,12 @@ function writeCachedCompatibility(
176
304
 
177
305
  export async function checkSdkCompatibility(
178
306
  baseUrl: string,
179
- options: { command?: string | null; skillsVersion?: string | null } = {},
307
+ options: {
308
+ command?: string | null;
309
+ skillsVersion?: string | null;
310
+ /** Blocking budget for the live request; defaults to the full timeout. */
311
+ timeoutMs?: number;
312
+ } = {},
180
313
  ): Promise<{
181
314
  response: SdkCompatibilityResponse | null;
182
315
  error: Error | null;
@@ -185,7 +318,10 @@ export async function checkSdkCompatibility(
185
318
  return { response: null, error: null };
186
319
  }
187
320
  const controller = new AbortController();
188
- const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
321
+ const timeout = setTimeout(
322
+ () => controller.abort(),
323
+ options.timeoutMs ?? CHECK_TIMEOUT_MS,
324
+ );
189
325
  try {
190
326
  const url = new URL('/api/v2/sdk/compat', baseUrl);
191
327
  url.searchParams.set('version', SDK_VERSION);
@@ -209,14 +345,24 @@ export async function checkSdkCompatibility(
209
345
  const data = (await response
210
346
  .json()
211
347
  .catch(() => null)) as SdkCompatibilityResponse | null;
212
- if (data) {
213
- writeCachedCompatibility(
214
- baseUrl,
215
- options.command,
216
- options.skillsVersion,
217
- data,
348
+ // Only a policy-shaped body counts as a response. A JSON error page from
349
+ // a proxy is a failed check: it is never cached, and it falls through to
350
+ // the cached-policy fallback below like a network error would.
351
+ if (
352
+ !data ||
353
+ typeof data.ok !== 'boolean' ||
354
+ typeof data.status !== 'string'
355
+ ) {
356
+ throw new Error(
357
+ `SDK compatibility endpoint returned a non-policy response (HTTP ${response.status}).`,
218
358
  );
219
359
  }
360
+ writeCachedCompatibility(
361
+ baseUrl,
362
+ options.command,
363
+ options.skillsVersion,
364
+ data,
365
+ );
220
366
  return { response: data, error: null };
221
367
  } catch (error) {
222
368
  // Live compat policy must win when the server is reachable: rollback and
@@ -228,6 +374,16 @@ export async function checkSdkCompatibility(
228
374
  options.skillsVersion,
229
375
  );
230
376
  if (cached) {
377
+ if (
378
+ options.timeoutMs !== undefined &&
379
+ options.timeoutMs < CHECK_TIMEOUT_MS
380
+ ) {
381
+ invalidateCachedCompatibility(
382
+ baseUrl,
383
+ options.command,
384
+ options.skillsVersion,
385
+ );
386
+ }
231
387
  return { response: cached, error: null };
232
388
  }
233
389
  return {
@@ -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.113',
203
+ version: '0.3.115',
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: {
@@ -31,11 +31,37 @@ function readPluginSkillsVersion(): string {
31
31
  }
32
32
  }
33
33
 
34
+ /**
35
+ * Agent names can reach the CLI from `--agent`. Every state path derived from
36
+ * an agent name goes through this slug so no value can escape the SDK state
37
+ * directory.
38
+ */
39
+ /**
40
+ * Every agent an installer may write for. `*` targets all of them, so any
41
+ * coordination keyed by agent must treat `*` as this whole set.
42
+ */
43
+ export const KNOWN_SKILL_AGENTS = [
44
+ 'antigravity',
45
+ 'claude-code',
46
+ 'cline',
47
+ 'codex',
48
+ 'cursor',
49
+ 'gemini-cli',
50
+ 'windsurf',
51
+ ] as const;
52
+
53
+ export function skillsAgentPathSegment(agent: string): string {
54
+ if (agent === '*') return 'all';
55
+ const slug = agent.replace(/[^a-z0-9]+/gi, '-').replace(/^-+|-+$/g, '');
56
+ return slug || 'agent';
57
+ }
58
+
34
59
  function sdkSkillsVersionPath(
35
60
  baseUrl: string,
36
61
  agents: readonly string[] = [],
37
62
  ): string {
38
- const suffix = agents.length > 0 ? `-${agents.join('-')}` : '';
63
+ const suffix =
64
+ agents.length > 0 ? `-${agents.map(skillsAgentPathSegment).join('-')}` : '';
39
65
  return join(sdkCliStateDirPath(baseUrl), `skills${suffix}-version`);
40
66
  }
41
67
 
@@ -13,8 +13,8 @@ import {
13
13
  import type { SignalRadarInboundMessage } from '@deepline/monitors/signal-radars/inbound-message';
14
14
 
15
15
  // Public inbound-queue surface used by the thin provider-callback receiver.
16
- // Re-exports the topic + producer and adds the Neon-free publish key helper and
17
- // the retry classifier the receiver/worker share.
16
+ // The receiver stays on this established producer until the receipt dispatch
17
+ // endpoint is already serving in the preceding reader release.
18
18
  export const SIGNAL_RADAR_INBOUND_TOPIC = SIGNAL_RADAR_INBOUND_TOPIC_VALUE;
19
19
 
20
20
  function headersToObject(headers: Headers): Record<string, string> {
@@ -38,6 +38,10 @@ export async function sendSignalRadarInboundMessage(
38
38
  return sendSignalRadarInbound(message, options);
39
39
  }
40
40
 
41
+ // The reconciliation runner uses the same queue while this reader release
42
+ // waits for the signed receipt endpoint to be live.
43
+ export { send } from '@deepline/monitors/signal-radars/inbound-queue';
44
+
41
45
  // Transient (retry) vs permanent (dead-letter) classifier, shared with the
42
46
  // worker's retry callback. See classifyInboundFailure for the semantics.
43
47
  export function classifySignalRadarInboundError(