@danieldeusing/seedr 0.1.80 → 0.1.82
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-5XFKC3T7.js → chunk-77M7PGDO.js} +106 -25
- package/dist/cli.js +162 -33
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +6 -9
|
@@ -2,33 +2,96 @@
|
|
|
2
2
|
|
|
3
3
|
// src/config/registry.ts
|
|
4
4
|
import { readFile, readdir, writeFile, mkdir } from "fs/promises";
|
|
5
|
+
import { existsSync } from "fs";
|
|
5
6
|
import { join, dirname } from "path";
|
|
6
7
|
import { fileURLToPath } from "url";
|
|
7
8
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
var
|
|
9
|
+
var FETCH_TIMEOUT_MS = 15e3;
|
|
10
|
+
function findPackageRoot(startDir) {
|
|
11
|
+
let dir = startDir;
|
|
12
|
+
for (; ; ) {
|
|
13
|
+
if (existsSync(join(dir, "package.json"))) return dir;
|
|
14
|
+
const parent = dirname(dir);
|
|
15
|
+
if (parent === dir) return null;
|
|
16
|
+
dir = parent;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function resolveLocalRegistryPath() {
|
|
20
|
+
const packageRoot = findPackageRoot(__dirname);
|
|
21
|
+
if (!packageRoot) return null;
|
|
22
|
+
return join(packageRoot, "..", "..", "registry");
|
|
23
|
+
}
|
|
24
|
+
var REGISTRY_PATH = resolveLocalRegistryPath();
|
|
9
25
|
var GITHUB_RAW_URL = "https://raw.githubusercontent.com/danieldeusing/seedr/main/registry";
|
|
26
|
+
var SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
27
|
+
function assertValidSlug(slug) {
|
|
28
|
+
if (!SLUG_PATTERN.test(slug)) {
|
|
29
|
+
throw new Error(`Invalid item slug: "${slug}"`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function assertSafeNodeName(name) {
|
|
33
|
+
if (name.includes("/") || name.includes("\\") || name.includes("..")) {
|
|
34
|
+
throw new Error(`Unsafe file name in registry content: "${name}"`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
10
37
|
var cache = {
|
|
11
38
|
index: null,
|
|
12
39
|
types: /* @__PURE__ */ new Map(),
|
|
13
40
|
assembled: null
|
|
14
41
|
};
|
|
42
|
+
function typeDirName(type) {
|
|
43
|
+
if (type === "mcp" || type === "settings") return type;
|
|
44
|
+
return `${type}s`;
|
|
45
|
+
}
|
|
46
|
+
function isValidManifestIndex(value) {
|
|
47
|
+
return typeof value === "object" && value !== null && typeof value.types === "object" && value.types !== null;
|
|
48
|
+
}
|
|
15
49
|
async function loadFile(filename) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
50
|
+
if (REGISTRY_PATH) {
|
|
51
|
+
try {
|
|
52
|
+
return await readFile(join(REGISTRY_PATH, filename), "utf-8");
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
20
55
|
}
|
|
56
|
+
return fetchRemote(`${GITHUB_RAW_URL}/${filename}`);
|
|
21
57
|
}
|
|
22
|
-
async function
|
|
23
|
-
|
|
58
|
+
async function fetchResponse(url) {
|
|
59
|
+
let response;
|
|
60
|
+
try {
|
|
61
|
+
response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
|
|
62
|
+
} catch (error2) {
|
|
63
|
+
if (error2 instanceof Error && error2.name === "TimeoutError") {
|
|
64
|
+
throw new Error(`Registry unreachable: timed out fetching ${url}`, { cause: error2 });
|
|
65
|
+
}
|
|
66
|
+
throw new Error(`Registry unreachable: ${url}`, { cause: error2 });
|
|
67
|
+
}
|
|
24
68
|
if (!response.ok) {
|
|
25
69
|
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
26
70
|
}
|
|
71
|
+
return response;
|
|
72
|
+
}
|
|
73
|
+
async function fetchRemote(url) {
|
|
74
|
+
const response = await fetchResponse(url);
|
|
27
75
|
return response.text();
|
|
28
76
|
}
|
|
77
|
+
async function fetchRemoteBuffer(url) {
|
|
78
|
+
const response = await fetchResponse(url);
|
|
79
|
+
return Buffer.from(await response.arrayBuffer());
|
|
80
|
+
}
|
|
29
81
|
async function loadIndex() {
|
|
30
82
|
if (cache.index) return cache.index;
|
|
31
|
-
|
|
83
|
+
if (REGISTRY_PATH) {
|
|
84
|
+
try {
|
|
85
|
+
const localContent = await readFile(join(REGISTRY_PATH, "manifest.json"), "utf-8");
|
|
86
|
+
const parsed = JSON.parse(localContent);
|
|
87
|
+
if (isValidManifestIndex(parsed)) {
|
|
88
|
+
cache.index = parsed;
|
|
89
|
+
return parsed;
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const content = await fetchRemote(`${GITHUB_RAW_URL}/manifest.json`);
|
|
32
95
|
const data = JSON.parse(content);
|
|
33
96
|
cache.index = data;
|
|
34
97
|
return data;
|
|
@@ -75,7 +138,8 @@ async function searchItems(query) {
|
|
|
75
138
|
);
|
|
76
139
|
}
|
|
77
140
|
async function getItemFull(item) {
|
|
78
|
-
|
|
141
|
+
assertValidSlug(item.slug);
|
|
142
|
+
const typeDir = typeDirName(item.type);
|
|
79
143
|
const itemJsonPath = `${typeDir}/${item.slug}/item.json`;
|
|
80
144
|
const content = await loadFile(itemJsonPath);
|
|
81
145
|
return JSON.parse(content);
|
|
@@ -85,9 +149,10 @@ function getItemBaseUrl(item) {
|
|
|
85
149
|
const rawUrl = item.externalUrl.replace("github.com", "raw.githubusercontent.com").replace("/tree/", "/");
|
|
86
150
|
return { local: null, remote: rawUrl };
|
|
87
151
|
}
|
|
88
|
-
|
|
152
|
+
assertValidSlug(item.slug);
|
|
153
|
+
const typeDir = typeDirName(item.type);
|
|
89
154
|
return {
|
|
90
|
-
local: join(REGISTRY_PATH, typeDir, item.slug),
|
|
155
|
+
local: REGISTRY_PATH ? join(REGISTRY_PATH, typeDir, item.slug) : null,
|
|
91
156
|
remote: `${GITHUB_RAW_URL}/${typeDir}/${item.slug}`
|
|
92
157
|
};
|
|
93
158
|
}
|
|
@@ -106,7 +171,11 @@ function getItemSourcePath(item) {
|
|
|
106
171
|
if (item.sourceType !== "toolr") {
|
|
107
172
|
return null;
|
|
108
173
|
}
|
|
109
|
-
|
|
174
|
+
if (!REGISTRY_PATH) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
assertValidSlug(item.slug);
|
|
178
|
+
const typeDir = typeDirName(item.type);
|
|
110
179
|
return join(REGISTRY_PATH, typeDir, item.slug);
|
|
111
180
|
}
|
|
112
181
|
async function fetchItemToDestination(item, destPath) {
|
|
@@ -124,14 +193,15 @@ async function fetchItemToDestination(item, destPath) {
|
|
|
124
193
|
const filesToFetch = item.type === "skill" ? ["SKILL.md"] : item.type === "plugin" ? [".claude-plugin/plugin.json"] : [`${item.type}.md`];
|
|
125
194
|
await mkdir(destPath, { recursive: true });
|
|
126
195
|
await Promise.all(filesToFetch.map(async (file) => {
|
|
127
|
-
const content = await
|
|
196
|
+
const content = await fetchRemoteBuffer(`${remote}/${file}`);
|
|
128
197
|
const filePath = join(destPath, file);
|
|
129
198
|
await mkdir(dirname(filePath), { recursive: true });
|
|
130
|
-
await writeFile(filePath, content
|
|
199
|
+
await writeFile(filePath, content);
|
|
131
200
|
}));
|
|
132
201
|
}
|
|
133
202
|
async function fetchFileTree(nodes, baseUrl, destPath) {
|
|
134
203
|
await Promise.all(nodes.map(async (node) => {
|
|
204
|
+
assertSafeNodeName(node.name);
|
|
135
205
|
const nodePath = join(destPath, node.name);
|
|
136
206
|
if (node.type === "directory") {
|
|
137
207
|
await mkdir(nodePath, { recursive: true });
|
|
@@ -139,8 +209,8 @@ async function fetchFileTree(nodes, baseUrl, destPath) {
|
|
|
139
209
|
await fetchFileTree(node.children, `${baseUrl}/${node.name}`, nodePath);
|
|
140
210
|
}
|
|
141
211
|
} else {
|
|
142
|
-
const content = await
|
|
143
|
-
await writeFile(nodePath, content
|
|
212
|
+
const content = await fetchRemoteBuffer(`${baseUrl}/${node.name}`);
|
|
213
|
+
await writeFile(nodePath, content);
|
|
144
214
|
}
|
|
145
215
|
}));
|
|
146
216
|
}
|
|
@@ -317,6 +387,7 @@ import {
|
|
|
317
387
|
cp,
|
|
318
388
|
rm
|
|
319
389
|
} from "fs/promises";
|
|
390
|
+
import { homedir as homedir2 } from "os";
|
|
320
391
|
import { dirname as dirname2, join as join3, relative, isAbsolute } from "path";
|
|
321
392
|
async function exists(path) {
|
|
322
393
|
try {
|
|
@@ -329,6 +400,11 @@ async function exists(path) {
|
|
|
329
400
|
async function ensureDir(path) {
|
|
330
401
|
await mkdir2(path, { recursive: true });
|
|
331
402
|
}
|
|
403
|
+
async function assertOverwritable(path, force) {
|
|
404
|
+
if (!force && await exists(path)) {
|
|
405
|
+
throw new Error(`${path} already exists; pass --force to overwrite`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
332
408
|
async function installFile(source, destination, method) {
|
|
333
409
|
await ensureDir(dirname2(destination));
|
|
334
410
|
try {
|
|
@@ -355,8 +431,9 @@ async function writeTextFile(path, content) {
|
|
|
355
431
|
await ensureDir(dirname2(path));
|
|
356
432
|
await writeFile2(path, content, "utf-8");
|
|
357
433
|
}
|
|
358
|
-
function getAgentsPath(contentType, slug, cwd) {
|
|
359
|
-
|
|
434
|
+
function getAgentsPath(contentType, slug, scope, cwd) {
|
|
435
|
+
const base = scope === "user" ? homedir2() : cwd;
|
|
436
|
+
return join3(base, ".agents", contentType + "s", slug);
|
|
360
437
|
}
|
|
361
438
|
async function copyDirectory(source, destination) {
|
|
362
439
|
await cp(source, destination, { recursive: true });
|
|
@@ -530,8 +607,9 @@ import { join as join4, relative as relative2, dirname as dirname3 } from "path"
|
|
|
530
607
|
import { readdir as readdir2, symlink as symlink2, rm as rm2 } from "fs/promises";
|
|
531
608
|
import chalk2 from "chalk";
|
|
532
609
|
import ora from "ora";
|
|
533
|
-
async function installToCentralLocation(item, sourcePath, cwd) {
|
|
534
|
-
const centralPath = getAgentsPath("skill", item.slug, cwd);
|
|
610
|
+
async function installToCentralLocation(item, sourcePath, scope, force, cwd) {
|
|
611
|
+
const centralPath = getAgentsPath("skill", item.slug, scope, cwd);
|
|
612
|
+
await assertOverwritable(centralPath, force);
|
|
535
613
|
await rm2(centralPath, { recursive: true, force: true });
|
|
536
614
|
if (sourcePath && await exists(sourcePath)) {
|
|
537
615
|
await copyDirectory(sourcePath, centralPath);
|
|
@@ -546,7 +624,7 @@ async function createAgentSymlink(centralPath, destPath) {
|
|
|
546
624
|
const relPath = relative2(dirname3(destPath), centralPath);
|
|
547
625
|
await symlink2(relPath, destPath);
|
|
548
626
|
}
|
|
549
|
-
async function installSkillForAgent(item, agent, scope, method, cwd, centralPath) {
|
|
627
|
+
async function installSkillForAgent(item, agent, scope, method, force, cwd, centralPath) {
|
|
550
628
|
const spinner = ora(
|
|
551
629
|
`Installing ${item.name} for ${CODING_AGENTS[agent].name}...`
|
|
552
630
|
).start();
|
|
@@ -556,6 +634,7 @@ async function installSkillForAgent(item, agent, scope, method, cwd, centralPath
|
|
|
556
634
|
throw new Error(`${CODING_AGENTS[agent].name} does not support skills`);
|
|
557
635
|
}
|
|
558
636
|
const destPath = join4(destDir, item.slug);
|
|
637
|
+
await assertOverwritable(destPath, force);
|
|
559
638
|
const sourcePath = getItemSourcePath(item);
|
|
560
639
|
if (method === "symlink" && centralPath) {
|
|
561
640
|
await createAgentSymlink(centralPath, destPath);
|
|
@@ -576,12 +655,12 @@ async function installSkillForAgent(item, agent, scope, method, cwd, centralPath
|
|
|
576
655
|
return { agent, success: false, path: "", error: errorMsg };
|
|
577
656
|
}
|
|
578
657
|
}
|
|
579
|
-
async function installSkill(item, agents, scope, method, cwd = process.cwd()) {
|
|
658
|
+
async function installSkill(item, agents, scope, method, force, cwd = process.cwd()) {
|
|
580
659
|
const results = [];
|
|
581
660
|
const sourcePath = getItemSourcePath(item);
|
|
582
661
|
let centralPath;
|
|
583
662
|
if (method === "symlink") {
|
|
584
|
-
centralPath = await installToCentralLocation(item, sourcePath, cwd);
|
|
663
|
+
centralPath = await installToCentralLocation(item, sourcePath, scope, force, cwd);
|
|
585
664
|
}
|
|
586
665
|
for (const agent of agents) {
|
|
587
666
|
const readsAgentsDir = agent === "gemini" || agent === "codex" || agent === "opencode";
|
|
@@ -594,6 +673,7 @@ async function installSkill(item, agents, scope, method, cwd = process.cwd()) {
|
|
|
594
673
|
agent,
|
|
595
674
|
scope,
|
|
596
675
|
method,
|
|
676
|
+
force,
|
|
597
677
|
cwd,
|
|
598
678
|
centralPath
|
|
599
679
|
);
|
|
@@ -621,8 +701,8 @@ async function getInstalledSkills(agent, scope, cwd = process.cwd()) {
|
|
|
621
701
|
}
|
|
622
702
|
var skillHandler = {
|
|
623
703
|
type: "skill",
|
|
624
|
-
async install(item, agents, scope, method, cwd) {
|
|
625
|
-
return installSkill(item, agents, scope, method, cwd);
|
|
704
|
+
async install(item, agents, scope, method, force, cwd) {
|
|
705
|
+
return installSkill(item, agents, scope, method, force, cwd);
|
|
626
706
|
},
|
|
627
707
|
async uninstall(slug, agent, scope, cwd) {
|
|
628
708
|
return uninstallSkill(slug, agent, scope, cwd);
|
|
@@ -642,6 +722,7 @@ export {
|
|
|
642
722
|
fetchItemToDestination,
|
|
643
723
|
exists,
|
|
644
724
|
ensureDir,
|
|
725
|
+
assertOverwritable,
|
|
645
726
|
installFile,
|
|
646
727
|
removeFile,
|
|
647
728
|
writeTextFile,
|
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ALL_AGENTS,
|
|
4
4
|
CODING_AGENTS,
|
|
5
|
+
assertOverwritable,
|
|
5
6
|
brand,
|
|
6
7
|
cancelled,
|
|
7
8
|
confirm,
|
|
@@ -38,7 +39,7 @@ import {
|
|
|
38
39
|
success,
|
|
39
40
|
warn,
|
|
40
41
|
writeTextFile
|
|
41
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-77M7PGDO.js";
|
|
42
43
|
|
|
43
44
|
// src/cli.ts
|
|
44
45
|
import { Command as Command5 } from "commander";
|
|
@@ -65,10 +66,45 @@ function handleCommandError(error2) {
|
|
|
65
66
|
process.exit(1);
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
// src/utils/validate-options.ts
|
|
70
|
+
var SCOPES = ["project", "user", "local"];
|
|
71
|
+
var METHODS = ["symlink", "copy"];
|
|
72
|
+
var TYPES = [
|
|
73
|
+
"skill",
|
|
74
|
+
"hook",
|
|
75
|
+
"agent",
|
|
76
|
+
"plugin",
|
|
77
|
+
"command",
|
|
78
|
+
"settings",
|
|
79
|
+
"mcp"
|
|
80
|
+
];
|
|
81
|
+
function validateScope(value) {
|
|
82
|
+
if (value === void 0) return null;
|
|
83
|
+
if (!SCOPES.includes(value)) {
|
|
84
|
+
return `Invalid scope "${value}". Must be one of: ${SCOPES.join(", ")}`;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
function validateMethod(value) {
|
|
89
|
+
if (value === void 0) return null;
|
|
90
|
+
if (!METHODS.includes(value)) {
|
|
91
|
+
return `Invalid method "${value}". Must be one of: ${METHODS.join(", ")}`;
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
function validateType(value) {
|
|
96
|
+
if (value === void 0) return null;
|
|
97
|
+
if (!TYPES.includes(value)) {
|
|
98
|
+
return `Invalid type "${value}". Must be one of: ${TYPES.join(", ")}`;
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
68
103
|
// src/utils/analytics.ts
|
|
69
104
|
var ANALYTICS_URL = "https://seedr.danieldeusing.de/api/installs";
|
|
70
105
|
function trackInstalls(slug, type, results, scope) {
|
|
71
106
|
if (process.env.SEEDR_NO_TELEMETRY) return;
|
|
107
|
+
const version = true ? "0.1.82" : "dev";
|
|
72
108
|
for (const result of results) {
|
|
73
109
|
if (!result.success) continue;
|
|
74
110
|
fetch(ANALYTICS_URL, {
|
|
@@ -77,9 +113,9 @@ function trackInstalls(slug, type, results, scope) {
|
|
|
77
113
|
body: JSON.stringify({
|
|
78
114
|
slug,
|
|
79
115
|
type,
|
|
80
|
-
|
|
116
|
+
tool: result.agent,
|
|
81
117
|
scope,
|
|
82
|
-
version
|
|
118
|
+
version
|
|
83
119
|
}),
|
|
84
120
|
signal: AbortSignal.timeout(4e3)
|
|
85
121
|
}).catch(() => {
|
|
@@ -107,7 +143,7 @@ import { join } from "path";
|
|
|
107
143
|
import { readdir } from "fs/promises";
|
|
108
144
|
import chalk2 from "chalk";
|
|
109
145
|
import ora from "ora";
|
|
110
|
-
async function installAgentForCodingAgent(item, agent, scope, method, cwd) {
|
|
146
|
+
async function installAgentForCodingAgent(item, agent, scope, method, force, cwd) {
|
|
111
147
|
const spinner = ora(
|
|
112
148
|
`Installing ${item.name} for ${CODING_AGENTS[agent].name}...`
|
|
113
149
|
).start();
|
|
@@ -117,6 +153,7 @@ async function installAgentForCodingAgent(item, agent, scope, method, cwd) {
|
|
|
117
153
|
throw new Error(`${CODING_AGENTS[agent].name} does not support agents`);
|
|
118
154
|
}
|
|
119
155
|
const destPath = join(destDir, `${item.slug}.md`);
|
|
156
|
+
await assertOverwritable(destPath, force);
|
|
120
157
|
const sourcePath = getItemSourcePath(item);
|
|
121
158
|
if (sourcePath && method === "symlink") {
|
|
122
159
|
const sourceFile = join(sourcePath, "AGENT.md");
|
|
@@ -144,10 +181,10 @@ async function installAgentForCodingAgent(item, agent, scope, method, cwd) {
|
|
|
144
181
|
return { agent, success: false, path: "", error: errorMsg };
|
|
145
182
|
}
|
|
146
183
|
}
|
|
147
|
-
async function installAgent(item, agents, scope, method, cwd = process.cwd()) {
|
|
184
|
+
async function installAgent(item, agents, scope, method, force, cwd = process.cwd()) {
|
|
148
185
|
const results = [];
|
|
149
186
|
for (const agent of agents) {
|
|
150
|
-
const result = await installAgentForCodingAgent(item, agent, scope, method, cwd);
|
|
187
|
+
const result = await installAgentForCodingAgent(item, agent, scope, method, force, cwd);
|
|
151
188
|
results.push(result);
|
|
152
189
|
}
|
|
153
190
|
return results;
|
|
@@ -171,8 +208,8 @@ async function getInstalledAgents(agent, scope, cwd = process.cwd()) {
|
|
|
171
208
|
}
|
|
172
209
|
var agentHandler = {
|
|
173
210
|
type: "agent",
|
|
174
|
-
async install(item, agents, scope, method, cwd) {
|
|
175
|
-
return installAgent(item, agents, scope, method, cwd);
|
|
211
|
+
async install(item, agents, scope, method, force, cwd) {
|
|
212
|
+
return installAgent(item, agents, scope, method, force, cwd);
|
|
176
213
|
},
|
|
177
214
|
async uninstall(slug, agent, scope, cwd) {
|
|
178
215
|
return uninstallAgent(slug, agent, scope, cwd);
|
|
@@ -253,7 +290,7 @@ function findScriptFile(item) {
|
|
|
253
290
|
}
|
|
254
291
|
return null;
|
|
255
292
|
}
|
|
256
|
-
async function installHookForAgent(item, agent, scope, _method, cwd) {
|
|
293
|
+
async function installHookForAgent(item, agent, scope, _method, force, cwd) {
|
|
257
294
|
const spinner = ora2(
|
|
258
295
|
`Installing ${item.name} for ${CODING_AGENTS[agent].name}...`
|
|
259
296
|
).start();
|
|
@@ -273,6 +310,7 @@ async function installHookForAgent(item, agent, scope, _method, cwd) {
|
|
|
273
310
|
await mkdir(hooksDir, { recursive: true });
|
|
274
311
|
const sourcePath = getItemSourcePath(item);
|
|
275
312
|
const destScriptPath = join2(hooksDir, scriptFile);
|
|
313
|
+
await assertOverwritable(destScriptPath, force);
|
|
276
314
|
if (sourcePath && await exists(sourcePath)) {
|
|
277
315
|
const sourceScriptPath = join2(sourcePath, scriptFile);
|
|
278
316
|
await copyFile(sourceScriptPath, destScriptPath);
|
|
@@ -327,10 +365,10 @@ async function installHookForAgent(item, agent, scope, _method, cwd) {
|
|
|
327
365
|
return { agent, success: false, path: "", error: errorMsg };
|
|
328
366
|
}
|
|
329
367
|
}
|
|
330
|
-
async function installHook(item, agents, scope, method, cwd = process.cwd()) {
|
|
368
|
+
async function installHook(item, agents, scope, method, force, cwd = process.cwd()) {
|
|
331
369
|
const results = [];
|
|
332
370
|
for (const agent of agents) {
|
|
333
|
-
const result = await installHookForAgent(item, agent, scope, method, cwd);
|
|
371
|
+
const result = await installHookForAgent(item, agent, scope, method, force, cwd);
|
|
334
372
|
results.push(result);
|
|
335
373
|
}
|
|
336
374
|
return results;
|
|
@@ -403,8 +441,8 @@ async function getInstalledHooks(agent, scope, cwd = process.cwd()) {
|
|
|
403
441
|
}
|
|
404
442
|
var hookHandler = {
|
|
405
443
|
type: "hook",
|
|
406
|
-
async install(item, agents, scope, method, cwd) {
|
|
407
|
-
return installHook(item, agents, scope, method, cwd);
|
|
444
|
+
async install(item, agents, scope, method, force, cwd) {
|
|
445
|
+
return installHook(item, agents, scope, method, force, cwd);
|
|
408
446
|
},
|
|
409
447
|
async uninstall(slug, agent, scope, cwd) {
|
|
410
448
|
return uninstallHook(slug, agent, scope, cwd);
|
|
@@ -424,7 +462,7 @@ function parseMcpDefinition(content) {
|
|
|
424
462
|
throw new Error("Invalid MCP definition: must be valid JSON");
|
|
425
463
|
}
|
|
426
464
|
}
|
|
427
|
-
async function installMcpForAgent(item, agent, scope, _method, cwd) {
|
|
465
|
+
async function installMcpForAgent(item, agent, scope, _method, force, cwd) {
|
|
428
466
|
const spinner = ora3(
|
|
429
467
|
`Installing ${item.name} for ${CODING_AGENTS[agent].name}...`
|
|
430
468
|
).start();
|
|
@@ -434,6 +472,11 @@ async function installMcpForAgent(item, agent, scope, _method, cwd) {
|
|
|
434
472
|
const configPath = getMcpPath(scope, cwd);
|
|
435
473
|
const config = await readJson(configPath);
|
|
436
474
|
config.mcpServers = config.mcpServers || {};
|
|
475
|
+
if (!force && mcpDef.name in config.mcpServers) {
|
|
476
|
+
throw new Error(
|
|
477
|
+
`MCP server "${mcpDef.name}" already exists in ${configPath}; pass --force to overwrite`
|
|
478
|
+
);
|
|
479
|
+
}
|
|
437
480
|
config.mcpServers[mcpDef.name] = mcpDef.config;
|
|
438
481
|
await writeJson(configPath, config);
|
|
439
482
|
spinner.succeed(
|
|
@@ -448,10 +491,10 @@ async function installMcpForAgent(item, agent, scope, _method, cwd) {
|
|
|
448
491
|
return { agent, success: false, path: "", error: errorMsg };
|
|
449
492
|
}
|
|
450
493
|
}
|
|
451
|
-
async function installMcp(item, agents, scope, method, cwd = process.cwd()) {
|
|
494
|
+
async function installMcp(item, agents, scope, method, force, cwd = process.cwd()) {
|
|
452
495
|
const results = [];
|
|
453
496
|
for (const agent of agents) {
|
|
454
|
-
const result = await installMcpForAgent(item, agent, scope, method, cwd);
|
|
497
|
+
const result = await installMcpForAgent(item, agent, scope, method, force, cwd);
|
|
455
498
|
results.push(result);
|
|
456
499
|
}
|
|
457
500
|
return results;
|
|
@@ -475,8 +518,8 @@ async function getInstalledMcpServers(_agent, scope, cwd = process.cwd()) {
|
|
|
475
518
|
}
|
|
476
519
|
var mcpHandler = {
|
|
477
520
|
type: "mcp",
|
|
478
|
-
async install(item, agents, scope, method, cwd) {
|
|
479
|
-
return installMcp(item, agents, scope, method, cwd);
|
|
521
|
+
async install(item, agents, scope, method, force, cwd) {
|
|
522
|
+
return installMcp(item, agents, scope, method, force, cwd);
|
|
480
523
|
},
|
|
481
524
|
async uninstall(slug, agent, scope, cwd) {
|
|
482
525
|
return uninstallMcp(slug, agent, scope, cwd);
|
|
@@ -496,7 +539,7 @@ function parseSettings(content) {
|
|
|
496
539
|
throw new Error("Invalid settings: must be valid JSON");
|
|
497
540
|
}
|
|
498
541
|
}
|
|
499
|
-
async function installSettingsForAgent(item, agent, scope, _method, cwd) {
|
|
542
|
+
async function installSettingsForAgent(item, agent, scope, _method, _force, cwd) {
|
|
500
543
|
const spinner = ora4(
|
|
501
544
|
`Installing ${item.name} for ${CODING_AGENTS[agent].name}...`
|
|
502
545
|
).start();
|
|
@@ -522,10 +565,10 @@ async function installSettingsForAgent(item, agent, scope, _method, cwd) {
|
|
|
522
565
|
return { agent, success: false, path: "", error: errorMsg };
|
|
523
566
|
}
|
|
524
567
|
}
|
|
525
|
-
async function installSettings(item, agents, scope, method, cwd = process.cwd()) {
|
|
568
|
+
async function installSettings(item, agents, scope, method, force, cwd = process.cwd()) {
|
|
526
569
|
const results = [];
|
|
527
570
|
for (const agent of agents) {
|
|
528
|
-
const result = await installSettingsForAgent(item, agent, scope, method, cwd);
|
|
571
|
+
const result = await installSettingsForAgent(item, agent, scope, method, force, cwd);
|
|
529
572
|
results.push(result);
|
|
530
573
|
}
|
|
531
574
|
return results;
|
|
@@ -585,8 +628,8 @@ async function getInstalledSettings(agent, scope, cwd = process.cwd()) {
|
|
|
585
628
|
}
|
|
586
629
|
var settingsHandler = {
|
|
587
630
|
type: "settings",
|
|
588
|
-
async install(item, agents, scope, method, cwd) {
|
|
589
|
-
return installSettings(item, agents, scope, method, cwd);
|
|
631
|
+
async install(item, agents, scope, method, force, cwd) {
|
|
632
|
+
return installSettings(item, agents, scope, method, force, cwd);
|
|
590
633
|
},
|
|
591
634
|
async uninstall(slug, agent, scope, cwd) {
|
|
592
635
|
return uninstallSettings(slug, agent, scope, cwd);
|
|
@@ -643,7 +686,7 @@ async function ensureMarketplaceRegistered(marketplace, item) {
|
|
|
643
686
|
};
|
|
644
687
|
await writeJson(KNOWN_MARKETPLACES_PATH, known);
|
|
645
688
|
}
|
|
646
|
-
async function installPluginForAgent(item, agent, scope, method, cwd) {
|
|
689
|
+
async function installPluginForAgent(item, agent, scope, method, force, cwd) {
|
|
647
690
|
const spinner = ora5(
|
|
648
691
|
`Installing ${item.name} for ${CODING_AGENTS[agent].name}...`
|
|
649
692
|
).start();
|
|
@@ -667,6 +710,12 @@ async function installPluginForAgent(item, agent, scope, method, cwd) {
|
|
|
667
710
|
const pluginId = getPluginId(pluginName, marketplace);
|
|
668
711
|
await ensureMarketplaceRegistered(marketplace, item);
|
|
669
712
|
const cachePath = getPluginCachePath(marketplace, pluginName, version);
|
|
713
|
+
try {
|
|
714
|
+
await assertOverwritable(cachePath, force);
|
|
715
|
+
} catch (error2) {
|
|
716
|
+
await rm2(tmpPath, { recursive: true, force: true });
|
|
717
|
+
throw error2;
|
|
718
|
+
}
|
|
670
719
|
await installDirectory(tmpPath, cachePath, "copy");
|
|
671
720
|
await rm2(tmpPath, { recursive: true, force: true });
|
|
672
721
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -705,10 +754,10 @@ async function installPluginForAgent(item, agent, scope, method, cwd) {
|
|
|
705
754
|
return { agent, success: false, path: "", error: errorMsg };
|
|
706
755
|
}
|
|
707
756
|
}
|
|
708
|
-
async function installPlugin(item, agents, scope, method, cwd = process.cwd()) {
|
|
757
|
+
async function installPlugin(item, agents, scope, method, force, cwd = process.cwd()) {
|
|
709
758
|
const results = [];
|
|
710
759
|
for (const agent of agents) {
|
|
711
|
-
const result = await installPluginForAgent(item, agent, scope, method, cwd);
|
|
760
|
+
const result = await installPluginForAgent(item, agent, scope, method, force, cwd);
|
|
712
761
|
results.push(result);
|
|
713
762
|
}
|
|
714
763
|
return results;
|
|
@@ -757,8 +806,8 @@ async function getInstalledPlugins(agent, scope, cwd = process.cwd()) {
|
|
|
757
806
|
}
|
|
758
807
|
var pluginHandler = {
|
|
759
808
|
type: "plugin",
|
|
760
|
-
async install(item, agents, scope, method, cwd) {
|
|
761
|
-
return installPlugin(item, agents, scope, method, cwd);
|
|
809
|
+
async install(item, agents, scope, method, force, cwd) {
|
|
810
|
+
return installPlugin(item, agents, scope, method, force, cwd);
|
|
762
811
|
},
|
|
763
812
|
async uninstall(slug, agent, scope, cwd) {
|
|
764
813
|
return uninstallPlugin(slug, agent, scope, cwd);
|
|
@@ -839,7 +888,7 @@ function printDryRunSummary(item, agents, scope, method, cwd) {
|
|
|
839
888
|
console.log(` Method: ${chalk7.white(method)}`);
|
|
840
889
|
console.log();
|
|
841
890
|
if (method === "symlink" && item.type === "skill") {
|
|
842
|
-
const centralPath = getAgentsPath("skill", item.slug, cwd);
|
|
891
|
+
const centralPath = getAgentsPath("skill", item.slug, scope, cwd);
|
|
843
892
|
console.log(brand(" Central storage:"));
|
|
844
893
|
console.log(` ${chalk7.gray("\u2192")} ${chalk7.gray(centralPath)}`);
|
|
845
894
|
console.log();
|
|
@@ -883,6 +932,11 @@ var addCommand = new Command("add").description("Install a skill, agent, hook, o
|
|
|
883
932
|
try {
|
|
884
933
|
printLogo();
|
|
885
934
|
intro("Seedr");
|
|
935
|
+
const optionError = validateType(options.type) || validateScope(options.scope) || validateMethod(options.method);
|
|
936
|
+
if (optionError) {
|
|
937
|
+
error(optionError);
|
|
938
|
+
process.exit(1);
|
|
939
|
+
}
|
|
886
940
|
const itemName = name;
|
|
887
941
|
const contentType = options.type;
|
|
888
942
|
const item = await resolveItem(itemName, contentType);
|
|
@@ -931,7 +985,7 @@ var addCommand = new Command("add").description("Install a skill, agent, hook, o
|
|
|
931
985
|
} else if (agents.length === 1) {
|
|
932
986
|
method = "copy";
|
|
933
987
|
} else {
|
|
934
|
-
const symlinkPath = getAgentsPath(item.type, item.slug, process.cwd());
|
|
988
|
+
const symlinkPath = getAgentsPath(item.type, item.slug, scope, process.cwd());
|
|
935
989
|
const selected = await selectMethod(symlinkPath);
|
|
936
990
|
if (p.isCancel(selected)) {
|
|
937
991
|
cancelled();
|
|
@@ -954,8 +1008,9 @@ var addCommand = new Command("add").description("Install a skill, agent, hook, o
|
|
|
954
1008
|
return;
|
|
955
1009
|
}
|
|
956
1010
|
}
|
|
1011
|
+
const force = Boolean(options.force) || !options.yes;
|
|
957
1012
|
console.log();
|
|
958
|
-
const results = await handler.install(item, agents, scope, method, process.cwd());
|
|
1013
|
+
const results = await handler.install(item, agents, scope, method, force, process.cwd());
|
|
959
1014
|
trackInstalls(item.slug, item.type, results, scope);
|
|
960
1015
|
printInstallSummary(results);
|
|
961
1016
|
outro("Installation complete");
|
|
@@ -1106,10 +1161,15 @@ var removeCommand = new Command3("remove").alias("rm").description("Remove an in
|
|
|
1106
1161
|
"Comma-separated coding agents or 'all'"
|
|
1107
1162
|
).option(
|
|
1108
1163
|
"--scope <scope>",
|
|
1109
|
-
"Installation scope: project, user, or
|
|
1164
|
+
"Installation scope: project, user, or local",
|
|
1110
1165
|
"project"
|
|
1111
1166
|
).option("-y, --yes", "Skip confirmation prompts").action(async (name, options) => {
|
|
1112
1167
|
try {
|
|
1168
|
+
const optionError = validateScope(options.scope) || validateType(options.type);
|
|
1169
|
+
if (optionError) {
|
|
1170
|
+
console.log(chalk9.red(optionError));
|
|
1171
|
+
process.exit(1);
|
|
1172
|
+
}
|
|
1113
1173
|
const scope = options.scope;
|
|
1114
1174
|
const type = options.type;
|
|
1115
1175
|
if (!type) {
|
|
@@ -1222,9 +1282,78 @@ Browse available skills at https://seedr.danieldeusing.de
|
|
|
1222
1282
|
}
|
|
1223
1283
|
});
|
|
1224
1284
|
|
|
1285
|
+
// package.json
|
|
1286
|
+
var package_default = {
|
|
1287
|
+
name: "@danieldeusing/seedr",
|
|
1288
|
+
version: "0.1.82",
|
|
1289
|
+
description: "Seed your projects with AI configurations",
|
|
1290
|
+
type: "module",
|
|
1291
|
+
bin: {
|
|
1292
|
+
seedr: "dist/cli.js"
|
|
1293
|
+
},
|
|
1294
|
+
exports: {
|
|
1295
|
+
".": {
|
|
1296
|
+
import: "./dist/index.js",
|
|
1297
|
+
types: "./dist/index.d.ts"
|
|
1298
|
+
}
|
|
1299
|
+
},
|
|
1300
|
+
files: [
|
|
1301
|
+
"dist"
|
|
1302
|
+
],
|
|
1303
|
+
scripts: {
|
|
1304
|
+
build: "tsup",
|
|
1305
|
+
dev: "tsx src/cli.ts",
|
|
1306
|
+
typecheck: "tsc --noEmit",
|
|
1307
|
+
lint: "eslint src/",
|
|
1308
|
+
"lint:fix": "eslint src/ --fix",
|
|
1309
|
+
clean: "rm -rf dist",
|
|
1310
|
+
test: "vitest run",
|
|
1311
|
+
"test:watch": "vitest",
|
|
1312
|
+
"test:coverage": "vitest run --coverage"
|
|
1313
|
+
},
|
|
1314
|
+
dependencies: {
|
|
1315
|
+
"@clack/prompts": "^1.0.1",
|
|
1316
|
+
chalk: "^5.3.0",
|
|
1317
|
+
commander: "^14.0.0",
|
|
1318
|
+
"gray-matter": "^4.0.3",
|
|
1319
|
+
inquirer: "^13.0.0",
|
|
1320
|
+
ora: "^9.0.0"
|
|
1321
|
+
},
|
|
1322
|
+
devDependencies: {
|
|
1323
|
+
"@seedr/shared": "workspace:*",
|
|
1324
|
+
"@types/inquirer": "^9.0.7",
|
|
1325
|
+
"@types/node": "^25.0.0",
|
|
1326
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
1327
|
+
memfs: "^4.14.0",
|
|
1328
|
+
tsup: "^8.3.0",
|
|
1329
|
+
tsx: "^4.19.0",
|
|
1330
|
+
typescript: "^5.7.0",
|
|
1331
|
+
vitest: "^4.1.0"
|
|
1332
|
+
},
|
|
1333
|
+
keywords: [
|
|
1334
|
+
"ai",
|
|
1335
|
+
"claude",
|
|
1336
|
+
"copilot",
|
|
1337
|
+
"gemini",
|
|
1338
|
+
"codex",
|
|
1339
|
+
"opencode",
|
|
1340
|
+
"configuration",
|
|
1341
|
+
"seeder"
|
|
1342
|
+
],
|
|
1343
|
+
repository: {
|
|
1344
|
+
type: "git",
|
|
1345
|
+
url: "git+https://github.com/danieldeusing/seedr.git"
|
|
1346
|
+
},
|
|
1347
|
+
homepage: "https://seedr.danieldeusing.de",
|
|
1348
|
+
bugs: {
|
|
1349
|
+
url: "https://github.com/danieldeusing/seedr/issues"
|
|
1350
|
+
},
|
|
1351
|
+
license: "MIT"
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1225
1354
|
// src/cli.ts
|
|
1226
1355
|
var program = new Command5();
|
|
1227
|
-
program.name("seedr").description("Seed your Coding Agents with capabilities").version(
|
|
1356
|
+
program.name("seedr").description("Seed your Coding Agents with capabilities").version(package_default.version).addCommand(addCommand).addCommand(listCommand).addCommand(removeCommand).addCommand(initCommand);
|
|
1228
1357
|
program.action(() => {
|
|
1229
1358
|
printLogo();
|
|
1230
1359
|
program.help();
|
package/dist/index.d.ts
CHANGED
|
@@ -69,7 +69,7 @@ interface InstallResult {
|
|
|
69
69
|
error?: string;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
declare function installSkill(item: RegistryItem, agents: CodingAgent[], scope: InstallScope, method: InstallMethod, cwd?: string): Promise<InstallResult[]>;
|
|
72
|
+
declare function installSkill(item: RegistryItem, agents: CodingAgent[], scope: InstallScope, method: InstallMethod, force: boolean, cwd?: string): Promise<InstallResult[]>;
|
|
73
73
|
declare function uninstallSkill(slug: string, agent: CodingAgent, scope: InstallScope, cwd?: string): Promise<boolean>;
|
|
74
74
|
declare function getInstalledSkills(agent: CodingAgent, scope: InstallScope, cwd?: string): Promise<string[]>;
|
|
75
75
|
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danieldeusing/seedr",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.82",
|
|
4
4
|
"description": "Seed your projects with AI configurations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"seedr": "
|
|
7
|
+
"seedr": "dist/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
@@ -30,23 +30,20 @@
|
|
|
30
30
|
"@clack/prompts": "^1.0.1",
|
|
31
31
|
"chalk": "^5.3.0",
|
|
32
32
|
"commander": "^14.0.0",
|
|
33
|
-
"fs-extra": "^11.2.0",
|
|
34
33
|
"gray-matter": "^4.0.3",
|
|
35
34
|
"inquirer": "^13.0.0",
|
|
36
|
-
"ora": "^9.0.0"
|
|
37
|
-
"simple-git": "^3.32.3"
|
|
35
|
+
"ora": "^9.0.0"
|
|
38
36
|
},
|
|
39
37
|
"devDependencies": {
|
|
40
38
|
"@seedr/shared": "workspace:*",
|
|
41
|
-
"@types/fs-extra": "^11.0.4",
|
|
42
39
|
"@types/inquirer": "^9.0.7",
|
|
43
40
|
"@types/node": "^25.0.0",
|
|
44
|
-
"@vitest/coverage-v8": "^4.
|
|
41
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
45
42
|
"memfs": "^4.14.0",
|
|
46
43
|
"tsup": "^8.3.0",
|
|
47
44
|
"tsx": "^4.19.0",
|
|
48
45
|
"typescript": "^5.7.0",
|
|
49
|
-
"vitest": "^4.
|
|
46
|
+
"vitest": "^4.1.0"
|
|
50
47
|
},
|
|
51
48
|
"keywords": [
|
|
52
49
|
"ai",
|
|
@@ -60,7 +57,7 @@
|
|
|
60
57
|
],
|
|
61
58
|
"repository": {
|
|
62
59
|
"type": "git",
|
|
63
|
-
"url": "https://github.com/danieldeusing/seedr.git"
|
|
60
|
+
"url": "git+https://github.com/danieldeusing/seedr.git"
|
|
64
61
|
},
|
|
65
62
|
"homepage": "https://seedr.danieldeusing.de",
|
|
66
63
|
"bugs": {
|