@waynesutton/convex-skills 1.0.6 → 1.0.8
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 +16 -0
- package/bin/cli.js +63 -18
- package/package.json +2 -2
- package/skills/convex-best-practices/SKILL.md +0 -4
package/README.md
CHANGED
|
@@ -35,6 +35,12 @@ convex-skills install convex-best-practices
|
|
|
35
35
|
# Install all skills
|
|
36
36
|
convex-skills install-all
|
|
37
37
|
|
|
38
|
+
# Install all skills to .agents/skills
|
|
39
|
+
convex-skills install-all --target agents
|
|
40
|
+
|
|
41
|
+
# Symlink SKILL.md files instead of copying
|
|
42
|
+
convex-skills install-all --target agents --link
|
|
43
|
+
|
|
38
44
|
# Install templates (CLAUDE.md + skill templates)
|
|
39
45
|
convex-skills install-templates
|
|
40
46
|
```
|
|
@@ -84,6 +90,15 @@ Codex will auto-discover `SKILL.md` files in that directory on the next start.
|
|
|
84
90
|
|
|
85
91
|
If you are working from a repo clone, Codex also auto-discovers skills from `.codex/skills` at the repo root. You can symlink this repo’s `skills/*` into `.codex/skills` so updates flow through without copying.
|
|
86
92
|
|
|
93
|
+
### Standard Agent Skills Path
|
|
94
|
+
|
|
95
|
+
Some tools are standardizing on `.agents/skills` for discovery. This repo supports that layout via the CLI:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
convex-skills install-all --target agents
|
|
99
|
+
convex-skills install-all --target agents --link
|
|
100
|
+
```
|
|
101
|
+
|
|
87
102
|
### OpenCode
|
|
88
103
|
|
|
89
104
|
OpenCode discovers skills from `~/.claude/skills/<name>/SKILL.md` automatically. See OpenCode Skills docs for more details.
|
|
@@ -142,6 +157,7 @@ convex-skills/
|
|
|
142
157
|
│ └── ...
|
|
143
158
|
├── .codex/ # Codex integration (symlink skills here)
|
|
144
159
|
│ └── README.md # Codex setup instructions
|
|
160
|
+
├── .agents/ # Standard agent skills path
|
|
145
161
|
├── command/ # Slash command definitions (OpenCode)
|
|
146
162
|
│ └── convex.md # /convex command entrypoint
|
|
147
163
|
├── templates/ # Templates for forking developers
|
package/bin/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
existsSync,
|
|
10
10
|
copyFileSync,
|
|
11
11
|
readdirSync,
|
|
12
|
+
symlinkSync,
|
|
12
13
|
} from "fs";
|
|
13
14
|
|
|
14
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -32,6 +33,12 @@ const SKILLS = {
|
|
|
32
33
|
"convex-component-authoring": "Creating reusable Convex components",
|
|
33
34
|
};
|
|
34
35
|
|
|
36
|
+
const TARGET_ALIASES = new Map([
|
|
37
|
+
["claude", ".claude/skills"],
|
|
38
|
+
["codex", ".codex/skills"],
|
|
39
|
+
["agents", ".agents/skills"],
|
|
40
|
+
]);
|
|
41
|
+
|
|
35
42
|
function printHelp() {
|
|
36
43
|
console.log(`
|
|
37
44
|
convex-skills - Agent skills for building Convex applications
|
|
@@ -49,12 +56,17 @@ COMMANDS:
|
|
|
49
56
|
|
|
50
57
|
OPTIONS:
|
|
51
58
|
--dir <path> Target directory (default: current directory)
|
|
59
|
+
--target <name|path> Install target: claude, codex, agents, or a path
|
|
60
|
+
--link Symlink SKILL.md instead of copying
|
|
52
61
|
--help, -h Show this help message
|
|
53
62
|
|
|
54
63
|
EXAMPLES:
|
|
55
64
|
convex-skills list
|
|
56
65
|
convex-skills install convex-best-practices
|
|
57
66
|
convex-skills install-all
|
|
67
|
+
convex-skills install-all --target agents
|
|
68
|
+
convex-skills install convex-functions --target .agents/skills
|
|
69
|
+
convex-skills install convex-best-practices --target codex --link
|
|
58
70
|
convex-skills install-templates
|
|
59
71
|
convex-skills show convex-functions
|
|
60
72
|
|
|
@@ -73,7 +85,27 @@ function listSkills() {
|
|
|
73
85
|
console.log("");
|
|
74
86
|
}
|
|
75
87
|
|
|
76
|
-
function
|
|
88
|
+
function ensureDir(dirPath) {
|
|
89
|
+
if (!existsSync(dirPath)) {
|
|
90
|
+
mkdirSync(dirPath, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function resolveTargetSkillsDir(targetDir, target) {
|
|
95
|
+
if (!target) {
|
|
96
|
+
return join(targetDir, ".claude", "skills");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const alias = TARGET_ALIASES.get(target);
|
|
100
|
+
if (alias) {
|
|
101
|
+
return join(targetDir, alias);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const resolved = resolve(targetDir, target);
|
|
105
|
+
return resolved.endsWith("skills") ? resolved : join(resolved, "skills");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function installSkill(skillName, targetSkillsDir, useSymlink) {
|
|
77
109
|
const skillsPath = join(packageRoot, "skills", skillName, "SKILL.md");
|
|
78
110
|
|
|
79
111
|
if (!existsSync(skillsPath)) {
|
|
@@ -82,24 +114,24 @@ function installSkill(skillName, targetDir) {
|
|
|
82
114
|
process.exit(1);
|
|
83
115
|
}
|
|
84
116
|
|
|
85
|
-
const targetPath = join(
|
|
86
|
-
targetDir,
|
|
87
|
-
".claude",
|
|
88
|
-
"skills",
|
|
89
|
-
skillName,
|
|
90
|
-
"SKILL.md",
|
|
91
|
-
);
|
|
117
|
+
const targetPath = join(targetSkillsDir, skillName, "SKILL.md");
|
|
92
118
|
const targetSkillDir = dirname(targetPath);
|
|
93
119
|
|
|
94
|
-
|
|
95
|
-
|
|
120
|
+
ensureDir(targetSkillDir);
|
|
121
|
+
|
|
122
|
+
if (useSymlink) {
|
|
123
|
+
if (!existsSync(targetPath)) {
|
|
124
|
+
symlinkSync(skillsPath, targetPath);
|
|
125
|
+
}
|
|
126
|
+
console.log(`Linked ${skillName} to ${targetPath}`);
|
|
127
|
+
return;
|
|
96
128
|
}
|
|
97
129
|
|
|
98
130
|
copyFileSync(skillsPath, targetPath);
|
|
99
131
|
console.log(`Installed ${skillName} to ${targetPath}`);
|
|
100
132
|
}
|
|
101
133
|
|
|
102
|
-
function installAllSkills(
|
|
134
|
+
function installAllSkills(targetSkillsDir, useSymlink) {
|
|
103
135
|
const skillsDir = join(packageRoot, "skills");
|
|
104
136
|
const skills = readdirSync(skillsDir, { withFileTypes: true })
|
|
105
137
|
.filter((dirent) => dirent.isDirectory())
|
|
@@ -108,11 +140,11 @@ function installAllSkills(targetDir) {
|
|
|
108
140
|
console.log(`Installing ${skills.length} skills...\n`);
|
|
109
141
|
|
|
110
142
|
skills.forEach((skillName) => {
|
|
111
|
-
installSkill(skillName,
|
|
143
|
+
installSkill(skillName, targetSkillsDir, useSymlink);
|
|
112
144
|
});
|
|
113
145
|
|
|
114
146
|
console.log(
|
|
115
|
-
`\nDone! Installed ${skills.length} skills to ${
|
|
147
|
+
`\nDone! Installed ${skills.length} skills to ${targetSkillsDir}`,
|
|
116
148
|
);
|
|
117
149
|
}
|
|
118
150
|
|
|
@@ -139,9 +171,7 @@ function installTemplates(targetDir) {
|
|
|
139
171
|
);
|
|
140
172
|
const targetSkillsDir = join(targetDir, ".claude", "skills");
|
|
141
173
|
|
|
142
|
-
|
|
143
|
-
mkdirSync(targetSkillsDir, { recursive: true });
|
|
144
|
-
}
|
|
174
|
+
ensureDir(targetSkillsDir);
|
|
145
175
|
|
|
146
176
|
templates.forEach((template) => {
|
|
147
177
|
const src = join(skillTemplatesDir, template);
|
|
@@ -184,6 +214,8 @@ function printSkillPath(skillName) {
|
|
|
184
214
|
// Parse arguments
|
|
185
215
|
const args = process.argv.slice(2);
|
|
186
216
|
let targetDir = process.cwd();
|
|
217
|
+
let target = null;
|
|
218
|
+
let useSymlink = false;
|
|
187
219
|
|
|
188
220
|
// Check for --dir flag
|
|
189
221
|
const dirIndex = args.indexOf("--dir");
|
|
@@ -192,8 +224,21 @@ if (dirIndex !== -1 && args[dirIndex + 1]) {
|
|
|
192
224
|
args.splice(dirIndex, 2);
|
|
193
225
|
}
|
|
194
226
|
|
|
227
|
+
const targetIndex = args.indexOf("--target");
|
|
228
|
+
if (targetIndex !== -1 && args[targetIndex + 1]) {
|
|
229
|
+
target = args[targetIndex + 1];
|
|
230
|
+
args.splice(targetIndex, 2);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const linkIndex = args.indexOf("--link");
|
|
234
|
+
if (linkIndex !== -1) {
|
|
235
|
+
useSymlink = true;
|
|
236
|
+
args.splice(linkIndex, 1);
|
|
237
|
+
}
|
|
238
|
+
|
|
195
239
|
const command = args[0];
|
|
196
240
|
const arg = args[1];
|
|
241
|
+
const targetSkillsDir = resolveTargetSkillsDir(targetDir, target);
|
|
197
242
|
|
|
198
243
|
switch (command) {
|
|
199
244
|
case "list":
|
|
@@ -205,10 +250,10 @@ switch (command) {
|
|
|
205
250
|
console.log("Run 'convex-skills list' to see available skills.");
|
|
206
251
|
process.exit(1);
|
|
207
252
|
}
|
|
208
|
-
installSkill(arg,
|
|
253
|
+
installSkill(arg, targetSkillsDir, useSymlink);
|
|
209
254
|
break;
|
|
210
255
|
case "install-all":
|
|
211
|
-
installAllSkills(
|
|
256
|
+
installAllSkills(targetSkillsDir, useSymlink);
|
|
212
257
|
break;
|
|
213
258
|
case "install-templates":
|
|
214
259
|
installTemplates(targetDir);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waynesutton/convex-skills",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Agent skills for building production-ready Convex applications. Includes best practices, functions, realtime patterns, schema validation, file storage, security audits, and more.",
|
|
5
|
-
"author": "Wayne Sutton",
|
|
5
|
+
"author": "Wayne Sutton - @waynesutton",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: convex-best-practices
|
|
3
|
-
displayName: Convex Best Practices
|
|
4
3
|
description: Guidelines for building production-ready Convex apps covering function organization, query patterns, validation, TypeScript usage, error handling, and the Zen of Convex design philosophy
|
|
5
|
-
version: 1.0.0
|
|
6
|
-
author: Convex
|
|
7
|
-
tags: [convex, best-practices, typescript, production, error-handling]
|
|
8
4
|
---
|
|
9
5
|
|
|
10
6
|
# Convex Best Practices
|