happyskills 0.37.0 → 0.38.0
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 +8 -0
- package/package.json +1 -1
- package/src/api/repos.js +1 -2
- package/src/commands/search.js +13 -9
- package/src/integration/cli.test.js +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.38.0] - 2026-05-01
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **BREAKING:** Make `--limit` required for the `search` command — there is no default. Running `happyskills search ...` without `--limit` now returns a usage error (exit code 2). The previous hidden default of 10 caused AI-agent callers to miss results without realizing a limit was being applied. Affects both smart-search and `--exact` keyword modes. Update help text and all examples to show `--limit` explicitly.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Fix `search --workspace <slug>` (in browse mode with no query, and in `--exact` keyword mode) silently excluding private skills the caller has access to. The CLI was omitting the auth token when only `--workspace` was specified without `--mine` or `--personal`, causing the API to fall back to public-only results. The auth token is now always attached when one is available, regardless of the search mode.
|
|
17
|
+
|
|
10
18
|
## [0.37.0] - 2026-04-25
|
|
11
19
|
|
|
12
20
|
### Added
|
package/package.json
CHANGED
package/src/api/repos.js
CHANGED
|
@@ -10,8 +10,7 @@ const search = (query, options = {}) => catch_errors('Search failed', async () =
|
|
|
10
10
|
if (options.workspace) params.set('workspace', options.workspace)
|
|
11
11
|
if (options.tags) params.set('tags', options.tags)
|
|
12
12
|
if (options.type) params.set('type', options.type)
|
|
13
|
-
const
|
|
14
|
-
const [errors, data] = await client.get(`/repos/search?${params}`, { auth: needs_auth || false })
|
|
13
|
+
const [errors, data] = await client.get(`/repos/search?${params}`)
|
|
15
14
|
if (errors) throw errors[errors.length - 1]
|
|
16
15
|
return data
|
|
17
16
|
})
|
package/src/commands/search.js
CHANGED
|
@@ -23,21 +23,21 @@ Options:
|
|
|
23
23
|
--tags <tags> Filter by tags (comma-separated)
|
|
24
24
|
--type <type> Filter by type (skill, kit)
|
|
25
25
|
--exact Use keyword-only matching instead of smart search
|
|
26
|
-
--limit <n> Max results (
|
|
26
|
+
--limit <n> Max results (required, 1-50)
|
|
27
27
|
--min-quality <n> Minimum quality score 0-100
|
|
28
28
|
--json Output as JSON
|
|
29
29
|
|
|
30
30
|
Aliases: s
|
|
31
31
|
|
|
32
32
|
Examples:
|
|
33
|
-
happyskills search deploy
|
|
34
|
-
happyskills search "REST API with Node.js"
|
|
35
|
-
happyskills search --mine
|
|
36
|
-
happyskills search deploy --workspace acme
|
|
37
|
-
happyskills search --type kit
|
|
38
|
-
happyskills s --personal --json
|
|
33
|
+
happyskills search deploy --limit 10
|
|
34
|
+
happyskills search "REST API with Node.js" --limit 10
|
|
35
|
+
happyskills search --mine --limit 20
|
|
36
|
+
happyskills search deploy --workspace acme --limit 50
|
|
37
|
+
happyskills search --type kit --limit 10
|
|
38
|
+
happyskills s --personal --json --limit 20
|
|
39
39
|
happyskills search "deploy to AWS" --limit 5
|
|
40
|
-
happyskills search deploy --exact`
|
|
40
|
+
happyskills search deploy --exact --limit 10`
|
|
41
41
|
|
|
42
42
|
const QUALITY_TIERS = [
|
|
43
43
|
{ min: 80, label: 'High quality', color: cyan },
|
|
@@ -95,7 +95,7 @@ const format_smart_result = (item, index) => {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
const run_smart_search = (args, query, options) => catch_errors('Smart search failed', async () => {
|
|
98
|
-
const limit =
|
|
98
|
+
const limit = parseInt(args.flags.limit)
|
|
99
99
|
const capped_limit = Math.min(Math.max(limit, 1), 50)
|
|
100
100
|
const min_quality = args.flags['min-quality'] != null ? parseInt(args.flags['min-quality']) : null
|
|
101
101
|
|
|
@@ -230,6 +230,10 @@ const run = (args) => catch_errors('Search failed', async () => {
|
|
|
230
230
|
throw new UsageError('Please provide a search query or use --mine, --personal, or --workspace.')
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
if (!args.flags.limit) {
|
|
234
|
+
throw new UsageError('--limit is required. Specify the number of results you want (e.g. --limit 10).')
|
|
235
|
+
}
|
|
236
|
+
|
|
233
237
|
if (type && !VALID_SKILL_TYPES.includes(type)) {
|
|
234
238
|
throw new UsageError(`--type must be one of: ${VALID_SKILL_TYPES.join(', ')}`)
|
|
235
239
|
}
|
|
@@ -276,8 +276,9 @@ describe('CLI — --json: stdout is always valid JSON', () => {
|
|
|
276
276
|
})
|
|
277
277
|
|
|
278
278
|
it('network error produces JSON with code NETWORK_ERROR', () => {
|
|
279
|
-
// search requires a network call; localhost:0 always fails
|
|
280
|
-
|
|
279
|
+
// search requires a network call; localhost:0 always fails.
|
|
280
|
+
// --limit is required, so it must be passed to reach the network call.
|
|
281
|
+
const { stdout, code } = run(['search', 'anything', '--json', '--limit', '10'])
|
|
281
282
|
assert.strictEqual(code, 4)
|
|
282
283
|
const out = parse_json_output(stdout, 'search --json network failure')
|
|
283
284
|
assert.strictEqual(out.error.code, 'NETWORK_ERROR')
|