happyskills 1.2.0 → 1.2.2
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,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.2] - 2026-06-02
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `validate` no longer warns when `skill.json` `keywords` is missing or omits a canonical slug. The `keywords` field is deprecated — it is not used for search, ranking, or discovery — so the warning and the canonical-slug check were removed. The field is still accepted in the manifest.
|
|
15
|
+
|
|
16
|
+
## [1.2.1] - 2026-06-02
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Emit tailored `next_step.instructions` for the three actions added in 1.2.0 (`retry_or_abandon`, `resolve_unknown_drift`, `review_publish_error`). They were registered in the enum but missing from `DEFAULT_INSTRUCTIONS`, so the envelope fell back to the generic "Follow the protocol step indicated by `action`." placeholder. Each now carries actionable guidance.
|
|
21
|
+
|
|
10
22
|
## [1.2.0] - 2026-06-02
|
|
11
23
|
|
|
12
24
|
### Added
|
package/package.json
CHANGED
package/src/ui/envelope.js
CHANGED
|
@@ -34,6 +34,9 @@ const DEFAULT_INSTRUCTIONS = {
|
|
|
34
34
|
retry: 'Transient failure. Retry shortly.',
|
|
35
35
|
reconcile_first: 'Drift must be resolved before this operation. Run reconcile, follow its next_step, then retry.',
|
|
36
36
|
pull_rebase_first: 'The local skill has diverged from the registry. Pull with --rebase, resolve any rejected patches, then retry.',
|
|
37
|
+
retry_or_abandon: 'The rebase step failed before any change landed. Retry the pull, or abandon and restore the snapshot.',
|
|
38
|
+
resolve_unknown_drift: 'Unrecognized drift subtype — surface the details to the principal for a manual decision.',
|
|
39
|
+
review_publish_error: 'The publish step failed. Inspect the wrapped publish error in context, resolve it, then retry.',
|
|
37
40
|
fix_validation_errors: 'Fix the listed validation errors and re-run.',
|
|
38
41
|
provide_changelog: 'CHANGELOG.md is missing the target version entry. Add it and re-run.',
|
|
39
42
|
self_update: 'Upgrade the happyskills CLI and re-run.',
|
|
@@ -6,7 +6,6 @@ const { SKILL_JSON, VALID_SKILL_TYPES, SKILL_TYPES, KIT_PREFIX } = require('../c
|
|
|
6
6
|
|
|
7
7
|
const NAME_PATTERN = /^[a-z0-9][a-z0-9_-]*$/
|
|
8
8
|
const KIT_NAME_PATTERN = /^_kit-[a-z0-9][a-z0-9-]*$/
|
|
9
|
-
const CANONICAL_SLUGS = ['deployment', 'database', 'security', 'ai', 'api', 'monitoring', 'testing', 'devops', 'cloud', 'analytics']
|
|
10
9
|
const REQUIRED_PLATFORMS = ['darwin', 'linux', 'win32']
|
|
11
10
|
|
|
12
11
|
const result = (field, rule, severity, message, value) => ({
|
|
@@ -90,27 +89,6 @@ const validate_description = (manifest) => {
|
|
|
90
89
|
return results
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
const validate_keywords = (manifest) => {
|
|
94
|
-
const results = []
|
|
95
|
-
const kw = manifest.keywords
|
|
96
|
-
|
|
97
|
-
if (!kw || !Array.isArray(kw)) {
|
|
98
|
-
results.push(result('keywords', 'recommended_field', 'warning', 'Keywords array is recommended — include at least one canonical slug'))
|
|
99
|
-
return results
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
results.push(result('keywords', 'recommended_field', 'pass', `keywords: ${kw.length} entries`))
|
|
103
|
-
|
|
104
|
-
const has_slug = kw.some(k => CANONICAL_SLUGS.includes(k))
|
|
105
|
-
if (!has_slug) {
|
|
106
|
-
results.push(result('keywords', 'canonical_slug', 'warning', `Keywords should include at least one canonical slug: ${CANONICAL_SLUGS.join(', ')}`))
|
|
107
|
-
} else {
|
|
108
|
-
results.push(result('keywords', 'canonical_slug', 'pass', 'Contains canonical slug'))
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return results
|
|
112
|
-
}
|
|
113
|
-
|
|
114
92
|
const validate_type = (manifest) => {
|
|
115
93
|
const results = []
|
|
116
94
|
const type = manifest.type
|
|
@@ -229,7 +207,6 @@ const validate_skill_json = (skill_dir) => catch_errors('Failed to validate skil
|
|
|
229
207
|
results.push(...validate_version(manifest))
|
|
230
208
|
results.push(...validate_type(manifest))
|
|
231
209
|
results.push(...validate_description(manifest))
|
|
232
|
-
results.push(...validate_keywords(manifest))
|
|
233
210
|
results.push(...validate_dependencies(manifest))
|
|
234
211
|
results.push(...validate_system_dependencies(manifest))
|
|
235
212
|
|
|
@@ -121,32 +121,6 @@ describe('validate_skill_json — description', () => {
|
|
|
121
121
|
})
|
|
122
122
|
})
|
|
123
123
|
|
|
124
|
-
describe('validate_skill_json — keywords', () => {
|
|
125
|
-
it('warns when keywords are missing', async () => {
|
|
126
|
-
write_json(tmp, { name: 'my-skill', version: '1.0.0' })
|
|
127
|
-
const [err, data] = await validate_skill_json(tmp)
|
|
128
|
-
assert.ifError(err)
|
|
129
|
-
const check = data.results.find(r => r.field === 'keywords' && r.rule === 'recommended_field')
|
|
130
|
-
assert.strictEqual(check.severity, 'warning')
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('warns when no canonical slug is present', async () => {
|
|
134
|
-
write_json(tmp, { name: 'my-skill', version: '1.0.0', keywords: ['custom'] })
|
|
135
|
-
const [err, data] = await validate_skill_json(tmp)
|
|
136
|
-
assert.ifError(err)
|
|
137
|
-
const check = data.results.find(r => r.rule === 'canonical_slug')
|
|
138
|
-
assert.strictEqual(check.severity, 'warning')
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
it('passes when a canonical slug is present', async () => {
|
|
142
|
-
write_json(tmp, { name: 'my-skill', version: '1.0.0', keywords: ['deployment', 'custom'] })
|
|
143
|
-
const [err, data] = await validate_skill_json(tmp)
|
|
144
|
-
assert.ifError(err)
|
|
145
|
-
const check = data.results.find(r => r.rule === 'canonical_slug')
|
|
146
|
-
assert.strictEqual(check.severity, 'pass')
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
|
|
150
124
|
describe('validate_skill_json — dependencies', () => {
|
|
151
125
|
it('errors when dependencies is an array', async () => {
|
|
152
126
|
write_json(tmp, { name: 'my-skill', version: '1.0.0', dependencies: ['acme/deploy'] })
|