happyskills 0.35.3 → 0.35.5
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 +11 -0
- package/package.json +1 -1
- package/src/commands/enable.js +8 -1
- package/src/commands/refresh.js +3 -2
- package/src/engine/installer.js +21 -12
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.35.5] - 2026-04-11
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Fix kits being symlinked to agent folders during `install`, `refresh`, and `enable` — kits are meta-packages not invocable by agents, only their dependency skills should be linked
|
|
14
|
+
- Block `enable` command for kits with a clear warning instead of silently creating useless symlinks
|
|
15
|
+
|
|
16
|
+
## [0.35.4] - 2026-04-11
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- Fix `refresh` symlink repair skipping dependency-installed skills — only directly-installed skills had their symlinks validated; transitive dependencies with stale symlinks were left untouched
|
|
20
|
+
|
|
10
21
|
## [0.35.3] - 2026-04-11
|
|
11
22
|
|
|
12
23
|
### Fixed
|
package/package.json
CHANGED
package/src/commands/enable.js
CHANGED
|
@@ -6,7 +6,7 @@ const { is_skill_enabled } = require('../agents/status')
|
|
|
6
6
|
const { file_exists } = require('../utils/fs')
|
|
7
7
|
const { print_help, print_json, print_success, print_warn, print_info } = require('../ui/output')
|
|
8
8
|
const { exit_with_error, UsageError } = require('../utils/errors')
|
|
9
|
-
const { EXIT_CODES } = require('../constants')
|
|
9
|
+
const { EXIT_CODES, SKILL_TYPES } = require('../constants')
|
|
10
10
|
|
|
11
11
|
const HELP_TEXT = `Usage: happyskills enable <skill> [skill2 ...] [options]
|
|
12
12
|
|
|
@@ -77,6 +77,13 @@ const run = (args) => catch_errors('Enable failed', async () => {
|
|
|
77
77
|
|
|
78
78
|
const { full, short } = resolved
|
|
79
79
|
|
|
80
|
+
// Kits are not agent-invocable — skip linking
|
|
81
|
+
if (locked_skills[full]?.type === SKILL_TYPES.KIT) {
|
|
82
|
+
print_warn(`${full} is a kit — kits are not linked to agent folders`)
|
|
83
|
+
results.push({ skill: full, status: 'kit_skipped' })
|
|
84
|
+
continue
|
|
85
|
+
}
|
|
86
|
+
|
|
80
87
|
// Verify the skill directory exists on disk
|
|
81
88
|
const dir = skill_install_dir(base_dir, short)
|
|
82
89
|
const [, exists] = await file_exists(dir)
|
package/src/commands/refresh.js
CHANGED
|
@@ -9,7 +9,7 @@ const { green, yellow, red } = require('../ui/colors')
|
|
|
9
9
|
const { create_spinner } = require('../ui/spinner')
|
|
10
10
|
const { exit_with_error } = require('../utils/errors')
|
|
11
11
|
const { find_project_root, lock_root, skills_dir, skill_install_dir } = require('../config/paths')
|
|
12
|
-
const { EXIT_CODES } = require('../constants')
|
|
12
|
+
const { EXIT_CODES, SKILL_TYPES } = require('../constants')
|
|
13
13
|
const { resolve_agents, verify_and_repair_symlinks } = require('../agents')
|
|
14
14
|
const { is_skill_enabled } = require('../agents/status')
|
|
15
15
|
|
|
@@ -123,7 +123,8 @@ const run = (args) => catch_errors('Refresh failed', async () => {
|
|
|
123
123
|
let symlink_repairs = []
|
|
124
124
|
if (detected_agents.length > 0) {
|
|
125
125
|
const skills_to_check = []
|
|
126
|
-
for (const [name] of
|
|
126
|
+
for (const [name, data] of entries) {
|
|
127
|
+
if (data.type === SKILL_TYPES.KIT) continue
|
|
127
128
|
const short_name = name.split('/')[1] || name
|
|
128
129
|
const source_dir = skill_install_dir(base_dir, short_name)
|
|
129
130
|
const [, enabled] = await is_skill_enabled(short_name, detected_agents, is_global, project_root)
|
package/src/engine/installer.js
CHANGED
|
@@ -10,7 +10,7 @@ const { read_lock, get_locked_skill } = require('../lock/reader')
|
|
|
10
10
|
const { write_lock, update_lock_skills } = require('../lock/writer')
|
|
11
11
|
const { skills_dir, tmp_dir, skill_install_dir, lock_root } = require('../config/paths')
|
|
12
12
|
const { ensure_dir, remove_dir, file_exists, read_json } = require('../utils/fs')
|
|
13
|
-
const { SKILL_JSON } = require('../constants')
|
|
13
|
+
const { SKILL_JSON, SKILL_TYPES } = require('../constants')
|
|
14
14
|
const { resolve_agents, link_to_agents, verify_and_repair_symlinks } = require('../agents')
|
|
15
15
|
const { is_skill_enabled } = require('../agents/status')
|
|
16
16
|
const { create_spinner } = require('../ui/spinner')
|
|
@@ -42,8 +42,8 @@ const install = (skill, options = {}) => catch_errors('Install failed', async ()
|
|
|
42
42
|
if (exists) {
|
|
43
43
|
const [, valid] = locked.integrity ? await verify_integrity(install_dir, locked.integrity) : [null, true]
|
|
44
44
|
if (valid !== false) {
|
|
45
|
-
// Verify and repair symlinks even for already-installed skills
|
|
46
|
-
if (agents.length > 0) {
|
|
45
|
+
// Verify and repair symlinks even for already-installed skills (skip kits — not agent-invocable)
|
|
46
|
+
if (agents.length > 0 && locked.type !== SKILL_TYPES.KIT) {
|
|
47
47
|
const name = skill.split('/')[1]
|
|
48
48
|
const [, enabled] = await is_skill_enabled(name, agents, is_global, project_root)
|
|
49
49
|
if (enabled) {
|
|
@@ -103,10 +103,12 @@ const install = (skill, options = {}) => catch_errors('Install failed', async ()
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
if (packages_to_install.length === 0) {
|
|
106
|
-
// Verify and repair symlinks for all skipped packages
|
|
106
|
+
// Verify and repair symlinks for all skipped packages (skip kits — not agent-invocable)
|
|
107
107
|
if (agents.length > 0) {
|
|
108
108
|
const skills_to_verify = []
|
|
109
109
|
for (const pkg of packages) {
|
|
110
|
+
const locked = get_locked_skill(lock_data, pkg.skill)
|
|
111
|
+
if (locked?.type === SKILL_TYPES.KIT) continue
|
|
110
112
|
const name = pkg.skill.split('/')[1]
|
|
111
113
|
const [, enabled] = await is_skill_enabled(name, agents, is_global, project_root)
|
|
112
114
|
if (enabled) {
|
|
@@ -190,10 +192,22 @@ const install = (skill, options = {}) => catch_errors('Install failed', async ()
|
|
|
190
192
|
await fs.promises.rename(tmp_path, final_dir)
|
|
191
193
|
}
|
|
192
194
|
|
|
195
|
+
// Read type from each installed package's skill.json (used for linking + lock writing)
|
|
196
|
+
const pkg_types = {}
|
|
197
|
+
for (const { pkg } of downloaded) {
|
|
198
|
+
const name = pkg.skill.split('/')[1]
|
|
199
|
+
const final_dir = skill_install_dir(base_dir, name)
|
|
200
|
+
const pkg_json_path = path.join(final_dir, SKILL_JSON)
|
|
201
|
+
const [, pkg_manifest] = await read_json(pkg_json_path)
|
|
202
|
+
if (pkg_manifest?.type) pkg_types[pkg.skill] = pkg_manifest.type
|
|
203
|
+
}
|
|
204
|
+
|
|
193
205
|
// Link to detected agents (non-fatal — warnings only)
|
|
194
|
-
// Skip linking for skills that were disabled before this install/update
|
|
206
|
+
// Skip linking for kits (not invocable by agents) and skills that were disabled before this install/update
|
|
195
207
|
if (agents.length > 0) {
|
|
196
|
-
const to_link = downloaded.filter(({ pkg }) =>
|
|
208
|
+
const to_link = downloaded.filter(({ pkg }) =>
|
|
209
|
+
pkg_types[pkg.skill] !== SKILL_TYPES.KIT && !disabled_skills.has(pkg.skill.split('/')[1])
|
|
210
|
+
)
|
|
197
211
|
if (to_link.length > 0) {
|
|
198
212
|
spinner.update(`Linking to ${agents.length} agent(s)...`)
|
|
199
213
|
for (const { pkg } of to_link) {
|
|
@@ -220,12 +234,7 @@ const install = (skill, options = {}) => catch_errors('Install failed', async ()
|
|
|
220
234
|
const final_dir = skill_install_dir(base_dir, name)
|
|
221
235
|
const [, integrity] = await hash_directory(final_dir)
|
|
222
236
|
|
|
223
|
-
|
|
224
|
-
let pkg_type
|
|
225
|
-
const pkg_json_path = path.join(final_dir, SKILL_JSON)
|
|
226
|
-
const [, pkg_manifest] = await read_json(pkg_json_path)
|
|
227
|
-
if (pkg_manifest?.type) pkg_type = pkg_manifest.type
|
|
228
|
-
|
|
237
|
+
const pkg_type = pkg_types[pkg.skill]
|
|
229
238
|
updates[pkg.skill] = {
|
|
230
239
|
version: pkg.version,
|
|
231
240
|
ref: pkg.ref,
|