happyskills 0.4.4 → 0.5.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 +12 -0
- package/package.json +1 -1
- package/src/api/repos.js +7 -2
- package/src/commands/search.js +41 -14
- package/src/index.js +1 -0
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
|
+
## [0.5.0] - 2026-03-05
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Add `--mine` flag to `search` command to browse skills across all user's workspaces
|
|
14
|
+
- Add `--personal` flag to `search` command to browse skills in the user's personal workspace only
|
|
15
|
+
- Add `-w` / `--workspace <slug>` flag to `search` command to search within specific workspace(s)
|
|
16
|
+
- Add `--tags <tags>` flag to `search` command to filter results by tags
|
|
17
|
+
- Add `scope` and `visibility` fields to `search` JSON output
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- Change `search` query argument from required to optional when `--mine`, `--personal`, or `--workspace` is provided (browse mode)
|
|
21
|
+
|
|
10
22
|
## [0.4.4] - 2026-03-05
|
|
11
23
|
|
|
12
24
|
### Fixed
|
package/package.json
CHANGED
package/src/api/repos.js
CHANGED
|
@@ -2,10 +2,15 @@ const { error: { catch_errors } } = require('puffy-core')
|
|
|
2
2
|
const client = require('./client')
|
|
3
3
|
|
|
4
4
|
const search = (query, options = {}) => catch_errors('Search failed', async () => {
|
|
5
|
-
const params = new URLSearchParams(
|
|
5
|
+
const params = new URLSearchParams()
|
|
6
|
+
if (query) params.set('q', query)
|
|
6
7
|
if (options.limit) params.set('limit', options.limit)
|
|
7
8
|
if (options.offset) params.set('offset', options.offset)
|
|
8
|
-
|
|
9
|
+
if (options.scope) params.set('scope', options.scope)
|
|
10
|
+
if (options.workspace) params.set('workspace', options.workspace)
|
|
11
|
+
if (options.tags) params.set('tags', options.tags)
|
|
12
|
+
const needs_auth = (options.scope && options.scope !== 'public') || options.workspace
|
|
13
|
+
const [errors, data] = await client.get(`/repos/search?${params}`, { auth: needs_auth || false })
|
|
9
14
|
if (errors) throw errors[errors.length - 1]
|
|
10
15
|
return data
|
|
11
16
|
})
|
package/src/commands/search.js
CHANGED
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
const { error: { catch_errors, wrap_errors: e } } = require('puffy-core')
|
|
2
2
|
const repos_api = require('../api/repos')
|
|
3
3
|
const { print_help, print_table, print_json, print_info } = require('../ui/output')
|
|
4
|
-
const { exit_with_error, UsageError } = require('../utils/errors')
|
|
4
|
+
const { exit_with_error, UsageError, AuthError } = require('../utils/errors')
|
|
5
5
|
const { EXIT_CODES } = require('../constants')
|
|
6
|
+
const { load_token } = require('../auth/token_store')
|
|
6
7
|
|
|
7
|
-
const HELP_TEXT = `Usage: happyskills search
|
|
8
|
+
const HELP_TEXT = `Usage: happyskills search [query] [options]
|
|
8
9
|
|
|
9
10
|
Search the skill registry.
|
|
10
11
|
|
|
11
12
|
Arguments:
|
|
12
|
-
query
|
|
13
|
+
query Search term (optional with --mine, --personal, or --workspace)
|
|
13
14
|
|
|
14
15
|
Options:
|
|
15
|
-
--
|
|
16
|
+
-w, --workspace <slug> Search within specific workspace(s) (comma-separated)
|
|
17
|
+
--mine Search across all your workspaces
|
|
18
|
+
--personal Search only your personal workspace
|
|
19
|
+
--tags <tags> Filter by tags (comma-separated)
|
|
20
|
+
--json Output as JSON
|
|
16
21
|
|
|
17
22
|
Aliases: s
|
|
18
23
|
|
|
19
24
|
Examples:
|
|
20
25
|
happyskills search deploy
|
|
21
|
-
happyskills
|
|
26
|
+
happyskills search --mine
|
|
27
|
+
happyskills search deploy --workspace acme
|
|
28
|
+
happyskills s --personal --json`
|
|
22
29
|
|
|
23
30
|
const run = (args) => catch_errors('Search failed', async () => {
|
|
24
31
|
if (args.flags._show_help) {
|
|
@@ -26,32 +33,52 @@ const run = (args) => catch_errors('Search failed', async () => {
|
|
|
26
33
|
return process.exit(EXIT_CODES.SUCCESS)
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
const query = args._.join(' ')
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
const query = args._.join(' ') || null
|
|
37
|
+
const { mine, personal, workspace, tags } = args.flags
|
|
38
|
+
const has_scope_flag = mine || personal || workspace
|
|
39
|
+
|
|
40
|
+
if (!query && !has_scope_flag && !tags) {
|
|
41
|
+
throw new UsageError('Please provide a search query or use --mine, --personal, or --workspace.')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const scope = mine ? 'mine' : personal ? 'personal' : undefined
|
|
45
|
+
|
|
46
|
+
if (has_scope_flag) {
|
|
47
|
+
const [, token_data] = await load_token()
|
|
48
|
+
if (!token_data) {
|
|
49
|
+
throw new AuthError('Authentication required. Run `happyskills login` first.')
|
|
50
|
+
}
|
|
32
51
|
}
|
|
33
52
|
|
|
34
|
-
const
|
|
53
|
+
const options = {}
|
|
54
|
+
if (scope) options.scope = scope
|
|
55
|
+
if (workspace) options.workspace = workspace
|
|
56
|
+
if (tags) options.tags = tags
|
|
57
|
+
|
|
58
|
+
const [errors, results] = await repos_api.search(query, options)
|
|
35
59
|
if (errors) throw e('Search failed', errors)
|
|
36
60
|
|
|
37
61
|
const items = Array.isArray(results) ? results : (results?.repos || results?.items || [])
|
|
62
|
+
const effective_scope = scope || (has_scope_flag ? undefined : undefined)
|
|
38
63
|
|
|
39
64
|
if (items.length === 0) {
|
|
40
65
|
if (args.flags.json) {
|
|
41
|
-
print_json({ data: { query, results: [], count: 0 } })
|
|
66
|
+
print_json({ data: { query, scope: effective_scope || 'all', results: [], count: 0 } })
|
|
42
67
|
return
|
|
43
68
|
}
|
|
44
|
-
|
|
69
|
+
const context = query ? ` for "${query}"` : ''
|
|
70
|
+
print_info(`No skills found${context}.`)
|
|
45
71
|
return
|
|
46
72
|
}
|
|
47
73
|
|
|
48
74
|
if (args.flags.json) {
|
|
49
|
-
const
|
|
75
|
+
const mapped = items.map(item => ({
|
|
50
76
|
skill: `${item.owner || item.workspace_slug}/${item.name}`,
|
|
51
77
|
description: item.description || '',
|
|
52
|
-
version: item.latest_version || item.version || '-'
|
|
78
|
+
version: item.latest_version || item.version || '-',
|
|
79
|
+
visibility: item.visibility || 'public'
|
|
53
80
|
}))
|
|
54
|
-
print_json({ data: { query, results, count:
|
|
81
|
+
print_json({ data: { query, scope: effective_scope || 'all', results: mapped, count: mapped.length } })
|
|
55
82
|
return
|
|
56
83
|
}
|
|
57
84
|
|