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
@@ -1271,7 +1271,7 @@ var SDK_RELEASE = {
1271
1271
  // getters keep their established compatibility behavior.
1272
1272
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
1273
1273
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
1274
- version: "0.3.113",
1274
+ version: "0.3.114",
1275
1275
  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.",
1276
1276
  packageCapabilities: {
1277
1277
  updatePreferences: 1
@@ -1487,8 +1487,22 @@ function readPluginSkillsVersion() {
1487
1487
  return "";
1488
1488
  }
1489
1489
  }
1490
+ var KNOWN_SKILL_AGENTS = [
1491
+ "antigravity",
1492
+ "claude-code",
1493
+ "cline",
1494
+ "codex",
1495
+ "cursor",
1496
+ "gemini-cli",
1497
+ "windsurf"
1498
+ ];
1499
+ function skillsAgentPathSegment(agent) {
1500
+ if (agent === "*") return "all";
1501
+ const slug = agent.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "");
1502
+ return slug || "agent";
1503
+ }
1490
1504
  function sdkSkillsVersionPath(baseUrl, agents = []) {
1491
- const suffix = agents.length > 0 ? `-${agents.join("-")}` : "";
1505
+ const suffix = agents.length > 0 ? `-${agents.map(skillsAgentPathSegment).join("-")}` : "";
1492
1506
  return join2(sdkCliStateDirPath(baseUrl), `skills${suffix}-version`);
1493
1507
  }
1494
1508
  function legacySdkSkillsVersionPath(baseUrl) {
@@ -4820,7 +4834,7 @@ function resolveToolExecuteTimeoutMs(toolId, input2) {
4820
4834
  if (usesExtendedBetterContactLauncherBudget(normalized)) {
4821
4835
  return BETTERCONTACT_LAUNCHER_CLIENT_TIMEOUT_MS;
4822
4836
  }
4823
- return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
4837
+ 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;
4824
4838
  }
4825
4839
  var RUNS_FAILED_LOG_LIMIT = 20;
4826
4840
  var RUN_LOGS_PAGE_LIMIT = 1e3;
@@ -8169,7 +8183,9 @@ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as rea
8169
8183
  import { homedir as homedir3 } from "os";
8170
8184
  import { dirname as dirname3, join as join3 } from "path";
8171
8185
  var CHECK_TIMEOUT_MS = 2e3;
8172
- var SDK_COMPATIBILITY_CACHE_TTL_MS = 5 * 60 * 1e3;
8186
+ var SDK_COMPATIBILITY_TRUST_MS = 10 * 60 * 1e3;
8187
+ var SDK_COMPATIBILITY_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
8188
+ var SDK_COMPATIBILITY_FAST_DEADLINE_MS = 400;
8173
8189
  function shouldSkipCompatibilityCheck() {
8174
8190
  const value = process.env.DEEPLINE_SKIP_SDK_COMPAT_CHECK?.trim().toLowerCase();
8175
8191
  return value === "1" || value === "true" || value === "yes";
@@ -8198,7 +8214,29 @@ function legacyCompatibilityCacheKey(baseUrl, command) {
8198
8214
  command: command?.trim() || null
8199
8215
  });
8200
8216
  }
