happyskills 0.35.0 → 0.35.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.35.1] - 2026-04-10
11
+
12
+ ### Fixed
13
+ - Fix multi-agent skill symlinks using absolute paths instead of relative — absolute symlinks break when the repo is cloned or pulled on a different machine; now uses `path.relative()` for portable symlinks
14
+ - Fix enable skip-check failing to recognize existing relative symlinks — resolves both relative and absolute link targets before comparing
15
+
10
16
  ## [0.35.0] - 2026-04-10
11
17
 
12
18
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "happyskills",
3
- "version": "0.35.0",
3
+ "version": "0.35.1",
4
4
  "description": "Package manager for AI agent skills",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Nicolas Dao <nic@cloudlesslabs.com> (https://cloudlesslabs.com)",
@@ -43,8 +43,10 @@ const _exists = async (target_path) => {
43
43
  */
44
44
  const _link_or_copy = async (source, target) => {
45
45
  try {
46
+ // Use relative path so symlinks work across machines (clones/pulls)
47
+ const relative_source = path.relative(path.dirname(target), source)
46
48
  // 'junction' works on Windows without admin; ignored on macOS/Linux
47
- await fs.promises.symlink(source, target, 'junction')
49
+ await fs.promises.symlink(relative_source, target, 'junction')
48
50
  return { method: 'symlink' }
49
51
  } catch (err) {
50
52
  if (err.code === 'EPERM' || err.code === 'ENOTSUP') {
@@ -77,7 +79,9 @@ const link_to_agents = (source_dir, agents, options = {}) => catch_errors('Agent
77
79
  if (is_link) {
78
80
  try {
79
81
  const link_target = await fs.promises.readlink(target)
80
- if (link_target === source_dir) {
82
+ // Resolve relative or absolute symlink to compare against source
83
+ const resolved_link = path.resolve(path.dirname(target), link_target)
84
+ if (resolved_link === source_dir) {
81
85
  results.push({ agent_id: agent.id, path: target, method: 'symlink', skipped: true })
82
86
  continue
83
87
  }
@@ -71,7 +71,9 @@ describe('link_to_agents', () => {
71
71
  const link_path = path.join(tmp, '.claude', 'skills', 'deploy-aws')
72
72
  const stat = fs.lstatSync(link_path)
73
73
  assert.ok(stat.isSymbolicLink())
74
- assert.equal(fs.readlinkSync(link_path), source)
74
+ // Symlink should be relative, not absolute
75
+ const link_target = fs.readlinkSync(link_path)
76
+ assert.equal(link_target, path.relative(path.dirname(link_path), source))
75
77
  })
76
78
 
77
79
  it('creates symlinks for multiple agents', async () => {
@@ -126,7 +128,9 @@ describe('link_to_agents', () => {
126
128
  assert.equal(results[0].skipped, undefined)
127
129
 
128
130
  const link_path = path.join(tmp, '.claude', 'skills', 'deploy-aws')
129
- assert.equal(fs.readlinkSync(link_path), source)
131
+ // Symlink should be relative, not absolute
132
+ const link_target = fs.readlinkSync(link_path)
133
+ assert.equal(link_target, path.relative(path.dirname(link_path), source))
130
134
  })
131
135
  })
132
136