@npeercy/skills 0.1.8 → 0.1.9

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.
package/lib/skills.js CHANGED
@@ -77,10 +77,9 @@ async function resolveSkillId(input, config) {
77
77
  }
78
78
 
79
79
  function linkNameForSkill(skillId) {
80
- if (skillId.startsWith('__builtin__/local/')) {
81
- return `builtin--${splitSkillId(skillId).name}`;
82
- }
83
- return symlinkName(skillId);
80
+ // Use bare skill name so directory matches name: field in SKILL.md.
81
+ // Pi expects these to match; mismatches show as "[Skill conflicts]".
82
+ return splitSkillId(skillId).name;
84
83
  }
85
84
 
86
85
  async function promptForToken(serverUrl) {
package/lib/startup.js CHANGED
@@ -1,4 +1,6 @@
1
- import { loadConfig, saveConfig } from './config.js';
1
+ import { existsSync, readdirSync, lstatSync, readlinkSync, unlinkSync, symlinkSync, mkdirSync } from 'fs';
2
+ import { join, resolve, dirname } from 'path';
3
+ import { loadConfig, saveConfig, loadState, saveState, detectAgents } from './config.js';
2
4
  import { ensureBuiltinsInstalled, getLocalDiagnostics } from './skills.js';
3
5
 
4
6
  function cmpSemver(a, b) {
@@ -52,10 +54,66 @@ async function runUpdateCheck(currentVersion, { silent = false } = {}) {
52
54
  }
53
55
  }
54
56
 
57
+ function migrateOldSymlinks() {
58
+ // Migrate from old naming (org--user--name, builtin--name) to bare skill name.
59
+ // Pi expects directory name == name: field in SKILL.md.
60
+ const st = loadState();
61
+ const agents = detectAgents();
62
+ let migrated = 0;
63
+
64
+ for (const [id, rec] of Object.entries(st.installed)) {
65
+ const parts = id.split('/');
66
+ const bareName = parts[parts.length - 1]; // the skill name
67
+
68
+ // Figure out old link name
69
+ let oldLinkName;
70
+ if (id.startsWith('__builtin__/local/')) {
71
+ oldLinkName = `builtin--${bareName}`;
72
+ } else {
73
+ oldLinkName = id.replace(/\//g, '--');
74
+ }
75
+
76
+ // If old == new, nothing to do
77
+ if (oldLinkName === bareName) continue;
78
+
79
+ for (const agentName of (rec.agents || [])) {
80
+ const agentPath = agents[agentName];
81
+ if (!agentPath || !existsSync(agentPath)) continue;
82
+
83
+ const oldLink = join(agentPath, oldLinkName);
84
+ const newLink = join(agentPath, bareName);
85
+
86
+ // Remove old symlink if it exists
87
+ try {
88
+ if (lstatSync(oldLink).isSymbolicLink()) {
89
+ unlinkSync(oldLink);
90
+ }
91
+ } catch { /* doesn't exist */ }
92
+
93
+ // Create new symlink if not already there
94
+ if (!existsSync(newLink) && rec.path && existsSync(rec.path)) {
95
+ try {
96
+ mkdirSync(agentPath, { recursive: true });
97
+ symlinkSync(rec.path, newLink);
98
+ migrated++;
99
+ } catch { /* best effort */ }
100
+ }
101
+ }
102
+ }
103
+
104
+ return migrated;
105
+ }
106
+
55
107
  async function runAutoHeal(command, { jsonMode = false } = {}) {
56
108
  if (process.env.SKILLS_NO_STARTUP_HEAL === '1') return;
57
109
  if (['init'].includes(command)) return;
58
110
 
111
+ // Migrate old-style symlinks (org--user--name → bare name)
112
+ const migrated = migrateOldSymlinks();
113
+ if (!jsonMode && migrated > 0) {
114
+ console.log(`✓ Startup heal: migrated ${migrated} symlink(s) to match Pi naming.`);
115
+ }
116
+
59
117
  const result = await ensureBuiltinsInstalled({ quiet: true });
60
118
  if (!jsonMode && result.changed) {
61
119
  console.log(`✓ Startup heal: installed ${result.installed.length} missing built-in skill(s).`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npeercy/skills",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "CLI-first skill marketplace for coding agents",
5
5
  "type": "module",
6
6
  "bin": {