8217
+ function isCleanCompatibilityPolicy(response) {
8218
+ if (!response) return false;
8219
+ return response.ok === true && response.update_required !== true && response.status !== "unsupported" && !response.auto_update?.should_auto_update && !response.cli_family;
8220
+ }
8221
+ function readFreshCleanCompatibility(baseUrl, command, skillsVersion) {
8222
+ const cached = readCachedCompatibility(baseUrl, command, skillsVersion);
8223
+ return isCleanCompatibilityPolicy(cached) ? cached : null;
8224
+ }
8225
+ function readTrustedCleanCompatibility(baseUrl, command, skillsVersion, now = Date.now()) {
8226
+ const entry = readCachedCompatibilityEntry(baseUrl, command, skillsVersion);
8227
+ if (!entry || !isSavedWithin(entry.savedAt, SDK_COMPATIBILITY_TRUST_MS, now))
8228
+ return null;
8229
+ return isCleanCompatibilityPolicy(entry.response) ? entry.response : null;
8230
+ }
8231
+ function isSavedWithin(savedAt, windowMs, now) {
8232
+ if (typeof savedAt !== "number") return false;
8233
+ const age = now - savedAt;
8234
+ return Number.isFinite(age) && age >= 0 && age <= windowMs;
8235
+ }
8201
8236
  function readCachedCompatibility(baseUrl, command, skillsVersion) {
8237
+ return readCachedCompatibilityEntry(baseUrl, command, skillsVersion)?.response ?? null;
8238
+ }
8239
+ function readCachedCompatibilityEntry(baseUrl, command, skillsVersion) {
8202
8240
  try {
8203
8241
  const path = sdkCompatibilityCachePath(baseUrl);
8204
8242
  const legacyPath = legacySdkCompatibilityCachePath();
@@ -8211,14 +8249,31 @@ function readCachedCompatibility(baseUrl, command, skillsVersion) {
8211
8249
  readFileSync3(cachePath, "utf8")
8212
8250
  );
8213
8251
  const entry = parsed.entries?.[compatibilityCacheKey(baseUrl, command, skillsVersion)] ?? (useLegacyCache ? parsed.entries?.[legacyCompatibilityCacheKey(baseUrl, command)] : void 0);
8214
- if (!entry || Date.now() - entry.savedAt > SDK_COMPATIBILITY_CACHE_TTL_MS) {
8252
+ if (!entry || !isSavedWithin(entry.savedAt, SDK_COMPATIBILITY_CACHE_TTL_MS, Date.now())) {
8215
8253
  return null;
8216
8254
  }
8217
- return entry.response;
8255
+ return entry;
8218
8256
  } catch {
8219
8257
  return null;
8220
8258
  }
8221
8259
  }
8260
+ function invalidateCachedCompatibility(baseUrl, command, skillsVersion) {
8261
+ try {
8262
+ const path = sdkCompatibilityCachePath(baseUrl);
8263
+ const legacyPath = legacySdkCompatibilityCachePath();
8264
+ const cachePath = !existsSync3(path) && existsSync3(legacyPath) ? legacyPath : path;
8265
+ if (!existsSync3(cachePath)) return;
8266
+ const existing = JSON.parse(
8267
+ readFileSync3(cachePath, "utf8")
8268
+ );
8269
+ const entries = existing.entries ?? {};
8270
+ delete entries[compatibilityCacheKey(baseUrl, command, skillsVersion)];
8271
+ delete entries[legacyCompatibilityCacheKey(baseUrl, command)];
8272
+ writeFileSync3(cachePath, `${JSON.stringify({ entries }, null, 2)}
8273
+ `);
8274
+ } catch {
8275
+ }
8276
+ }
8222
8277
  function writeCachedCompatibility(baseUrl, command, skillsVersion, response) {
8223
8278
  try {
8224
8279
  const path = sdkCompatibilityCachePath(baseUrl);
@@ -8239,7 +8294,10 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
8239
8294
  return { response: null, error: null };
8240
8295
  }
8241
8296
  const controller = new AbortController();
8242
- const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
8297
+ const timeout = setTimeout(
8298
+ () => controller.abort(),
8299
+ options.timeoutMs ?? CHECK_TIMEOUT_MS
8300
+ );
8243
8301
  try {
8244
8302
  const url = new URL("/api/v2/sdk/compat", baseUrl);
8245
8303
  url.searchParams.set("version", SDK_VERSION);
@@ -8261,14 +8319,17 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
8261
8319
  signal: controller.signal
8262
8320
  });
8263
8321
  const data = await response.json().catch(() => null);
8264
- if (data) {
8265
- writeCachedCompatibility(
8266
- baseUrl,
8267
- options.command,
8268
- options.skillsVersion,
8269
- data
8322
+ if (!data || typeof data.ok !== "boolean" || typeof data.status !== "string") {
8323
+ throw new Error(
8324
+ `SDK compatibility endpoint returned a non-policy response (HTTP ${response.status}).`
8270
8325
  );
8271
8326
  }
8327
+ writeCachedCompatibility(
8328
+ baseUrl,
8329
+ options.command,
8330
+ options.skillsVersion,
8331
+ data
8332
+ );
8272
8333
  return { response: data, error: null };
8273
8334
  } catch (error) {
8274
8335
  const cached = readCachedCompatibility(
@@ -8277,6 +8338,13 @@ async function checkSdkCompatibility(baseUrl, options = {}) {
8277
8338
  options.skillsVersion
8278
8339
  );
8279
8340
  if (cached) {
8341
+ if (options.timeoutMs !== void 0 && options.timeoutMs < CHECK_TIMEOUT_MS) {
8342
+ invalidateCachedCompatibility(
8343
+ baseUrl,
8344
+ options.command,
8345
+ options.skillsVersion
8346
+ );
8347
+ }
8280
8348
  return { response: cached, error: null };
8281
8349
  }
8282
8350
  return {
@@ -35166,7 +35234,19 @@ function renderMonitorGet(payload) {
35166
35234
  const field = asRecord2(value);
35167
35235
  const path = asString(field?.path);
35168
35236
  const description = asString(field?.description);
35169
- return path ? [{ path, description }] : [];
35237
+ const semantics = asString(field?.semantics);
35238
+ const applicability = asString(field?.applicability);
35239
+ const grammar = asRecord2(field?.grammar);
35240
+ const grammarSyntax = asString(grammar?.syntax);
35241
+ return path ? [
35242
+ {
35243
+ path,
35244
+ description,
35245
+ semantics,
35246
+ applicability,
35247
+ grammarSyntax
35248
+ }
35249
+ ] : [];
35170
35250
  }) : [];
35171
35251
  if (specFields.length > 0) {
35172
35252
  lines.push("", "Monitor spec:");
@@ -35174,6 +35254,15 @@ function renderMonitorGet(payload) {
35174
35254
  lines.push(
35175
35255
  ` ${field.path}${field.description ? ` \u2014 ${field.description}` : ""}`
35176
35256
  );
35257
+ if (field.semantics && field.semantics !== field.description) {
35258
+ lines.push(` Behavior: ${field.semantics}`);
35259
+ }
35260
+ if (field.applicability) {
35261
+ lines.push(` Applies to: ${field.applicability}`);
35262
+ }
35263
+ if (field.grammarSyntax) {
35264
+ lines.push(` Format: ${field.grammarSyntax}`);
35265
+ }
35177
35266
  }
35178
35267
  }
35179
35268
  lines.push("", `Current SQL listener consumers (${boundPlays.length}):`);
@@ -35938,8 +36027,10 @@ Notes:
35938
36027
  Read-only. Returns the exact editable definition, selected Deepline pricing,
35939
36028
  billing state, output streams, dependent published plays, and monitor_spec.
35940
36029
  When monitor_spec.available is true, its fields describe the deployed type's
35941
- editable fields and constraints; otherwise use the stored definition and check
35942
- before proposing an update so scope and downstream effects are visible.
36030
+ editable fields, constraints, and provider-specific behavior. For TAMRadar,
36031
+ this includes the effective updates_since precision and engagement timing
36032
+ rules. Otherwise use the stored definition and check before proposing an
36033
+ update so scope and downstream effects are visible.
35943
36034
 
35944
36035
  Examples:
35945
36036
  deepline monitors get my-monitor --json
@@ -38329,13 +38420,12 @@ function buildSkillsAddArgs(baseUrl, skillName, options = {}) {
38329
38420
  import { spawn as spawn2, spawnSync } from "child_process";
38330
38421
  import { randomUUID as randomUUID7 } from "crypto";
38331
38422
  import {
38423
+ appendFileSync,
38332
38424
  existsSync as existsSync13,
38333
38425
  mkdirSync as mkdirSync10,
38334
- readdirSync as readdirSync4,
38335
38426
  readFileSync as readFileSync14,
38336
38427
  renameSync,
38337
- rmdirSync,
38338
- statSync as statSync5,
38428
+ rmSync as rmSync5,
38339
38429
  unlinkSync as unlinkSync2,
38340
38430
  writeFileSync as writeFileSync14
38341
38431
  } from "fs";
@@ -38694,7 +38784,6 @@ async function maybeReportSdkCliFailure(input2) {
38694
38784
 
38695
38785
  // src/cli/skills-sync.ts
38696
38786
  var CHECK_TIMEOUT_MS2 = 3e3;
38697
- var SKILLS_SYNC_CLAIM_MAX_AGE_MS = 60 * 60 * 1e3;
38698
38787
  function shouldSkipSkillsSync() {
38699
38788
  if (detectAgentRuntime() === "claude_cowork") {
38700
38789
  return true;
@@ -38705,65 +38794,286 @@ function shouldSkipSkillsSync() {
38705
38794
  function unavailableSkillsNoticePath(baseUrl) {
38706
38795
  return join15(sdkCliStateDirPath(baseUrl), "skills-sync-unavailable-version");
38707
38796
  }
38708
- function failedSkillsSyncPath(baseUrl, agents) {
38797
+ var SKILLS_SYNC_IN_PROGRESS_TTL_MS = 10 * 60 * 1e3;
38798
+ var SKILLS_SYNC_IN_PROGRESS_PID_CAP_MS = 6 * 60 * 60 * 1e3;
38799
+ var agentLeaseSegment = skillsAgentPathSegment;
38800
+ function sortedLeaseAgents(agents) {
38801
+ const expanded = agents.includes("*") ? [...agents, ...KNOWN_SKILL_AGENTS] : agents;
38802
+ return [...new Set(expanded)].sort((a, b) => a.localeCompare(b));
38803
+ }
38804
+ function inProgressSkillsSyncPath(baseUrl, agent) {
38709
38805
  return join15(
38710
38806
  sdkCliStateDirPath(baseUrl),
38711
- `skills-sync-failed-${agents.join("-")}-version`
38807
+ `skills-sync-in-progress-${agentLeaseSegment(agent)}`
38712
38808
  );
38713
38809
  }
38714
- function inProgressSkillsSyncPath(baseUrl, agents) {
38715
- return join15(
38716
- sdkCliStateDirPath(baseUrl),
38717
- `skills-sync-in-progress-${agents.join("-")}`
38810
+ function readInProgressSkillsSyncLeaseFromDir(dir) {
38811
+ const claim = readMarkedSkillsSyncVersion(join15(dir, "claim"));
38812
+ const [version = "", startedAt = ""] = claim.split(" ");
38813
+ const pidRaw = readMarkedSkillsSyncVersion(join15(dir, "pid"));
38814
+ return {
38815
+ claimToken: version && startedAt ? `${version} ${startedAt}` : "",
38816
+ version,
38817
+ startedAt: Number(startedAt),
38818
+ pid: /^\d+$/.test(pidRaw) ? Number(pidRaw) : null,
38819
+ owner: readMarkedSkillsSyncVersion(join15(dir, "owner"))
38820
+ };
38821
+ }
38822
+ function readInProgressSkillsSyncLease(baseUrl, agent) {
38823
+ return readInProgressSkillsSyncLeaseFromDir(
38824
+ inProgressSkillsSyncPath(baseUrl, agent)
38825
+ );
38826
+ }
38827
+ function readInProgressSkillsSyncLeases(baseUrl, agents) {
38828
+ return new Map(
38829
+ sortedLeaseAgents(agents).map((agent) => [
38830
+ agent,
38831
+ readInProgressSkillsSyncLease(baseUrl, agent)
38832
+ ])
38718
38833
  );
38719
38834
  }
38720
- function removeSkillsSyncClaim(path, token) {
38835
+ var UNRESOLVED_SKILLS_CLAIM_VERSION = "unresolved";
38836
+ function claimedSkillsVersion(leases) {
38837
+ for (const lease of leases.values()) {
38838
+ if (lease.version && lease.version !== UNRESOLVED_SKILLS_CLAIM_VERSION) {
38839
+ return lease.version;
38840
+ }
38841
+ }
38842
+ return "";
38843
+ }
38844
+ function isProcessAlive(pid) {
38721
38845
  try {
38722
- unlinkSync2(join15(path, token));
38723
- rmdirSync(path);
38724
- } catch {
38846
+ process.kill(pid, 0);
38847
+ return true;
38848
+ } catch (error) {
38849
+ return error.code === "EPERM";
38725
38850
  }
38726
38851
  }
38727
- function claimSkillsSync(baseUrl, agents) {
38728
- const path = inProgressSkillsSyncPath(baseUrl, agents);
38852
+ function isFreshInProgressSkillsSync(lease, now = Date.now()) {
38853
+ if (!Number.isFinite(lease.startedAt)) return false;
38854
+ const age = now - lease.startedAt;
38855
+ if (age < 0) return false;
38856
+ if (lease.pid !== null && isProcessAlive(lease.pid)) {
38857
+ return age < SKILLS_SYNC_IN_PROGRESS_PID_CAP_MS;
38858
+ }
38859
+ return age < SKILLS_SYNC_IN_PROGRESS_TTL_MS;
38860
+ }
38861
+ function quarantine(path, tag) {
38862
+ const holding = `${path}.${tag}-${process.pid}-${Date.now()}`;
38729
38863
  try {
38730
- mkdirSync10(dirname14(path), { recursive: true });
38864
+ renameSync(path, holding);
38865
+ return holding;
38731
38866
  } catch {
38732
- return { status: "unavailable" };
38867
+ return null;
38733
38868
  }
38734
- const token = randomUUID7();
38735
- for (let attempt = 0; attempt < 2; attempt += 1) {
38736
- const pendingPath = `${path}-pending-${token}`;
38869
+ }
38870
+ function claimOneInProgressSkillsSync(baseUrl, remoteVersion, agent, owner) {
38871
+ const dir = inProgressSkillsSyncPath(baseUrl, agent);
38872
+ const errorCode = (error) => error.code;
38873
+ const create = () => {
38874
+ const claimToken = `${remoteVersion} ${Date.now()}`;
38875
+ const staging = `${dir}.staging-${process.pid}-${Date.now()}`;
38876
+ mkdirSync10(staging);
38877
+ writeFileSync14(join15(staging, "claim"), `${claimToken}
38878
+ `, "utf-8");
38879
+ writeFileSync14(join15(staging, "owner"), `${owner}
38880
+ `, "utf-8");
38737
38881
  try {
38738
- mkdirSync10(pendingPath);
38739
- writeFileSync14(join15(pendingPath, token), "", { flag: "wx" });
38740
- renameSync(pendingPath, path);
38741
- return { status: "claimed", token };
38742
- } catch {
38743
- removeSkillsSyncClaim(pendingPath, token);
38744
- if (!existsSync13(path)) continue;
38882
+ renameSync(staging, dir);
38883
+ } catch (error) {
38884
+ rmSync5(staging, { recursive: true, force: true });
38885
+ const code = errorCode(error);
38886
+ const err = new Error("lease directory already exists");
38887
+ err.code = code === "EEXIST" || code === "ENOTEMPTY" ? "EEXIST" : String(code ?? "");
38888
+ throw err;
38889
+ }
38890
+ return { state: "claimed", claimToken };
38891
+ };
38892
+ try {
38893
+ mkdirSync10(dirname14(dir), { recursive: true });
38894
+ return create();
38895
+ } catch (error) {
38896
+ if (errorCode(error) !== "EEXIST") return { state: "unavailable" };
38897
+ }
38898
+ if (isFreshInProgressSkillsSync(readInProgressSkillsSyncLease(baseUrl, agent))) {
38899
+ return { state: "held" };
38900
+ }
38901
+ const tombstone = quarantine(dir, "stale");
38902
+ if (!tombstone) {
38903
+ return { state: "held" };
38904
+ }
38905
+ rmSync5(tombstone, { recursive: true, force: true });
38906
+ try {
38907
+ return create();
38908
+ } catch (error) {
38909
+ return errorCode(error) === "EEXIST" ? { state: "held" } : { state: "unavailable" };
38910
+ }
38911
+ }
38912
+ function claimInProgressSkillsSync(baseUrl, remoteVersion, agents) {
38913
+ const claimTokens = /* @__PURE__ */ new Map();
38914
+ const owner = randomUUID7();
38915
+ for (const agent of sortedLeaseAgents(agents)) {
38916
+ const claim = claimOneInProgressSkillsSync(
38917
+ baseUrl,
38918
+ remoteVersion,
38919
+ agent,
38920
+ owner
38921
+ );
38922
+ if (claim.state !== "claimed") {
38923
+ releaseInProgressSkillsSync(baseUrl, claimTokens);
38924
+ return { state: claim.state };
38925
+ }
38926
+ claimTokens.set(agent, claim.claimToken);
38927
+ }
38928
+ return { state: "claimed", claimTokens, owner };
38929
+ }
38930
+ function claimAndSpawnDetachedSkillsSync(baseUrl, agents, remoteVersion, spawnDetached) {
38931
+ const claim = claimInProgressSkillsSync(baseUrl, remoteVersion, agents);
38932
+ if (claim.state !== "claimed") return claim.state;
38933
+ const { claimTokens, owner } = claim;
38934
+ spawnDetached([SKILLS_AUTO_SYNC_COMMAND, "--claim", owner], () => {
38935
+ releaseInProgressSkillsSync(baseUrl, claimTokens);
38936
+ if (remoteVersion !== UNRESOLVED_SKILLS_CLAIM_VERSION) {
38937
+ markFailedSkillsSync(baseUrl, remoteVersion, agents);
38745
38938
  }
38746
- if (attempt > 0) return { status: "held" };
38939
+ deferSkillsNotice(
38940
+ baseUrl,
38941
+ agents
38942
+ )(
38943
+ "Deepline skills refresh failed to start; run `deepline skills` to retry."
38944
+ );
38945
+ });
38946
+ return "claimed";
38947
+ }
38948
+ function recordOwnPidOnInProgressSkillsSync(baseUrl, leases) {
38949
+ for (const [agent, lease] of leases) {
38950
+ if (!lease.claimToken) continue;
38747
38951
  try {
38748
- if (Date.now() - statSync5(path).mtimeMs <= SKILLS_SYNC_CLAIM_MAX_AGE_MS) {
38749
- return { status: "held" };
38952
+ writeFileSync14(
38953
+ join15(inProgressSkillsSyncPath(baseUrl, agent), "pid"),
38954
+ `${process.pid}
38955
+ `,
38956
+ "utf-8"
38957
+ );
38958
+ } catch {
38959
+ }
38960
+ }
38961
+ }
38962
+ function releaseInProgressSkillsSync(baseUrl, claimTokens) {
38963
+ for (const [agent, claimToken] of claimTokens) {
38964
+ const dir = inProgressSkillsSyncPath(baseUrl, agent);
38965
+ if (!claimToken) {
38966
+ try {
38967
+ rmSync5(dir, { recursive: true, force: true });
38968
+ } catch {
38750
38969
  }
38751
- const owners = readdirSync4(path);
38752
- if (owners.length === 0) {
38753
- rmdirSync(path);
38970
+ continue;
38971
+ }
38972
+ const tombstone = quarantine(dir, "release");
38973
+ if (!tombstone) continue;
38974
+ try {
38975
+ if (readInProgressSkillsSyncLeaseFromDir(tombstone).claimToken !== claimToken) {
38976
+ renameSync(tombstone, dir);
38754
38977
  continue;
38755
38978
  }
38756
- if (owners.length !== 1) return { status: "held" };
38757
- renameSync(path, `${path}-stale-${owners[0]}`);
38758
38979
  } catch {
38759
- return { status: "held" };
38980
+ }
38981
+ rmSync5(tombstone, { recursive: true, force: true });
38982
+ }
38983
+ }
38984
+ function claimTokensOf(leases) {
38985
+ return new Map(
38986
+ [...leases].map(([agent, lease]) => [agent, lease.claimToken])
38987
+ );
38988
+ }
38989
+ async function acquireSkillsInstallLease(baseUrl, agents, version, options = {
38990
+ waitMs: 9e4
38991
+ }) {
38992
+ const pollMs = options.pollMs ?? 250;
38993
+ const deadline = Date.now() + options.waitMs;
38994
+ let waited = false;
38995
+ for (; ; ) {
38996
+ const claim = claimInProgressSkillsSync(baseUrl, version, agents);
38997
+ if (claim.state === "unavailable") {
38998
+ return { release: () => {
38999
+ } };
39000
+ }
39001
+ if (claim.state === "claimed") {
39002
+ recordOwnPidOnInProgressSkillsSync(
39003
+ baseUrl,
39004
+ readInProgressSkillsSyncLeases(baseUrl, agents)
39005
+ );
39006
+ return {
39007
+ release: () => releaseInProgressSkillsSync(baseUrl, claim.claimTokens)
39008
+ };
39009
+ }
39010
+ if (Date.now() >= deadline) return null;
39011
+ if (!waited) {
39012
+ waited = true;
39013
+ options.onWait?.();
39014
+ }
39015
+ await new Promise((resolve21) => setTimeout(resolve21, pollMs));
39016
+ }
39017
+ }
39018
+ function skillsInstallLeasePath(baseUrl, agents) {
39019
+ return sortedLeaseAgents(agents).map((agent) => inProgressSkillsSyncPath(baseUrl, agent)).join(", ");
39020
+ }
39021
+ function deferredSkillsNoticePath(baseUrl, agents) {
39022
+ return join15(
39023
+ sdkCliStateDirPath(baseUrl),
39024
+ `skills-sync-notice-${sortedLeaseAgents(agents).map(agentLeaseSegment).join("-")}`
39025
+ );
39026
+ }
39027
+ function deferSkillsNotice(baseUrl, agents) {
39028
+ const path = deferredSkillsNoticePath(baseUrl, agents);
39029
+ return (text) => {
39030
+ try {
39031
+ mkdirSync10(dirname14(path), { recursive: true });
39032
+ appendFileSync(path, `${text.trimEnd()}
39033
+ `, "utf-8");
39034
+ } catch {
39035
+ }
39036
+ };
39037
+ }
39038
+ function flushDeferredSkillsNotices(baseUrl, agents) {
39039
+ const path = deferredSkillsNoticePath(baseUrl, agents);
39040
+ if (!existsSync13(path)) return;
39041
+ const tombstone = quarantine(path, "consuming");
39042
+ if (!tombstone) return;
39043
+ let text = "";
39044
+ try {
39045
+ text = readFileSync14(tombstone, "utf-8");
39046
+ } catch {
39047
+ return;
39048
+ } finally {
39049
+ try {
39050
+ unlinkSync2(tombstone);
39051
+ } catch {
38760
39052
  }
38761
39053
  }
38762
- return { status: "held" };
39054
+ if (text.trim()) writeSdkSkillsStatusLine(text.trimEnd());
39055
+ }
39056
+ function flushDeferredSkillsSyncNotices(baseUrl) {
39057
+ if (shouldSkipSkillsSync() || hasActivePluginSkills()) return;
39058
+ const agents = resolveAutoSyncSkillAgents();
39059
+ if (agents.length === 0) return;
39060
+ flushDeferredSkillsNotices(baseUrl, agents);
39061
+ }
39062
+ var SKILLS_AUTO_SYNC_COMMAND = "skills-auto-sync";
39063
+ function spawnDetachedSkillsSyncChild(argv, onSpawnError) {
39064
+ const child = spawn2(process.execPath, [process.argv[1] ?? "", ...argv], {
39065
+ detached: true,
39066
+ stdio: "ignore",
39067
+ env: process.env
39068
+ });
39069
+ child.on("error", () => onSpawnError?.());
39070
+ child.unref();
38763
39071
  }
38764
- function clearSkillsSyncClaim(baseUrl, agents, token) {
38765
- const path = inProgressSkillsSyncPath(baseUrl, agents);
38766
- removeSkillsSyncClaim(path, token);
39072
+ function failedSkillsSyncPath(baseUrl, agents) {
39073
+ return join15(
39074
+ sdkCliStateDirPath(baseUrl),
39075
+ `skills-sync-failed-${agents.map(agentLeaseSegment).join("-")}-version`
39076
+ );
38767
39077
  }
38768
39078
  function hasMarkedSkillsSyncVersion(path, version) {
38769
39079
  return Boolean(version) && readMarkedSkillsSyncVersion(path) === version;
@@ -38785,12 +39095,12 @@ function writeMarkedSkillsSyncVersion(path, version) {
38785
39095
  return false;
38786
39096
  }
38787
39097
  }
38788
- function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames) {
39098
+ function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames, notice = writeSdkSkillsStatusLine) {
38789
39099
  const path = unavailableSkillsNoticePath(baseUrl);
38790
39100
  if (hasMarkedSkillsSyncVersion(path, remoteVersion)) return;
38791
39101
  writeMarkedSkillsSyncVersion(path, remoteVersion);
38792
39102
  const manualCommand = `npx ${buildSkillsInstallArgs(baseUrl, skillNames).join(" ")}`;
38793
- writeSdkSkillsStatusLine(
39103
+ notice(
38794
39104
  `Deepline agent skills are out of date, but neither \`bunx\` nor \`npx\` is available. Install Node.js/npm or Bun, then run:
38795
39105
  ${manualCommand}`
38796
39106
  );
@@ -38975,7 +39285,7 @@ function runOneSkillsInstall(install) {
38975
39285
  });
38976
39286
  });
38977
39287
  }
38978
- async function runSkillsInstall(installs, agents) {
39288
+ async function runSkillsInstall(installs, agents, notice = writeSdkSkillsStatusLine) {
38979
39289
  const failures = [];
38980
39290
  for (const install of installs) {
38981
39291
  const result = await runOneSkillsInstall(install);
@@ -38985,15 +39295,14 @@ async function runSkillsInstall(installs, agents) {
38985
39295
  const details = failures.map((failure) => failure.detail).filter(Boolean).join("\n");
38986
39296
  const attemptedCommands = failures.map((failure) => ` ${failure.manualCommand}`).join("\n");
38987
39297
  const retryAgent = agents.at(0);
38988
- process.stderr.write(
39298
+ notice(
38989
39299
  `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.
38990
39300
  ` + (attemptedCommands ? `Attempted installer command${failures.length === 1 ? "" : "s"}:
38991
39301
  ${attemptedCommands}
38992
39302
  ` : "") + (details ? `Installer output:
38993
39303
  ${details}
38994
39304
  ` : "") + (retryAgent ? `To retry with full installer output: deepline skills --agent ${retryAgent} --json
38995
- ` : "") + `To temporarily suppress automatic skills sync: ${temporarySkillsSyncSkipCommand()}
38996
- `
39305
+ ` : "") + `To temporarily suppress automatic skills sync: ${temporarySkillsSyncSkipCommand()}`
38997
39306
  );
38998
39307
  return {
38999
39308
  installed: false,
@@ -39068,72 +39377,132 @@ async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
39068
39377
  if (usingPluginSkills) {
39069
39378
  return;
39070
39379
  }
39071
- const localVersion = readSdkSkillsLocalVersion(baseUrl);
39072
- const update = options.update === void 0 ? await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
39073
- needsUpdate: options.update.needs_update,
39074
- remoteVersion: options.update.remote.version
39075
- } : null;
39076
- if (!update?.needsUpdate || !update.remoteVersion) {
39077
- return;
39078
- }
39079
39380
  const agents = resolveAutoSyncSkillAgents();
39080
- if (agents.length > 0 && hasFailedSkillsSync(baseUrl, update.remoteVersion, agents)) {
39381
+ if (options.mode === "detached" && agents.length > 0) {
39382
+ flushDeferredSkillsNotices(baseUrl, agents);
39383
+ }
39384
+ const ownsInProgressMarker = options.mode !== "detached" && agents.length > 0 && Boolean(options.claim);
39385
+ const leases = ownsInProgressMarker ? readInProgressSkillsSyncLeases(baseUrl, agents) : null;
39386
+ if (leases && [...leases.values()].some((lease) => lease.owner !== options.claim)) {
39081
39387
  return;
39082
39388
  }
39389
+ if (leases) recordOwnPidOnInProgressSkillsSync(baseUrl, leases);
39390
+ const claimedVersion = leases ? claimedSkillsVersion(leases) : "";
39391
+ if (options.mode === "detached" && agents.length > 0 && options.update === void 0 && !claimedVersion) {
39392
+ const outcome = claimAndSpawnDetachedSkillsSync(
39393
+ baseUrl,
39394
+ agents,
39395
+ UNRESOLVED_SKILLS_CLAIM_VERSION,
39396
+ options.spawnDetached ?? spawnDetachedSkillsSyncChild
39397
+ );
39398
+ if (outcome !== "unavailable") return;
39399
+ }
39400
+ try {
39401
+ const localVersion = readSdkSkillsLocalVersion(baseUrl);
39402
+ const update = options.update === void 0 ? claimedVersion ? { needsUpdate: true, remoteVersion: claimedVersion } : await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
39403
+ needsUpdate: options.update.needs_update,
39404
+ remoteVersion: options.update.remote.version
39405
+ } : null;
39406
+ if (!update?.needsUpdate || !update.remoteVersion) {
39407
+ return;
39408
+ }
39409
+ if (agents.length > 0 && hasFailedSkillsSync(baseUrl, update.remoteVersion, agents)) {
39410
+ return;
39411
+ }
39412
+ if (options.mode === "detached" && agents.length === 0) {
39413
+ writeUnavailableSkillsNotice(
39414
+ baseUrl,
39415
+ update.remoteVersion,
39416
+ buildSdkSkillNames(DEFAULT_SDK_SKILL_NAMES)
39417
+ );
39418
+ return;
39419
+ }
39420
+ if (options.mode === "detached" && agents.length > 0) {
39421
+ const outcome = claimAndSpawnDetachedSkillsSync(
39422
+ baseUrl,
39423
+ agents,
39424
+ update.remoteVersion,
39425
+ options.spawnDetached ?? spawnDetachedSkillsSyncChild
39426
+ );
39427
+ if (outcome === "held") return;
39428
+ if (outcome === "claimed") {
39429
+ writeSdkSkillsStatusLine(
39430
+ "Deepline skills changed; refreshing agent skills in the background."
39431
+ );
39432
+ return;
39433
+ }
39434
+ }
39435
+ await runInlineSkillsSync(
39436
+ baseUrl,
39437
+ update.remoteVersion,
39438
+ agents,
39439
+ options.notices ?? "print"
39440
+ );
39441
+ } finally {
39442
+ if (leases) {
39443
+ releaseInProgressSkillsSync(baseUrl, claimTokensOf(leases));
39444
+ }
39445
+ }
39446
+ }
39447
+ async function runInlineSkillsSync(baseUrl, remoteVersion, agents, notices) {
39448
+ const update = { remoteVersion };
39449
+ const notice = notices === "defer" ? deferSkillsNotice(baseUrl, agents) : writeSdkSkillsStatusLine;
39083
39450
  const remoteSkillNames = await fetchV1SkillNames(baseUrl);
39084
39451
  const skillNames = buildSdkSkillNames(
39085
39452
  remoteSkillNames.length > 0 ? remoteSkillNames : DEFAULT_SDK_SKILL_NAMES
39086
39453
  );
39087
39454
  if (skillNames.length === 0) return;
39088
39455
  if (agents.length === 0) {
39089
- writeUnavailableSkillsNotice(baseUrl, update.remoteVersion, skillNames);
39456
+ writeUnavailableSkillsNotice(
39457
+ baseUrl,
39458
+ update.remoteVersion,
39459
+ skillNames,
39460
+ notice
39461
+ );
39090
39462
  return;
39091
39463
  }
39092
39464
  const installs = resolveSkillsInstallCommands(baseUrl, skillNames, agents);
39093
39465
  if (installs.length === 0) {
39094
- writeUnavailableSkillsNotice(baseUrl, update.remoteVersion, skillNames);
39466
+ writeUnavailableSkillsNotice(
39467
+ baseUrl,
39468
+ update.remoteVersion,
39469
+ skillNames,
39470
+ notice
39471
+ );
39095
39472
  return;
39096
39473
  }
39097
- const claim = claimSkillsSync(baseUrl, agents);
39098
- if (claim.status === "held") return;
39099
- try {
39100
- if (hasFailedSkillsSync(baseUrl, update.remoteVersion, agents) || readSdkSkillsLocalVersion(baseUrl) === update.remoteVersion) {
39101
- return;
39102
- }
39474
+ if (notices === "print") {
39103
39475
  writeSdkSkillsStatusLine(
39104
39476
  "Deepline skills changed; syncing agent skills..."
39105
39477
  );
39106
- const installResult = await runSkillsInstall(installs, agents);
39107
- if (!installResult.installed) {
39108
- const markerWritten = markFailedSkillsSync(
39109
- baseUrl,
39110
- update.remoteVersion,
39111
- agents
39112
- );
39113
- void maybeReportAutomaticSkillsSyncFailure({
39114
- baseUrl,
39115
- remoteSkillsVersion: update.remoteVersion,
39116
- agents,
39117
- skillsPackage: SKILLS_NPX_PACKAGE,
39118
- targetSkillCount: skillNames.length,
39119
- markerWritten,
39120
- attempts: installResult.attempts
39121
- });
39122
- return;
39123
- }
39124
- runLegacySkillsCleanup(agents);
39125
- writeSdkSkillsLocalVersion(baseUrl, update.remoteVersion, agents);
39126
- clearUnavailableSkillsNotice(baseUrl);
39127
- clearFailedSkillsSync(baseUrl, agents);
39128
- writeSdkSkillsStatusLine("Deepline agent skills are up to date.");
39129
- } finally {
39130
- if (claim.status === "claimed") {
39131
- clearSkillsSyncClaim(baseUrl, agents, claim.token);
39132
- }
39133
39478
  }
39479
+ const installResult = await runSkillsInstall(installs, agents, notice);
39480
+ if (!installResult.installed) {
39481
+ const markerWritten = markFailedSkillsSync(
39482
+ baseUrl,
39483
+ update.remoteVersion,
39484
+ agents
39485
+ );
39486
+ void maybeReportAutomaticSkillsSyncFailure({
39487
+ baseUrl,
39488
+ remoteSkillsVersion: update.remoteVersion,
39489
+ agents,
39490
+ skillsPackage: SKILLS_NPX_PACKAGE,
39491
+ targetSkillCount: skillNames.length,
39492
+ markerWritten,
39493
+ attempts: installResult.attempts
39494
+ });
39495
+ return;
39496
+ }
39497
+ runLegacySkillsCleanup(agents);
39498
+ writeSdkSkillsLocalVersion(baseUrl, update.remoteVersion, agents);
39499
+ clearUnavailableSkillsNotice(baseUrl);
39500
+ clearFailedSkillsSync(baseUrl, agents);
39501
+ notice("Deepline agent skills are up to date.");
39134
39502
  }
39135
39503
 
39136
39504
  // src/cli/commands/skills.ts
39505
+ var SKILLS_INSTALL_LEASE_WAIT_MS = 9e4;
39137
39506
  var SKILLS_PROCESS_TIMEOUT_MS = 45e3;
39138
39507
  var RUNTIME_TO_SKILLS_AGENT = {
39139
39508
  antigravity: "antigravity",
@@ -39390,6 +39759,45 @@ async function runSkillsCommand(options, dependencies = {}) {
39390
39759
  )
39391
39760
  ]);
39392
39761
  }
39762
+ const lease = scope === "global" ? await acquireSkillsInstallLease(baseUrl, agents, plan.version, {
39763
+ waitMs: dependencies.installLeaseWaitMs ?? SKILLS_INSTALL_LEASE_WAIT_MS,
39764
+ onWait: () => process.stderr.write(
39765
+ "Waiting for a background Deepline skills refresh to finish...\n"
39766
+ )
39767
+ }) : { release: () => {
39768
+ } };
39769
+ if (!lease) {
39770
+ printCommandEnvelope(
39771
+ {
39772
+ ok: false,
39773
+ status: "failed",
39774
+ code: "SKILLS_SYNC_IN_PROGRESS",
39775
+ exitCode: 7,
39776
+ scope,
39777
+ agents,
39778
+ message: "A background Deepline skills refresh is still running for these agents.",
39779
+ next: `Retry in a moment: deepline skills --scope ${scope} --json. If no refresh is running, remove ${skillsInstallLeasePath(baseUrl, agents)}`
39780
+ },
39781
+ { json: options.json }
39782
+ );
39783
+ return 7;
39784
+ }
39785
+ try {
39786
+ return await runSkillsInstallWithLease({
39787
+ options,
39788
+ dependencies,
39789
+ baseUrl,
39790
+ scope,
39791
+ root,
39792
+ agents,
39793
+ plan
39794
+ });
39795
+ } finally {
39796
+ lease.release();
39797
+ }
39798
+ }
39799
+ async function runSkillsInstallWithLease(input2) {
39800
+ const { options, dependencies, baseUrl, scope, root, agents, plan } = input2;
39393
39801
  process.stderr.write(
39394
39802
  `Replacing Deepline skills for ${agents.join(", ")} (${scope})...
39395
39803
  `
@@ -39502,6 +39910,31 @@ Examples:
39502
39910
  ).action(async (options) => {
39503
39911
  process.exitCode = await runSkillsCommand(options);
39504
39912
  });
39913
+ program.command(SKILLS_AUTO_SYNC_COMMAND, { hidden: true }).description("Refresh Deepline agent skills in the background.").option(
39914
+ "--claim <token>",
39915
+ "Owner token of the leases this child was started for."
39916
+ ).action(async (options) => {
39917
+ const claim = options.claim?.trim();
39918
+ if (!claim) {
39919
+ printCommandEnvelope(
39920
+ {
39921
+ ok: false,
39922
+ status: "failed",
39923
+ code: "SKILLS_AUTO_SYNC_CLAIM_REQUIRED",
39924
+ exitCode: 2,
39925
+ message: "skills-auto-sync is started by ordinary deepline commands and requires the lease token they pass; run `deepline skills` to install skills yourself."
39926
+ },
39927
+ { json: true }
39928
+ );
39929
+ process.exitCode = 2;
39930
+ return;
39931
+ }
39932
+ await syncSdkSkillsIfNeeded(autoDetectBaseUrl().replace(/\/$/, ""), {
39933
+ mode: "inline",
39934
+ notices: "defer",
39935
+ claim
39936
+ });
39937
+ });
39505
39938
  }
39506
39939
 
39507
39940
  // src/cli/commands/setup.ts
@@ -40448,7 +40881,7 @@ import {
40448
40881
  mkdirSync as mkdirSync13,
40449
40882
  readFileSync as readFileSync17,
40450
40883
  renameSync as renameSync2,
40451
- rmSync as rmSync5,
40884
+ rmSync as rmSync6,
40452
40885
  writeFileSync as writeFileSync17
40453
40886
  } from "fs";
40454
40887
  import { homedir as homedir10 } from "os";
@@ -40518,7 +40951,7 @@ function writeCliUpdatePreferences(preferences, homeDir2 = homedir10()) {
40518
40951
  });
40519
40952
  renameSync2(tempPath, path);
40520
40953
  } finally {
40521
- rmSync5(tempPath, { force: true });
40954
+ rmSync6(tempPath, { force: true });
40522
40955
  }
40523
40956
  }
40524
40957
  function setCliAutoUpdateEnabled(enabled, homeDir2 = homedir10()) {
@@ -40574,7 +41007,7 @@ import {
40574
41007
  realpathSync as realpathSync5,
40575
41008
  readFileSync as readFileSync19,
40576
41009
  renameSync as renameSync3,
40577
- rmSync as rmSync6,
41010
+ rmSync as rmSync7,
40578
41011
  unlinkSync as unlinkSync3,
40579
41012
  writeFileSync as writeFileSync18
40580
41013
  } from "fs";
@@ -40590,7 +41023,7 @@ import {
40590
41023
 
40591
41024
  // src/cli/install-integrity.ts
40592
41025
  import { createRequire } from "module";
40593
- import { existsSync as existsSync17, readFileSync as readFileSync18, statSync as statSync6 } from "fs";
41026
+ import { existsSync as existsSync17, readFileSync as readFileSync18, statSync as statSync5 } from "fs";
40594
41027
  import { isAbsolute as isAbsolute6, join as join19, relative as relative6, resolve as resolve17 } from "path";
40595
41028
  var SDK_SIDECAR_CRITICAL_PACKAGE_FILES = [
40596
41029
  "dist/cli/index.mjs",
@@ -40630,7 +41063,7 @@ function parseJson(path) {
40630
41063
  }
40631
41064
  function isFile(path) {
40632
41065
  try {
40633
- return statSync6(path).isFile();
41066
+ return statSync5(path).isFile();
40634
41067
  } catch {
40635
41068
  return false;
40636
41069
  }
@@ -41302,7 +41735,7 @@ async function runPythonSidecarUpdatePlan(plan) {
41302
41735
  versionsDir,
41303
41736
  `.tmp-sdk-update-${process.pid}-${Date.now()}`
41304
41737
  );
41305
- rmSync6(tempDir, { recursive: true, force: true });
41738
+ rmSync7(tempDir, { recursive: true, force: true });
41306
41739
  mkdirSync14(tempDir, { recursive: true });
41307
41740
  writeFileSync18(join20(tempDir, "package.json"), NPM_SDK_SIDECAR_PACKAGE_JSON);
41308
41741
  const env = {
@@ -41324,7 +41757,7 @@ async function runPythonSidecarUpdatePlan(plan) {
41324
41757
  );
41325
41758
  const installExitCode = installResult.exitCode;
41326
41759
  if (installExitCode !== 0) {
41327
- rmSync6(tempDir, { recursive: true, force: true });
41760
+ rmSync7(tempDir, { recursive: true, force: true });
41328
41761
  return installExitCode;
41329
41762
  }
41330
41763
  const installedVersion = installedPackageVersion(tempDir);
@@ -41332,7 +41765,7 @@ async function runPythonSidecarUpdatePlan(plan) {
41332
41765
  process.stderr.write(
41333
41766
  "Updated Deepline SDK package did not report a version.\n"
41334
41767
  );
41335
- rmSync6(tempDir, { recursive: true, force: true });
41768
+ rmSync7(tempDir, { recursive: true, force: true });
41336
41769
  return 1;
41337
41770
  }
41338
41771
  const stagedFailure = sidecarInstallFailure(tempDir);
@@ -41341,7 +41774,7 @@ async function runPythonSidecarUpdatePlan(plan) {
41341
41774
  `Updated Deepline SDK package is incomplete: ${stagedFailure}.
41342
41775
  `
41343
41776
  );
41344
- rmSync6(tempDir, { recursive: true, force: true });
41777
+ rmSync7(tempDir, { recursive: true, force: true });
41345
41778
  return 1;
41346
41779
  }
41347
41780
  const finalDir = join20(versionsDir, installedVersion);
@@ -41349,7 +41782,7 @@ async function runPythonSidecarUpdatePlan(plan) {
41349
41782
  const finalFailure = sidecarInstallFailure(finalDir);
41350
41783
  let backupDir = null;
41351
41784
  if (!finalFailure) {
41352
- rmSync6(tempDir, { recursive: true, force: true });
41785
+ rmSync7(tempDir, { recursive: true, force: true });
41353
41786
  } else {
41354
41787
  let shouldPublishTemp = true;
41355
41788
  if (existsSync18(finalDir)) {
@@ -41362,11 +41795,11 @@ async function runPythonSidecarUpdatePlan(plan) {
41362
41795
  } catch (error) {
41363
41796
  const concurrentlyPublishedFailure = sidecarInstallFailure(finalDir);
41364
41797
  if (!concurrentlyPublishedFailure) {
41365
- rmSync6(tempDir, { recursive: true, force: true });
41798
+ rmSync7(tempDir, { recursive: true, force: true });
41366
41799
  backupDir = null;
41367
41800
  shouldPublishTemp = false;
41368
41801
  } else {
41369
- rmSync6(tempDir, { recursive: true, force: true });
41802
+ rmSync7(tempDir, { recursive: true, force: true });
41370
41803
  process.stderr.write(
41371
41804
  `Failed to preserve the incomplete Deepline SDK sidecar before repair: ${error.message}.
41372
41805
  `
@@ -41379,10 +41812,10 @@ async function runPythonSidecarUpdatePlan(plan) {
41379
41812
  try {
41380
41813
  renameSync3(tempDir, finalDir);
41381
41814
  } catch (error) {
41382
- rmSync6(tempDir, { recursive: true, force: true });
41815
+ rmSync7(tempDir, { recursive: true, force: true });
41383
41816
  const concurrentlyPublishedFailure = sidecarInstallFailure(finalDir);
41384
41817
  if (!concurrentlyPublishedFailure) {
41385
- if (backupDir) rmSync6(backupDir, { recursive: true, force: true });
41818
+ if (backupDir) rmSync7(backupDir, { recursive: true, force: true });
41386
41819
  backupDir = null;
41387
41820
  } else {
41388
41821
  let restoreFailure = "";
@@ -41406,7 +41839,7 @@ async function runPythonSidecarUpdatePlan(plan) {
41406
41839
  const publishedFailure = sidecarStructureFailure(finalDir);
41407
41840
  if (publishedFailure) {
41408
41841
  if (backupDir && existsSync18(backupDir)) {
41409
- rmSync6(finalDir, { recursive: true, force: true });
41842
+ rmSync7(finalDir, { recursive: true, force: true });
41410
41843
  try {
41411
41844
  renameSync3(backupDir, finalDir);
41412
41845
  backupDir = null;
@@ -41419,7 +41852,7 @@ async function runPythonSidecarUpdatePlan(plan) {
41419
41852
  );
41420
41853
  return 1;
41421
41854
  }
41422
- if (backupDir) rmSync6(backupDir, { recursive: true, force: true });
41855
+ if (backupDir) rmSync7(backupDir, { recursive: true, force: true });
41423
41856
  writeSidecarLauncher({
41424
41857
  path: plan.sidecarPath,
41425
41858
  hostUrl: plan.hostUrl,
@@ -43560,14 +43993,15 @@ Examples:
43560
43993
  deepline tools describe hunter_email_verifier --json
43561
43994
  deepline tools describe deeplineagent --model openai/gpt-5.5 --json
43562
43995
  deepline tools describe ai_inference --estimate-payload @payload.json --json
43996
+ deepline tools describe ai_evaluate --estimate-payload @payload.json --json
43563
43997
  deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
43564
43998
  `
43565
43999
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option(
43566
44000
  "--model <model>",
43567
- "For deeplineagent, include AI Gateway model/provider option metadata"
44001
+ "For language tools, include AI Gateway metadata; for ai_evaluate, set the quote payload model"
43568
44002
  ).option(
43569
44003
  "--estimate-payload <payload>",
43570
- "Quote an ai_inference or deeplineagent JSON payload (inline or @file)"
44004
+ "Quote an ai_evaluate, ai_inference, or deeplineagent JSON payload (inline or @file)"
43571
44005
  ).option("--pricing-only", "Only print pricing and billing semantics").option("--schema-only", "Only print input schema fields").option(
43572
44006
  "--examples-only",
43573
44007
  "Only print runnable examples and sample payloads"
@@ -43669,9 +44103,9 @@ async function getTool(toolId, options = {}) {
43669
44103
  }
43670
44104
  let inferenceQuote = null;
43671
44105
  if (options.estimatePayload) {
43672
- if (toolId !== "deeplineagent" && toolId !== "ai_inference") {
44106
+ if (toolId !== "deeplineagent" && toolId !== "ai_inference" && toolId !== "ai_evaluate") {
43673
44107
  console.error(
43674
- "--estimate-payload is only supported for deeplineagent and ai_inference."
44108
+ "--estimate-payload is only supported for ai_evaluate, deeplineagent, and ai_inference."
43675
44109
  );
43676
44110
  return 2;
43677
44111
  }
@@ -43685,7 +44119,7 @@ async function getTool(toolId, options = {}) {
43685
44119
  inferenceQuote = await client2.quoteInferenceTool(toolId, estimatePayload);
43686
44120
  }
43687
44121
  const modelDescription = options.model && (toolId === "deeplineagent" || toolId === "ai_inference") ? await client2.describeModel(options.model) : null;
43688
- if (options.model && !modelDescription) {
44122
+ if (options.model && !modelDescription && toolId !== "ai_evaluate") {
43689
44123
  console.error(
43690
44124
  "--model is only supported for deeplineagent and ai_inference."
43691
44125
  );
@@ -46263,7 +46697,7 @@ Exit codes:
46263
46697
  `
46264
46698
  );
46265
46699
  program.hook("preAction", async (_thisCommand, actionCommand) => {
46266
- if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "setup" || actionCommand.name() === "skills" || actionCommand.name() === "doctor" || isAutoUpdateSettingsInvocation() || isDeprecatedCommandInvocation()) {
46700
+ if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "setup" || actionCommand.name() === "skills" || actionCommand.name() === SKILLS_AUTO_SYNC_COMMAND || actionCommand.name() === "doctor" || isAutoUpdateSettingsInvocation() || isDeprecatedCommandInvocation()) {
46267
46701
  return;
46268
46702
  }
46269
46703
  const compatibilityCommand = compatibilityCommandPath(actionCommand) || actionCommand.name();
@@ -46271,18 +46705,42 @@ Exit codes:
46271
46705
  progress?.phase("checking sdk compatibility");
46272
46706
  }
46273
46707
  const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
46708
+ flushDeferredSkillsSyncNotices(baseUrl);
46274
46709
  const shouldDeferSkillsSync = shouldDeferSkillsSyncForCommand();
46275
46710
  const skillsVersion = shouldDeferSkillsSync ? void 0 : readSdkSkillsLocalVersion(baseUrl);
46276
- const compatibility = await traceCliSpan(
46711
+ const trusted = readTrustedCleanCompatibility(
46712
+ baseUrl,
46713
+ compatibilityCommand,
46714
+ skillsVersion
46715
+ );
46716
+ const fastDeadline = trusted === null && readFreshCleanCompatibility(
46717
+ baseUrl,
46718
+ compatibilityCommand,
46719
+ skillsVersion
46720
+ ) !== null;
46721
+ if (trusted) {
46722
+ recordCliTrace({
46723
+ phase: "cli.sdk_compatibility",
46724
+ ms: 0,
46725
+ ok: true,
46726
+ baseUrl,
46727
+ command: compatibilityCommand,
46728
+ skillsVersion: skillsVersion ?? null,
46729
+ source: "trusted_cache"
46730
+ });
46731
+ }
46732
+ const compatibility = trusted ? { response: trusted, error: null } : await traceCliSpan(
46277
46733
  "cli.sdk_compatibility",
46278
46734
  {
46279
46735
  baseUrl,
46280
46736
  command: compatibilityCommand,
46281
- skillsVersion: skillsVersion ?? null
46737
+ skillsVersion: skillsVersion ?? null,
46738
+ fastDeadline
46282
46739
  },
46283
46740
  () => checkSdkCompatibility(baseUrl, {
46284
46741
  command: compatibilityCommand,
46285
- skillsVersion
46742
+ skillsVersion,
46743
+ ...fastDeadline ? { timeoutMs: SDK_COMPATIBILITY_FAST_DEADLINE_MS } : {}
46286
46744
  })
46287
46745
  );
46288
46746
  if (compatibility.error) {
@@ -46305,7 +46763,8 @@ Exit codes:
46305
46763
  "cli.sdk_skills_sync",
46306
46764
  { baseUrl },
46307
46765
  () => syncSdkSkillsIfNeeded(baseUrl, {
46308
- update: skillsUpdate
46766
+ update: skillsUpdate,
46767
+ mode: "detached"
46309
46768
  })
46310
46769
  );
46311
46770
  }