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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "happyskills",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
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)",
@@ -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'] })