skillex 0.2.0 → 0.2.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/CHANGELOG.md +11 -0
- package/README.md +33 -7
- package/dist/adapters.js +8 -6
- package/dist/cli.js +5 -2
- package/dist/config.d.ts +4 -0
- package/dist/config.js +7 -0
- package/dist/fs.js +4 -4
- package/dist/sync.js +5 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.1] - 2026-04-07
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Skills and generated symlink sources are now stored in `~/.skillex/` (user-level) instead of `<project>/.agent-skills/`, so a single install is shared across all workspaces and symlinks always resolve correctly
|
|
14
|
+
- `claude` adapter: switched from managed-block in `CLAUDE.md` to a dedicated file at `.claude/skills/skillex-skills.md`; old `CLAUDE.md` block cleaned up automatically on next `sync`
|
|
15
|
+
- `gemini` adapter: switched from managed-block in `GEMINI.md` to a dedicated file at `.gemini/skills/skillex-skills.md`; old `GEMINI.md` block cleaned up automatically on next `sync`
|
|
16
|
+
- `codex` adapter: switched from managed-block in `AGENTS.md` to a dedicated file at `.codex/skills/skillex-skills.md` (introduced in this cycle)
|
|
17
|
+
- Symlinks are now absolute paths instead of relative, ensuring they work regardless of project depth
|
|
18
|
+
- `copilot` is now the only adapter that uses managed-block injection
|
|
19
|
+
- `--agent-skills-dir` flag still overrides to a project-local directory when isolation is needed
|
|
20
|
+
|
|
10
21
|
## [0.2.0] - 2026-04-07
|
|
11
22
|
|
|
12
23
|
### Added
|
package/README.md
CHANGED
|
@@ -42,10 +42,13 @@ npx skillex@latest list
|
|
|
42
42
|
# 3. Install a skill
|
|
43
43
|
npx skillex@latest install create-skills
|
|
44
44
|
|
|
45
|
-
# 4.
|
|
45
|
+
# 4. Write the installed skills into your agent's config file
|
|
46
|
+
# ⚠️ This step is required — without it, your agent cannot see the skills.
|
|
46
47
|
npx skillex@latest sync
|
|
47
48
|
```
|
|
48
49
|
|
|
50
|
+
> **Important:** `install` downloads skill files locally. `sync` is what actually writes the skill instructions into your agent's configuration file (e.g. `.claude/skills/skillex-skills.md`, `.codex/skills/skillex-skills.md`, `.github/copilot-instructions.md`). **You must run `sync` after every install or update for your agent to pick up the changes.** Use `--auto-sync` at `init` time to have this happen automatically.
|
|
51
|
+
|
|
49
52
|
After `init`, Skillex saves the configured source list in the local lockfile. New workspaces start with `lgili/skillex@main` by default, and you can add more sources later with `skillex source add`.
|
|
50
53
|
|
|
51
54
|
---
|
|
@@ -162,6 +165,8 @@ skillex install owner/repo/path/to/skill@main --trust
|
|
|
162
165
|
| `--repo <owner/repo>` | Limit resolution to a single source when needed. |
|
|
163
166
|
| `--trust` | Skip confirmation prompt for direct GitHub installs. |
|
|
164
167
|
|
|
168
|
+
> **After installing,** run `skillex sync` to write the skills into your agent's config file. Without this step, the agent will not see the newly installed skills. If you initialized with `--auto-sync`, this happens automatically.
|
|
169
|
+
|
|
165
170
|
---
|
|
166
171
|
|
|
167
172
|
### `update`
|
|
@@ -191,7 +196,7 @@ skillex rm git-master code-review
|
|
|
191
196
|
|
|
192
197
|
### `sync`
|
|
193
198
|
|
|
194
|
-
Write all installed skills into the active adapter's config file.
|
|
199
|
+
Write all installed skills into the active adapter's config file (e.g. `.claude/skills/skillex-skills.md`, `.codex/skills/skillex-skills.md`, `.github/copilot-instructions.md`). **This is the step that makes skills visible to your AI agent.** Run it after every `install`, `update`, or `remove`.
|
|
195
200
|
|
|
196
201
|
```bash
|
|
197
202
|
# Sync to the detected adapter
|
|
@@ -213,6 +218,25 @@ skillex sync --mode copy
|
|
|
213
218
|
| `--adapter <id>` | Override the active adapter for this sync. |
|
|
214
219
|
| `--mode copy\|symlink` | File write strategy (default: `symlink` for dedicated-file adapters). |
|
|
215
220
|
|
|
221
|
+
#### Using multiple agents in the same workspace
|
|
222
|
+
|
|
223
|
+
`sync` writes to one adapter at a time. If you use more than one AI agent in the same folder (e.g. Claude and Codex), run `sync` once for each:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# Write skills into .claude/skills/skillex-skills.md
|
|
227
|
+
skillex sync --adapter claude
|
|
228
|
+
|
|
229
|
+
# Write skills into .codex/skills/skillex-skills.md
|
|
230
|
+
skillex sync --adapter codex
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Each adapter writes to its own target file, so the two syncs are independent and non-destructive. To avoid running both commands manually after every change, initialize with `--auto-sync` and then re-run `skillex init --adapter <id>` for each adapter you want covered — or simply alias both commands in your workflow:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Sync to all agents at once (shell alias / Makefile target)
|
|
237
|
+
skillex sync --adapter claude && skillex sync --adapter codex
|
|
238
|
+
```
|
|
239
|
+
|
|
216
240
|
---
|
|
217
241
|
|
|
218
242
|
### `run`
|
|
@@ -337,17 +361,19 @@ Skillex auto-detects the AI agent you use by looking for known marker files in y
|
|
|
337
361
|
|
|
338
362
|
| Adapter ID | Agent | Detection Markers | Sync Target |
|
|
339
363
|
|------------|-------|-------------------|-------------|
|
|
340
|
-
| `codex` | OpenAI Codex | `AGENTS.md`, `.codex/` |
|
|
364
|
+
| `codex` | OpenAI Codex | `AGENTS.md`, `.codex/` | `.codex/skills/skillex-skills.md` |
|
|
341
365
|
| `copilot` | GitHub Copilot | `.github/copilot-instructions.md` | `.github/copilot-instructions.md` |
|
|
342
366
|
| `cline` | Cline / Roo Code | `.cline/`, `.roo/`, `.clinerules` | `.clinerules/skillex-skills.md` |
|
|
343
367
|
| `cursor` | Cursor | `.cursor/`, `.cursorrules` | `.cursor/rules/skillex-skills.mdc` |
|
|
344
|
-
| `claude` | Claude Code | `CLAUDE.md`, `.claude/` |
|
|
345
|
-
| `gemini` | Gemini CLI | `GEMINI.md`, `.gemini/` |
|
|
368
|
+
| `claude` | Claude Code | `CLAUDE.md`, `.claude/` | `.claude/skills/skillex-skills.md` |
|
|
369
|
+
| `gemini` | Gemini CLI | `GEMINI.md`, `.gemini/` | `.gemini/skills/skillex-skills.md` |
|
|
346
370
|
| `windsurf` | Windsurf | `.windsurf/`, `.windsurf/rules/` | `.windsurf/rules/skillex-skills.md` |
|
|
347
371
|
|
|
348
|
-
**Shared-file
|
|
372
|
+
**Shared-file adapter** (`copilot`) uses a **managed block** — Skillex writes between `<!-- SKILLEX:START -->` and `<!-- SKILLEX:END -->` markers inside `.github/copilot-instructions.md`, preserving everything else in the file.
|
|
373
|
+
|
|
374
|
+
**Dedicated-file adapters** (`codex`, `cline`, `claude`, `cursor`, `gemini`, `windsurf`) each generate a file in `~/.skillex/generated/<adapter>/` and create an absolute symlink at the adapter's target path (e.g. `.claude/skills/skillex-skills.md`). Use `--mode copy` to write directly instead.
|
|
349
375
|
|
|
350
|
-
|
|
376
|
+
> **Migrating from a previous version?** If you had skill content injected into `CLAUDE.md`, `GEMINI.md`, or `AGENTS.md` by an older version of Skillex, those legacy files are cleaned up automatically on the next `sync`. You can also remove the block manually.
|
|
351
377
|
|
|
352
378
|
Compatibility aliases are normalized automatically: `claude-code` → `claude`, `github-copilot` → `copilot`, `roo-code` → `cline`, `gemini-cli` → `gemini`.
|
|
353
379
|
|
package/dist/adapters.js
CHANGED
|
@@ -10,8 +10,8 @@ const ADAPTERS = [
|
|
|
10
10
|
{ path: ".codex", weight: 12 },
|
|
11
11
|
{ path: ".codex/skills", weight: 16 },
|
|
12
12
|
],
|
|
13
|
-
syncTarget: "
|
|
14
|
-
syncMode: "managed-
|
|
13
|
+
syncTarget: ".codex/skills/skillex-skills.md",
|
|
14
|
+
syncMode: "managed-file",
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
id: "copilot",
|
|
@@ -52,8 +52,9 @@ const ADAPTERS = [
|
|
|
52
52
|
{ path: "CLAUDE.md", weight: 16 },
|
|
53
53
|
{ path: ".claude", weight: 18 },
|
|
54
54
|
],
|
|
55
|
-
syncTarget: "
|
|
56
|
-
|
|
55
|
+
syncTarget: ".claude/skills/skillex-skills.md",
|
|
56
|
+
legacySyncTargets: ["CLAUDE.md"],
|
|
57
|
+
syncMode: "managed-file",
|
|
57
58
|
},
|
|
58
59
|
{
|
|
59
60
|
id: "gemini",
|
|
@@ -62,8 +63,9 @@ const ADAPTERS = [
|
|
|
62
63
|
{ path: "GEMINI.md", weight: 16 },
|
|
63
64
|
{ path: ".gemini", weight: 18 },
|
|
64
65
|
],
|
|
65
|
-
syncTarget: "
|
|
66
|
-
|
|
66
|
+
syncTarget: ".gemini/skills/skillex-skills.md",
|
|
67
|
+
legacySyncTargets: ["GEMINI.md"],
|
|
68
|
+
syncMode: "managed-file",
|
|
67
69
|
},
|
|
68
70
|
{
|
|
69
71
|
id: "windsurf",
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { listAdapters } from "./adapters.js";
|
|
3
3
|
import { computeCatalogCacheKey, loadCatalog, readCatalogCache, searchCatalogSkills, } from "./catalog.js";
|
|
4
|
-
import { DEFAULT_AGENT_SKILLS_DIR, getStatePaths } from "./config.js";
|
|
4
|
+
import { DEFAULT_AGENT_SKILLS_DIR, getDefaultSkillsDir, getStatePaths } from "./config.js";
|
|
5
5
|
import { addProjectSource, getInstalledSkills, initProject, installSkills, listProjectSources, loadProjectCatalogs, removeProjectSource, removeSkills, resolveProjectSource, syncInstalledSkills, updateInstalledSkills, } from "./install.js";
|
|
6
6
|
import * as output from "./output.js";
|
|
7
7
|
import { setVerbose } from "./output.js";
|
|
@@ -750,12 +750,15 @@ function commonOptions(flags, userConfig = {}) {
|
|
|
750
750
|
options.timeout = timeout;
|
|
751
751
|
if (noCache !== undefined)
|
|
752
752
|
options.noCache = noCache;
|
|
753
|
+
// Default to user-level storage so symlinks always point to a stable path.
|
|
754
|
+
if (!options.agentSkillsDir)
|
|
755
|
+
options.agentSkillsDir = getDefaultSkillsDir();
|
|
753
756
|
return options;
|
|
754
757
|
}
|
|
755
758
|
/** Returns cache-related options to spread into a loadCatalog call. */
|
|
756
759
|
function cacheOptions(opts) {
|
|
757
760
|
const cwd = opts.cwd ?? process.cwd();
|
|
758
|
-
const stateDir = path.
|
|
761
|
+
const stateDir = path.resolve(cwd, opts.agentSkillsDir ?? getDefaultSkillsDir());
|
|
759
762
|
return {
|
|
760
763
|
cacheDir: path.join(stateDir, ".cache"),
|
|
761
764
|
...(opts.noCache !== undefined ? { noCache: opts.noCache } : {}),
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { StatePaths } from "./types.js";
|
|
2
2
|
export declare const DEFAULT_AGENT_SKILLS_DIR = ".agent-skills";
|
|
3
|
+
/**
|
|
4
|
+
* Returns the default user-level Skillex directory (`~/.skillex`).
|
|
5
|
+
*/
|
|
6
|
+
export declare function getDefaultSkillsDir(): string;
|
|
3
7
|
export declare const DEFAULT_LOCKFILE = "skills.json";
|
|
4
8
|
export declare const DEFAULT_LOCAL_SKILLS_DIR = "skills";
|
|
5
9
|
export declare const DEFAULT_GENERATED_DIR = "generated";
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
1
2
|
import * as path from "node:path";
|
|
2
3
|
export const DEFAULT_AGENT_SKILLS_DIR = ".agent-skills";
|
|
4
|
+
/**
|
|
5
|
+
* Returns the default user-level Skillex directory (`~/.skillex`).
|
|
6
|
+
*/
|
|
7
|
+
export function getDefaultSkillsDir() {
|
|
8
|
+
return path.join(os.homedir(), ".skillex");
|
|
9
|
+
}
|
|
3
10
|
export const DEFAULT_LOCKFILE = "skills.json";
|
|
4
11
|
export const DEFAULT_LOCAL_SKILLS_DIR = "skills";
|
|
5
12
|
export const DEFAULT_GENERATED_DIR = "generated";
|
package/dist/fs.js
CHANGED
|
@@ -97,15 +97,15 @@ export async function removePath(targetPath) {
|
|
|
97
97
|
* @returns Symlink creation result.
|
|
98
98
|
*/
|
|
99
99
|
export async function createSymlink(targetPath, linkPath) {
|
|
100
|
-
const
|
|
100
|
+
const absoluteTarget = path.resolve(targetPath);
|
|
101
101
|
await ensureDir(path.dirname(linkPath));
|
|
102
102
|
await removePath(linkPath);
|
|
103
103
|
try {
|
|
104
|
-
await fs.symlink(
|
|
104
|
+
await fs.symlink(absoluteTarget, linkPath);
|
|
105
105
|
return {
|
|
106
106
|
ok: true,
|
|
107
107
|
fallback: false,
|
|
108
|
-
relativeTarget,
|
|
108
|
+
relativeTarget: absoluteTarget,
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
111
|
catch (error) {
|
|
@@ -116,7 +116,7 @@ export async function createSymlink(targetPath, linkPath) {
|
|
|
116
116
|
return {
|
|
117
117
|
ok: false,
|
|
118
118
|
fallback: true,
|
|
119
|
-
relativeTarget,
|
|
119
|
+
relativeTarget: absoluteTarget,
|
|
120
120
|
};
|
|
121
121
|
}
|
|
122
122
|
throw error;
|
package/dist/sync.js
CHANGED
|
@@ -139,7 +139,7 @@ export async function prepareSyncAdapterFiles(options) {
|
|
|
139
139
|
const generatedSourcePath = path.join(options.statePaths.generatedDirPath, adapter.id, path.basename(adapter.syncTarget));
|
|
140
140
|
const currentDescriptor = await describeTarget(targetPath);
|
|
141
141
|
const currentVisibleContent = (await readText(targetPath, "")) || "";
|
|
142
|
-
const nextDescriptor = `symlink -> ${toPosix(
|
|
142
|
+
const nextDescriptor = `symlink -> ${toPosix(generatedSourcePath)}\n`;
|
|
143
143
|
const descriptorChanged = normalizeComparableText(currentDescriptor) !== normalizeComparableText(nextDescriptor);
|
|
144
144
|
const contentChanged = normalizeComparableText(currentVisibleContent) !== normalizeComparableText(nextContent);
|
|
145
145
|
return {
|
|
@@ -154,7 +154,7 @@ export async function prepareSyncAdapterFiles(options) {
|
|
|
154
154
|
targetPath: relativeTargetPath,
|
|
155
155
|
currentDescriptor,
|
|
156
156
|
nextDescriptor,
|
|
157
|
-
generatedPath: toPosix(
|
|
157
|
+
generatedPath: toPosix(generatedSourcePath),
|
|
158
158
|
currentContent: currentVisibleContent,
|
|
159
159
|
nextContent,
|
|
160
160
|
}),
|
|
@@ -237,6 +237,9 @@ function buildManagedFileContent(adapterId, body, autoInjectBlock) {
|
|
|
237
237
|
"",
|
|
238
238
|
].join("\n");
|
|
239
239
|
case "cline":
|
|
240
|
+
case "codex":
|
|
241
|
+
case "claude":
|
|
242
|
+
case "gemini":
|
|
240
243
|
return `${sections.join("\n\n")}\n`;
|
|
241
244
|
default:
|
|
242
245
|
throw new SyncError(`Adapter desconhecido: ${adapterId}`, "SYNC_ADAPTER_UNKNOWN");
|