skillbox 0.2.2 → 0.3.1
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/README.md +71 -153
- package/dist/cli.js +13 -13
- package/dist/commands/add-repo.js +63 -44
- package/dist/commands/add.js +28 -25
- package/dist/commands/agent.js +5 -11
- package/dist/commands/config.js +8 -10
- package/dist/commands/convert.js +21 -6
- package/dist/commands/import.js +64 -67
- package/dist/commands/list.js +129 -91
- package/dist/commands/meta.js +5 -7
- package/dist/commands/project.js +24 -39
- package/dist/commands/remove.js +45 -20
- package/dist/commands/status.js +110 -84
- package/dist/commands/update.js +167 -75
- package/dist/lib/agent-detect.js +4 -13
- package/dist/lib/agents.js +65 -41
- package/dist/lib/command.js +4 -4
- package/dist/lib/config.js +18 -14
- package/dist/lib/discovery.js +3 -11
- package/dist/lib/fetcher.js +3 -3
- package/dist/lib/fs-utils.js +17 -0
- package/dist/lib/github.js +10 -10
- package/dist/lib/global-skills.js +24 -15
- package/dist/lib/grouping.js +6 -6
- package/dist/lib/index.js +13 -11
- package/dist/lib/installs.js +15 -14
- package/dist/lib/onboarding.js +31 -32
- package/dist/lib/options.js +4 -4
- package/dist/lib/output.js +13 -11
- package/dist/lib/paths.js +12 -4
- package/dist/lib/project-paths.js +2 -2
- package/dist/lib/project-root.js +3 -12
- package/dist/lib/projects.js +13 -11
- package/dist/lib/repo-skills.js +29 -41
- package/dist/lib/runtime.js +12 -12
- package/dist/lib/skill-parser.js +12 -12
- package/dist/lib/skill-store.js +13 -13
- package/dist/lib/source-grouping.js +49 -0
- package/dist/lib/sync.js +48 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,200 +1,118 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Skillbox
|
|
2
2
|
|
|
3
|
-
> Local-first, agent-agnostic skills manager
|
|
3
|
+
> Local-first, agent-agnostic skills manager for AI coding agents.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/christiananagnostou/skillbox/actions/workflows/ci.yml)
|
|
6
6
|
[](https://www.npmjs.com/package/skillbox)
|
|
7
7
|
|
|
8
|
-
##
|
|
9
|
-
|
|
10
|
-
### npm (recommended)
|
|
8
|
+
## Install
|
|
11
9
|
|
|
12
10
|
```bash
|
|
13
11
|
npm install -g skillbox
|
|
14
12
|
```
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Skillbox will detect installed agents on your machine. Repo and URL installs track their origin so updates stay one command away.
|
|
19
|
-
|
|
20
|
-
> Tip: run `skillbox list` right after install to see existing skills.
|
|
14
|
+
On first run, Skillbox auto-detects your installed agents and configures itself.
|
|
21
15
|
|
|
22
|
-
|
|
16
|
+
**Quick start:** Install the skillbox skill to teach your agent how to manage skills:
|
|
23
17
|
|
|
24
18
|
```bash
|
|
25
|
-
|
|
26
|
-
skillbox add owner/repo
|
|
27
|
-
# list skills in repo
|
|
28
|
-
skillbox add owner/repo --list
|
|
29
|
-
# install single repo skill
|
|
30
|
-
skillbox add owner/repo --skill linting
|
|
31
|
-
# add skill from URL
|
|
32
|
-
skillbox add https://example.com/skills/linting/SKILL.md
|
|
33
|
-
# list installed skills
|
|
34
|
-
skillbox list
|
|
35
|
-
# check for updates
|
|
36
|
-
skillbox status
|
|
37
|
-
# update one skill
|
|
38
|
-
skillbox update linting
|
|
19
|
+
skillbox add christiananagnostou/skillbox
|
|
39
20
|
```
|
|
40
21
|
|
|
41
|
-
|
|
42
|
-
- GitHub unauthenticated API limit: 60 req/hr per IP
|
|
43
|
-
- use `skillbox convert` for non-skill URLs
|
|
22
|
+
## Golden Workflow
|
|
44
23
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
### Core Commands
|
|
24
|
+
These three commands cover most use cases:
|
|
48
25
|
|
|
49
26
|
```bash
|
|
50
|
-
#
|
|
51
|
-
skillbox
|
|
52
|
-
|
|
53
|
-
skillbox add <repo> [--list] [--skill <name>] [--global] [--agents ...]
|
|
54
|
-
# convert content to skill
|
|
55
|
-
skillbox convert <url> [--name <name>] [--output <dir>] [--agent]
|
|
56
|
-
# list skills
|
|
57
|
-
skillbox list [--group=category|namespace|source|project] [--json]
|
|
58
|
-
# check for updates
|
|
59
|
-
skillbox status [--group=project|source] [--json]
|
|
60
|
-
# update skills
|
|
61
|
-
skillbox update [name] [--project <path>]
|
|
62
|
-
# remove skills
|
|
63
|
-
skillbox remove <name> [--project <path>]
|
|
64
|
-
# import existing skills
|
|
65
|
-
skillbox import <path>
|
|
66
|
-
# update metadata
|
|
67
|
-
skillbox meta set <name> --category foo --tag bar --namespace baz
|
|
68
|
-
# open agent REPL
|
|
69
|
-
skillbox agent
|
|
27
|
+
skillbox list # see installed skills
|
|
28
|
+
skillbox status # check for updates
|
|
29
|
+
skillbox update [name] # update skills
|
|
70
30
|
```
|
|
71
31
|
|
|
72
|
-
|
|
32
|
+
## Adding Skills
|
|
73
33
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
skillbox
|
|
77
|
-
|
|
78
|
-
skillbox
|
|
79
|
-
|
|
80
|
-
skillbox
|
|
81
|
-
# resync project skills
|
|
82
|
-
skillbox project sync <path>
|
|
83
|
-
```
|
|
34
|
+
| Command | Description |
|
|
35
|
+
|---------|-------------|
|
|
36
|
+
| `skillbox add owner/repo` | Install all skills from a GitHub repo |
|
|
37
|
+
| `skillbox add owner/repo --list` | List available skills in a repo |
|
|
38
|
+
| `skillbox add owner/repo --skill name` | Install a specific skill from a repo |
|
|
39
|
+
| `skillbox add <url>` | Install skill from a direct URL |
|
|
40
|
+
| `skillbox add <url> --name my-skill` | Install with custom name |
|
|
84
41
|
|
|
85
|
-
|
|
42
|
+
> **Note:** GitHub unauthenticated API limit is 60 requests/hour per IP.
|
|
86
43
|
|
|
87
|
-
|
|
88
|
-
# show config
|
|
89
|
-
skillbox config get
|
|
90
|
-
# set default scope
|
|
91
|
-
skillbox config set --default-scope user
|
|
92
|
-
# replace default agents
|
|
93
|
-
skillbox config set --default-agent claude --default-agent cursor
|
|
94
|
-
# add default agent
|
|
95
|
-
skillbox config set --add-agent codex
|
|
96
|
-
# use symlink installs
|
|
97
|
-
skillbox config set --install-mode symlink
|
|
98
|
-
# use file copies
|
|
99
|
-
skillbox config set --install-mode copy
|
|
100
|
-
```
|
|
44
|
+
## All Commands
|
|
101
45
|
|
|
102
|
-
|
|
46
|
+
### Skills
|
|
103
47
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
48
|
+
| Command | Description |
|
|
49
|
+
|---------|-------------|
|
|
50
|
+
| `skillbox list` | List installed skills |
|
|
51
|
+
| `skillbox status` | Check for outdated skills |
|
|
52
|
+
| `skillbox update [name]` | Update all or one skill |
|
|
53
|
+
| `skillbox remove <name>` | Remove a skill |
|
|
54
|
+
| `skillbox import <path>` | Import existing skill directory |
|
|
55
|
+
| `skillbox import --global` | Import all skills from agent folders |
|
|
107
56
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Use `--json` for machine-readable output.
|
|
57
|
+
### Config
|
|
111
58
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
skillbox
|
|
115
|
-
|
|
116
|
-
skillbox
|
|
117
|
-
|
|
118
|
-
skillbox update linting --json
|
|
119
|
-
```
|
|
59
|
+
| Command | Description |
|
|
60
|
+
|---------|-------------|
|
|
61
|
+
| `skillbox config get` | Show current config |
|
|
62
|
+
| `skillbox config set --add-agent <name>` | Add an agent |
|
|
63
|
+
| `skillbox config set --default-scope <scope>` | Set default scope (`user` or `project`) |
|
|
64
|
+
| `skillbox config set --install-mode <mode>` | Set install mode (`symlink` or `copy`) |
|
|
120
65
|
|
|
121
|
-
###
|
|
66
|
+
### Projects
|
|
122
67
|
|
|
123
|
-
|
|
124
|
-
|
|
68
|
+
| Command | Description |
|
|
69
|
+
|---------|-------------|
|
|
70
|
+
| `skillbox project add <path>` | Register a project |
|
|
71
|
+
| `skillbox project list` | List registered projects |
|
|
72
|
+
| `skillbox project sync <path>` | Re-sync skills to a project |
|
|
125
73
|
|
|
126
|
-
|
|
127
|
-
1) skillbox list --json
|
|
128
|
-
2) skillbox status --json
|
|
129
|
-
3) skillbox update <name> --json
|
|
74
|
+
## Supported Agents
|
|
130
75
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
76
|
+
| Agent | User Path | Project Path |
|
|
77
|
+
|-------|-----------|--------------|
|
|
78
|
+
| Claude | `~/.claude/skills/` | `.claude/skills/` |
|
|
79
|
+
| Cursor | `~/.cursor/skills/` | `.cursor/skills/` |
|
|
80
|
+
| Codex | `~/.codex/skills/` | `.codex/skills/` |
|
|
81
|
+
| OpenCode | `~/.config/opencode/skills/` | `.opencode/skills/` |
|
|
82
|
+
| Amp | `~/.config/agents/skills/` | `.agents/skills/` |
|
|
83
|
+
| Antigravity | `~/.gemini/antigravity/skills/` | `.agent/skills/` |
|
|
134
84
|
|
|
135
|
-
|
|
136
|
-
# list skills in repo
|
|
137
|
-
skillbox add owner/repo --list
|
|
138
|
-
# install single repo skill
|
|
139
|
-
skillbox add owner/repo --skill <name>
|
|
140
|
-
# install all repo skills
|
|
141
|
-
skillbox add owner/repo
|
|
85
|
+
## JSON Mode
|
|
142
86
|
|
|
143
|
-
|
|
87
|
+
All commands support `--json` for machine-readable output:
|
|
144
88
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
skillbox
|
|
89
|
+
```bash
|
|
90
|
+
skillbox list --json
|
|
91
|
+
skillbox status --json
|
|
92
|
+
skillbox update my-skill --json
|
|
148
93
|
```
|
|
149
94
|
|
|
150
|
-
##
|
|
151
|
-
|
|
152
|
-
Skillbox maintains a canonical store and syncs into agent-native folders.
|
|
153
|
-
|
|
154
|
-
Canonical store:
|
|
155
|
-
|
|
156
|
-
- `~/.config/skillbox/skills/<name>/`
|
|
157
|
-
|
|
158
|
-
Index + config:
|
|
159
|
-
|
|
160
|
-
- `~/.config/skillbox/index.json`
|
|
161
|
-
- `~/.config/skillbox/projects.json`
|
|
162
|
-
- `~/.config/skillbox/config.json`
|
|
163
|
-
|
|
164
|
-
Agent paths (default):
|
|
165
|
-
|
|
166
|
-
- OpenCode: `.opencode/skills/`, `~/.config/opencode/skills/` (Claude-compatible `.claude/skills/` also supported)
|
|
167
|
-
- Claude: `.claude/skills/`, `~/.claude/skills/`
|
|
168
|
-
- Cursor: `.cursor/skills/`, `.claude/skills/`, `~/.cursor/skills/`, `~/.claude/skills/`
|
|
169
|
-
- Codex: `$REPO_ROOT/.codex/skills/`, `~/.codex/skills/`
|
|
170
|
-
- Amp: `.agents/skills/`, `~/.config/agents/skills/` (Claude-compatible `.claude/skills/` also supported)
|
|
171
|
-
- Antigravity: `.agent/skills/`, `~/.gemini/antigravity/skills/`
|
|
95
|
+
## For AI Agents
|
|
172
96
|
|
|
173
|
-
|
|
97
|
+
Install the skillbox skill to teach your agent how to use skillbox:
|
|
174
98
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
The simplest approach is to instruct your agent to use Skillbox:
|
|
178
|
-
|
|
179
|
-
```
|
|
180
|
-
Use skillbox to manage skills for this repo. Run skillbox --help for all commands.
|
|
99
|
+
```bash
|
|
100
|
+
skillbox add christiananagnostou/skillbox
|
|
181
101
|
```
|
|
182
102
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
Add this to your project instructions for more consistent results:
|
|
103
|
+
Or add this to your `CLAUDE.md` / `AGENTS.md`:
|
|
186
104
|
|
|
187
105
|
```markdown
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
Use `skillbox` to manage skills. Run `skillbox --help` for all commands.
|
|
106
|
+
Use `skillbox` to manage skills. Run `skillbox --help` for commands.
|
|
107
|
+
```
|
|
191
108
|
|
|
192
|
-
|
|
109
|
+
## File Locations
|
|
193
110
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
111
|
+
| Path | Purpose |
|
|
112
|
+
|------|---------|
|
|
113
|
+
| `~/.config/skillbox/skills/` | Canonical skill store |
|
|
114
|
+
| `~/.config/skillbox/config.json` | Configuration |
|
|
115
|
+
| `~/.config/skillbox/index.json` | Skill index |
|
|
198
116
|
|
|
199
117
|
## Development
|
|
200
118
|
|
package/dist/cli.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { registerAdd } from "./commands/add.js";
|
|
4
|
+
import { registerAgent } from "./commands/agent.js";
|
|
5
|
+
import { registerConfig } from "./commands/config.js";
|
|
4
6
|
import { registerConvert } from "./commands/convert.js";
|
|
5
|
-
import { registerList } from "./commands/list.js";
|
|
6
|
-
import { registerStatus } from "./commands/status.js";
|
|
7
|
-
import { registerUpdate } from "./commands/update.js";
|
|
8
7
|
import { registerImport } from "./commands/import.js";
|
|
8
|
+
import { registerList } from "./commands/list.js";
|
|
9
9
|
import { registerMeta } from "./commands/meta.js";
|
|
10
10
|
import { registerProject } from "./commands/project.js";
|
|
11
|
-
import { registerAgent } from "./commands/agent.js";
|
|
12
|
-
import { registerConfig } from "./commands/config.js";
|
|
13
11
|
import { registerRemove } from "./commands/remove.js";
|
|
12
|
+
import { registerStatus } from "./commands/status.js";
|
|
13
|
+
import { registerUpdate } from "./commands/update.js";
|
|
14
14
|
const program = new Command();
|
|
15
|
-
program.name("skillbox").description("Local-first, agent-agnostic skills manager").version("0.1
|
|
15
|
+
program.name("skillbox").description("Local-first, agent-agnostic skills manager").version("0.3.1");
|
|
16
16
|
registerAdd(program);
|
|
17
|
+
registerAgent(program);
|
|
18
|
+
registerConfig(program);
|
|
17
19
|
registerConvert(program);
|
|
18
|
-
registerList(program);
|
|
19
|
-
registerStatus(program);
|
|
20
|
-
registerUpdate(program);
|
|
21
20
|
registerImport(program);
|
|
21
|
+
registerList(program);
|
|
22
22
|
registerMeta(program);
|
|
23
23
|
registerProject(program);
|
|
24
|
-
registerAgent(program);
|
|
25
|
-
registerConfig(program);
|
|
26
24
|
registerRemove(program);
|
|
27
|
-
|
|
25
|
+
registerStatus(program);
|
|
26
|
+
registerUpdate(program);
|
|
27
|
+
async function run() {
|
|
28
28
|
const { runOnboarding } = await import("./lib/onboarding.js");
|
|
29
29
|
await runOnboarding();
|
|
30
30
|
program.parse();
|
|
31
|
-
}
|
|
31
|
+
}
|
|
32
32
|
void run();
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { parseSkillMarkdown, buildMetadata } from "../lib/skill-parser.js";
|
|
3
|
-
import { writeSkillMetadata } from "../lib/skill-store.js";
|
|
1
|
+
import { getErrorMessage } from "../lib/command.js";
|
|
4
2
|
import { loadConfig } from "../lib/config.js";
|
|
5
|
-
import {
|
|
6
|
-
import { resolveRuntime, ensureProjectRegistered } from "../lib/runtime.js";
|
|
7
|
-
import { buildSymlinkWarning, buildTargets, installSkillToTargets } from "../lib/sync.js";
|
|
3
|
+
import { parseRepoRef } from "../lib/github.js";
|
|
8
4
|
import { loadIndex, saveIndex, sortIndex, upsertSkill } from "../lib/index.js";
|
|
9
5
|
import { printInfo, printJson } from "../lib/output.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
6
|
+
import { buildProjectAgentPaths } from "../lib/project-paths.js";
|
|
7
|
+
import { fetchRepoFile, listRepoSkills, normalizeRepoRef, writeRepoSkillDirectory, } from "../lib/repo-skills.js";
|
|
8
|
+
import { ensureProjectRegistered, resolveRuntime } from "../lib/runtime.js";
|
|
9
|
+
import { buildMetadata, parseSkillMarkdown } from "../lib/skill-parser.js";
|
|
10
|
+
import { writeSkillMetadata } from "../lib/skill-store.js";
|
|
11
|
+
import { buildSymlinkWarning, buildTargets, installSkillToTargets } from "../lib/sync.js";
|
|
12
|
+
function normalizeSkillSelection(skills, selections) {
|
|
13
13
|
if (selections.length === 0) {
|
|
14
14
|
return skills;
|
|
15
15
|
}
|
|
16
16
|
const selectionSet = new Set(selections);
|
|
17
17
|
return skills.filter((name) => selectionSet.has(name));
|
|
18
|
-
}
|
|
19
|
-
|
|
18
|
+
}
|
|
19
|
+
async function ensureRepoRef(input) {
|
|
20
20
|
const ref = parseRepoRef(input);
|
|
21
21
|
if (!ref) {
|
|
22
22
|
throw new Error("Unsupported repo URL or shorthand.");
|
|
23
23
|
}
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
|
|
24
|
+
return normalizeRepoRef(ref);
|
|
25
|
+
}
|
|
26
|
+
async function installSkillTargets(skillName, options, installs) {
|
|
27
27
|
const { projectRoot, scope, agentList } = await resolveRuntime({
|
|
28
28
|
global: options.global,
|
|
29
29
|
agents: options.agents,
|
|
@@ -41,26 +41,24 @@ const installSkillTargets = async (skillName, options, installs) => {
|
|
|
41
41
|
const written = results
|
|
42
42
|
.filter((result) => result.mode !== "skipped")
|
|
43
43
|
.map((result) => result.path);
|
|
44
|
-
const
|
|
45
|
-
|
|
44
|
+
const warnings = buildSymlinkWarning(agent, results);
|
|
45
|
+
for (const warning of warnings) {
|
|
46
46
|
printInfo(warning);
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
56
|
-
}
|
|
48
|
+
for (const target of written) {
|
|
49
|
+
installs.push({
|
|
50
|
+
scope,
|
|
51
|
+
agent,
|
|
52
|
+
path: target,
|
|
53
|
+
projectRoot: scope === "project" ? projectRoot : undefined,
|
|
54
|
+
});
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
|
-
}
|
|
60
|
-
export
|
|
57
|
+
}
|
|
58
|
+
export function isRepoUrl(input) {
|
|
61
59
|
return Boolean(parseRepoRef(input));
|
|
62
|
-
}
|
|
63
|
-
export
|
|
60
|
+
}
|
|
61
|
+
export async function handleRepoInstall(input, options) {
|
|
64
62
|
const ref = await ensureRepoRef(input);
|
|
65
63
|
const { skills } = await listRepoSkills(ref);
|
|
66
64
|
const skillNames = skills.map((skill) => skill.name).sort();
|
|
@@ -69,9 +67,11 @@ export const handleRepoInstall = async (input, options) => {
|
|
|
69
67
|
printJson({ ok: true, command: "add", data: { repo: input, skills: skillNames } });
|
|
70
68
|
return;
|
|
71
69
|
}
|
|
72
|
-
printInfo(`Skills
|
|
70
|
+
printInfo(`Repo Skills: ${ref.owner}/${ref.repo}`);
|
|
71
|
+
printInfo("");
|
|
72
|
+
printInfo(`Found ${skillNames.length} skill(s):`);
|
|
73
73
|
for (const name of skillNames) {
|
|
74
|
-
printInfo(
|
|
74
|
+
printInfo(` - ${name}`);
|
|
75
75
|
}
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
@@ -133,25 +133,44 @@ export const handleRepoInstall = async (input, options) => {
|
|
|
133
133
|
}
|
|
134
134
|
await saveIndex(sortIndex(index));
|
|
135
135
|
if (options.json) {
|
|
136
|
-
printJson({ ok: true, command: "add", data: summary });
|
|
136
|
+
printJson({ ok: true, command: "add", data: { repo: `${ref.owner}/${ref.repo}`, ...summary } });
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
}
|
|
139
|
+
printInfo(`Skills Added from: ${ref.owner}/${ref.repo}`);
|
|
140
|
+
printInfo("");
|
|
141
|
+
printInfo("Source: git");
|
|
142
|
+
printInfo(` ${ref.owner}/${ref.repo}${ref.path ? `/${ref.path}` : ""} (${ref.ref})`);
|
|
145
143
|
if (summary.installed.length > 0) {
|
|
146
|
-
printInfo(
|
|
144
|
+
printInfo("");
|
|
145
|
+
printInfo(`Installed (${summary.installed.length}):`);
|
|
146
|
+
for (const name of summary.installed) {
|
|
147
|
+
printInfo(` ✓ ${name}`);
|
|
148
|
+
}
|
|
147
149
|
}
|
|
148
150
|
if (summary.updated.length > 0) {
|
|
149
|
-
printInfo(
|
|
151
|
+
printInfo("");
|
|
152
|
+
printInfo(`Updated (${summary.updated.length}):`);
|
|
153
|
+
for (const name of summary.updated) {
|
|
154
|
+
printInfo(` ✓ ${name}`);
|
|
155
|
+
}
|
|
150
156
|
}
|
|
151
157
|
if (summary.skipped.length > 0) {
|
|
152
|
-
printInfo(
|
|
158
|
+
printInfo("");
|
|
159
|
+
printInfo(`Skipped (${summary.skipped.length}):`);
|
|
160
|
+
for (const name of summary.skipped) {
|
|
161
|
+
printInfo(` - ${name} (missing description)`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (summary.failed.length > 0) {
|
|
165
|
+
printInfo("");
|
|
166
|
+
printInfo(`Failed (${summary.failed.length}):`);
|
|
167
|
+
for (const failure of summary.failed) {
|
|
168
|
+
printInfo(` ✗ ${failure.name} (${failure.reason})`);
|
|
169
|
+
}
|
|
153
170
|
}
|
|
154
|
-
|
|
155
|
-
|
|
171
|
+
const total = summary.installed.length + summary.updated.length;
|
|
172
|
+
if (total === 0) {
|
|
173
|
+
printInfo("");
|
|
174
|
+
printInfo("No skills were added.");
|
|
156
175
|
}
|
|
157
|
-
}
|
|
176
|
+
}
|
package/dist/commands/add.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { isJsonEnabled, printInfo, printJson } from "../lib/output.js";
|
|
2
|
-
import { fetchText } from "../lib/fetcher.js";
|
|
3
|
-
import { parseSkillMarkdown, inferNameFromUrl, buildMetadata } from "../lib/skill-parser.js";
|
|
4
1
|
import { handleCommandError } from "../lib/command.js";
|
|
5
|
-
import {
|
|
2
|
+
import { loadConfig } from "../lib/config.js";
|
|
3
|
+
import { fetchText } from "../lib/fetcher.js";
|
|
4
|
+
import { collect } from "../lib/fs-utils.js";
|
|
6
5
|
import { loadIndex, saveIndex, sortIndex, upsertSkill } from "../lib/index.js";
|
|
7
|
-
import {
|
|
6
|
+
import { isJsonEnabled, printInfo, printJson } from "../lib/output.js";
|
|
8
7
|
import { buildProjectAgentPaths } from "../lib/project-paths.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { ensureProjectRegistered, resolveRuntime } from "../lib/runtime.js";
|
|
9
|
+
import { buildMetadata, inferNameFromUrl, parseSkillMarkdown } from "../lib/skill-parser.js";
|
|
10
|
+
import { ensureSkillsDir, writeSkillFiles } from "../lib/skill-store.js";
|
|
11
|
+
import { buildSymlinkWarning, buildTargets, installSkillToTargets } from "../lib/sync.js";
|
|
11
12
|
import { handleRepoInstall, isRepoUrl } from "./add-repo.js";
|
|
12
|
-
export
|
|
13
|
+
export function registerAdd(program) {
|
|
13
14
|
program
|
|
14
15
|
.command("add")
|
|
15
16
|
.argument("<url>", "Skill URL or repo")
|
|
@@ -41,10 +42,10 @@ export const registerAdd = (program) => {
|
|
|
41
42
|
if (!parsed.name && !options.name) {
|
|
42
43
|
throw new Error("Skill frontmatter missing name. Provide --name to continue.");
|
|
43
44
|
}
|
|
44
|
-
const metadata = buildMetadata(parsed, { type: "url", url }, skillName);
|
|
45
45
|
if (!parsed.description) {
|
|
46
46
|
throw new Error("Skill frontmatter missing description. Convert the source into a valid skill.");
|
|
47
47
|
}
|
|
48
|
+
const metadata = buildMetadata(parsed, { type: "url", url }, skillName);
|
|
48
49
|
await ensureSkillsDir();
|
|
49
50
|
await writeSkillFiles(skillName, skillMarkdown, metadata);
|
|
50
51
|
const index = await loadIndex();
|
|
@@ -73,8 +74,8 @@ export const registerAdd = (program) => {
|
|
|
73
74
|
const written = results
|
|
74
75
|
.filter((result) => result.mode !== "skipped")
|
|
75
76
|
.map((result) => result.path);
|
|
76
|
-
const
|
|
77
|
-
|
|
77
|
+
const warnings = buildSymlinkWarning(agent, results);
|
|
78
|
+
for (const warning of warnings) {
|
|
78
79
|
printInfo(warning);
|
|
79
80
|
}
|
|
80
81
|
if (written.length > 0) {
|
|
@@ -103,30 +104,32 @@ export const registerAdd = (program) => {
|
|
|
103
104
|
command: "add",
|
|
104
105
|
data: {
|
|
105
106
|
name: skillName,
|
|
106
|
-
url,
|
|
107
|
+
source: { type: "url", url },
|
|
107
108
|
scope,
|
|
108
|
-
|
|
109
|
+
installs,
|
|
109
110
|
},
|
|
110
111
|
});
|
|
111
112
|
return;
|
|
112
113
|
}
|
|
113
|
-
printInfo(`
|
|
114
|
-
printInfo(
|
|
115
|
-
printInfo(
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
printInfo(`Skill Added: ${skillName}`);
|
|
115
|
+
printInfo("");
|
|
116
|
+
printInfo("Source: url");
|
|
117
|
+
printInfo(` ${url}`);
|
|
118
|
+
if (installs.length > 0) {
|
|
119
|
+
printInfo("");
|
|
120
|
+
printInfo("Installed to:");
|
|
121
|
+
for (const install of installs) {
|
|
122
|
+
const scopeLabel = install.scope === "project" ? `project:${install.projectRoot}` : "user";
|
|
123
|
+
printInfo(` ✓ ${scopeLabel}/${install.agent}`);
|
|
124
|
+
}
|
|
118
125
|
}
|
|
119
126
|
else {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
127
|
+
printInfo("");
|
|
128
|
+
printInfo("No agent targets were updated.");
|
|
123
129
|
}
|
|
124
130
|
}
|
|
125
131
|
catch (error) {
|
|
126
132
|
handleCommandError(options, "add", error);
|
|
127
133
|
}
|
|
128
134
|
});
|
|
129
|
-
}
|
|
130
|
-
const collect = (value, previous = []) => {
|
|
131
|
-
return [...previous, value];
|
|
132
|
-
};
|
|
135
|
+
}
|
package/dist/commands/agent.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isJsonEnabled, printInfo, printJson } from "../lib/output.js";
|
|
2
|
-
const
|
|
2
|
+
const AGENT_SNIPPET = `Use skillbox for skill management.
|
|
3
3
|
|
|
4
4
|
Common workflow:
|
|
5
5
|
1) skillbox list --json
|
|
@@ -12,22 +12,16 @@ skillbox add <url> [--name <name>]
|
|
|
12
12
|
If a URL is not a valid skill, run:
|
|
13
13
|
skillbox convert <url> --agent
|
|
14
14
|
`;
|
|
15
|
-
export
|
|
15
|
+
export function registerAgent(program) {
|
|
16
16
|
program
|
|
17
17
|
.command("agent")
|
|
18
18
|
.description("Print agent-friendly usage")
|
|
19
19
|
.option("--json", "JSON output")
|
|
20
20
|
.action((options) => {
|
|
21
21
|
if (isJsonEnabled(options)) {
|
|
22
|
-
printJson({
|
|
23
|
-
ok: true,
|
|
24
|
-
command: "agent",
|
|
25
|
-
data: {
|
|
26
|
-
snippet: agentSnippet,
|
|
27
|
-
},
|
|
28
|
-
});
|
|
22
|
+
printJson({ ok: true, command: "agent", data: { snippet: AGENT_SNIPPET } });
|
|
29
23
|
return;
|
|
30
24
|
}
|
|
31
|
-
printInfo(
|
|
25
|
+
printInfo(AGENT_SNIPPET);
|
|
32
26
|
});
|
|
33
|
-
}
|
|
27
|
+
}
|
package/dist/commands/config.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { isJsonEnabled, printInfo, printJson } from "../lib/output.js";
|
|
2
|
-
import { loadConfig, saveConfig } from "../lib/config.js";
|
|
3
1
|
import { handleCommandError } from "../lib/command.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
7
|
-
export
|
|
2
|
+
import { loadConfig, saveConfig } from "../lib/config.js";
|
|
3
|
+
import { collect } from "../lib/fs-utils.js";
|
|
4
|
+
import { isJsonEnabled, printInfo, printJson } from "../lib/output.js";
|
|
5
|
+
export function registerConfig(program) {
|
|
8
6
|
const config = program.command("config").description("View or edit skillbox config");
|
|
9
7
|
config
|
|
10
8
|
.command("get")
|
|
@@ -36,13 +34,13 @@ export const registerConfig = (program) => {
|
|
|
36
34
|
if (nextScope !== "project" && nextScope !== "user") {
|
|
37
35
|
throw new Error("defaultScope must be 'project' or 'user'.");
|
|
38
36
|
}
|
|
39
|
-
const addedAgents = options.addAgent ?? [];
|
|
40
|
-
const nextAgents = options.defaultAgent ?? current.defaultAgents;
|
|
41
|
-
const mergedAgents = Array.from(new Set([...(nextAgents ?? []), ...addedAgents].filter((agent) => agent.length > 0)));
|
|
42
37
|
const nextMode = options.installMode ?? current.installMode;
|
|
43
38
|
if (nextMode !== "symlink" && nextMode !== "copy") {
|
|
44
39
|
throw new Error("installMode must be 'symlink' or 'copy'.");
|
|
45
40
|
}
|
|
41
|
+
const addedAgents = options.addAgent ?? [];
|
|
42
|
+
const nextAgents = options.defaultAgent ?? current.defaultAgents;
|
|
43
|
+
const mergedAgents = Array.from(new Set([...(nextAgents ?? []), ...addedAgents].filter((agent) => agent.length > 0)));
|
|
46
44
|
const next = {
|
|
47
45
|
...current,
|
|
48
46
|
defaultAgents: mergedAgents,
|
|
@@ -60,4 +58,4 @@ export const registerConfig = (program) => {
|
|
|
60
58
|
handleCommandError(options, "config set", error);
|
|
61
59
|
}
|
|
62
60
|
});
|
|
63
|
-
}
|
|
61
|
+
}
|