happyskills 0.7.0 → 0.7.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,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.1] - 2026-03-06
11
+
12
+ ### Fixed
13
+ - Fix `uninstall` incorrectly orphaning all user-installed skills — `find_orphans` now treats `__root__` as a protected requester, so only skills that were installed solely as transitive dependencies are pruned
14
+
10
15
  ## [0.7.0] - 2026-03-06
11
16
 
12
17
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "happyskills",
3
- "version": "0.7.0",
3
+ "version": "0.7.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)",
@@ -9,11 +9,8 @@ const find_orphans = (skills, removed_skill) => {
9
9
  const orphans = []
10
10
  for (const [name, data] of Object.entries(skills)) {
11
11
  if (name === removed_skill) continue
12
- if (!data.requested_by || data.requested_by.length === 0) {
13
- orphans.push(name)
14
- continue
15
- }
16
- const remaining = data.requested_by.filter(r => r !== removed_skill && skills[r])
12
+ const requested_by = data.requested_by || []
13
+ const remaining = requested_by.filter(r => r === '__root__' || (r !== removed_skill && skills[r]))
17
14
  if (remaining.length === 0) {
18
15
  orphans.push(name)
19
16
  }
@@ -87,12 +87,12 @@ describe('find_orphans', () => {
87
87
  assert.ok(result.includes('acme/auth'))
88
88
  })
89
89
 
90
- it('treats __root__ like any other requester (not in skills map)', () => {
90
+ it('protects skills installed by the user (requested_by includes __root__)', () => {
91
91
  const skills = {
92
92
  'acme/deploy': { requested_by: ['__root__'] }
93
93
  }
94
- // __root__ is not a key in skills, so deploy is considered orphaned
94
+ // __root__ marks a user-installed (root) package should never be orphaned
95
95
  const result = find_orphans(skills, 'acme/other')
96
- assert.ok(result.includes('acme/deploy'))
96
+ assert.ok(!result.includes('acme/deploy'))
97
97
  })
98
98
  })