deepline 0.3.113 → 0.3.114

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 (48) 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/queue-health.ts +291 -6
  7. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +24 -24
  8. package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +2 -0
  9. package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +29 -1
  10. package/dist/bundling-sources/shared_libs/play-runtime/admission-transport-policy.ts +91 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +2 -0
  12. package/dist/bundling-sources/shared_libs/play-runtime/direct-admission-deadline.ts +34 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +1 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +325 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/play-admission-outcome.ts +134 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +13 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/index.ts +4 -1
  18. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +13 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/play-webhook-admission-probe.ts +32 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/play-webhook-identity.ts +28 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +7 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-cron-fire-task.ts +100 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +313 -0
  24. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +111 -3
  25. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +16 -0
  26. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +67 -8
  27. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +1394 -22
  28. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +74 -13
  29. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/submit-admission.ts +79 -15
  30. package/dist/bundling-sources/shared_libs/play-runtime/webhook-receipt-retry.ts +21 -21
  31. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +4 -1
  32. package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +64 -0
  33. package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +1 -1
  34. package/dist/bundling-sources/shared_libs/product-notifications/events.ts +20 -1
  35. package/dist/bundling-sources/shared_libs/security/receipt-admission-token.ts +224 -0
  36. package/dist/cli/index.js +574 -114
  37. package/dist/cli/index.mjs +592 -133
  38. package/dist/index.d.mts +54 -1
  39. package/dist/index.d.ts +54 -1
  40. package/dist/index.js +8 -3
  41. package/dist/index.mjs +8 -3
  42. package/dist/install-integrity.json +7 -0
  43. package/dist/plays/bundle-play-file.mjs +1 -1
  44. package/dist/release.d.mts +1 -1
  45. package/dist/release.d.ts +1 -1
  46. package/dist/release.js +1 -1
  47. package/dist/release.mjs +1 -1
  48. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -1298,7 +1298,7 @@ var SDK_RELEASE = {
1298
1298
  // getters keep their established compatibility behavior.
1299
1299
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
1300
1300
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
1301
- version: "0.3.113",
1301
+ version: "0.3.114",
1302
1302
  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.",
1303
1303
  packageCapabilities: {
1304
1304
  updatePreferences: 1
@@ -1514,8 +1514,22 @@ function readPluginSkillsVersion() {
1514
1514
  return "";
1515
1515
  }
1516
1516
  }
1517
+ var KNOWN_SKILL_AGENTS = [
1518
+ "antigravity",
1519
+ "claude-code",
1520
+ "cline",
1521
+ "codex",
1522
+ "cursor",
1523
+ "gemini-cli",
1524
+ "windsurf"
1525
+ ];
1526
+ function skillsAgentPathSegment(agent) {
1527
+ if (agent === "*") return "all";
1528
+ const slug = agent.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "");
1529
+ return slug || "agent";
1530
+ }
1517
1531
  function sdkSkillsVersionPath(baseUrl, agents = []) {
1518
- const suffix = agents.length > 0 ? `-${agents.join("-")}` : "";
1532
+ const suffix = agents.length > 0 ? `-${agents.map(skillsAgentPathSegment).join("-")}` : "";
1519
1533
  return (0, import_node_path2.join)(sdkCliStateDirPath(baseUrl), `skills${suffix}-version`);
1520
1534
  }
1521
1535
  function legacySdkSkillsVersionPath(baseUrl) {
@@ -4847,7 +4861,7 @@ function resolveToolExecuteTimeoutMs(toolId, input2) {
4847
4861
  if (usesExtendedBetterContactLauncherBudget(normalized)) {
4848
4862
  return BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS;
4849
4863
  }
4850
- return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
4864
+ return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "ai_evaluate" || normalized === "deeplineagent_ai_evaluate" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
4851
4865
  }
4852
4866
  var RUNS_FAILED_LOG_LIMIT = 20;
4853
4867
  var RUN_LOGS_PAGE_LIMIT = 1e3;
@@ -8196,7 +8210,9 @@ var import_node_fs3 = require("fs");
8196
8210
  var import_node_os3 = require("os");
8197
8211
  var import_node_path3 = require("path");
8198
8212
  var CHECK_TIMEOUT_MS = 2e3;
8199
- var SDK_COMPATIBILITY_CACHE_TTL_MS = 5 * 60 * 1e3;
8213
+ var SDK_COMPATIBILITY_TRUST_MS = 10 * 60 * 1e3;
8214
+ var SDK_COMPATIBILITY_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
8215
+ var SDK_COMPATIBILITY_FAST_DEADLINE_MS = 400;
8200
8216
  function shouldSkipCompatibilityCheck() {
8201
8217
  const value = process.env.DEEPLINE_SKIP_SDK_COMPAT_CHECK?.trim().toLowerCase();
8202
8218
  return value === "1" || value === "true" || value === "yes";
@@ -8225,7 +8241,29 @@ function legacyCompatibilityCacheKey(baseUrl, command) {
8225
8241
  command: command?.trim() || null
8226
8242
  });
8227
8243
  }
