@cleocode/caamp 1.1.2 → 1.2.1

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.
@@ -1134,8 +1134,8 @@ async function linkToAgent(canonicalPath, provider, skillName, isGlobal, project
1134
1134
  await mkdir2(targetSkillsDir, { recursive: true });
1135
1135
  const linkPath = join4(targetSkillsDir, skillName);
1136
1136
  if (existsSync8(linkPath)) {
1137
- const stat = lstatSync(linkPath);
1138
- if (stat.isSymbolicLink()) {
1137
+ const stat2 = lstatSync(linkPath);
1138
+ if (stat2.isSymbolicLink()) {
1139
1139
  await rm(linkPath);
1140
1140
  } else {
1141
1141
  await rm(linkPath, { recursive: true });
@@ -1287,8 +1287,8 @@ async function snapshotSkillState(providerTargets, operation, projectDir, backup
1287
1287
  pathSnapshots.push({ linkPath, state: "missing" });
1288
1288
  continue;
1289
1289
  }
1290
- const stat = lstatSync2(linkPath);
1291
- if (stat.isSymbolicLink()) {
1290
+ const stat2 = lstatSync2(linkPath);
1291
+ if (stat2.isSymbolicLink()) {
1292
1292
  pathSnapshots.push({
1293
1293
  linkPath,
1294
1294
  state: "symlink",
@@ -1298,7 +1298,7 @@ async function snapshotSkillState(providerTargets, operation, projectDir, backup
1298
1298
  }
1299
1299
  const backupPath = join5(backupRoot, "links", provider.id, `${skillName}-${basename(linkPath)}`);
1300
1300
  await mkdir3(dirname4(backupPath), { recursive: true });
1301
- if (stat.isDirectory()) {
1301
+ if (stat2.isDirectory()) {
1302
1302
  await cp2(linkPath, backupPath, { recursive: true });
1303
1303
  pathSnapshots.push({ linkPath, state: "directory", backupPath });
1304
1304
  continue;
@@ -1614,12 +1614,24 @@ async function configureProviderGlobalAndProject(provider, options) {
1614
1614
  }
1615
1615
 
1616
1616
  // src/core/lock-utils.ts
1617
- import { open, readFile as readFile6, writeFile as writeFile6, mkdir as mkdir4, rm as rm3, rename } from "fs/promises";
1617
+ import { open, readFile as readFile6, writeFile as writeFile6, mkdir as mkdir4, rm as rm3, rename, stat } from "fs/promises";
1618
1618
  import { existsSync as existsSync10 } from "fs";
1619
1619
  var LOCK_GUARD_PATH = `${LOCK_FILE_PATH}.lock`;
1620
+ var STALE_LOCK_MS = 5e3;
1620
1621
  function sleep(ms) {
1621
1622
  return new Promise((resolve3) => setTimeout(resolve3, ms));
1622
1623
  }
1624
+ async function removeStaleLock() {
1625
+ try {
1626
+ const info = await stat(LOCK_GUARD_PATH);
1627
+ if (Date.now() - info.mtimeMs > STALE_LOCK_MS) {
1628
+ await rm3(LOCK_GUARD_PATH, { force: true });
1629
+ return true;
1630
+ }
1631
+ } catch {
1632
+ }
1633
+ return false;
1634
+ }
1623
1635
  async function acquireLockGuard(retries = 40, delayMs = 25) {
1624
1636
  await mkdir4(AGENTS_HOME, { recursive: true });
1625
1637
  for (let attempt = 0; attempt < retries; attempt += 1) {
@@ -1631,6 +1643,10 @@ async function acquireLockGuard(retries = 40, delayMs = 25) {
1631
1643
  if (!(error instanceof Error) || !("code" in error) || error.code !== "EEXIST") {
1632
1644
  throw error;
1633
1645
  }
1646
+ if (attempt === 0) {
1647
+ const removed = await removeStaleLock();
1648
+ if (removed) continue;
1649
+ }
1634
1650
  await sleep(delayMs);
1635
1651
  }
1636
1652
  }
@@ -1715,7 +1731,12 @@ var GITLAB_URL = /^https?:\/\/(?:www\.)?gitlab\.com\/([^/]+)\/([^/]+)(?:\/-\/(?:
1715
1731
  var HTTP_URL = /^https?:\/\//;
1716
1732
  var NPM_SCOPED = /^@[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/;
1717
1733
  var NPM_PACKAGE = /^[a-zA-Z0-9_.-]+$/;
1734
+ var LIBRARY_SKILL = /^(@[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+|[a-zA-Z0-9_.-]+):([a-zA-Z0-9_.-]+)$/;
1718
1735
  function inferName(source, type) {
1736
+ if (type === "library") {
1737
+ const match = source.match(LIBRARY_SKILL);
1738
+ return match?.[2] ?? source;
1739
+ }
1719
1740
  if (type === "remote") {
1720
1741
  try {
1721
1742
  const url = new URL(source);
@@ -1829,6 +1850,18 @@ function parseSource(input) {
1829
1850
  path
1830
1851
  };
1831
1852
  }
1853
+ const libraryMatch = input.match(LIBRARY_SKILL);
1854
+ if (libraryMatch) {
1855
+ return {
1856
+ type: "library",
1857
+ value: input,
1858
+ inferredName: inferName(input, "library"),
1859
+ owner: libraryMatch[1],
1860
+ // This will be the package name, e.g. @cleocode/ct-skills
1861
+ repo: libraryMatch[2]
1862
+ // This will be the skill name, e.g. ct-research-agent
1863
+ };
1864
+ }
1832
1865
  if (NPM_SCOPED.test(input)) {
1833
1866
  return {
1834
1867
  type: "package",
@@ -2407,19 +2440,6 @@ function discoverLibrary() {
2407
2440
  } catch {
2408
2441
  }
2409
2442
  }
2410
- const canonicalPath = join7(getAgentsHome(), "skill-library");
2411
- if (existsSync12(canonicalPath)) {
2412
- try {
2413
- const indexPath = join7(canonicalPath, "index.js");
2414
- if (existsSync12(indexPath)) {
2415
- return loadLibraryFromModule(canonicalPath);
2416
- }
2417
- if (existsSync12(join7(canonicalPath, "skills.json"))) {
2418
- return buildLibraryFromFiles(canonicalPath);
2419
- }
2420
- } catch {
2421
- }
2422
- }
2423
2443
  return null;
2424
2444
  }
2425
2445
  function getLibrary() {
@@ -2589,6 +2609,9 @@ async function discoverSkillsMulti(dirs) {
2589
2609
 
2590
2610
  // src/core/skills/lock.ts
2591
2611
  import { simpleGit } from "simple-git";
2612
+ import { execFile } from "child_process";
2613
+ import { promisify } from "util";
2614
+ var execFileAsync = promisify(execFile);
2592
2615
  async function recordSkillInstall(skillName, scopedName, source, sourceType, agents, canonicalPath, isGlobal, projectDir, version) {
2593
2616
  await updateLockFile((lock) => {
2594
2617
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -2635,13 +2658,21 @@ async function fetchLatestSha(repoUrl, ref) {
2635
2658
  return null;
2636
2659
  }
2637
2660
  }
2661
+ async function fetchLatestPackageVersion(packageName) {
2662
+ try {
2663
+ const { stdout } = await execFileAsync("npm", ["view", packageName, "version"]);
2664
+ return stdout.trim() || null;
2665
+ } catch {
2666
+ return null;
2667
+ }
2668
+ }
2638
2669
  async function checkSkillUpdate(skillName) {
2639
2670
  const lock = await readLockFile();
2640
2671
  const entry = lock.skills[skillName];
2641
2672
  if (!entry) {
2642
2673
  return { hasUpdate: false, status: "unknown" };
2643
2674
  }
2644
- if (entry.sourceType !== "github" && entry.sourceType !== "gitlab") {
2675
+ if (entry.sourceType !== "github" && entry.sourceType !== "gitlab" && entry.sourceType !== "library") {
2645
2676
  return {
2646
2677
  hasUpdate: false,
2647
2678
  currentVersion: entry.version,
@@ -2649,7 +2680,33 @@ async function checkSkillUpdate(skillName) {
2649
2680
  };
2650
2681
  }
2651
2682
  const parsed = parseSource(entry.source);
2652
- if (!parsed.owner || !parsed.repo) {
2683
+ if (!parsed.owner) {
2684
+ return {
2685
+ hasUpdate: false,
2686
+ currentVersion: entry.version,
2687
+ status: "unknown"
2688
+ };
2689
+ }
2690
+ if (entry.sourceType === "library") {
2691
+ const packageName = parsed.owner;
2692
+ const latestVersion = await fetchLatestPackageVersion(packageName);
2693
+ if (!latestVersion) {
2694
+ return {
2695
+ hasUpdate: false,
2696
+ currentVersion: entry.version,
2697
+ status: "unknown"
2698
+ };
2699
+ }
2700
+ const currentVersion2 = entry.version;
2701
+ const hasUpdate2 = !currentVersion2 || currentVersion2 !== latestVersion;
2702
+ return {
2703
+ hasUpdate: hasUpdate2,
2704
+ currentVersion: currentVersion2 ?? "unknown",
2705
+ latestVersion,
2706
+ status: hasUpdate2 ? "update-available" : "up-to-date"
2707
+ };
2708
+ }
2709
+ if (!parsed.repo) {
2653
2710
  return {
2654
2711
  hasUpdate: false,
2655
2712
  currentVersion: entry.version,
@@ -2675,6 +2732,15 @@ async function checkSkillUpdate(skillName) {
2675
2732
  status: hasUpdate ? "update-available" : "up-to-date"
2676
2733
  };
2677
2734
  }
2735
+ async function checkAllSkillUpdates() {
2736
+ const lock = await readLockFile();
2737
+ const skillNames = Object.keys(lock.skills);
2738
+ const results = {};
2739
+ await Promise.all(skillNames.map(async (name) => {
2740
+ results[name] = await checkSkillUpdate(name);
2741
+ }));
2742
+ return results;
2743
+ }
2678
2744
 
2679
2745
  // src/core/skills/recommendation.ts
2680
2746
  var RECOMMENDATION_ERROR_CODES = {
@@ -3652,6 +3718,7 @@ export {
3652
3718
  removeSkillFromLock,
3653
3719
  getTrackedSkills,
3654
3720
  checkSkillUpdate,
3721
+ checkAllSkillUpdates,
3655
3722
  RECOMMENDATION_ERROR_CODES,
3656
3723
  tokenizeCriteriaValue,
3657
3724
  validateRecommendationCriteria,
@@ -3666,4 +3733,4 @@ export {
3666
3733
  toSarif,
3667
3734
  validateSkill
3668
3735
  };
3669
- //# sourceMappingURL=chunk-7YV3KXEJ.js.map
3736
+ //# sourceMappingURL=chunk-GR47LTXR.js.map