deepline 0.3.188 → 0.3.190

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.
@@ -3046,7 +3046,7 @@ var SDK_RELEASE = {
3046
3046
  // getters keep their established compatibility behavior.
3047
3047
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
3048
3048
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
3049
- version: "0.3.188",
3049
+ version: "0.3.190",
3050
3050
  updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
3051
3051
  packageCapabilities: {
3052
3052
  updatePreferences: 1
@@ -3271,6 +3271,13 @@ var KNOWN_SKILL_AGENTS = [
3271
3271
  "gemini-cli",
3272
3272
  "windsurf"
3273
3273
  ];
3274
+ var DEFAULT_SKILL_AGENTS = [
3275
+ "codex",
3276
+ "claude-code",
3277
+ "cursor",
3278
+ "gemini-cli",
3279
+ "antigravity"
3280
+ ];
3274
3281
  function skillsAgentPathSegment(agent) {
3275
3282
  if (agent === "*") return "all";
3276
3283
  const slug = agent.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "");
@@ -3283,6 +3290,13 @@ function sdkSkillsVersionPath(baseUrl, agents = []) {
3283
3290
  function legacySdkSkillsVersionPath(baseUrl) {
3284
3291
  return join2(dirname2(sdkCliStateDirPath(baseUrl)), "sdk-skills", ".version");
3285
3292
  }
3293
+ function readSkillsVersionFile(path) {
3294
+ try {
3295
+ return readFileSync2(path, "utf-8").trim();
3296
+ } catch {
3297
+ return "";
3298
+ }
3299
+ }
3286
3300
  function resolveAutoSyncSkillAgents() {
3287
3301
  switch (detectAgentRuntime()) {
3288
3302
  case "codex":
@@ -3295,6 +3309,8 @@ function resolveAutoSyncSkillAgents() {
3295
3309
  return ["gemini-cli"];
3296
3310
  case "antigravity":
3297
3311
  return ["antigravity"];
3312
+ case "unknown":
3313
+ return [...DEFAULT_SKILL_AGENTS];
3298
3314
  default:
3299
3315
  return [];
3300
3316
  }
@@ -3303,6 +3319,13 @@ function readSdkSkillsLocalVersion(baseUrl) {
3303
3319
  const pluginVersion = readPluginSkillsVersion();
3304
3320
  if (pluginVersion) return pluginVersion;
3305
3321
  const agents = resolveAutoSyncSkillAgents();
3322
+ if (agents.length > 1) {
3323
+ const versions = agents.map(
3324
+ (agent) => readSkillsVersionFile(sdkSkillsVersionPath(baseUrl, [agent]))
3325
+ );
3326
+ const first = versions[0];
3327
+ return first && versions.every((version) => version === first) ? first : "";
3328
+ }
3306
3329
  const scopedPath = sdkSkillsVersionPath(baseUrl, agents);
3307
3330
  if (agents.length > 0 && existsSync2(scopedPath)) {
3308
3331
  try {
@@ -3329,10 +3352,19 @@ function readSdkSkillsLocalVersion(baseUrl) {
3329
3352
  }
3330
3353
  }
3331
3354
  function writeSdkSkillsLocalVersion(baseUrl, version, agents) {
3332
- const path = sdkSkillsVersionPath(baseUrl, agents);
3333
- mkdirSync2(dirname2(path), { recursive: true });
3334
- writeFileSync2(path, `${version}
3355
+ const targets = agents.length > 1 ? agents.map((agent) => [agent]) : [agents];
3356
+ let complete = true;
3357
+ for (const target of targets) {
3358
+ const path = sdkSkillsVersionPath(baseUrl, target);
3359
+ try {
3360
+ mkdirSync2(dirname2(path), { recursive: true });
3361
+ writeFileSync2(path, `${version}
3335
3362
  `, "utf-8");
3363
+ } catch {
3364
+ complete = false;
3365
+ }
3366
+ }
3367
+ return complete;
3336
3368
  }
3337
3369
 
3338
3370
  // ../play-runtime/coordinator-headers.ts
@@ -42817,7 +42849,7 @@ import {
42817
42849
  realpathSync as realpathSync5,
42818
42850
  writeFileSync as writeFileSync16
42819
42851
  } from "fs";
42820
- import { homedir as homedir9 } from "os";
42852
+ import { homedir as homedir10 } from "os";
42821
42853
  import { dirname as dirname16, join as join20, resolve as resolve17 } from "path";
42822
42854
 
42823
42855
  // src/cli/installation-lifecycle.ts
@@ -42951,7 +42983,7 @@ function isOwnedInstallerCommandPath(input2) {
42951
42983
  // src/cli/commands/skills.ts
42952
42984
  import { spawn as spawn3 } from "child_process";
42953
42985
  import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync15 } from "fs";
42954
- import { homedir as homedir8 } from "os";
42986
+ import { homedir as homedir9 } from "os";
42955
42987
  import { dirname as dirname15, join as join19 } from "path";
42956
42988
 
42957
42989
  // contracts/install-commands.json
@@ -42987,7 +43019,6 @@ var install_commands_default = {
42987
43019
 
42988
43020
  // src/cli/install-commands.ts
42989
43021
  var INSTALL_COMMANDS = install_commands_default;
42990
- var DEFAULT_SKILL_AGENTS = INSTALL_COMMANDS.skills.default_agents;
42991
43022
  var skillsNpxPackage = INSTALL_COMMANDS.skills.npx_add_args_template.find(
42992
43023
  (arg) => /^skills@\d+\.\d+\.\d+$/.test(arg)
42993
43024
  );
@@ -43038,7 +43069,7 @@ function skillsSourceUrl(baseUrl) {
43038
43069
  function buildSkillsAddArgs(baseUrl, skillName, options = {}) {
43039
43070
  const skillNames = Array.isArray(skillName) ? skillName : [skillName];
43040
43071
  const [firstSkillName, ...extraSkillNames] = skillNames;
43041
- const agents = options.agents ?? INSTALL_COMMANDS.skills.default_agents;
43072
+ const agents = options.agents ?? DEFAULT_SKILL_AGENTS;
43042
43073
  const values = {
43043
43074
  skills_index_url: skillsIndexUrl(baseUrl),
43044
43075
  skills_source_url: skillsSourceUrl(baseUrl),
@@ -43066,11 +43097,14 @@ function buildSkillsAddArgs(baseUrl, skillName, options = {}) {
43066
43097
 
43067
43098
  // src/cli/skills-sync.ts
43068
43099
  import { spawn as spawn2, spawnSync } from "child_process";
43069
- import { randomUUID as randomUUID8 } from "crypto";
43100
+ import { createHash as createHash6, randomUUID as randomUUID8 } from "crypto";
43101
+ import { homedir as homedir8 } from "os";
43102
+ import { gunzipSync } from "zlib";
43070
43103
  import {
43071
43104
  appendFileSync,
43072
43105
  existsSync as existsSync13,
43073
43106
  mkdirSync as mkdirSync10,
43107
+ readdirSync as readdirSync4,
43074
43108
  readFileSync as readFileSync15,
43075
43109
  renameSync,
43076
43110
  rmSync as rmSync5,
@@ -43432,6 +43466,8 @@ async function maybeReportSdkCliFailure(input2) {
43432
43466
 
43433
43467
  // src/cli/skills-sync.ts
43434
43468
  var CHECK_TIMEOUT_MS2 = 3e3;
43469
+ var INSTALLER_PROBE_TIMEOUT_MS = 1500;
43470
+ var PUBLISHED_VERIFICATION_RETRY_MS = 5 * 6e4;
43435
43471
  function shouldSkipSkillsSync() {
43436
43472
  if (detectAgentRuntime() === "claude_cowork" || isCiEnvironment()) {
43437
43473
  return true;
@@ -43720,7 +43756,7 @@ function spawnDetachedSkillsSyncChild(argv, onSpawnError) {
43720
43756
  function failedSkillsSyncPath(baseUrl, agents) {
43721
43757
  return join18(
43722
43758
  sdkCliStateDirPath(baseUrl),
43723
- `skills-sync-failed-${agents.map(agentLeaseSegment).join("-")}-version`
43759
+ `skills-sync-failed-${sortedLeaseAgents(agents).map(agentLeaseSegment).join("-")}-version`
43724
43760
  );
43725
43761
  }
43726
43762
  function hasMarkedSkillsSyncVersion(path, version) {
@@ -43743,13 +43779,15 @@ function writeMarkedSkillsSyncVersion(path, version) {
43743
43779
  return false;
43744
43780
  }
43745
43781
  }
43746
- function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames, notice = writeSdkSkillsStatusLine) {
43782
+ function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames, reason, notice = writeSdkSkillsStatusLine, knownProbes) {
43747
43783
  const path = unavailableSkillsNoticePath(baseUrl);
43748
43784
  if (hasMarkedSkillsSyncVersion(path, remoteVersion)) return;
43749
43785
  writeMarkedSkillsSyncVersion(path, remoteVersion);
43750
- const manualCommand = `npx ${buildSkillsInstallArgs(baseUrl, skillNames).join(" ")}`;
43786
+ const probes = reason === "no-installer" ? knownProbes ?? probeInstallers() : null;
43787
+ const manualCommand = probes?.npx === "missing" && probes.bunx !== "missing" ? `bunx ${buildBunxSkillsInstallArgs(baseUrl, skillNames, DEFAULT_SKILL_AGENTS).map(shellQuote4).join(" ")}` : `npx ${buildSkillsInstallArgs(baseUrl, skillNames).join(" ")}`;
43788
+ const explanation = reason === "unsupported-agent" ? "the detected agent has no automatic skills sync target. Automatic sync was skipped." : probes?.bunx === "missing" && probes.npx === "missing" ? "neither `bunx` nor `npx` was found on PATH. Make one available." : `installer version check failed for ${Object.entries(probes ?? {}).filter(([, result]) => result === "failed").map(([command]) => `\`${command}\``).join(" and ")}. Check those commands with --version.`;
43751
43789
  notice(
43752
- `Deepline agent skills are out of date, but neither \`bunx\` nor \`npx\` is available. Install Node.js/npm or Bun, then run:
43790
+ `Deepline agent skills are out of date, but ${explanation} To install manually, run:
43753
43791
  ${manualCommand}`
43754
43792
  );
43755
43793
  }
@@ -43760,10 +43798,17 @@ function clearUnavailableSkillsNotice(baseUrl) {
43760
43798
  }
43761
43799
  }
43762
43800
  function hasFailedSkillsSync(baseUrl, remoteVersion, agents) {
43763
- return hasMarkedSkillsSyncVersion(
43764
- failedSkillsSyncPath(baseUrl, agents),
43765
- remoteVersion
43801
+ const marked = readMarkedSkillsSyncVersion(
43802
+ failedSkillsSyncPath(baseUrl, agents)
43766
43803
  );
43804
+ if (marked === remoteVersion) return true;
43805
+ try {
43806
+ const retry = JSON.parse(marked);
43807
+ const now = Date.now();
43808
+ return retry.version === remoteVersion && typeof retry.retryAfter === "number" && retry.retryAfter > now && retry.retryAfter <= now + PUBLISHED_VERIFICATION_RETRY_MS;
43809
+ } catch {
43810
+ return false;
43811
+ }
43767
43812
  }
43768
43813
  function hasFailedAutomaticSkillsSync(baseUrl, agents) {
43769
43814
  return existsSync13(failedSkillsSyncPath(baseUrl, agents));
@@ -43774,6 +43819,15 @@ function markFailedSkillsSync(baseUrl, remoteVersion, agents) {
43774
43819
  remoteVersion
43775
43820
  );
43776
43821
  }
43822
+ function deferPublishedVerificationRetry(baseUrl, remoteVersion, agents) {
43823
+ return writeMarkedSkillsSyncVersion(
43824
+ failedSkillsSyncPath(baseUrl, agents),
43825
+ JSON.stringify({
43826
+ version: remoteVersion,
43827
+ retryAfter: Date.now() + PUBLISHED_VERIFICATION_RETRY_MS
43828
+ })
43829
+ );
43830
+ }
43777
43831
  function clearFailedSkillsSync(baseUrl, agents) {
43778
43832
  try {
43779
43833
  unlinkSync2(failedSkillsSyncPath(baseUrl, agents));
@@ -43788,7 +43842,7 @@ function sortedUniqueSkillNames(names) {
43788
43842
  (a, b) => a.localeCompare(b)
43789
43843
  );
43790
43844
  }
43791
- async function fetchV1SkillNames(baseUrl) {
43845
+ async function fetchV1SkillIndex(baseUrl) {
43792
43846
  const controller = new AbortController();
43793
43847
  const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
43794
43848
  try {
@@ -43796,20 +43850,175 @@ async function fetchV1SkillNames(baseUrl) {
43796
43850
  new URL("/.well-known/skills/index.json", baseUrl),
43797
43851
  { signal: controller.signal }
43798
43852
  );
43799
- if (!response.ok) return [];
43853
+ if (!response.ok) return null;
43800
43854
  const data = await response.json().catch(() => null);
43801
- const names = (data?.skills ?? []).filter((skill) => skill.install_surface === "v1").map((skill) => skill.name).filter(
43802
- (name) => typeof name === "string" && name.length > 0
43803
- );
43804
- return sortedUniqueSkillNames(names);
43855
+ return data;
43805
43856
  } catch {
43806
- return [];
43857
+ return null;
43807
43858
  } finally {
43808
43859
  clearTimeout(timeout);
43809
43860
  }
43810
43861
  }
43811
- function buildSdkSkillNames(v1SkillNames) {
43812
- return sortedUniqueSkillNames(v1SkillNames);
43862
+ function v1SkillNames(index) {
43863
+ const skills = Array.isArray(index?.skills) ? index.skills : [];
43864
+ return sortedUniqueSkillNames(
43865
+ skills.filter((skill) => skill && skill.install_surface === "v1").map((skill) => skill.name).filter(
43866
+ (name) => typeof name === "string" && name.length > 0
43867
+ )
43868
+ );
43869
+ }
43870
+ function buildSdkSkillNames(v1SkillNames2) {
43871
+ return sortedUniqueSkillNames(v1SkillNames2);
43872
+ }
43873
+ function isDefaultAgentSet(agents) {
43874
+ return agents.length === DEFAULT_SKILL_AGENTS.length && agents.every((agent, index) => agent === DEFAULT_SKILL_AGENTS[index]);
43875
+ }
43876
+ function safeSkillFilePath(value) {
43877
+ if (typeof value !== "string" || !value) return false;
43878
+ return value.split("/").every(
43879
+ (part) => /^[a-zA-Z0-9._-]+$/.test(part) && part !== "." && part !== ".."
43880
+ );
43881
+ }
43882
+ function installedSkillFiles(root, prefix = "") {
43883
+ const files = [];
43884
+ for (const entry of readdirSync4(join18(root, prefix), {
43885
+ withFileTypes: true
43886
+ })) {
43887
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
43888
+ if (entry.isDirectory()) {
43889
+ files.push(...installedSkillFiles(root, relativePath));
43890
+ } else if (entry.isFile()) {
43891
+ files.push(relativePath);
43892
+ } else {
43893
+ throw new Error(`unexpected installed entry in ${root}`);
43894
+ }
43895
+ }
43896
+ return files.sort((a, b) => a.localeCompare(b));
43897
+ }
43898
+ function publishedArchiveFiles(bytes, expectedFiles, name) {
43899
+ const tar = gunzipSync(bytes, { maxOutputLength: 128 * 1024 * 1024 });
43900
+ const expected = new Set(expectedFiles);
43901
+ const files = /* @__PURE__ */ new Map();
43902
+ let offset = 0;
43903
+ while (offset + 512 <= tar.length) {
43904
+ const header = tar.subarray(offset, offset + 512);
43905
+ if (header.every((byte) => byte === 0)) {
43906
+ if (!tar.subarray(offset).every((byte) => byte === 0)) {
43907
+ throw new Error(`invalid published archive for ${name}`);
43908
+ }
43909
+ break;
43910
+ }
43911
+ const file = header.toString("utf8", 0, 100).split("\0", 1)[0] ?? "";
43912
+ const sizeText = header.toString("ascii", 124, 136).replace(/\0/g, "").trim();
43913
+ const size = /^[0-7]+$/.test(sizeText) ? Number.parseInt(sizeText, 8) : NaN;
43914
+ const type = header[156];
43915
+ if (!safeSkillFilePath(file) || !expected.has(file) || files.has(file) || !Number.isSafeInteger(size) || size < 0 || type !== 0 && type !== 48 || header.subarray(345, 500).some((byte) => byte !== 0)) {
43916
+ throw new Error(`invalid published archive entry for ${name}`);
43917
+ }
43918
+ const start = offset + 512;
43919
+ const end = start + size;
43920
+ if (end > tar.length) {
43921
+ throw new Error(`incomplete published archive for ${name}`);
43922
+ }
43923
+ files.set(file, tar.subarray(start, end));
43924
+ offset = start + Math.ceil(size / 512) * 512;
43925
+ }
43926
+ if (files.size !== expected.size) {
43927
+ throw new Error(`published archive file list differs for ${name}`);
43928
+ }
43929
+ return files;
43930
+ }
43931
+ var PublishedSkillsVerificationError = class extends Error {
43932
+ };
43933
+ async function verifyDefaultAgentSkillsInstall(baseUrl, remoteVersion, skillNames, index) {
43934
+ if (index?.version !== remoteVersion) {
43935
+ throw new PublishedSkillsVerificationError(
43936
+ "the published skill index version does not match the server version"
43937
+ );
43938
+ }
43939
+ const published = /* @__PURE__ */ new Map();
43940
+ const entries = Array.isArray(index.skills) ? index.skills : [];
43941
+ for (const name of skillNames) {
43942
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(name)) {
43943
+ throw new PublishedSkillsVerificationError(
43944
+ `unsafe published skill name: ${name}`
43945
+ );
43946
+ }
43947
+ const entry = entries.find(
43948
+ (skill) => skill && skill.name === name && skill.install_surface === "v1"
43949
+ );
43950
+ if (!Array.isArray(entry?.files) || !entry.files.length || !entry.files.every(safeSkillFilePath) || new Set(entry.files).size !== entry.files.length || !entry.files.includes("SKILL.md") || entry.type !== "archive" || entry.url !== `./archives/${name}.tar.gz` || typeof entry.digest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(entry.digest)) {
43951
+ throw new PublishedSkillsVerificationError(
43952
+ `invalid published file list for ${name}`
43953
+ );
43954
+ }
43955
+ published.set(name, {
43956
+ files: [...entry.files].sort((a, b) => a.localeCompare(b)),
43957
+ digest: entry.digest
43958
+ });
43959
+ }
43960
+ const expected = /* @__PURE__ */ new Map();
43961
+ const jobs = [...published];
43962
+ const controller = new AbortController();
43963
+ const timeout = setTimeout(() => controller.abort(), 12e4);
43964
+ let cursor = 0;
43965
+ try {
43966
+ await Promise.all(
43967
+ Array.from({ length: Math.min(8, jobs.length) }, async () => {
43968
+ while (cursor < jobs.length) {
43969
+ const job = jobs[cursor++];
43970
+ if (!job) break;
43971
+ const [name, publishedSkill] = job;
43972
+ const url = new URL(
43973
+ `/.well-known/skills/archives/${name}.tar.gz`,
43974
+ baseUrl
43975
+ );
43976
+ const response = await fetch(url, { signal: controller.signal });
43977
+ if (!response.ok) {
43978
+ throw new Error(`published archive is unavailable: ${name}`);
43979
+ }
43980
+ const bytes = Buffer.from(await response.arrayBuffer());
43981
+ const digest = `sha256:${createHash6("sha256").update(bytes).digest("hex")}`;
43982
+ if (digest !== publishedSkill.digest) {
43983
+ throw new Error(`published archive digest differs for ${name}`);
43984
+ }
43985
+ for (const [file, content] of publishedArchiveFiles(
43986
+ bytes,
43987
+ publishedSkill.files,
43988
+ name
43989
+ )) {
43990
+ expected.set(`${name}/${file}`, content);
43991
+ }
43992
+ }
43993
+ })
43994
+ );
43995
+ } catch (error) {
43996
+ throw new PublishedSkillsVerificationError(
43997
+ error instanceof Error ? error.message : String(error)
43998
+ );
43999
+ } finally {
44000
+ clearTimeout(timeout);
44001
+ controller.abort();
44002
+ }
44003
+ const home = homedir8();
44004
+ const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join18(home, ".claude");
44005
+ for (const [name, { files }] of published) {
44006
+ for (const root of [
44007
+ join18(home, ".agents", "skills", name),
44008
+ join18(claudeConfigDir, "skills", name)
44009
+ ]) {
44010
+ const installed = installedSkillFiles(root);
44011
+ if (installed.length !== files.length || installed.some((file, index2) => file !== files[index2])) {
44012
+ throw new Error(`installed file tree differs for ${name}`);
44013
+ }
44014
+ for (const file of files) {
44015
+ const publishedContent = expected.get(`${name}/${file}`);
44016
+ if (!publishedContent || !readFileSync15(join18(root, file)).equals(publishedContent)) {
44017
+ throw new Error(`installed content differs for ${name}/${file}`);
44018
+ }
44019
+ }
44020
+ }
44021
+ }
43813
44022
  }
43814
44023
  async function fetchSkillsUpdate(baseUrl, localVersion) {
43815
44024
  const controller = new AbortController();
@@ -43850,13 +44059,58 @@ function buildBunxSkillsInstallArgs(baseUrl, skillNames, agents) {
43850
44059
  agents
43851
44060
  });
43852
44061
  }
43853
- function hasCommand(command) {
44062
+ var NEGATIVE_INSTALLER_PROBE_TTL_MS = 5 * 60 * 1e3;
44063
+ function probeInstallers(timeoutMs) {
44064
+ return {
44065
+ bunx: probeCommand("bunx", timeoutMs),
44066
+ npx: probeCommand("npx", timeoutMs)
44067
+ };
44068
+ }
44069
+ function noInstallerProbePath(baseUrl) {
44070
+ return join18(
44071
+ sdkCliStateDirPath(baseUrl),
44072
+ "skills-sync-no-installer-unknown.json"
44073
+ );
44074
+ }
44075
+ function dueUnknownInstallerProbes(baseUrl, remoteVersion) {
44076
+ const path = noInstallerProbePath(baseUrl);
44077
+ try {
44078
+ const cached = JSON.parse(readFileSync15(path, "utf-8"));
44079
+ if (cached.version === remoteVersion && typeof cached.checkedAt === "number" && cached.checkedAt <= Date.now() && Date.now() - cached.checkedAt < NEGATIVE_INSTALLER_PROBE_TTL_MS && (cached.probes?.bunx === "missing" || cached.probes?.bunx === "failed") && (cached.probes?.npx === "missing" || cached.probes?.npx === "failed")) {
44080
+ return cached.probes;
44081
+ }
44082
+ } catch {
44083
+ }
44084
+ const probes = probeInstallers(INSTALLER_PROBE_TIMEOUT_MS);
44085
+ if (probes.bunx !== "available" && probes.npx !== "available") {
44086
+ try {
44087
+ mkdirSync10(dirname14(path), { recursive: true });
44088
+ writeFileSync14(
44089
+ path,
44090
+ JSON.stringify({
44091
+ version: remoteVersion,
44092
+ checkedAt: Date.now(),
44093
+ probes
44094
+ }),
44095
+ "utf-8"
44096
+ );
44097
+ } catch {
44098
+ }
44099
+ }
44100
+ return probes;
44101
+ }
44102
+ function probeCommand(command, timeoutMs) {
43854
44103
  const plan = resolveShellSpawn(command, ["--version"]);
43855
44104
  const result = spawnSync(plan.command, plan.args, {
43856
44105
  stdio: "ignore",
43857
- shell: plan.shell
44106
+ shell: plan.shell,
44107
+ timeout: timeoutMs
43858
44108
  });
43859
- return result.status === 0;
44109
+ if (result.status === 0) return "available";
44110
+ return result.error?.code === "ENOENT" ? "missing" : "failed";
44111
+ }
44112
+ function hasCommand(command) {
44113
+ return probeCommand(command) === "available";
43860
44114
  }
43861
44115
  function shellQuote4(arg) {
43862
44116
  return `'${arg.replace(/'/g, `'\\''`)}'`;
@@ -43942,7 +44196,7 @@ async function runSkillsInstall(installs, agents, notice = writeSdkSkillsStatusL
43942
44196
  }
43943
44197
  const details = failures.map((failure) => failure.detail).filter(Boolean).join("\n");
43944
44198
  const attemptedCommands = failures.map((failure) => ` ${failure.manualCommand}`).join("\n");
43945
- const retryAgent = agents.at(0);
44199
+ const retryAgent = agents.length === 1 ? agents[0] : void 0;
43946
44200
  notice(
43947
44201
  `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.
43948
44202
  ` + (attemptedCommands ? `Attempted installer command${failures.length === 1 ? "" : "s"}:
@@ -44029,6 +44283,9 @@ async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
44029
44283
  if (options.mode === "detached" && agents.length > 0) {
44030
44284
  flushDeferredSkillsNotices(baseUrl, agents);
44031
44285
  }
44286
+ if (options.mode === "detached" && options.update === void 0 && isDefaultAgentSet(agents)) {
44287
+ return;
44288
+ }
44032
44289
  const ownsInProgressMarker = options.mode !== "detached" && agents.length > 0 && Boolean(options.claim);
44033
44290
  const leases = ownsInProgressMarker ? readInProgressSkillsSyncLeases(baseUrl, agents) : null;
44034
44291
  if (leases && [...leases.values()].some((lease) => lease.owner !== options.claim)) {
@@ -44061,11 +44318,33 @@ async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
44061
44318
  writeUnavailableSkillsNotice(
44062
44319
  baseUrl,
44063
44320
  update.remoteVersion,
44064
- buildSdkSkillNames(DEFAULT_SDK_SKILL_NAMES)
44321
+ buildSdkSkillNames(DEFAULT_SDK_SKILL_NAMES),
44322
+ "unsupported-agent"
44065
44323
  );
44066
44324
  return;
44067
44325
  }
44068
44326
  if (options.mode === "detached" && agents.length > 0) {
44327
+ if (isDefaultAgentSet(agents)) {
44328
+ if (agents.some(
44329
+ (agent) => isFreshInProgressSkillsSync(
44330
+ readInProgressSkillsSyncLease(baseUrl, agent)
44331
+ )
44332
+ )) {
44333
+ return;
44334
+ }
44335
+ const probes = dueUnknownInstallerProbes(baseUrl, update.remoteVersion);
44336
+ if (probes.bunx !== "available" && probes.npx !== "available") {
44337
+ writeUnavailableSkillsNotice(
44338
+ baseUrl,
44339
+ update.remoteVersion,
44340
+ buildSdkSkillNames(DEFAULT_SDK_SKILL_NAMES),
44341
+ "no-installer",
44342
+ writeSdkSkillsStatusLine,
44343
+ probes
44344
+ );
44345
+ return;
44346
+ }
44347
+ }
44069
44348
  const outcome = claimAndSpawnDetachedSkillsSync(
44070
44349
  baseUrl,
44071
44350
  agents,
@@ -44075,10 +44354,11 @@ async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
44075
44354
  if (outcome === "held") return;
44076
44355
  if (outcome === "claimed") {
44077
44356
  writeSdkSkillsStatusLine(
44078
- "Deepline skills changed; refreshing agent skills in the background."
44357
+ "Deepline skills are out of date; updating in the background."
44079
44358
  );
44080
44359
  return;
44081
44360
  }
44361
+ if (isDefaultAgentSet(agents)) return;
44082
44362
  }
44083
44363
  await runInlineSkillsSync(
44084
44364
  baseUrl,
@@ -44095,7 +44375,8 @@ async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
44095
44375
  async function runInlineSkillsSync(baseUrl, remoteVersion, agents, notices) {
44096
44376
  const update = { remoteVersion };
44097
44377
  const notice = notices === "defer" ? deferSkillsNotice(baseUrl, agents) : writeSdkSkillsStatusLine;
44098
- const remoteSkillNames = await fetchV1SkillNames(baseUrl);
44378
+ const index = await fetchV1SkillIndex(baseUrl);
44379
+ const remoteSkillNames = v1SkillNames(index);
44099
44380
  const skillNames = buildSdkSkillNames(
44100
44381
  remoteSkillNames.length > 0 ? remoteSkillNames : DEFAULT_SDK_SKILL_NAMES
44101
44382
  );
@@ -44105,6 +44386,7 @@ async function runInlineSkillsSync(baseUrl, remoteVersion, agents, notices) {
44105
44386
  baseUrl,
44106
44387
  update.remoteVersion,
44107
44388
  skillNames,
44389
+ "unsupported-agent",
44108
44390
  notice
44109
44391
  );
44110
44392
  return;
@@ -44115,6 +44397,7 @@ async function runInlineSkillsSync(baseUrl, remoteVersion, agents, notices) {
44115
44397
  baseUrl,
44116
44398
  update.remoteVersion,
44117
44399
  skillNames,
44400
+ "no-installer",
44118
44401
  notice
44119
44402
  );
44120
44403
  return;
@@ -44140,10 +44423,47 @@ async function runInlineSkillsSync(baseUrl, remoteVersion, agents, notices) {
44140
44423
  markerWritten,
44141
44424
  attempts: installResult.attempts
44142
44425
  });
44426
+ if (isDefaultAgentSet(agents)) {
44427
+ notice(
44428
+ `After fixing the installer, remove ${failedSkillsSyncPath(baseUrl, agents)} to retry this skills version automatically.`
44429
+ );
44430
+ }
44143
44431
  return;
44144
44432
  }
44433
+ if (isDefaultAgentSet(agents)) {
44434
+ try {
44435
+ await verifyDefaultAgentSkillsInstall(
44436
+ baseUrl,
44437
+ update.remoteVersion,
44438
+ skillNames,
44439
+ index
44440
+ );
44441
+ } catch (error) {
44442
+ const detail = error instanceof Error ? error.message : String(error);
44443
+ const publishedFailure = error instanceof PublishedSkillsVerificationError;
44444
+ const markerWritten = publishedFailure ? deferPublishedVerificationRetry(baseUrl, update.remoteVersion, agents) : markFailedSkillsSync(baseUrl, update.remoteVersion, agents);
44445
+ notice(
44446
+ publishedFailure ? `Deepline could not verify the published skills: ${detail}. The local version remains stale; it will retry automatically on a later command.` : `Deepline agent-skills refresh could not verify the five installed targets: ${detail}. The local version remains stale. After fixing the install, remove ${failedSkillsSyncPath(baseUrl, agents)} to retry this version automatically.`
44447
+ );
44448
+ void maybeReportAutomaticSkillsSyncFailure({
44449
+ baseUrl,
44450
+ remoteSkillsVersion: update.remoteVersion,
44451
+ agents,
44452
+ skillsPackage: SKILLS_NPX_PACKAGE,
44453
+ targetSkillCount: skillNames.length,
44454
+ markerWritten,
44455
+ attempts: []
44456
+ });
44457
+ return;
44458
+ }
44459
+ }
44145
44460
  runLegacySkillsCleanup(agents);
44146
- writeSdkSkillsLocalVersion(baseUrl, update.remoteVersion, agents);
44461
+ if (!writeSdkSkillsLocalVersion(baseUrl, update.remoteVersion, agents)) {
44462
+ notice(
44463
+ "Deepline agent skills installed, but the local skills version could not be recorded. A later command will retry the refresh."
44464
+ );
44465
+ return;
44466
+ }
44147
44467
  clearUnavailableSkillsNotice(baseUrl);
44148
44468
  clearFailedSkillsSync(baseUrl, agents);
44149
44469
  notice("Deepline agent skills are up to date.");
@@ -44212,7 +44532,7 @@ function detectSkillsAgents(input2) {
44212
44532
  if (knownAgent) return [knownAgent];
44213
44533
  const roots = [
44214
44534
  ...input2.scope === "local" && input2.root ? [input2.root] : [],
44215
- input2.homeDir ?? homedir8()
44535
+ input2.homeDir ?? homedir9()
44216
44536
  ];
44217
44537
  const detected = AGENT_MARKERS.filter(
44218
44538
  (marker) => roots.some(
@@ -44796,7 +45116,7 @@ function safeRead(path) {
44796
45116
  function removeKnownLegacyPaths(baseUrl) {
44797
45117
  return CliInstallation.forUser({
44798
45118
  baseUrlSlug: baseUrlSlug(baseUrl),
44799
- home: homedir9()
45119
+ home: homedir10()
44800
45120
  }).removeRetiredArtifacts();
44801
45121
  }
44802
45122
  function resolvePathCommands(command) {
@@ -45559,7 +45879,7 @@ import {
45559
45879
  rmSync as rmSync6,
45560
45880
  writeFileSync as writeFileSync17
45561
45881
  } from "fs";
45562
- import { homedir as homedir10 } from "os";
45882
+ import { homedir as homedir11 } from "os";
45563
45883
  import { dirname as dirname17, join as join21 } from "path";
45564
45884
  var UPDATE_PREFERENCES_SCHEMA_VERSION = 1;
45565
45885
  var CLI_UPDATE_MESSAGES = [
@@ -45588,7 +45908,7 @@ function unreadablePreferences(path, error) {
45588
45908
  acknowledgedMessages: CLI_UPDATE_MESSAGES.map(({ id }) => id)
45589
45909
  };
45590
45910
  }
45591
- function cliUpdatePreferencesPath(homeDir2 = homedir10()) {
45911
+ function cliUpdatePreferencesPath(homeDir2 = homedir11()) {
45592
45912
  return join21(
45593
45913
  homeDir2,
45594
45914
  ".local",
@@ -45597,7 +45917,7 @@ function cliUpdatePreferencesPath(homeDir2 = homedir10()) {
45597
45917
  "update-preferences.json"
45598
45918
  );
45599
45919
  }
45600
- function readCliUpdatePreferences(homeDir2 = homedir10()) {
45920
+ function readCliUpdatePreferences(homeDir2 = homedir11()) {
45601
45921
  const path = cliUpdatePreferencesPath(homeDir2);
45602
45922
  if (!existsSync16(path)) return defaultPreferences();
45603
45923
  try {
@@ -45614,7 +45934,7 @@ function readCliUpdatePreferences(homeDir2 = homedir10()) {
45614
45934
  return unreadablePreferences(path, error);
45615
45935
  }
45616
45936
  }
45617
- function writeCliUpdatePreferences(preferences, homeDir2 = homedir10()) {
45937
+ function writeCliUpdatePreferences(preferences, homeDir2 = homedir11()) {
45618
45938
  const path = cliUpdatePreferencesPath(homeDir2);
45619
45939
  const tempPath = `${path}.${process.pid}.tmp`;
45620
45940
  mkdirSync13(dirname17(path), { recursive: true });
@@ -45629,7 +45949,7 @@ function writeCliUpdatePreferences(preferences, homeDir2 = homedir10()) {
45629
45949
  rmSync6(tempPath, { force: true });
45630
45950
  }
45631
45951
  }
45632
- function setCliAutoUpdateEnabled(enabled, homeDir2 = homedir10()) {
45952
+ function setCliAutoUpdateEnabled(enabled, homeDir2 = homedir11()) {
45633
45953
  const current = readCliUpdatePreferences(homeDir2);
45634
45954
  const next = {
45635
45955
  ...current,
@@ -45639,7 +45959,7 @@ function setCliAutoUpdateEnabled(enabled, homeDir2 = homedir10()) {
45639
45959
  writeCliUpdatePreferences(next, homeDir2);
45640
45960
  return next;
45641
45961
  }
45642
- function setCliPinnedVersion(version, homeDir2 = homedir10()) {
45962
+ function setCliPinnedVersion(version, homeDir2 = homedir11()) {
45643
45963
  const next = {
45644
45964
  ...readCliUpdatePreferences(homeDir2),
45645
45965
  pinnedVersion: version
@@ -45647,18 +45967,18 @@ function setCliPinnedVersion(version, homeDir2 = homedir10()) {
45647
45967
  writeCliUpdatePreferences(next, homeDir2);
45648
45968
  return next;
45649
45969
  }
45650
- function clearCliPinnedVersion(homeDir2 = homedir10()) {
45970
+ function clearCliPinnedVersion(homeDir2 = homedir11()) {
45651
45971
  const current = readCliUpdatePreferences(homeDir2);
45652
45972
  if (current.pinnedVersion === null) return current;
45653
45973
  const next = { ...current, pinnedVersion: null };
45654
45974
  writeCliUpdatePreferences(next, homeDir2);
45655
45975
  return next;
45656
45976
  }
45657
- function shouldRunCliAutoUpdate(homeDir2 = homedir10()) {
45977
+ function shouldRunCliAutoUpdate(homeDir2 = homedir11()) {
45658
45978
  const preferences = readCliUpdatePreferences(homeDir2);
45659
45979
  return preferences.autoUpdateEnabled && preferences.pinnedVersion === null;
45660
45980
  }
45661
- function consumePendingCliUpdateMessages(homeDir2 = homedir10()) {
45981
+ function consumePendingCliUpdateMessages(homeDir2 = homedir11()) {
45662
45982
  const preferences = readCliUpdatePreferences(homeDir2);
45663
45983
  const acknowledged = new Set(preferences.acknowledgedMessages);
45664
45984
  const pending = CLI_UPDATE_MESSAGES.filter(({ id }) => !acknowledged.has(id));
@@ -45686,7 +46006,7 @@ import {
45686
46006
  unlinkSync as unlinkSync3,
45687
46007
  writeFileSync as writeFileSync18
45688
46008
  } from "fs";
45689
- import { homedir as homedir11 } from "os";
46009
+ import { homedir as homedir12 } from "os";
45690
46010
  import {
45691
46011
  basename as basename7,
45692
46012
  dirname as dirname18,
@@ -46068,7 +46388,7 @@ function isHomebrewFormulaEntrypoint(entrypoint) {
46068
46388
  }
46069
46389
  function resolveUpdatePlan(options = {}) {
46070
46390
  const env = options.env ?? process.env;
46071
- const homeDir2 = options.homeDir ?? homedir11();
46391
+ const homeDir2 = options.homeDir ?? homedir12();
46072
46392
  const entrypoint = options.entrypoint ?? (process.argv[1] ? resolve19(process.argv[1]) : "");
46073
46393
  const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname18(entrypoint)) : null;
46074
46394
  if (sourceRoot) {
@@ -46126,7 +46446,7 @@ function autoUpdateFailurePath(plan) {
46126
46446
  return join23(plan.stateDir, AUTO_UPDATE_FAILURE_FILE);
46127
46447
  }
46128
46448
  return join23(
46129
- homedir11(),
46449
+ homedir12(),
46130
46450
  ".local",
46131
46451
  "deepline",
46132
46452
  "sdk-cli",
@@ -47608,7 +47928,7 @@ Examples:
47608
47928
 
47609
47929
  // src/cli/commands/tools.ts
47610
47930
  import { Option as Option4 } from "commander";
47611
- import { createHash as createHash6, randomUUID as randomUUID9 } from "crypto";
47931
+ import { createHash as createHash7, randomUUID as randomUUID9 } from "crypto";
47612
47932
 
47613
47933
  // ../plays/row-identity.ts
47614
47934
  function stableValue(value) {
@@ -47648,7 +47968,7 @@ import {
47648
47968
  writeFileSync as writeFileSync19,
47649
47969
  writeSync
47650
47970
  } from "fs";
47651
- import { homedir as homedir12 } from "os";
47971
+ import { homedir as homedir13 } from "os";
47652
47972
  import { dirname as dirname19, join as join24 } from "path";
47653
47973
  function isPlainObject(value) {
47654
47974
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -47776,7 +48096,7 @@ function projectRowOutput(conversion) {
47776
48096
  };
47777
48097
  }
47778
48098
  function ensureOutputDir() {
47779
- const outputDir = join24(homedir12(), ".local", "share", "deepline", "data");
48099
+ const outputDir = join24(homedir13(), ".local", "share", "deepline", "data");
47780
48100
  mkdirSync15(outputDir, { recursive: true });
47781
48101
  return outputDir;
47782
48102
  }
@@ -50135,7 +50455,7 @@ function parseToolExecuteTimeout(raw) {
50135
50455
  }
50136
50456
  function pendingToolExecutionPath(input2) {
50137
50457
  const config = resolveConfig();
50138
- const fingerprint = createHash6("sha256").update(config.baseUrl).update("\0").update(createHash6("sha256").update(config.apiKey).digest("hex")).update("\0").update(input2.toolId).update("\0").update(stableStringify(input2.params)).update("\0").update(input2.responseIntent).digest("hex");
50458
+ const fingerprint = createHash7("sha256").update(config.baseUrl).update("\0").update(createHash7("sha256").update(config.apiKey).digest("hex")).update("\0").update(input2.toolId).update("\0").update(stableStringify(input2.params)).update("\0").update(input2.responseIntent).digest("hex");
50139
50459
  return join25(
50140
50460
  sdkCliStateDirPath(resolveConfig().baseUrl),
50141
50461
  `pending-tool-execution-${fingerprint}.json`
@@ -50718,7 +51038,7 @@ import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from
50718
51038
  import { dirname as dirname21, join as join26, resolve as resolve21 } from "path";
50719
51039
 
50720
51040
  // src/cli/workflow-to-play.ts
50721
- import { createHash as createHash7 } from "crypto";
51041
+ import { createHash as createHash8 } from "crypto";
50722
51042
  var HITL_WAIT_FOR_SIGNAL_TOOL = "deepline_workflow_wait_for_signal";
50723
51043
  var HITL_SLACK_TOOL = "slack_message_with_hitl";
50724
51044
  var SUB_WORKFLOW_TOOL_PREFIX = "deepline_workflow_";
@@ -50824,7 +51144,7 @@ function sanitizePlayNameSegment(value) {
50824
51144
  }
50825
51145
  function deriveWorkflowPlayName(workflowName) {
50826
51146
  const base = sanitizePlayNameSegment(workflowName) || "workflow";
50827
- const suffix = createHash7("sha256").update(workflowName).digest("hex").slice(0, 8);
51147
+ const suffix = createHash8("sha256").update(workflowName).digest("hex").slice(0, 8);
50828
51148
  const reserved = suffix.length + 1;
50829
51149
  const allowedBase = Math.max(1, MAX_PLAY_NAME_LENGTH - reserved);
50830
51150
  let name = `${base.slice(0, allowedBase)}_${suffix}`;