8244
+ function isCleanCompatibilityPolicy(response) {
8245
+ if (!response) return false;
8246
+ return response.ok === true && response.update_required !== true && response.status !== "unsupported" && !response.auto_update?.should_auto_update && !response.cli_family;
8247
+ }
8248
+ function readFreshCleanCompatibility(baseUrl, command, skillsVersion) {
8249
+ const cached = readCachedCompatibility(baseUrl, command, skillsVersion);
8250
+ return isCleanCompatibilityPolicy(cached) ? cached : null;
8251
+ }
8252
+ function readTrustedCleanCompatibility(baseUrl, command, skillsVersion, now = Date.now()) {
8253
+ const entry = readCachedCompatibilityEntry(baseUrl, command, skillsVersion);
8254
+ if (!entry || !isSavedWithin(entry.savedAt, SDK_COMPATIBILITY_TRUST_MS, now))
8255
+ return null;
8256
+ return isCleanCompatibilityPolicy(entry.response) ? entry.response : null;
8257
+ }
8258
+ function isSavedWithin(savedAt, windowMs, now) {
8259
+ if (typeof savedAt !== "number") return false;
8260
+ const age = now - savedAt;
8261
+ return Number.isFinite(age) && age >= 0 && age <= windowMs;
8262
+ }
8228
8263
  function readCachedCompatibility(baseUrl, command, skillsVersion) {
8264
+ return readCachedCompatibilityEntry(baseUrl, command, skillsVersion)?.response ?? null;
8265
+ }
8266
+ function readCachedCompatibilityEntry(baseUrl, command, skillsVersion) {
8229
8267
  try {
8230
8268
  const path = sdkCompatibilityCachePath(baseUrl);
8231
8269
  const legacyPath = legacySdkCompatibilityCachePath();
@@ -8238,14 +8276,31 @@ function readCachedCompatibility(baseUrl, command, skillsVersion) {
8238
8276
  (0, import_node_fs3.readFileSync)(cachePath, "utf8")
8239
8277
  );
8240
8278
  const entry = parsed.entries?.[compatibilityCacheKey(baseUrl, command, skillsVersion)] ?? (useLegacyCache ? parsed.entries?.[legacyCompatibilityCacheKey(baseUrl, command)] : void 0);
8241
- if (!entry || Date.now() - entry.savedAt > SDK_COMPATIBILITY_CACHE_TTL_MS) {
8279
+ if (!entry || !isSavedWithin(entry.savedAt, SDK_COMPATIBILITY_CACHE_TTL_MS, Date.now())) {
8242
8280
  return null;
8243
8281
  }
8244
- return entry.response;
8282
+ return entry;
8245
8283
  } catch {
8246
8284
  return null;
8247
8285
  }
8248
8286
  }
8287
+ function invalidateCachedCompatibility(baseUrl, command, skillsVersion) {
8288
+ try {
8289
+ const path = sdkCompatibilityCachePath(baseUrl);
8290
+ const legacyPath = legacySdkCompatibilityCachePath();
8291
+ const cachePath = !(0, import_node_fs3.existsSync)(path) && (0, import_node_fs3.existsSync)(legacyPath) ? legacyPath : path;
8292
+ if (!(0, import_node_fs3.existsSync)(cachePath)) return;
8293
+ const existing = JSON.parse(
8294
+ (0, import_node_fs3.readFileSync)(cachePath, "utf8")
8295
+ );
8296
+ const entries = existing.entries ?? {};
8297
+ delete entries[compatibilityCacheKey(baseUrl, command, skillsVersion)];
8298
+ delete entries[legacyCompatibilityCacheKey(baseUrl, command)];
8299
+ (0, import_node_fs3.writeFileSync)(cachePath, `${JSON.stringify({ entries }, null, 2)}
8300
+ `);
8301
+ } catch {
8302
+ }
8303
+ }
8249
8304
  function writeCachedCompatibility(baseUrl, command, skillsVersion, response) {
8250
8305
  try {
8251
8306
  const path = sdkCompatibilityCachePath(baseUrl);
@@ -8266,7 +8321,10 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
8266
8321
  return { response: null, error: null };
8267
8322
  }
8268
8323
  const controller = new AbortController();
8269
- const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
8324
+ const timeout = setTimeout(
8325
+ () => controller.abort(),
8326
+ options.timeoutMs ?? CHECK_TIMEOUT_MS
8327
+ );
8270
8328
  try {
8271
8329
  const url = new URL("/api/v2/sdk/compat", baseUrl);
8272
8330
  url.searchParams.set("version", SDK_VERSION);
@@ -8288,14 +8346,17 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
8288
8346
  signal: controller.signal
8289
8347
  });
8290
8348
  const data = await response.json().catch(() => null);
8291
- if (data) {
8292
- writeCachedCompatibility(
8293
- baseUrl,
8294
- options.command,
8295
- options.skillsVersion,
8296
- data
8349
+ if (!data || typeof data.ok !== "boolean" || typeof data.status !== "string") {
8350
+ throw new Error(
8351
+ `SDK compatibility endpoint returned a non-policy response (HTTP ${response.status}).`
8297
8352
  );
8298
8353
  }
8354
+ writeCachedCompatibility(
8355
+ baseUrl,
8356
+ options.command,
8357
+ options.skillsVersion,
8358
+ data
8359
+ );
8299
8360
  return { response: data, error: null };
8300
8361
  } catch (error) {
8301
8362
  const cached = readCachedCompatibility(
@@ -8304,6 +8365,13 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
8304
8365
  options.skillsVersion
8305
8366
  );
8306
8367
  if (cached) {
8368
+ if (options.timeoutMs !== void 0 && options.timeoutMs < CHECK_TIMEOUT_MS) {
8369
+ invalidateCachedCompatibility(
8370
+ baseUrl,
8371
+ options.command,
8372
+ options.skillsVersion
8373
+ );
8374
+ }
8307
8375
  return { response: cached, error: null };
8308
8376
  }
8309
8377
  return {
@@ -35109,7 +35177,19 @@ function renderMonitorGet(payload) {
35109
35177
  const field = asRecord2(value);
35110
35178
  const path = asString(field?.path);
35111
35179
  const description = asString(field?.description);
35112
- return path ? [{ path, description }] : [];
35180
+ const semantics = asString(field?.semantics);
35181
+ const applicability = asString(field?.applicability);
35182
+ const grammar = asRecord2(field?.grammar);
35183
+ const grammarSyntax = asString(grammar?.syntax);
35184
+ return path ? [
35185
+ {
35186
+ path,
35187
+ description,
35188
+ semantics,
35189
+ applicability,
35190
+ grammarSyntax
35191
+ }
35192
+ ] : [];
35113
35193
  }) : [];
35114
35194
  if (specFields.length > 0) {
35115
35195
  lines.push("", "Monitor spec:");
@@ -35117,6 +35197,15 @@ function renderMonitorGet(payload) {
35117
35197
  lines.push(
35118
35198
  ` ${field.path}${field.description ? ` \u2014 ${field.description}` : ""}`
35119
35199
  );
35200
+ if (field.semantics && field.semantics !== field.description) {
35201
+ lines.push(` Behavior: ${field.semantics}`);
35202
+ }
35203
+ if (field.applicability) {
35204
+ lines.push(` Applies to: ${field.applicability}`);
35205
+ }
35206
+ if (field.grammarSyntax) {
35207
+ lines.push(` Format: ${field.grammarSyntax}`);
35208
+ }
35120
35209
  }
35121
35210
  }
35122
35211
  lines.push("", `Current SQL listener consumers (${boundPlays.length}):`);
@@ -35881,8 +35970,10 @@ Notes:
35881
35970
  Read-only. Returns the exact editable definition, selected Deepline pricing,
35882
35971
  billing state, output streams, dependent published plays, and monitor_spec.
35883
35972
  When monitor_spec.available is true, its fields describe the deployed type's
35884
- editable fields and constraints; otherwise use the stored definition and check
35885
- before proposing an update so scope and downstream effects are visible.
35973
+ editable fields, constraints, and provider-specific behavior. For TAMRadar,
35974
+ this includes the effective updates_since precision and engagement timing
35975
+ rules. Otherwise use the stored definition and check before proposing an
35976
+ update so scope and downstream effects are visible.
35886
35977
 
35887
35978
  Examples:
35888
35979
  deepline monitors get my-monitor --json
@@ -38608,7 +38699,6 @@ async function maybeReportSdkCliFailure(input2) {
38608
38699
 
38609
38700
  // src/cli/skills-sync.ts
38610
38701
  var CHECK_TIMEOUT_MS2 = 3e3;
38611
- var SKILLS_SYNC_CLAIM_MAX_AGE_MS = 60 * 60 * 1e3;
38612
38702
  function shouldSkipSkillsSync() {
38613
38703
  if (detectAgentRuntime() === "claude_cowork") {
38614
38704
  return true;
@@ -38619,65 +38709,286 @@ function shouldSkipSkillsSync() {
38619
38709
  function unavailableSkillsNoticePath(baseUrl) {
38620
38710
  return (0, import_node_path20.join)(sdkCliStateDirPath(baseUrl), "skills-sync-unavailable-version");
38621
38711
  }
38622
- function failedSkillsSyncPath(baseUrl, agents) {
38712
+ var SKILLS_SYNC_IN_PROGRESS_TTL_MS = 10 * 60 * 1e3;
38713
+ var SKILLS_SYNC_IN_PROGRESS_PID_CAP_MS = 6 * 60 * 60 * 1e3;
38714
+ var agentLeaseSegment = skillsAgentPathSegment;
38715
+ function sortedLeaseAgents(agents) {
38716
+ const expanded = agents.includes("*") ? [...agents, ...KNOWN_SKILL_AGENTS] : agents;
38717
+ return [...new Set(expanded)].sort((a, b) => a.localeCompare(b));
38718
+ }
38719
+ function inProgressSkillsSyncPath(baseUrl, agent) {
38623
38720
  return (0, import_node_path20.join)(
38624
38721
  sdkCliStateDirPath(baseUrl),
38625
- `skills-sync-failed-${agents.join("-")}-version`
38722
+ `skills-sync-in-progress-${agentLeaseSegment(agent)}`
38626
38723
  );
38627
38724
  }
38628
- function inProgressSkillsSyncPath(baseUrl, agents) {
38629
- return (0, import_node_path20.join)(
38630
- sdkCliStateDirPath(baseUrl),
38631
- `skills-sync-in-progress-${agents.join("-")}`
38725
+ function readInProgressSkillsSyncLeaseFromDir(dir) {
38726
+ const claim = readMarkedSkillsSyncVersion((0, import_node_path20.join)(dir, "claim"));
38727
+ const [version = "", startedAt = ""] = claim.split(" ");
38728
+ const pidRaw = readMarkedSkillsSyncVersion((0, import_node_path20.join)(dir, "pid"));
38729
+ return {
38730
+ claimToken: version && startedAt ? `${version} ${startedAt}` : "",
38731
+ version,
38732
+ startedAt: Number(startedAt),
38733
+ pid: /^\d+$/.test(pidRaw) ? Number(pidRaw) : null,
38734
+ owner: readMarkedSkillsSyncVersion((0, import_node_path20.join)(dir, "owner"))
38735
+ };
38736
+ }
38737
+ function readInProgressSkillsSyncLease(baseUrl, agent) {
38738
+ return readInProgressSkillsSyncLeaseFromDir(
38739
+ inProgressSkillsSyncPath(baseUrl, agent)
38632
38740
  );
38633
38741
  }
38634
- function removeSkillsSyncClaim(path, token) {
38742
+ function readInProgressSkillsSyncLeases(baseUrl, agents) {
38743
+ return new Map(
38744
+ sortedLeaseAgents(agents).map((agent) => [
38745
+ agent,
38746
+ readInProgressSkillsSyncLease(baseUrl, agent)
38747
+ ])
38748
+ );
38749
+ }
38750
+ var UNRESOLVED_SKILLS_CLAIM_VERSION = "unresolved";
38751
+ function claimedSkillsVersion(leases) {
38752
+ for (const lease of leases.values()) {
38753
+ if (lease.version && lease.version !== UNRESOLVED_SKILLS_CLAIM_VERSION) {
38754
+ return lease.version;
38755
+ }
38756
+ }
38757
+ return "";
38758
+ }
38759
+ function isProcessAlive(pid) {
38635
38760
  try {
38636
- (0, import_node_fs18.unlinkSync)((0, import_node_path20.join)(path, token));
38637
- (0, import_node_fs18.rmdirSync)(path);
38638
- } catch {
38761
+ process.kill(pid, 0);
38762
+ return true;
38763
+ } catch (error) {
38764
+ return error.code === "EPERM";
38639
38765
  }
38640
38766
  }
38641
- function claimSkillsSync(baseUrl, agents) {
38642
- const path = inProgressSkillsSyncPath(baseUrl, agents);
38767
+ function isFreshInProgressSkillsSync(lease, now = Date.now()) {
38768
+ if (!Number.isFinite(lease.startedAt)) return false;
38769
+ const age = now - lease.startedAt;
38770
+ if (age < 0) return false;
38771
+ if (lease.pid !== null && isProcessAlive(lease.pid)) {
38772
+ return age < SKILLS_SYNC_IN_PROGRESS_PID_CAP_MS;
38773
+ }
38774
+ return age < SKILLS_SYNC_IN_PROGRESS_TTL_MS;
38775
+ }
38776
+ function quarantine(path, tag) {
38777
+ const holding = `${path}.${tag}-${process.pid}-${Date.now()}`;
38643
38778
  try {
38644
- (0, import_node_fs18.mkdirSync)((0, import_node_path20.dirname)(path), { recursive: true });
38779
+ (0, import_node_fs18.renameSync)(path, holding);
38780
+ return holding;
38645
38781
  } catch {
38646
- return { status: "unavailable" };
38782
+ return null;
38647
38783
  }
38648
- const token = (0, import_node_crypto10.randomUUID)();
38649
- for (let attempt = 0; attempt < 2; attempt += 1) {
38650
- const pendingPath = `${path}-pending-${token}`;
38784
+ }
38785
+ function claimOneInProgressSkillsSync(baseUrl, remoteVersion, agent, owner) {
38786
+ const dir = inProgressSkillsSyncPath(baseUrl, agent);
38787
+ const errorCode = (error) => error.code;
38788
+ const create = () => {
38789
+ const claimToken = `${remoteVersion} ${Date.now()}`;
38790
+ const staging = `${dir}.staging-${process.pid}-${Date.now()}`;
38791
+ (0, import_node_fs18.mkdirSync)(staging);
38792
+ (0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(staging, "claim"), `${claimToken}
38793
+ `, "utf-8");
38794
+ (0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(staging, "owner"), `${owner}
38795
+ `, "utf-8");
38651
38796
  try {
38652
- (0, import_node_fs18.mkdirSync)(pendingPath);
38653
- (0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(pendingPath, token), "", { flag: "wx" });
38654
- (0, import_node_fs18.renameSync)(pendingPath, path);
38655
- return { status: "claimed", token };
38656
- } catch {
38657
- removeSkillsSyncClaim(pendingPath, token);
38658
- if (!(0, import_node_fs18.existsSync)(path)) continue;
38797
+ (0, import_node_fs18.renameSync)(staging, dir);
38798
+ } catch (error) {
38799
+ (0, import_node_fs18.rmSync)(staging, { recursive: true, force: true });
38800
+ const code = errorCode(error);
38801
+ const err = new Error("lease directory already exists");
38802
+ err.code = code === "EEXIST" || code === "ENOTEMPTY" ? "EEXIST" : String(code ?? "");
38803
+ throw err;
38804
+ }
38805
+ return { state: "claimed", claimToken };
38806
+ };
38807
+ try {
38808
+ (0, import_node_fs18.mkdirSync)((0, import_node_path20.dirname)(dir), { recursive: true });
38809
+ return create();
38810
+ } catch (error) {
38811
+ if (errorCode(error) !== "EEXIST") return { state: "unavailable" };
38812
+ }
38813
+ if (isFreshInProgressSkillsSync(readInProgressSkillsSyncLease(baseUrl, agent))) {
38814
+ return { state: "held" };
38815
+ }
38816
+ const tombstone = quarantine(dir, "stale");
38817
+ if (!tombstone) {
38818
+ return { state: "held" };
38819
+ }
38820
+ (0, import_node_fs18.rmSync)(tombstone, { recursive: true, force: true });
38821
+ try {
38822
+ return create();
38823
+ } catch (error) {
38824
+ return errorCode(error) === "EEXIST" ? { state: "held" } : { state: "unavailable" };
38825
+ }
38826
+ }
38827
+ function claimInProgressSkillsSync(baseUrl, remoteVersion, agents) {
38828
+ const claimTokens = /* @__PURE__ */ new Map();
38829
+ const owner = (0, import_node_crypto10.randomUUID)();
38830
+ for (const agent of sortedLeaseAgents(agents)) {
38831
+ const claim = claimOneInProgressSkillsSync(
38832
+ baseUrl,
38833
+ remoteVersion,
38834
+ agent,
38835
+ owner
38836
+ );
38837
+ if (claim.state !== "claimed") {
38838
+ releaseInProgressSkillsSync(baseUrl, claimTokens);
38839
+ return { state: claim.state };
38840
+ }
38841
+ claimTokens.set(agent, claim.claimToken);
38842
+ }
38843
+ return { state: "claimed", claimTokens, owner };
38844
+ }
38845
+ function claimAndSpawnDetachedSkillsSync(baseUrl, agents, remoteVersion, spawnDetached) {
38846
+ const claim = claimInProgressSkillsSync(baseUrl, remoteVersion, agents);
38847
+ if (claim.state !== "claimed") return claim.state;
38848
+ const { claimTokens, owner } = claim;
38849
+ spawnDetached([SKILLS_AUTO_SYNC_COMMAND, "--claim", owner], () => {
38850
+ releaseInProgressSkillsSync(baseUrl, claimTokens);
38851
+ if (remoteVersion !== UNRESOLVED_SKILLS_CLAIM_VERSION) {
38852
+ markFailedSkillsSync(baseUrl, remoteVersion, agents);
38659
38853
  }
38660
- if (attempt > 0) return { status: "held" };
38854
+ deferSkillsNotice(
38855
+ baseUrl,
38856
+ agents
38857
+ )(
38858
+ "Deepline skills refresh failed to start; run `deepline skills` to retry."
38859
+ );
38860
+ });
38861
+ return "claimed";
38862
+ }
38863
+ function recordOwnPidOnInProgressSkillsSync(baseUrl, leases) {
38864
+ for (const [agent, lease] of leases) {
38865
+ if (!lease.claimToken) continue;
38661
38866
  try {
38662
- if (Date.now() - (0, import_node_fs18.statSync)(path).mtimeMs <= SKILLS_SYNC_CLAIM_MAX_AGE_MS) {
38663
- return { status: "held" };
38867
+ (0, import_node_fs18.writeFileSync)(
38868
+ (0, import_node_path20.join)(inProgressSkillsSyncPath(baseUrl, agent), "pid"),
38869
+ `${process.pid}
38870
+ `,
38871
+ "utf-8"
38872
+ );
38873
+ } catch {
38874
+ }
38875
+ }
38876
+ }
38877
+ function releaseInProgressSkillsSync(baseUrl, claimTokens) {
38878
+ for (const [agent, claimToken] of claimTokens) {
38879
+ const dir = inProgressSkillsSyncPath(baseUrl, agent);
38880
+ if (!claimToken) {
38881
+ try {
38882
+ (0, import_node_fs18.rmSync)(dir, { recursive: true, force: true });
38883
+ } catch {
38664
38884
  }
38665
- const owners = (0, import_node_fs18.readdirSync)(path);
38666
- if (owners.length === 0) {
38667
- (0, import_node_fs18.rmdirSync)(path);
38885
+ continue;
38886
+ }
38887
+ const tombstone = quarantine(dir, "release");
38888
+ if (!tombstone) continue;
38889
+ try {
38890
+ if (readInProgressSkillsSyncLeaseFromDir(tombstone).claimToken !== claimToken) {
38891
+ (0, import_node_fs18.renameSync)(tombstone, dir);
38668
38892
  continue;
38669
38893
  }
38670
- if (owners.length !== 1) return { status: "held" };
38671
- (0, import_node_fs18.renameSync)(path, `${path}-stale-${owners[0]}`);
38672
38894
  } catch {
38673
- return { status: "held" };
38895
+ }
38896
+ (0, import_node_fs18.rmSync)(tombstone, { recursive: true, force: true });
38897
+ }
38898
+ }
38899
+ function claimTokensOf(leases) {
38900
+ return new Map(
38901
+ [...leases].map(([agent, lease]) => [agent, lease.claimToken])
38902
+ );
38903
+ }
38904
+ async function acquireSkillsInstallLease(baseUrl, agents, version, options = {
38905
+ waitMs: 9e4
38906
+ }) {
38907
+ const pollMs = options.pollMs ?? 250;
38908
+ const deadline = Date.now() + options.waitMs;
38909
+ let waited = false;
38910
+ for (; ; ) {
38911
+ const claim = claimInProgressSkillsSync(baseUrl, version, agents);
38912
+ if (claim.state === "unavailable") {
38913
+ return { release: () => {
38914
+ } };
38915
+ }
38916
+ if (claim.state === "claimed") {
38917
+ recordOwnPidOnInProgressSkillsSync(
38918
+ baseUrl,
38919
+ readInProgressSkillsSyncLeases(baseUrl, agents)
38920
+ );
38921
+ return {
38922
+ release: () => releaseInProgressSkillsSync(baseUrl, claim.claimTokens)
38923
+ };
38924
+ }
38925
+ if (Date.now() >= deadline) return null;
38926
+ if (!waited) {
38927
+ waited = true;
38928
+ options.onWait?.();
38929
+ }
38930
+ await new Promise((resolve21) => setTimeout(resolve21, pollMs));
38931
+ }
38932
+ }
38933
+ function skillsInstallLeasePath(baseUrl, agents) {
38934
+ return sortedLeaseAgents(agents).map((agent) => inProgressSkillsSyncPath(baseUrl, agent)).join(", ");
38935
+ }
38936
+ function deferredSkillsNoticePath(baseUrl, agents) {
38937
+ return (0, import_node_path20.join)(
38938
+ sdkCliStateDirPath(baseUrl),
38939
+ `skills-sync-notice-${sortedLeaseAgents(agents).map(agentLeaseSegment).join("-")}`
38940
+ );
38941
+ }
38942
+ function deferSkillsNotice(baseUrl, agents) {
38943
+ const path = deferredSkillsNoticePath(baseUrl, agents);
38944
+ return (text) => {
38945
+ try {
38946
+ (0, import_node_fs18.mkdirSync)((0, import_node_path20.dirname)(path), { recursive: true });
38947
+ (0, import_node_fs18.appendFileSync)(path, `${text.trimEnd()}
38948
+ `, "utf-8");
38949
+ } catch {
38950
+ }
38951
+ };
38952
+ }
38953
+ function flushDeferredSkillsNotices(baseUrl, agents) {
38954
+ const path = deferredSkillsNoticePath(baseUrl, agents);
38955
+ if (!(0, import_node_fs18.existsSync)(path)) return;
38956
+ const tombstone = quarantine(path, "consuming");
38957
+ if (!tombstone) return;
38958
+ let text = "";
38959
+ try {
38960
+ text = (0, import_node_fs18.readFileSync)(tombstone, "utf-8");
38961
+ } catch {
38962
+ return;
38963
+ } finally {
38964
+ try {
38965
+ (0, import_node_fs18.unlinkSync)(tombstone);
38966
+ } catch {
38674
38967
  }
38675
38968
  }
38676
- return { status: "held" };
38969
+ if (text.trim()) writeSdkSkillsStatusLine(text.trimEnd());
38677
38970
  }
38678
- function clearSkillsSyncClaim(baseUrl, agents, token) {
38679
- const path = inProgressSkillsSyncPath(baseUrl, agents);
38680
- removeSkillsSyncClaim(path, token);
38971
+ function flushDeferredSkillsSyncNotices(baseUrl) {
38972
+ if (shouldSkipSkillsSync() || hasActivePluginSkills()) return;
38973
+ const agents = resolveAutoSyncSkillAgents();
38974
+ if (agents.length === 0) return;
38975
+ flushDeferredSkillsNotices(baseUrl, agents);
38976
+ }
38977
+ var SKILLS_AUTO_SYNC_COMMAND = "skills-auto-sync";
38978
+ function spawnDetachedSkillsSyncChild(argv, onSpawnError) {
38979
+ const child = (0, import_node_child_process2.spawn)(process.execPath, [process.argv[1] ?? "", ...argv], {
38980
+ detached: true,
38981
+ stdio: "ignore",
38982
+ env: process.env
38983
+ });
38984
+ child.on("error", () => onSpawnError?.());
38985
+ child.unref();
38986
+ }
38987
+ function failedSkillsSyncPath(baseUrl, agents) {
38988
+ return (0, import_node_path20.join)(
38989
+ sdkCliStateDirPath(baseUrl),
38990
+ `skills-sync-failed-${agents.map(agentLeaseSegment).join("-")}-version`
38991
+ );
38681
38992
  }
38682
38993
  function hasMarkedSkillsSyncVersion(path, version) {
38683
38994
  return Boolean(version) && readMarkedSkillsSyncVersion(path) === version;
@@ -38699,12 +39010,12 @@ function writeMarkedSkillsSyncVersion(path, version) {
38699
39010
  return false;
38700
39011
  }
38701
39012
  }
38702
- function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames) {
39013
+ function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames, notice = writeSdkSkillsStatusLine) {
38703
39014
  const path = unavailableSkillsNoticePath(baseUrl);
38704
39015
  if (hasMarkedSkillsSyncVersion(path, remoteVersion)) return;
38705
39016
  writeMarkedSkillsSyncVersion(path, remoteVersion);
38706
39017
  const manualCommand = `npx ${buildSkillsInstallArgs(baseUrl, skillNames).join(" ")}`;
38707
- writeSdkSkillsStatusLine(
39018
+ notice(
38708
39019
  `Deepline agent skills are out of date, but neither \`bunx\` nor \`npx\` is available. Install Node.js/npm or Bun, then run:
38709
39020
  ${manualCommand}`
38710
39021
  );
@@ -38889,7 +39200,7 @@ function runOneSkillsInstall(install) {
38889
39200
  });
38890
39201
  });
38891
39202
  }
38892
- async function runSkillsInstall(installs, agents) {
39203
+ async function runSkillsInstall(installs, agents, notice = writeSdkSkillsStatusLine) {
38893
39204
  const failures = [];
38894
39205
  for (const install of installs) {
38895
39206
  const result = await runOneSkillsInstall(install);
@@ -38899,15 +39210,14 @@ async function runSkillsInstall(installs, agents) {
38899
39210
  const details = failures.map((failure) => failure.detail).filter(Boolean).join("\n");
38900
39211
  const attemptedCommands = failures.map((failure) => ` ${failure.manualCommand}`).join("\n");
38901
39212
  const retryAgent = agents.at(0);
38902
- process.stderr.write(
39213
+ notice(
38903
39214
  `Deepline agent-skills refresh failed for ${agents.join(", ")}. The Deepline command will continue; this only affects optional local agent instructions, not authentication, data, or billing.
38904
39215
  ` + (attemptedCommands ? `Attempted installer command${failures.length === 1 ? "" : "s"}:
38905
39216
  ${attemptedCommands}
38906
39217
  ` : "") + (details ? `Installer output:
38907
39218
  ${details}
38908
39219
  ` : "") + (retryAgent ? `To retry with full installer output: deepline skills --agent ${retryAgent} --json
38909
- ` : "") + `To temporarily suppress automatic skills sync: ${temporarySkillsSyncSkipCommand()}
38910
- `
39220
+ ` : "") + `To temporarily suppress automatic skills sync: ${temporarySkillsSyncSkipCommand()}`
38911
39221
  );
38912
39222
  return {
38913
39223
  installed: false,
@@ -38982,72 +39292,132 @@ async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
38982
39292
  if (usingPluginSkills) {
38983
39293
  return;
38984
39294
  }
38985
- const localVersion = readSdkSkillsLocalVersion(baseUrl);
38986
- const update = options.update === void 0 ? await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
38987
- needsUpdate: options.update.needs_update,
38988
- remoteVersion: options.update.remote.version
38989
- } : null;
38990
- if (!update?.needsUpdate || !update.remoteVersion) {
38991
- return;
38992
- }
38993
39295
  const agents = resolveAutoSyncSkillAgents();
38994
- if (agents.length > 0 && hasFailedSkillsSync(baseUrl, update.remoteVersion, agents)) {
39296
+ if (options.mode === "detached" && agents.length > 0) {
39297
+ flushDeferredSkillsNotices(baseUrl, agents);
39298
+ }
39299
+ const ownsInProgressMarker = options.mode !== "detached" && agents.length > 0 && Boolean(options.claim);
39300
+ const leases = ownsInProgressMarker ? readInProgressSkillsSyncLeases(baseUrl, agents) : null;
39301
+ if (leases && [...leases.values()].some((lease) => lease.owner !== options.claim)) {
38995
39302
  return;
38996
39303
  }
39304
+ if (leases) recordOwnPidOnInProgressSkillsSync(baseUrl, leases);
39305
+ const claimedVersion = leases ? claimedSkillsVersion(leases) : "";
39306
+ if (options.mode === "detached" && agents.length > 0 && options.update === void 0 && !claimedVersion) {
39307
+ const outcome = claimAndSpawnDetachedSkillsSync(
39308
+ baseUrl,
39309
+ agents,
39310
+ UNRESOLVED_SKILLS_CLAIM_VERSION,
39311
+ options.spawnDetached ?? spawnDetachedSkillsSyncChild
39312
+ );
39313
+ if (outcome !== "unavailable") return;
39314
+ }
39315
+ try {
39316
+ const localVersion = readSdkSkillsLocalVersion(baseUrl);
39317
+ const update = options.update === void 0 ? claimedVersion ? { needsUpdate: true, remoteVersion: claimedVersion } : await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
39318
+ needsUpdate: options.update.needs_update,
39319
+ remoteVersion: options.update.remote.version
39320
+ } : null;
39321
+ if (!update?.needsUpdate || !update.remoteVersion) {
39322
+ return;
39323
+ }
39324
+ if (agents.length > 0 && hasFailedSkillsSync(baseUrl, update.remoteVersion, agents)) {
39325
+ return;
39326
+ }
39327
+ if (options.mode === "detached" && agents.length === 0) {
39328
+ writeUnavailableSkillsNotice(
39329
+ baseUrl,
39330
+ update.remoteVersion,
39331
+ buildSdkSkillNames(DEFAULT_SDK_SKILL_NAMES)
39332
+ );
39333
+ return;
39334
+ }
39335
+ if (options.mode === "detached" && agents.length > 0) {
39336
+ const outcome = claimAndSpawnDetachedSkillsSync(
39337
+ baseUrl,
39338
+ agents,
39339
+ update.remoteVersion,
39340
+ options.spawnDetached ?? spawnDetachedSkillsSyncChild
39341
+ );
39342
+ if (outcome === "held") return;
39343
+ if (outcome === "claimed") {
39344
+ writeSdkSkillsStatusLine(
39345
+ "Deepline skills changed; refreshing agent skills in the background."
39346
+ );
39347
+ return;
39348
+ }
39349
+ }
39350
+ await runInlineSkillsSync(
39351
+ baseUrl,
39352
+ update.remoteVersion,
39353
+ agents,
39354
+ options.notices ?? "print"
39355
+ );
39356
+ } finally {
39357
+ if (leases) {
39358
+ releaseInProgressSkillsSync(baseUrl, claimTokensOf(leases));
39359
+ }
39360
+ }
39361
+ }
39362
+ async function runInlineSkillsSync(baseUrl, remoteVersion, agents, notices) {
39363
+ const update = { remoteVersion };
39364
+ const notice = notices === "defer" ? deferSkillsNotice(baseUrl, agents) : writeSdkSkillsStatusLine;
38997
39365
  const remoteSkillNames = await fetchV1SkillNames(baseUrl);
38998
39366
  const skillNames = buildSdkSkillNames(
38999
39367
  remoteSkillNames.length > 0 ? remoteSkillNames : DEFAULT_SDK_SKILL_NAMES
39000
39368
  );
39001
39369
  if (skillNames.length === 0) return;
39002
39370
  if (agents.length === 0) {
39003
- writeUnavailableSkillsNotice(baseUrl, update.remoteVersion, skillNames);
39371
+ writeUnavailableSkillsNotice(
39372
+ baseUrl,
39373
+ update.remoteVersion,
39374
+ skillNames,
39375
+ notice
39376
+ );
39004
39377
  return;
39005
39378
  }
39006
39379
  const installs = resolveSkillsInstallCommands(baseUrl, skillNames, agents);
39007
39380
  if (installs.length === 0) {
39008
- writeUnavailableSkillsNotice(baseUrl, update.remoteVersion, skillNames);
39381
+ writeUnavailableSkillsNotice(
39382
+ baseUrl,
39383
+ update.remoteVersion,
39384
+ skillNames,
39385
+ notice
39386
+ );
39009
39387
  return;
39010
39388
  }
39011
- const claim = claimSkillsSync(baseUrl, agents);
39012
- if (claim.status === "held") return;
39013
- try {
39014
- if (hasFailedSkillsSync(baseUrl, update.remoteVersion, agents) || readSdkSkillsLocalVersion(baseUrl) === update.remoteVersion) {
39015
- return;
39016
- }
39389
+ if (notices === "print") {
39017
39390
  writeSdkSkillsStatusLine(
39018
39391
  "Deepline skills changed; syncing agent skills..."
39019
39392
  );
39020
- const installResult = await runSkillsInstall(installs, agents);
39021
- if (!installResult.installed) {
39022
- const markerWritten = markFailedSkillsSync(
39023
- baseUrl,
39024
- update.remoteVersion,
39025
- agents
39026
- );
39027
- void maybeReportAutomaticSkillsSyncFailure({
39028
- baseUrl,
39029
- remoteSkillsVersion: update.remoteVersion,
39030
- agents,
39031
- skillsPackage: SKILLS_NPX_PACKAGE,
39032
- targetSkillCount: skillNames.length,
39033
- markerWritten,
39034
- attempts: installResult.attempts
39035
- });
39036
- return;
39037
- }
39038
- runLegacySkillsCleanup(agents);
39039
- writeSdkSkillsLocalVersion(baseUrl, update.remoteVersion, agents);
39040
- clearUnavailableSkillsNotice(baseUrl);
39041
- clearFailedSkillsSync(baseUrl, agents);
39042
- writeSdkSkillsStatusLine("Deepline agent skills are up to date.");
39043
- } finally {
39044
- if (claim.status === "claimed") {
39045
- clearSkillsSyncClaim(baseUrl, agents, claim.token);
39046
- }
39047
39393
  }
39394
+ const installResult = await runSkillsInstall(installs, agents, notice);
39395
+ if (!installResult.installed) {
39396
+ const markerWritten = markFailedSkillsSync(
39397
+ baseUrl,
39398
+ update.remoteVersion,
39399
+ agents
39400
+ );
39401
+ void maybeReportAutomaticSkillsSyncFailure({
39402
+ baseUrl,
39403
+ remoteSkillsVersion: update.remoteVersion,
39404
+ agents,
39405
+ skillsPackage: SKILLS_NPX_PACKAGE,
39406
+ targetSkillCount: skillNames.length,
39407
+ markerWritten,
39408
+ attempts: installResult.attempts
39409
+ });
39410
+ return;
39411
+ }
39412
+ runLegacySkillsCleanup(agents);
39413
+ writeSdkSkillsLocalVersion(baseUrl, update.remoteVersion, agents);
39414
+ clearUnavailableSkillsNotice(baseUrl);
39415
+ clearFailedSkillsSync(baseUrl, agents);
39416
+ notice("Deepline agent skills are up to date.");
39048
39417
  }
39049
39418
 
39050
39419
  // src/cli/commands/skills.ts
39420
+ var SKILLS_INSTALL_LEASE_WAIT_MS = 9e4;
39051
39421
  var SKILLS_PROCESS_TIMEOUT_MS = 45e3;
39052
39422
  var RUNTIME_TO_SKILLS_AGENT = {
39053
39423
  antigravity: "antigravity",
@@ -39304,6 +39674,45 @@ async function runSkillsCommand(options, dependencies = {}) {
39304
39674
  )
39305
39675
  ]);
39306
39676
  }
39677
+ const lease = scope === "global" ? await acquireSkillsInstallLease(baseUrl, agents, plan.version, {
39678
+ waitMs: dependencies.installLeaseWaitMs ?? SKILLS_INSTALL_LEASE_WAIT_MS,
39679
+ onWait: () => process.stderr.write(
39680
+ "Waiting for a background Deepline skills refresh to finish...\n"
39681
+ )
39682
+ }) : { release: () => {
39683
+ } };
39684
+ if (!lease) {
39685
+ printCommandEnvelope(
39686
+ {
39687
+ ok: false,
39688
+ status: "failed",
39689
+ code: "SKILLS_SYNC_IN_PROGRESS",
39690
+ exitCode: 7,
39691
+ scope,
39692
+ agents,
39693
+ message: "A background Deepline skills refresh is still running for these agents.",
39694
+ next: `Retry in a moment: deepline skills --scope ${scope} --json. If no refresh is running, remove ${skillsInstallLeasePath(baseUrl, agents)}`
39695
+ },
39696
+ { json: options.json }
39697
+ );
39698
+ return 7;
39699
+ }
39700
+ try {
39701
+ return await runSkillsInstallWithLease({
39702
+ options,
39703
+ dependencies,
39704
+ baseUrl,
39705
+ scope,
39706
+ root,
39707
+ agents,
39708
+ plan
39709
+ });
39710
+ } finally {
39711
+ lease.release();
39712
+ }
39713
+ }
39714
+ async function runSkillsInstallWithLease(input2) {
39715
+ const { options, dependencies, baseUrl, scope, root, agents, plan } = input2;
39307
39716
  process.stderr.write(
39308
39717
  `Replacing Deepline skills for ${agents.join(", ")} (${scope})...
39309
39718
  `
@@ -39416,6 +39825,31 @@ Examples:
39416
39825
  ).action(async (options) => {
39417
39826
  process.exitCode = await runSkillsCommand(options);
39418
39827
  });
39828
+ program.command(SKILLS_AUTO_SYNC_COMMAND, { hidden: true }).description("Refresh Deepline agent skills in the background.").option(
39829
+ "--claim <token>",
39830
+ "Owner token of the leases this child was started for."
39831
+ ).action(async (options) => {
39832
+ const claim = options.claim?.trim();
39833
+ if (!claim) {
39834
+ printCommandEnvelope(
39835
+ {
39836
+ ok: false,
39837
+ status: "failed",
39838
+ code: "SKILLS_AUTO_SYNC_CLAIM_REQUIRED",
39839
+ exitCode: 2,
39840
+ message: "skills-auto-sync is started by ordinary deepline commands and requires the lease token they pass; run `deepline skills` to install skills yourself."
39841
+ },
39842
+ { json: true }
39843
+ );
39844
+ process.exitCode = 2;
39845
+ return;
39846
+ }
39847
+ await syncSdkSkillsIfNeeded(autoDetectBaseUrl().replace(/\/$/, ""), {
39848
+ mode: "inline",
39849
+ notices: "defer",
39850
+ claim
39851
+ });
39852
+ });
39419
39853
  }
39420
39854
 
39421
39855
  // src/cli/commands/setup.ts
@@ -43439,14 +43873,15 @@ Examples:
43439
43873
  deepline tools describe hunter_email_verifier --json
43440
43874
  deepline tools describe deeplineagent --model openai/gpt-5.5 --json
43441
43875
  deepline tools describe ai_inference --estimate-payload @payload.json --json
43876
+ deepline tools describe ai_evaluate --estimate-payload @payload.json --json
43442
43877
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
43443
43878
  `
43444
43879
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
43445
43880
  "--model <model>",
43446
- "For deeplineagent, include AI Gateway model/provider option metadata"
43881
+ "For language tools, include AI Gateway metadata; for ai_evaluate, set the quote payload model"
43447
43882
  ).option(
43448
43883
  "--estimate-payload <payload>",
43449
- "Quote an ai_inference or deeplineagent JSON payload (inline or @file)"
43884
+ "Quote an ai_evaluate, ai_inference, or deeplineagent JSON payload (inline or @file)"
43450
43885
  ).option("--pricing-only", "Only print pricing and billing semantics").option("--schema-only", "Only print input schema fields").option(
43451
43886
  "--examples-only",
43452
43887
  "Only print runnable examples and sample payloads"
@@ -43548,9 +43983,9 @@ async function getTool(toolId, options = {}) {
43548
43983
  }
43549
43984
  let inferenceQuote = null;
43550
43985
  if (options.estimatePayload) {
43551
- if (toolId !== "deeplineagent" && toolId !== "ai_inference") {
43986
+ if (toolId !== "deeplineagent" && toolId !== "ai_inference" && toolId !== "ai_evaluate") {
43552
43987
  console.error(
43553
- "--estimate-payload is only supported for deeplineagent and ai_inference."
43988
+ "--estimate-payload is only supported for ai_evaluate, deeplineagent, and ai_inference."
43554
43989
  );
43555
43990
  return 2;
43556
43991
  }
@@ -43564,7 +43999,7 @@ async function getTool(toolId, options = {}) {
43564
43999
  inferenceQuote = await client2.quoteInferenceTool(toolId, estimatePayload);
43565
44000
  }
43566
44001
  const modelDescription = options.model && (toolId === "deeplineagent" || toolId === "ai_inference") ? await client2.describeModel(options.model) : null;
43567
- if (options.model && !modelDescription) {
44002
+ if (options.model && !modelDescription && toolId !== "ai_evaluate") {
43568
44003
  console.error(
43569
44004
  "--model is only supported for deeplineagent and ai_inference."
43570
44005
  );
@@ -46142,7 +46577,7 @@ Exit codes:
46142
46577
  `
46143
46578
  );
46144
46579
  program.hook("preAction", async (_thisCommand, actionCommand) => {
46145
- if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "setup" || actionCommand.name() === "skills" || actionCommand.name() === "doctor" || isAutoUpdateSettingsInvocation() || isDeprecatedCommandInvocation()) {
46580
+ if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "setup" || actionCommand.name() === "skills" || actionCommand.name() === SKILLS_AUTO_SYNC_COMMAND || actionCommand.name() === "doctor" || isAutoUpdateSettingsInvocation() || isDeprecatedCommandInvocation()) {
46146
46581
  return;
46147
46582
  }
46148
46583
  const compatibilityCommand = compatibilityCommandPath(actionCommand) || actionCommand.name();
@@ -46150,18 +46585,42 @@ Exit codes:
46150
46585
  progress?.phase("checking sdk compatibility");
46151
46586
  }
46152
46587
  const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
46588
+ flushDeferredSkillsSyncNotices(baseUrl);
46153
46589
  const shouldDeferSkillsSync = shouldDeferSkillsSyncForCommand();
46154
46590
  const skillsVersion = shouldDeferSkillsSync ? void 0 : readSdkSkillsLocalVersion(baseUrl);
46155
- const compatibility = await traceCliSpan(
46591
+ const trusted = readTrustedCleanCompatibility(
46592
+ baseUrl,
46593
+ compatibilityCommand,
46594
+ skillsVersion
46595
+ );
46596
+ const fastDeadline = trusted === null && readFreshCleanCompatibility(
46597
+ baseUrl,
46598
+ compatibilityCommand,
46599
+ skillsVersion
46600
+ ) !== null;
46601
+ if (trusted) {
46602
+ recordCliTrace({
46603
+ phase: "cli.sdk_compatibility",
46604
+ ms: 0,
46605
+ ok: true,
46606
+ baseUrl,
46607
+ command: compatibilityCommand,
46608
+ skillsVersion: skillsVersion ?? null,
46609
+ source: "trusted_cache"
46610
+ });
46611
+ }
46612
+ const compatibility = trusted ? { response: trusted, error: null } : await traceCliSpan(
46156
46613
  "cli.sdk_compatibility",
46157
46614
  {
46158
46615
  baseUrl,
46159
46616
  command: compatibilityCommand,
46160
- skillsVersion: skillsVersion ?? null
46617
+ skillsVersion: skillsVersion ?? null,
46618
+ fastDeadline
46161
46619
  },
46162
46620
  () => checkSdkCompatibility(baseUrl, {
46163
46621
  command: compatibilityCommand,
46164
- skillsVersion
46622
+ skillsVersion,
46623
+ ...fastDeadline ? { timeoutMs: SDK_COMPATIBILITY_FAST_DEADLINE_MS } : {}
46165
46624
  })
46166
46625
  );
46167
46626
  if (compatibility.error) {
@@ -46184,7 +46643,8 @@ Exit codes:
46184
46643
  "cli.sdk_skills_sync",
46185
46644
  { baseUrl },
46186
46645
  () => syncSdkSkillsIfNeeded(baseUrl, {
46187
- update: skillsUpdate
46646
+ update: skillsUpdate,
46647
+ mode: "detached"
46188
46648
  })
46189
46649
  );
46190
46650
  }