@jesdi/skills-cli 0.1.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/dist/chunk-OYYAZFA5.js +273 -0
- package/dist/index.js +78 -0
- package/dist/wizard-RO45GYUU.js +65 -0
- package/package.json +27 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
// src/paths.ts
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
var AGENTS = {
|
|
4
|
+
claude: { label: "Claude Code" },
|
|
5
|
+
opencode: { label: "OpenCode (.agents standard)" }
|
|
6
|
+
};
|
|
7
|
+
var AGENT_SUBDIR = {
|
|
8
|
+
claude: join(".claude", "skills"),
|
|
9
|
+
opencode: join(".agents", "skills")
|
|
10
|
+
};
|
|
11
|
+
function scopeRoot(scope, ctx) {
|
|
12
|
+
return scope === "global" ? ctx.home : ctx.project;
|
|
13
|
+
}
|
|
14
|
+
function agentSkillsDir(agent, scope, ctx) {
|
|
15
|
+
return join(scopeRoot(scope, ctx), AGENT_SUBDIR[agent]);
|
|
16
|
+
}
|
|
17
|
+
function storeDir(scope, ctx) {
|
|
18
|
+
return join(scopeRoot(scope, ctx), ".my-skills");
|
|
19
|
+
}
|
|
20
|
+
function globalStateFile(ctx) {
|
|
21
|
+
return join(ctx.home, ".config", "my-skills", "state.json");
|
|
22
|
+
}
|
|
23
|
+
function projectStateFile(ctx) {
|
|
24
|
+
return join(ctx.project, ".my-skills.json");
|
|
25
|
+
}
|
|
26
|
+
function cacheDir(ctx) {
|
|
27
|
+
return join(ctx.home, ".cache", "my-skills");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/registry.ts
|
|
31
|
+
import { mkdir, readFile, readdir, writeFile, rm } from "fs/promises";
|
|
32
|
+
import { existsSync } from "fs";
|
|
33
|
+
import { join as join2 } from "path";
|
|
34
|
+
import * as tar from "tar";
|
|
35
|
+
var PACKAGE = "@jesdi%2fskills";
|
|
36
|
+
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
37
|
+
async function loadFromCache(cacheDir2, version) {
|
|
38
|
+
const pkgDir = join2(cacheDir2, version, "package");
|
|
39
|
+
const manifest = JSON.parse(
|
|
40
|
+
await readFile(join2(pkgDir, "skills-manifest.json"), "utf8")
|
|
41
|
+
);
|
|
42
|
+
if (manifest.schemaVersion > 1) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`skills manifest schemaVersion ${manifest.schemaVersion} is newer than this CLI supports \u2014 update @jesdi/skills-cli`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return { packageVersion: version, manifest, skillsDir: join2(pkgDir, "skills") };
|
|
48
|
+
}
|
|
49
|
+
async function newestCached(cacheDir2, cause) {
|
|
50
|
+
let versions = [];
|
|
51
|
+
try {
|
|
52
|
+
versions = (await readdir(cacheDir2)).sort();
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
const newest = versions.at(-1);
|
|
56
|
+
if (!newest) {
|
|
57
|
+
throw new Error(`could not reach the npm registry and no cached skills exist: ${cause}`);
|
|
58
|
+
}
|
|
59
|
+
return loadFromCache(cacheDir2, newest);
|
|
60
|
+
}
|
|
61
|
+
async function fetchLatest(opts) {
|
|
62
|
+
const f = opts.fetchImpl ?? fetch;
|
|
63
|
+
const registry = opts.registryUrl ?? DEFAULT_REGISTRY;
|
|
64
|
+
let meta;
|
|
65
|
+
try {
|
|
66
|
+
const res = await f(`${registry}/${PACKAGE}/latest`);
|
|
67
|
+
if (!res.ok) throw new Error(`registry responded ${res.status}`);
|
|
68
|
+
meta = await res.json();
|
|
69
|
+
} catch (err) {
|
|
70
|
+
return newestCached(opts.cacheDir, err);
|
|
71
|
+
}
|
|
72
|
+
const versionDir = join2(opts.cacheDir, meta.version);
|
|
73
|
+
if (!existsSync(join2(versionDir, "package", "skills-manifest.json"))) {
|
|
74
|
+
const res = await f(meta.dist.tarball);
|
|
75
|
+
if (!res.ok) throw new Error(`tarball download failed: ${res.status}`);
|
|
76
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
77
|
+
await rm(versionDir, { recursive: true, force: true });
|
|
78
|
+
await mkdir(versionDir, { recursive: true });
|
|
79
|
+
const tmpTar = join2(versionDir, "pkg.tgz");
|
|
80
|
+
await writeFile(tmpTar, buf);
|
|
81
|
+
await tar.extract({ file: tmpTar, cwd: versionDir });
|
|
82
|
+
await rm(tmpTar);
|
|
83
|
+
}
|
|
84
|
+
return loadFromCache(opts.cacheDir, meta.version);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/state.ts
|
|
88
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
89
|
+
import { dirname } from "path";
|
|
90
|
+
function stateFile(scope, ctx) {
|
|
91
|
+
return scope === "global" ? globalStateFile(ctx) : projectStateFile(ctx);
|
|
92
|
+
}
|
|
93
|
+
function emptyState(scope) {
|
|
94
|
+
return scope === "global" ? { schemaVersion: 1, skills: {}, declined: {} } : { schemaVersion: 1, skills: {} };
|
|
95
|
+
}
|
|
96
|
+
async function loadState(scope, ctx) {
|
|
97
|
+
try {
|
|
98
|
+
return JSON.parse(await readFile2(stateFile(scope, ctx), "utf8"));
|
|
99
|
+
} catch {
|
|
100
|
+
return emptyState(scope);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async function saveState(scope, ctx, state) {
|
|
104
|
+
const file = stateFile(scope, ctx);
|
|
105
|
+
await mkdir2(dirname(file), { recursive: true });
|
|
106
|
+
await writeFile2(file, JSON.stringify(state, null, 2) + "\n");
|
|
107
|
+
}
|
|
108
|
+
async function loadGlobalState(ctx) {
|
|
109
|
+
return await loadState("global", ctx);
|
|
110
|
+
}
|
|
111
|
+
async function saveGlobalState(ctx, state) {
|
|
112
|
+
await saveState("global", ctx, state);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/store.ts
|
|
116
|
+
import { cp, lstat, mkdir as mkdir3, readlink, rm as rm2, symlink } from "fs/promises";
|
|
117
|
+
import { join as join3, resolve } from "path";
|
|
118
|
+
var ForeignEntryError = class extends Error {
|
|
119
|
+
};
|
|
120
|
+
async function removeOurEntry(linkPath, storeDir2) {
|
|
121
|
+
const stat = await lstat(linkPath).catch(() => null);
|
|
122
|
+
if (!stat) return;
|
|
123
|
+
if (!stat.isSymbolicLink()) {
|
|
124
|
+
throw new ForeignEntryError(
|
|
125
|
+
`${linkPath} exists and was not created by skills-cli \u2014 refusing to touch it`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const target = await readlink(linkPath);
|
|
129
|
+
if (!resolve(target).startsWith(resolve(storeDir2))) {
|
|
130
|
+
throw new ForeignEntryError(
|
|
131
|
+
`${linkPath} is a symlink to ${target}, outside the skills-cli store \u2014 refusing to touch it`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
await rm2(linkPath);
|
|
135
|
+
}
|
|
136
|
+
async function installSkill(opts) {
|
|
137
|
+
const storeCopy = join3(opts.storeDir, opts.name);
|
|
138
|
+
for (const dir of opts.agentDirs) {
|
|
139
|
+
const stat = await lstat(join3(dir, opts.name)).catch(() => null);
|
|
140
|
+
if (stat && !stat.isSymbolicLink()) {
|
|
141
|
+
throw new ForeignEntryError(
|
|
142
|
+
`${join3(dir, opts.name)} exists and was not created by skills-cli \u2014 refusing to touch it`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
await rm2(storeCopy, { recursive: true, force: true });
|
|
147
|
+
await mkdir3(opts.storeDir, { recursive: true });
|
|
148
|
+
await cp(opts.sourceDir, storeCopy, { recursive: true });
|
|
149
|
+
for (const dir of opts.agentDirs) {
|
|
150
|
+
await mkdir3(dir, { recursive: true });
|
|
151
|
+
const linkPath = join3(dir, opts.name);
|
|
152
|
+
await removeOurEntry(linkPath, opts.storeDir);
|
|
153
|
+
await symlink(storeCopy, linkPath, "dir");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async function uninstallSkill(opts) {
|
|
157
|
+
for (const dir of opts.agentDirs) {
|
|
158
|
+
await removeOurEntry(join3(dir, opts.name), opts.storeDir);
|
|
159
|
+
}
|
|
160
|
+
await rm2(join3(opts.storeDir, opts.name), { recursive: true, force: true });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/ops.ts
|
|
164
|
+
import { join as join4 } from "path";
|
|
165
|
+
async function fetchSkills(ctx) {
|
|
166
|
+
return fetchLatest({
|
|
167
|
+
cacheDir: cacheDir(ctx),
|
|
168
|
+
registryUrl: ctx.registryUrl,
|
|
169
|
+
fetchImpl: ctx.fetchImpl
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
async function opInstall(names, agents, scope, ctx) {
|
|
173
|
+
const { manifest, skillsDir } = await fetchSkills(ctx);
|
|
174
|
+
const available = new Map(manifest.skills.map((s) => [s.name, s]));
|
|
175
|
+
for (const name of names) {
|
|
176
|
+
if (!available.has(name)) throw new Error(`unknown skill: ${name}`);
|
|
177
|
+
}
|
|
178
|
+
const state = await loadState(scope, ctx);
|
|
179
|
+
const installed = [];
|
|
180
|
+
for (const name of names) {
|
|
181
|
+
const skill = available.get(name);
|
|
182
|
+
await installSkill({
|
|
183
|
+
name,
|
|
184
|
+
sourceDir: join4(skillsDir, name),
|
|
185
|
+
storeDir: storeDir(scope, ctx),
|
|
186
|
+
agentDirs: agents.map((a) => agentSkillsDir(a, scope, ctx))
|
|
187
|
+
});
|
|
188
|
+
state.skills[name] = { version: skill.version, agents };
|
|
189
|
+
installed.push({ name, version: skill.version });
|
|
190
|
+
}
|
|
191
|
+
await saveState(scope, ctx, state);
|
|
192
|
+
return installed;
|
|
193
|
+
}
|
|
194
|
+
async function opUninstall(name, scope, ctx) {
|
|
195
|
+
const state = await loadState(scope, ctx);
|
|
196
|
+
const entry = state.skills[name];
|
|
197
|
+
if (!entry) throw new Error(`skill not installed (${scope}): ${name}`);
|
|
198
|
+
await uninstallSkill({
|
|
199
|
+
name,
|
|
200
|
+
storeDir: storeDir(scope, ctx),
|
|
201
|
+
agentDirs: entry.agents.map((a) => agentSkillsDir(a, scope, ctx))
|
|
202
|
+
});
|
|
203
|
+
delete state.skills[name];
|
|
204
|
+
await saveState(scope, ctx, state);
|
|
205
|
+
}
|
|
206
|
+
async function opCheckUpdates(scope, ctx) {
|
|
207
|
+
const { manifest } = await fetchSkills(ctx);
|
|
208
|
+
const available = new Map(manifest.skills.map((s) => [s.name, s]));
|
|
209
|
+
const state = await loadState(scope, ctx);
|
|
210
|
+
const globalState = await loadGlobalState(ctx);
|
|
211
|
+
const candidates = [];
|
|
212
|
+
for (const [name, installed] of Object.entries(state.skills)) {
|
|
213
|
+
const latest = available.get(name);
|
|
214
|
+
if (!latest || latest.version === installed.version) continue;
|
|
215
|
+
if (globalState.declined[name] === latest.version) continue;
|
|
216
|
+
candidates.push({ name, from: installed.version, to: latest.version });
|
|
217
|
+
}
|
|
218
|
+
return candidates;
|
|
219
|
+
}
|
|
220
|
+
async function opApplyUpdates(names, scope, ctx) {
|
|
221
|
+
const state = await loadState(scope, ctx);
|
|
222
|
+
const globalState = await loadGlobalState(ctx);
|
|
223
|
+
for (const name of names) {
|
|
224
|
+
const entry = state.skills[name];
|
|
225
|
+
if (!entry) throw new Error(`skill not installed (${scope}): ${name}`);
|
|
226
|
+
await opInstall([name], entry.agents, scope, ctx);
|
|
227
|
+
if (globalState.declined[name]) {
|
|
228
|
+
delete globalState.declined[name];
|
|
229
|
+
await saveGlobalState(ctx, globalState);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async function opDecline(name, version, ctx) {
|
|
234
|
+
const globalState = await loadGlobalState(ctx);
|
|
235
|
+
globalState.declined[name] = version;
|
|
236
|
+
await saveGlobalState(ctx, globalState);
|
|
237
|
+
}
|
|
238
|
+
async function opSync(ctx) {
|
|
239
|
+
const state = await loadState("local", ctx);
|
|
240
|
+
const entries = Object.entries(state.skills);
|
|
241
|
+
if (entries.length === 0) {
|
|
242
|
+
throw new Error("no .my-skills.json with skills found in this project \u2014 nothing to sync");
|
|
243
|
+
}
|
|
244
|
+
const results = [];
|
|
245
|
+
for (const [name, entry] of entries) {
|
|
246
|
+
const [installed] = await opInstall([name], entry.agents, "local", ctx);
|
|
247
|
+
results.push(installed);
|
|
248
|
+
}
|
|
249
|
+
return results;
|
|
250
|
+
}
|
|
251
|
+
async function opList(ctx) {
|
|
252
|
+
const { manifest } = await fetchSkills(ctx);
|
|
253
|
+
const globalState = await loadState("global", ctx);
|
|
254
|
+
const localState = await loadState("local", ctx);
|
|
255
|
+
return manifest.skills.map((s) => ({
|
|
256
|
+
name: s.name,
|
|
257
|
+
description: s.description,
|
|
258
|
+
latest: s.version,
|
|
259
|
+
installedGlobal: globalState.skills[s.name]?.version,
|
|
260
|
+
installedLocal: localState.skills[s.name]?.version
|
|
261
|
+
}));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export {
|
|
265
|
+
AGENTS,
|
|
266
|
+
opInstall,
|
|
267
|
+
opUninstall,
|
|
268
|
+
opCheckUpdates,
|
|
269
|
+
opApplyUpdates,
|
|
270
|
+
opDecline,
|
|
271
|
+
opSync,
|
|
272
|
+
opList
|
|
273
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
AGENTS,
|
|
4
|
+
opApplyUpdates,
|
|
5
|
+
opCheckUpdates,
|
|
6
|
+
opInstall,
|
|
7
|
+
opList,
|
|
8
|
+
opSync,
|
|
9
|
+
opUninstall
|
|
10
|
+
} from "./chunk-OYYAZFA5.js";
|
|
11
|
+
|
|
12
|
+
// src/program.ts
|
|
13
|
+
import { readFileSync } from "fs";
|
|
14
|
+
import { homedir } from "os";
|
|
15
|
+
import { Command } from "commander";
|
|
16
|
+
var pkg = JSON.parse(
|
|
17
|
+
readFileSync(new URL("../package.json", import.meta.url), "utf8")
|
|
18
|
+
);
|
|
19
|
+
function parseAgents(value) {
|
|
20
|
+
const agents = value.split(",").map((a) => a.trim());
|
|
21
|
+
for (const a of agents) {
|
|
22
|
+
if (!(a in AGENTS)) throw new Error(`unknown agent: ${a} (expected claude|opencode)`);
|
|
23
|
+
}
|
|
24
|
+
return agents;
|
|
25
|
+
}
|
|
26
|
+
function scopeOf(opts) {
|
|
27
|
+
return opts.global ? "global" : "local";
|
|
28
|
+
}
|
|
29
|
+
function buildProgram(ctx) {
|
|
30
|
+
const cliCtx = ctx ?? { home: homedir(), project: process.cwd() };
|
|
31
|
+
const program = new Command("skills-cli");
|
|
32
|
+
program.description("Install jesdi's agent skills into Claude Code and OpenCode").version(pkg.version);
|
|
33
|
+
program.command("install").argument("<skills...>", "skill names to install").option("--agent <list>", "comma-separated agents: claude,opencode", "claude").option("--global", "install for the whole machine instead of this project").action(async (skills, opts) => {
|
|
34
|
+
const installed = await opInstall(skills, parseAgents(opts.agent), scopeOf(opts), cliCtx);
|
|
35
|
+
for (const s of installed) console.log(`installed ${s.name}@${s.version}`);
|
|
36
|
+
});
|
|
37
|
+
program.command("update").argument("[skill]", "update a single skill").option("--all", "apply every available update").option("--global", "operate on the global scope").action(async (skill, opts) => {
|
|
38
|
+
const scope = scopeOf(opts);
|
|
39
|
+
const candidates = await opCheckUpdates(scope, cliCtx);
|
|
40
|
+
if (candidates.length === 0) {
|
|
41
|
+
console.log("everything is up to date");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const names = skill ? [skill] : opts.all ? candidates.map((c) => c.name) : null;
|
|
45
|
+
if (!names) {
|
|
46
|
+
for (const c of candidates) console.log(`${c.name}: ${c.from} -> ${c.to}`);
|
|
47
|
+
console.log("run `skills-cli update --all` or `skills-cli update <skill>` to apply");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
await opApplyUpdates(names, scope, cliCtx);
|
|
51
|
+
for (const n of names) console.log(`updated ${n}`);
|
|
52
|
+
});
|
|
53
|
+
program.command("sync").description("install everything listed in this project's .my-skills.json").action(async () => {
|
|
54
|
+
const results = await opSync(cliCtx);
|
|
55
|
+
for (const s of results) console.log(`synced ${s.name}@${s.version}`);
|
|
56
|
+
});
|
|
57
|
+
program.command("list").description("list available skills and where they are installed").action(async () => {
|
|
58
|
+
for (const s of await opList(cliCtx)) {
|
|
59
|
+
const marks = [
|
|
60
|
+
s.installedGlobal ? `global@${s.installedGlobal}` : null,
|
|
61
|
+
s.installedLocal ? `local@${s.installedLocal}` : null
|
|
62
|
+
].filter(Boolean).join(", ");
|
|
63
|
+
console.log(`${s.name}@${s.latest}${marks ? ` [${marks}]` : ""} \u2014 ${s.description}`);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
program.command("uninstall").argument("<skill>").option("--global", "uninstall from the global scope").action(async (skill, opts) => {
|
|
67
|
+
await opUninstall(skill, scopeOf(opts), cliCtx);
|
|
68
|
+
console.log(`uninstalled ${skill}`);
|
|
69
|
+
});
|
|
70
|
+
program.action(async () => {
|
|
71
|
+
const { runWizard } = await import("./wizard-RO45GYUU.js");
|
|
72
|
+
await runWizard(cliCtx);
|
|
73
|
+
});
|
|
74
|
+
return program;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/index.ts
|
|
78
|
+
await buildProgram().parseAsync(process.argv);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AGENTS,
|
|
3
|
+
opApplyUpdates,
|
|
4
|
+
opCheckUpdates,
|
|
5
|
+
opDecline,
|
|
6
|
+
opInstall,
|
|
7
|
+
opList
|
|
8
|
+
} from "./chunk-OYYAZFA5.js";
|
|
9
|
+
|
|
10
|
+
// src/wizard.ts
|
|
11
|
+
import * as p from "@clack/prompts";
|
|
12
|
+
async function runWizard(ctx) {
|
|
13
|
+
p.intro("@jesdi/skills");
|
|
14
|
+
for (const scope2 of ["global", "local"]) {
|
|
15
|
+
const candidates = await opCheckUpdates(scope2, ctx);
|
|
16
|
+
for (const c of candidates) {
|
|
17
|
+
const answer = await p.confirm({
|
|
18
|
+
message: `Update ${c.name} (${scope2}) ${c.from} -> ${c.to}?`
|
|
19
|
+
});
|
|
20
|
+
if (p.isCancel(answer)) return cancel2();
|
|
21
|
+
if (answer) await opApplyUpdates([c.name], scope2, ctx);
|
|
22
|
+
else await opDecline(c.name, c.to, ctx);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const available = await opList(ctx);
|
|
26
|
+
const skills = await p.multiselect({
|
|
27
|
+
message: "Which skills do you want to install?",
|
|
28
|
+
options: available.map((s) => ({
|
|
29
|
+
value: s.name,
|
|
30
|
+
label: s.name,
|
|
31
|
+
hint: s.description.slice(0, 80)
|
|
32
|
+
})),
|
|
33
|
+
required: true
|
|
34
|
+
});
|
|
35
|
+
if (p.isCancel(skills)) return cancel2();
|
|
36
|
+
const agents = await p.multiselect({
|
|
37
|
+
message: "Install for which agents?",
|
|
38
|
+
options: Object.entries(AGENTS).map(([id, a]) => ({
|
|
39
|
+
value: id,
|
|
40
|
+
label: a.label
|
|
41
|
+
})),
|
|
42
|
+
initialValues: ["claude"],
|
|
43
|
+
required: true
|
|
44
|
+
});
|
|
45
|
+
if (p.isCancel(agents)) return cancel2();
|
|
46
|
+
const scope = await p.select({
|
|
47
|
+
message: "Install where?",
|
|
48
|
+
options: [
|
|
49
|
+
{ value: "local", label: `This project (${ctx.project})` },
|
|
50
|
+
{ value: "global", label: "Globally (whole machine)" }
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
if (p.isCancel(scope)) return cancel2();
|
|
54
|
+
const spinner2 = p.spinner();
|
|
55
|
+
spinner2.start("Installing\u2026");
|
|
56
|
+
const installed = await opInstall(skills, agents, scope, ctx);
|
|
57
|
+
spinner2.stop(`Installed ${installed.map((s) => `${s.name}@${s.version}`).join(", ")}`);
|
|
58
|
+
p.outro("Done \u2014 your agents will pick the skills up on next launch.");
|
|
59
|
+
}
|
|
60
|
+
function cancel2() {
|
|
61
|
+
p.cancel("Cancelled \u2014 nothing was changed.");
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
runWizard
|
|
65
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jesdi/skills-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Install jesdi's agent skills into Claude Code and OpenCode",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/jesdi/general-skills.git",
|
|
9
|
+
"directory": "cli"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"bin": { "skills-cli": "./dist/index.js" },
|
|
13
|
+
"files": ["dist"],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup src/index.ts --format esm --clean",
|
|
16
|
+
"dev": "tsx src/index.ts"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@clack/prompts": "^0.11.0",
|
|
20
|
+
"commander": "^12.1.0",
|
|
21
|
+
"tar": "^7.4.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"tsup": "^8.3.0"
|
|
25
|
+
},
|
|
26
|
+
"engines": { "node": ">=20" }
|
|
27
|
+
}
|