skilllib 1.12.2 → 1.14.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/README.md +24 -15
- package/dist/{chunk-YQFLFWAY.js → chunk-XMXC2XM2.js} +844 -112
- package/dist/index.js +31 -9
- package/dist/json.d.cts +702 -2
- package/dist/json.d.ts +702 -2
- package/dist/{tui-P3HKRNHI.js → tui-N6NRJYLZ.js} +30 -20
- package/package.json +6 -2
- package/skills/skilllib/SKILL.md +9 -7
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
FEATURED_HARNESSES,
|
|
2
3
|
HARNESSES,
|
|
3
4
|
PROJECT_SKILLS_DIR,
|
|
4
5
|
addRefusal,
|
|
@@ -87,7 +88,7 @@ import {
|
|
|
87
88
|
versionHistory,
|
|
88
89
|
visibleProjects,
|
|
89
90
|
withoutForceHint
|
|
90
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-XMXC2XM2.js";
|
|
91
92
|
|
|
92
93
|
// src/tui/index.tsx
|
|
93
94
|
import { render } from "ink";
|
|
@@ -302,17 +303,6 @@ function copyText(text) {
|
|
|
302
303
|
return { copied: false, savedTo };
|
|
303
304
|
}
|
|
304
305
|
|
|
305
|
-
// src/search.ts
|
|
306
|
-
function matchScore(text, query) {
|
|
307
|
-
if (!query) return 0;
|
|
308
|
-
const t = text.toLowerCase();
|
|
309
|
-
const q = query.toLowerCase();
|
|
310
|
-
if (t.startsWith(q)) return 0;
|
|
311
|
-
if (t.includes(q)) return 1;
|
|
312
|
-
const initials = t.split(/[-_\s./]+/).filter(Boolean).map((w) => w[0]).join("");
|
|
313
|
-
return q.length >= 2 && initials.startsWith(q) ? 2 : null;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
306
|
// src/tui/world.ts
|
|
317
307
|
var failed = (message) => ({ message, failed: true });
|
|
318
308
|
var isFailure = (r) => typeof r !== "string" && "failed" in r;
|
|
@@ -623,7 +613,12 @@ function groupLabel(g, names) {
|
|
|
623
613
|
return `${top} + ${names.length - 1} more \xB7 ${g.label}`;
|
|
624
614
|
}
|
|
625
615
|
function matches(name, query) {
|
|
626
|
-
|
|
616
|
+
if (!query) return true;
|
|
617
|
+
const text = name.toLowerCase();
|
|
618
|
+
const q = query.toLowerCase();
|
|
619
|
+
if (text.includes(q)) return true;
|
|
620
|
+
const initials = text.split(/[-_\s./]+/).filter(Boolean).map((w) => w[0]).join("");
|
|
621
|
+
return q.length >= 2 && initials.startsWith(q);
|
|
627
622
|
}
|
|
628
623
|
function addRows(w, target, q) {
|
|
629
624
|
const taken = new Set(target ? project(w, target).skills.map((s) => s.name) : []);
|
|
@@ -1509,8 +1504,11 @@ function App({ initial, reload, loadUsage: loadUsage2 }) {
|
|
|
1509
1504
|
}
|
|
1510
1505
|
useEffect(() => {
|
|
1511
1506
|
const folder = () => !initial.roots.length && askForFolder("Where are your projects? skilllib finds the git repos in there");
|
|
1512
|
-
if (!initial.agentsChosen)
|
|
1513
|
-
|
|
1507
|
+
if (!initial.agentsChosen) {
|
|
1508
|
+
const installed = HARNESSES.filter((h) => h.installed()).map((h) => h.id);
|
|
1509
|
+
const ids = [...FEATURED_HARNESSES, ...installed.filter((id) => !FEATURED_HARNESSES.includes(id))];
|
|
1510
|
+
setModal({ kind: "agents", selected: initial.agents, ids, cursor: 0, then: folder });
|
|
1511
|
+
} else folder();
|
|
1514
1512
|
}, []);
|
|
1515
1513
|
function openInGlobal(name) {
|
|
1516
1514
|
goPlace("global");
|
|
@@ -1530,14 +1528,24 @@ function App({ initial, reload, loadUsage: loadUsage2 }) {
|
|
|
1530
1528
|
cells: [{ text, width: 34, color: c }, { text: sub, grow: true, color: color.faint }],
|
|
1531
1529
|
onEnter
|
|
1532
1530
|
});
|
|
1531
|
+
const shown = [
|
|
1532
|
+
...FEATURED_HARNESSES.map((id) => harness(id)),
|
|
1533
|
+
...world.agents.filter((id) => !FEATURED_HARNESSES.includes(id)).map((id) => harness(id))
|
|
1534
|
+
];
|
|
1533
1535
|
return [
|
|
1534
1536
|
header("#agents", "Agents"),
|
|
1535
|
-
...
|
|
1537
|
+
...shown.map(
|
|
1536
1538
|
(h) => row(`agent:${h.id}`, `${world.agents.includes(h.id) ? "[x]" : "[ ]"} ${h.icon} ${h.name}`, h.projectDirs.join(", "), () => {
|
|
1537
1539
|
const wasOn = world.agents.includes(h.id);
|
|
1538
1540
|
apply((w) => (w.ops.setAgents(wasOn ? w.agents.filter((a) => a !== h.id) : HARNESSES.map((x) => x.id).filter((id) => id === h.id || w.agents.includes(id))), `${h.name} ${wasOn ? "off" : "on"}`));
|
|
1539
1541
|
})
|
|
1540
1542
|
),
|
|
1543
|
+
row(
|
|
1544
|
+
"agents:more",
|
|
1545
|
+
"More agents\u2026",
|
|
1546
|
+
"Copilot, Gemini, OpenCode, Windsurf, and the rest",
|
|
1547
|
+
() => setModal({ kind: "agents", selected: world.agents, ids: HARNESSES.map((h) => h.id), cursor: 0 })
|
|
1548
|
+
),
|
|
1541
1549
|
// The skill that lets your agents use skilllib: installing adds a global skill, so it asks first.
|
|
1542
1550
|
row(
|
|
1543
1551
|
"agent-skill",
|
|
@@ -1667,11 +1675,13 @@ function App({ initial, reload, loadUsage: loadUsage2 }) {
|
|
|
1667
1675
|
if (m.kind === "add") return addKeys(m, input, key);
|
|
1668
1676
|
}
|
|
1669
1677
|
function agentsKeys(m, input, key) {
|
|
1678
|
+
const list2 = m.ids.map((id) => harness(id));
|
|
1670
1679
|
if (key.escape && !m.then) return setModal(null);
|
|
1671
1680
|
if (key.upArrow) return setModal({ ...m, cursor: Math.max(0, m.cursor - 1) });
|
|
1672
|
-
if (key.downArrow) return setModal({ ...m, cursor: Math.min(
|
|
1681
|
+
if (key.downArrow) return setModal({ ...m, cursor: Math.min(list2.length - 1, m.cursor + 1) });
|
|
1673
1682
|
if (input === " ") {
|
|
1674
|
-
const id =
|
|
1683
|
+
const id = list2[m.cursor]?.id;
|
|
1684
|
+
if (!id) return;
|
|
1675
1685
|
return setModal({ ...m, selected: m.selected.includes(id) ? m.selected.filter((x) => x !== id) : [...m.selected, id] });
|
|
1676
1686
|
}
|
|
1677
1687
|
if (key.return) {
|
|
@@ -1905,11 +1915,11 @@ function App({ initial, reload, loadUsage: loadUsage2 }) {
|
|
|
1905
1915
|
empty: "",
|
|
1906
1916
|
header: /* @__PURE__ */ jsx2(Text2, { color: color.muted, children: "skilllib makes your skills visible to each one. Detected ones are ticked." }),
|
|
1907
1917
|
headerHeight: 1,
|
|
1908
|
-
rows:
|
|
1918
|
+
rows: modal.ids.map((id) => harness(id)).map((h) => ({
|
|
1909
1919
|
key: h.id,
|
|
1910
1920
|
cells: [
|
|
1911
1921
|
{ text: modal.selected.includes(h.id) ? "[x] " : "[ ] ", width: 4, color: modal.selected.includes(h.id) ? color.green : color.faint },
|
|
1912
|
-
{ text: `${h.icon} ${h.name}`, width:
|
|
1922
|
+
{ text: `${h.icon} ${h.name}`, width: 22, color: h.color },
|
|
1913
1923
|
{ text: `reads ${h.projectDirs.join(", ")}`, grow: true, color: color.faint }
|
|
1914
1924
|
]
|
|
1915
1925
|
}))
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skilllib",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Manage your agent skills like dependencies. One library
|
|
3
|
+
"version": "1.14.0",
|
|
4
|
+
"description": "Manage your agent skills like dependencies. One library, install from skills.sh, and every agent you use can see them.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
7
7
|
"skills",
|
|
8
|
+
"skills.sh",
|
|
8
9
|
"skill-md",
|
|
9
10
|
"claude-code",
|
|
10
11
|
"claude",
|
|
11
12
|
"cursor",
|
|
12
13
|
"codex",
|
|
14
|
+
"gemini",
|
|
15
|
+
"github-copilot",
|
|
16
|
+
"opencode",
|
|
13
17
|
"zed",
|
|
14
18
|
"grok",
|
|
15
19
|
"ai-agents",
|
package/skills/skilllib/SKILL.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: skilllib
|
|
3
|
-
description: Agent skills (SKILL.md) loaded in this repo and the user's skill library, via the skilllib CLI. Use for which skills you can use here and where each comes from, which library skills to add, what's out of date, broken or duplicated,
|
|
3
|
+
description: Agent skills (SKILL.md) loaded in this repo and the user's skill library, via the skilllib CLI. Use for which skills you can use here and where each comes from, which library skills to add, what's out of date, broken or duplicated, adding, removing or updating skills, and installing skills from skills.sh or GitHub.
|
|
4
4
|
allowed-tools: Bash(skilllib:*)
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# skilllib
|
|
8
8
|
|
|
9
|
-
The user manages agent skills with the `skilllib` CLI. Their **library** (`~/.skilllib/library`, "my skills", "the registry") holds versioned skills that load nowhere until added to a repo.
|
|
9
|
+
The user manages agent skills with the `skilllib` CLI. Their **library** (`~/.skilllib/library`, "my skills", "the registry") holds versioned skills that load nowhere until added to a repo. Adding a skill pins it in the user's personal pins (`~/.skilllib/pins`, kept out of git: `personal: true`). `skilllib.json` is only for sharing a skill with the team, and only when they ask: `--shared` writes it, and they commit it.
|
|
10
10
|
|
|
11
|
-
Always pass `--json` (one line of JSON on stdout; messages go to stderr). A failure exits 1 with `{"error": "..."}` as that line. `link`, `tidy`, `global` (its listing, `keep` and `unkeep`), `restore`, `new`, `folders`, `harnesses`, `scan` and `unhide` print messages only (read the exit code). Unknown flags are errors. Never run bare `skilllib` or `skilllib ui`: that's an interactive app.
|
|
11
|
+
Always pass `--json` (one line of JSON on stdout; messages go to stderr). A failure exits 1 with `{"error": "..."}` as that line. `link`, `tidy`, `global` (its listing, `keep` and `unkeep`), `restore`, `new`, `folders`, `harnesses`, `scan`, `search` (without `--json`) and `unhide` print messages only (read the exit code). Unknown flags are errors. Never run bare `skilllib` or `skilllib ui`: that's an interactive app.
|
|
12
12
|
|
|
13
13
|
## Reading
|
|
14
14
|
|
|
@@ -23,9 +23,11 @@ The **Now** section at the end has this repo's `status` and `list` output. Answe
|
|
|
23
23
|
|
|
24
24
|
Also: `usage --json` (Claude Code usage only, so "unused" is a hint; each skill lists the `projects` that used it), `projects --json` (every repo), `outdated --all --json`, `doctor --json` (every issue in every repo and globally, each with an `id`).
|
|
25
25
|
|
|
26
|
+
`check --json` reads the global skills and, in a repo, that repo's. It stores nothing. `brief` is the report: how many tokens the names and descriptions cost on every prompt, whether that is heavy, and the cuts that can actually be made. A Claude Code plugin it names turns off with `plugin off <id> --json`, and `plugin on <id>` puts it back. Run that only after the user agrees: the switch is global, and a skill in the plugin that was used goes too. Cursor plugins turn off in Cursor. claude.ai skills turn off on claude.ai. Built-ins ship with Cursor, Codex, and Grok, and skilllib can't unload them. Your own unused globals can move into the repos that need them. `uses` is Claude Code only, so 0 means it wasn't seen. Read `brief` to the user. The `skills` list is there if they ask about one.
|
|
27
|
+
|
|
26
28
|
## Changing (ask first unless the user asked for this exact change)
|
|
27
29
|
|
|
28
|
-
`add <name>...` (pins
|
|
30
|
+
`plugin off|on <id>` (a Claude Code plugin, `name@marketplace` from `check`; a name alone works when only one plugin has it; it stays installed. The copy that loads in every repo. A per-repo install is left on, and the message says where) · `add <name>...` (personal pins; `--shared` writes `skilllib.json` for the team, and only when they asked to share it; `--personal` moves a shared pin back. Either flag moves an existing pin without changing its version. A pin stays where it already is) · `remove <name>...` (skills skilllib manages, `source: library`) · `update [name...]` · `sync` (installs what's pinned, personal pins and `skilllib.json`; takes no names). Pass several names in one call. Their result is `[{name, action, from, to, dirs, personal, moved, reason, blocked, uncommitted, inTheWay, backedUp}]` (`personal: true` when the pin is in your personal pins; `moved` when `--personal`/`--shared` moved it), which is the whole result: there's no need to check files afterwards. `import <dir>...` (into the library) prints `[{path, name, status}]` and exits 1 if a folder was skipped (`exists`, `no SKILL.md`). `doctor --fix` prints doctor's issues, each fix with `fixed: {ok, message}`.
|
|
29
31
|
|
|
30
32
|
- `skipped` + `reason`: nothing changed for that skill, and the command exits 1; tell the user. `--force` overwrites local edits (`backedUp` says where they went; `skilllib restore <name>` brings them back), but only use it with their OK.
|
|
31
33
|
- `removed` + `reason`: removed from skilllib.json, but something was left as it is (its copy behind a folder that links out of the repo, a file of the user's, or a link in such a folder). Tell the user what the reason says is still there.
|
|
@@ -33,16 +35,16 @@ Also: `usage --json` (Claude Code usage only, so "unused" is a hint; each skill
|
|
|
33
35
|
- `inTheWay`: something else is where a link goes (a file, or another copy), so that agent may not run this copy there, and the command exits 1. Tell the user what's there; once they move it, `skilllib link` adds the link. (A skills folder that's a file or links out of the repo makes the skill `skipped` instead, with the reason.)
|
|
34
36
|
- `blocked`: git tracks that folder. Re-run with `--allow-tracked` (for that command only) only with their OK.
|
|
35
37
|
- `uncommitted`: git tracks that folder but not the skill's real copy, so a link there would break for teammates; `--allow-tracked` doesn't change that. Once the copy is committed, `link --allow-tracked` adds it.
|
|
36
|
-
- Changes apply from the agent's next session.
|
|
38
|
+
- Changes apply from the agent's next session. A `personal` change has nothing to commit. Without `personal` (`--shared`, or a pin that was already in `skilllib.json`), remind the user to commit `skilllib.json` and the folders in `dirs`.
|
|
37
39
|
|
|
38
40
|
**Prefer per-repo skills to global ones.** A global skill loads in every repo, for every agent. When `usage --json` shows one used in only a few repos, propose moving it there:
|
|
39
41
|
|
|
40
|
-
- `global move <name>... --to <repo>[,<repo>...]` (a project name from `projects`, or the path of a repo's top folder): imports it into the library, adds it to each repo, and only then stops loading it globally (restorable with `skilllib restore`). Prints `[{skill, moved, reason, left, projects: [{project, path, change}]}]` (`left`: links in a repo or its packages that now point at nothing, though a copy in the repo still serves them; tell the user to remove them); `moved: false` means it still loads globally, and `reason` says why
|
|
42
|
+
- `global move <name>... --to <repo>[,<repo>...]` (a project name from `projects`, or the path of a repo's top folder): imports it into the library, adds it to each repo, and only then stops loading it globally (restorable with `skilllib restore`). Prints `[{skill, moved, reason, left, projects: [{project, path, change}]}]` (`left`: links in a repo or its packages that now point at nothing, though a copy in the repo still serves them; tell the user to remove them); `moved: false` means it still loads globally, and `reason` says why.
|
|
41
43
|
- `global keep <name>...`: the user wants it everywhere; skilllib stops flagging it.
|
|
42
44
|
|
|
43
45
|
**Fixes and decisions.** `apply <id> [choice]` runs one problem's `fix`, or the choice you name: its label (safest), or its number from 1. With several choices it needs one. Prints `{id, applied, ok, message}`. Ids come from `issues` in `status --json` (Now, below) or from `doctor --json` (every repo; pass `apply` the same `--days` you gave `doctor`). A few issues span repos and offer different choices in each; then `apply` takes only the label.
|
|
44
46
|
|
|
45
|
-
**Importing.** `import <dir>...` copies skill folders (each with a `SKILL.md`) into the library;
|
|
47
|
+
**Importing and installing.** `import <dir>...` copies skill folders (each with a `SKILL.md`) into the library; it doesn't download anything. `install <source>...` does: `owner/repo`, `owner/repo@skill`, a `https://skills.sh/...` or GitHub URL, or a local folder. It puts each skill in the library. In a repo it also adds them here; `--global` loads them in every repo instead (and marks them kept). A repo with several skills is listed, not installed, until you pass `@name` or `--all`. `search <query>` lists matches from skills.sh. `install` and `search` accept `--json`.
|
|
46
48
|
|
|
47
49
|
## Now
|
|
48
50
|
|