happyskills 0.4.2 → 0.4.4
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 +10 -0
- package/package.json +1 -1
- package/src/config/paths.js +1 -23
- package/src/config/paths.test.js +13 -28
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.4.4] - 2026-03-05
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Fix all commands (`install`, `list`, `setup`, `update`, `uninstall`, `check`, `bump`, `convert`) inheriting skills from a parent directory; `find_project_root()` now always uses the current working directory and never walks up the directory tree
|
|
14
|
+
|
|
15
|
+
## [0.4.3] - 2026-03-05
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Fix `find_project_root()` still treating the home directory as a project root via `~/skills-lock.json`; the home directory is now fully excluded from all project root detection checks
|
|
19
|
+
|
|
10
20
|
## [0.4.2] - 2026-03-05
|
|
11
21
|
|
|
12
22
|
### Fixed
|
package/package.json
CHANGED
package/src/config/paths.js
CHANGED
|
@@ -34,29 +34,7 @@ const lock_file_path = (project_root = process.cwd()) => path.join(project_root,
|
|
|
34
34
|
|
|
35
35
|
const skill_install_dir = (base_skills_dir, name) => path.join(base_skills_dir, name)
|
|
36
36
|
|
|
37
|
-
const find_project_root = (start_dir = process.cwd()) =>
|
|
38
|
-
let dir = path.resolve(start_dir)
|
|
39
|
-
while (true) {
|
|
40
|
-
const skills = path.join(dir, '.claude', 'skills')
|
|
41
|
-
const lock = path.join(dir, 'skills-lock.json')
|
|
42
|
-
// Skip if this would match the global skills dir (~/.claude/skills)
|
|
43
|
-
// to avoid treating the home directory as a project root
|
|
44
|
-
if (skills !== global_skills_dir()) {
|
|
45
|
-
try {
|
|
46
|
-
fs.statSync(skills)
|
|
47
|
-
return dir
|
|
48
|
-
} catch {}
|
|
49
|
-
}
|
|
50
|
-
try {
|
|
51
|
-
fs.statSync(lock)
|
|
52
|
-
return dir
|
|
53
|
-
} catch {}
|
|
54
|
-
const parent = path.dirname(dir)
|
|
55
|
-
if (parent === dir) break
|
|
56
|
-
dir = parent
|
|
57
|
-
}
|
|
58
|
-
return start_dir
|
|
59
|
-
}
|
|
37
|
+
const find_project_root = (start_dir = process.cwd()) => path.resolve(start_dir)
|
|
60
38
|
|
|
61
39
|
module.exports = {
|
|
62
40
|
home_dir,
|
package/src/config/paths.test.js
CHANGED
|
@@ -100,62 +100,47 @@ describe('paths', () => {
|
|
|
100
100
|
})
|
|
101
101
|
|
|
102
102
|
describe('find_project_root', () => {
|
|
103
|
-
it('
|
|
103
|
+
it('returns the given directory as-is', () => {
|
|
104
104
|
const tmp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'hs-test-')))
|
|
105
105
|
try {
|
|
106
|
-
fs.mkdirSync(path.join(tmp, '.claude', 'skills'), { recursive: true })
|
|
107
|
-
assert.strictEqual(paths.find_project_root(tmp), tmp)
|
|
108
|
-
} finally {
|
|
109
|
-
fs.rmSync(tmp, { recursive: true })
|
|
110
|
-
}
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('finds project root by skills-lock.json', () => {
|
|
114
|
-
const tmp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'hs-test-')))
|
|
115
|
-
try {
|
|
116
|
-
fs.writeFileSync(path.join(tmp, 'skills-lock.json'), '{}')
|
|
117
106
|
assert.strictEqual(paths.find_project_root(tmp), tmp)
|
|
118
107
|
} finally {
|
|
119
108
|
fs.rmSync(tmp, { recursive: true })
|
|
120
109
|
}
|
|
121
110
|
})
|
|
122
111
|
|
|
123
|
-
it('
|
|
112
|
+
it('does not walk up to a parent with .claude/skills', () => {
|
|
124
113
|
const tmp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'hs-test-')))
|
|
125
114
|
try {
|
|
126
115
|
fs.mkdirSync(path.join(tmp, '.claude', 'skills'), { recursive: true })
|
|
127
|
-
const sub = path.join(tmp, '
|
|
116
|
+
const sub = path.join(tmp, 'sub')
|
|
128
117
|
fs.mkdirSync(sub, { recursive: true })
|
|
129
|
-
|
|
118
|
+
// should return sub, not tmp
|
|
119
|
+
assert.strictEqual(paths.find_project_root(sub), sub)
|
|
130
120
|
} finally {
|
|
131
121
|
fs.rmSync(tmp, { recursive: true })
|
|
132
122
|
}
|
|
133
123
|
})
|
|
134
124
|
|
|
135
|
-
it('
|
|
125
|
+
it('does not walk up to a parent with skills-lock.json', () => {
|
|
136
126
|
const tmp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'hs-test-')))
|
|
137
127
|
try {
|
|
128
|
+
fs.writeFileSync(path.join(tmp, 'skills-lock.json'), '{}')
|
|
138
129
|
const sub = path.join(tmp, 'sub')
|
|
139
130
|
fs.mkdirSync(sub, { recursive: true })
|
|
131
|
+
// should return sub, not tmp
|
|
140
132
|
assert.strictEqual(paths.find_project_root(sub), sub)
|
|
141
133
|
} finally {
|
|
142
134
|
fs.rmSync(tmp, { recursive: true })
|
|
143
135
|
}
|
|
144
136
|
})
|
|
145
137
|
|
|
146
|
-
it('
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
try { fs.statSync(global_skills); global_exists = true } catch {}
|
|
150
|
-
if (!global_exists) return // skip if global dir not present on this machine
|
|
138
|
+
it('returns home dir only when explicitly called with it', () => {
|
|
139
|
+
assert.strictEqual(paths.find_project_root(os.homedir()), os.homedir())
|
|
140
|
+
})
|
|
151
141
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
// tmp has no project markers — should fall back to tmp, not home dir
|
|
155
|
-
assert.strictEqual(paths.find_project_root(tmp), tmp)
|
|
156
|
-
} finally {
|
|
157
|
-
fs.rmSync(tmp, { recursive: true })
|
|
158
|
-
}
|
|
142
|
+
it('defaults to cwd when no argument given', () => {
|
|
143
|
+
assert.strictEqual(paths.find_project_root(), path.resolve(process.cwd()))
|
|
159
144
|
})
|
|
160
145
|
})
|
|
161
146
|
})
|