agentpacks 0.5.0 → 0.6.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 +8 -1
- package/dist/api.js +98 -19
- package/dist/cli/export-cmd.js +76 -19
- package/dist/cli/generate.js +29 -0
- package/dist/cli/install.js +7 -0
- package/dist/cli/models-explain.js +7 -0
- package/dist/cli/pack/list.js +7 -0
- package/dist/cli/pack/validate.js +7 -0
- package/dist/cli/publish.js +7 -0
- package/dist/core/config.d.ts +7 -0
- package/dist/core/config.js +7 -0
- package/dist/core/index.js +7 -0
- package/dist/core/metarepo.js +7 -0
- package/dist/core/pack-loader.js +7 -0
- package/dist/exporters/cursor-plugin.d.ts +18 -18
- package/dist/exporters/cursor-plugin.js +117 -29
- package/dist/exporters/index.js +117 -29
- package/dist/index.js +98 -19
- package/dist/node/api.js +98 -19
- package/dist/node/cli/export-cmd.js +76 -19
- package/dist/node/cli/generate.js +29 -0
- package/dist/node/cli/install.js +7 -0
- package/dist/node/cli/models-explain.js +7 -0
- package/dist/node/cli/pack/list.js +7 -0
- package/dist/node/cli/pack/validate.js +7 -0
- package/dist/node/cli/publish.js +7 -0
- package/dist/node/core/config.js +7 -0
- package/dist/node/core/index.js +7 -0
- package/dist/node/core/metarepo.js +7 -0
- package/dist/node/core/pack-loader.js +7 -0
- package/dist/node/exporters/cursor-plugin.js +117 -29
- package/dist/node/exporters/index.js +117 -29
- package/dist/node/index.js +98 -19
- package/dist/node/targets/cursor.js +67 -7
- package/dist/node/targets/index.js +22 -0
- package/dist/node/targets/registry.js +22 -0
- package/dist/targets/cursor.d.ts +1 -1
- package/dist/targets/cursor.js +67 -7
- package/dist/targets/index.js +22 -0
- package/dist/targets/registry.js +22 -0
- package/package.json +2 -2
|
@@ -129,28 +129,84 @@ function serializeFrontmatter(data, content) {
|
|
|
129
129
|
return matter.stringify(content, filtered);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
// src/features/hooks.ts
|
|
133
|
+
import { join as join2 } from "path";
|
|
134
|
+
var TARGET_OVERRIDE_KEYS = ["cursor", "claudecode", "opencode"];
|
|
135
|
+
function parseHooks(packDir, packName) {
|
|
136
|
+
const hooksPath = join2(packDir, "hooks", "hooks.json");
|
|
137
|
+
const raw = readJsonOrNull(hooksPath);
|
|
138
|
+
if (!raw)
|
|
139
|
+
return null;
|
|
140
|
+
const shared = raw.hooks ?? {};
|
|
141
|
+
const targetOverrides = {};
|
|
142
|
+
for (const key of TARGET_OVERRIDE_KEYS) {
|
|
143
|
+
const override = raw[key];
|
|
144
|
+
if (override && typeof override === "object" && "hooks" in override && override.hooks) {
|
|
145
|
+
targetOverrides[key] = override.hooks;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
packName,
|
|
150
|
+
sourcePath: hooksPath,
|
|
151
|
+
version: raw.version,
|
|
152
|
+
shared,
|
|
153
|
+
targetOverrides
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function resolveHooksForTarget(hooks, targetId) {
|
|
157
|
+
const merged = {};
|
|
158
|
+
for (const [event, entries] of Object.entries(hooks.shared)) {
|
|
159
|
+
merged[event] = [...entries];
|
|
160
|
+
}
|
|
161
|
+
const overrides = hooks.targetOverrides[targetId];
|
|
162
|
+
if (overrides) {
|
|
163
|
+
for (const [event, entries] of Object.entries(overrides)) {
|
|
164
|
+
merged[event] = [...merged[event] ?? [], ...entries];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return merged;
|
|
168
|
+
}
|
|
169
|
+
|
|
132
170
|
// src/exporters/cursor-plugin.ts
|
|
133
|
-
import { resolve, join as
|
|
171
|
+
import { resolve, join as join3 } from "path";
|
|
134
172
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
135
173
|
function exportCursorPlugin(pack, outputDir) {
|
|
136
174
|
const filesWritten = [];
|
|
137
|
-
const
|
|
175
|
+
const pluginName = normalizeCursorPluginName(pack.manifest.name);
|
|
176
|
+
const pluginDir = resolve(outputDir, pluginName);
|
|
138
177
|
mkdirSync2(pluginDir, { recursive: true });
|
|
139
178
|
const manifest = {
|
|
140
|
-
name:
|
|
141
|
-
version: pack.manifest.version,
|
|
142
|
-
description: pack.manifest.description
|
|
179
|
+
name: pluginName
|
|
143
180
|
};
|
|
144
|
-
if (pack.manifest.
|
|
145
|
-
manifest.
|
|
181
|
+
if (pack.manifest.version) {
|
|
182
|
+
manifest.version = pack.manifest.version;
|
|
183
|
+
}
|
|
184
|
+
if (pack.manifest.description) {
|
|
185
|
+
manifest.description = pack.manifest.description;
|
|
186
|
+
}
|
|
187
|
+
const author = toCursorPluginAuthor(pack.manifest.author);
|
|
188
|
+
if (author) {
|
|
189
|
+
manifest.author = author;
|
|
190
|
+
}
|
|
191
|
+
if (pack.manifest.homepage) {
|
|
192
|
+
manifest.homepage = pack.manifest.homepage;
|
|
193
|
+
}
|
|
194
|
+
if (pack.manifest.repository) {
|
|
195
|
+
manifest.repository = typeof pack.manifest.repository === "string" ? pack.manifest.repository : pack.manifest.repository.url;
|
|
196
|
+
}
|
|
197
|
+
if (pack.manifest.license) {
|
|
198
|
+
manifest.license = pack.manifest.license;
|
|
199
|
+
}
|
|
200
|
+
if (pack.manifest.logo) {
|
|
201
|
+
manifest.logo = pack.manifest.logo;
|
|
146
202
|
}
|
|
147
203
|
if (pack.manifest.tags.length > 0) {
|
|
148
|
-
manifest.
|
|
204
|
+
manifest.keywords = pack.manifest.tags;
|
|
149
205
|
}
|
|
150
206
|
if (pack.rules.length > 0) {
|
|
151
|
-
const rulesDir =
|
|
207
|
+
const rulesDir = join3(pluginDir, "rules");
|
|
152
208
|
ensureDir(rulesDir);
|
|
153
|
-
manifest.rules =
|
|
209
|
+
manifest.rules = "rules";
|
|
154
210
|
for (const rule of pack.rules) {
|
|
155
211
|
const cursorMeta = rule.meta.cursor ?? {};
|
|
156
212
|
const fm = {
|
|
@@ -161,70 +217,102 @@ function exportCursorPlugin(pack, outputDir) {
|
|
|
161
217
|
if (globs)
|
|
162
218
|
fm.globs = globs;
|
|
163
219
|
const filename = `${rule.name}.mdc`;
|
|
164
|
-
const filepath =
|
|
220
|
+
const filepath = join3(rulesDir, filename);
|
|
165
221
|
writeFileSync2(filepath, serializeFrontmatter(fm, rule.content));
|
|
166
222
|
filesWritten.push(filepath);
|
|
167
|
-
manifest.rules.push(filename);
|
|
168
223
|
}
|
|
169
224
|
}
|
|
170
225
|
if (pack.agents.length > 0) {
|
|
171
|
-
const agentsDir =
|
|
226
|
+
const agentsDir = join3(pluginDir, "agents");
|
|
172
227
|
ensureDir(agentsDir);
|
|
173
|
-
manifest.agents =
|
|
228
|
+
manifest.agents = "agents";
|
|
174
229
|
for (const agent of pack.agents) {
|
|
175
230
|
const fm = {
|
|
176
231
|
name: agent.name,
|
|
177
232
|
description: agent.meta.description ?? ""
|
|
178
233
|
};
|
|
179
234
|
const filename = `${agent.name}.md`;
|
|
180
|
-
const filepath =
|
|
235
|
+
const filepath = join3(agentsDir, filename);
|
|
181
236
|
writeFileSync2(filepath, serializeFrontmatter(fm, agent.content));
|
|
182
237
|
filesWritten.push(filepath);
|
|
183
|
-
manifest.agents.push(filename);
|
|
184
238
|
}
|
|
185
239
|
}
|
|
186
240
|
if (pack.skills.length > 0) {
|
|
187
|
-
const skillsDir =
|
|
241
|
+
const skillsDir = join3(pluginDir, "skills");
|
|
188
242
|
ensureDir(skillsDir);
|
|
189
|
-
manifest.skills =
|
|
243
|
+
manifest.skills = "skills";
|
|
190
244
|
for (const skill of pack.skills) {
|
|
191
|
-
const skillSubDir =
|
|
245
|
+
const skillSubDir = join3(skillsDir, skill.name);
|
|
192
246
|
ensureDir(skillSubDir);
|
|
193
247
|
const fm = {
|
|
194
248
|
name: skill.name,
|
|
195
249
|
description: skill.meta.description ?? ""
|
|
196
250
|
};
|
|
197
|
-
const filepath =
|
|
251
|
+
const filepath = join3(skillSubDir, "SKILL.md");
|
|
198
252
|
writeFileSync2(filepath, serializeFrontmatter(fm, skill.content));
|
|
199
253
|
filesWritten.push(filepath);
|
|
200
|
-
manifest.skills.push(skill.name);
|
|
201
254
|
}
|
|
202
255
|
}
|
|
203
256
|
if (pack.commands.length > 0) {
|
|
204
|
-
const commandsDir =
|
|
257
|
+
const commandsDir = join3(pluginDir, "commands");
|
|
205
258
|
ensureDir(commandsDir);
|
|
206
|
-
manifest.commands =
|
|
259
|
+
manifest.commands = "commands";
|
|
207
260
|
for (const cmd of pack.commands) {
|
|
261
|
+
const fm = {
|
|
262
|
+
name: cmd.name
|
|
263
|
+
};
|
|
264
|
+
if (cmd.meta.description) {
|
|
265
|
+
fm.description = cmd.meta.description;
|
|
266
|
+
}
|
|
208
267
|
const filename = `${cmd.name}.md`;
|
|
209
|
-
const filepath =
|
|
210
|
-
writeFileSync2(filepath, cmd.content);
|
|
268
|
+
const filepath = join3(commandsDir, filename);
|
|
269
|
+
writeFileSync2(filepath, serializeFrontmatter(fm, cmd.content));
|
|
270
|
+
filesWritten.push(filepath);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (pack.hooks) {
|
|
274
|
+
const events = resolveHooksForTarget(pack.hooks, "cursor");
|
|
275
|
+
if (Object.keys(events).length > 0) {
|
|
276
|
+
const hooksDir = join3(pluginDir, "hooks");
|
|
277
|
+
ensureDir(hooksDir);
|
|
278
|
+
const filepath = join3(hooksDir, "hooks.json");
|
|
279
|
+
writeFileSync2(filepath, JSON.stringify({ version: pack.hooks.version ?? 1, hooks: events }, null, 2) + `
|
|
280
|
+
`);
|
|
211
281
|
filesWritten.push(filepath);
|
|
212
|
-
manifest.
|
|
282
|
+
manifest.hooks = "hooks/hooks.json";
|
|
213
283
|
}
|
|
214
284
|
}
|
|
215
285
|
if (pack.mcp && Object.keys(pack.mcp.servers).length > 0) {
|
|
216
|
-
manifest.
|
|
217
|
-
const filepath =
|
|
286
|
+
manifest.mcpServers = ".mcp.json";
|
|
287
|
+
const filepath = join3(pluginDir, ".mcp.json");
|
|
218
288
|
writeFileSync2(filepath, JSON.stringify({ mcpServers: pack.mcp.servers }, null, 2) + `
|
|
219
289
|
`);
|
|
220
290
|
filesWritten.push(filepath);
|
|
221
291
|
}
|
|
222
|
-
const
|
|
292
|
+
const manifestDir = join3(pluginDir, ".cursor-plugin");
|
|
293
|
+
ensureDir(manifestDir);
|
|
294
|
+
const manifestPath = join3(manifestDir, "plugin.json");
|
|
223
295
|
writeFileSync2(manifestPath, JSON.stringify(manifest, null, 2) + `
|
|
224
296
|
`);
|
|
225
297
|
filesWritten.push(manifestPath);
|
|
226
298
|
return { outputDir: pluginDir, filesWritten, manifest };
|
|
227
299
|
}
|
|
300
|
+
function normalizeCursorPluginName(name) {
|
|
301
|
+
const normalized = name.toLowerCase().replace(/[^a-z0-9.-]+/g, "-").replace(/-+/g, "-").replace(/^[^a-z0-9]+/, "").replace(/[^a-z0-9]+$/, "");
|
|
302
|
+
return normalized.length > 0 ? normalized : "agentpacks-plugin";
|
|
303
|
+
}
|
|
304
|
+
function toCursorPluginAuthor(author) {
|
|
305
|
+
if (!author) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
if (typeof author === "string") {
|
|
309
|
+
return { name: author };
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
name: author.name,
|
|
313
|
+
...author.email ? { email: author.email } : {}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
228
316
|
export {
|
|
229
317
|
exportCursorPlugin
|
|
230
318
|
};
|
package/dist/exporters/index.js
CHANGED
|
@@ -129,28 +129,84 @@ function serializeFrontmatter(data, content) {
|
|
|
129
129
|
return matter.stringify(content, filtered);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
// src/features/hooks.ts
|
|
133
|
+
import { join as join2 } from "path";
|
|
134
|
+
var TARGET_OVERRIDE_KEYS = ["cursor", "claudecode", "opencode"];
|
|
135
|
+
function parseHooks(packDir, packName) {
|
|
136
|
+
const hooksPath = join2(packDir, "hooks", "hooks.json");
|
|
137
|
+
const raw = readJsonOrNull(hooksPath);
|
|
138
|
+
if (!raw)
|
|
139
|
+
return null;
|
|
140
|
+
const shared = raw.hooks ?? {};
|
|
141
|
+
const targetOverrides = {};
|
|
142
|
+
for (const key of TARGET_OVERRIDE_KEYS) {
|
|
143
|
+
const override = raw[key];
|
|
144
|
+
if (override && typeof override === "object" && "hooks" in override && override.hooks) {
|
|
145
|
+
targetOverrides[key] = override.hooks;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
packName,
|
|
150
|
+
sourcePath: hooksPath,
|
|
151
|
+
version: raw.version,
|
|
152
|
+
shared,
|
|
153
|
+
targetOverrides
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function resolveHooksForTarget(hooks, targetId) {
|
|
157
|
+
const merged = {};
|
|
158
|
+
for (const [event, entries] of Object.entries(hooks.shared)) {
|
|
159
|
+
merged[event] = [...entries];
|
|
160
|
+
}
|
|
161
|
+
const overrides = hooks.targetOverrides[targetId];
|
|
162
|
+
if (overrides) {
|
|
163
|
+
for (const [event, entries] of Object.entries(overrides)) {
|
|
164
|
+
merged[event] = [...merged[event] ?? [], ...entries];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return merged;
|
|
168
|
+
}
|
|
169
|
+
|
|
132
170
|
// src/exporters/cursor-plugin.ts
|
|
133
|
-
import { resolve, join as
|
|
171
|
+
import { resolve, join as join3 } from "path";
|
|
134
172
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
135
173
|
function exportCursorPlugin(pack, outputDir) {
|
|
136
174
|
const filesWritten = [];
|
|
137
|
-
const
|
|
175
|
+
const pluginName = normalizeCursorPluginName(pack.manifest.name);
|
|
176
|
+
const pluginDir = resolve(outputDir, pluginName);
|
|
138
177
|
mkdirSync2(pluginDir, { recursive: true });
|
|
139
178
|
const manifest = {
|
|
140
|
-
name:
|
|
141
|
-
version: pack.manifest.version,
|
|
142
|
-
description: pack.manifest.description
|
|
179
|
+
name: pluginName
|
|
143
180
|
};
|
|
144
|
-
if (pack.manifest.
|
|
145
|
-
manifest.
|
|
181
|
+
if (pack.manifest.version) {
|
|
182
|
+
manifest.version = pack.manifest.version;
|
|
183
|
+
}
|
|
184
|
+
if (pack.manifest.description) {
|
|
185
|
+
manifest.description = pack.manifest.description;
|
|
186
|
+
}
|
|
187
|
+
const author = toCursorPluginAuthor(pack.manifest.author);
|
|
188
|
+
if (author) {
|
|
189
|
+
manifest.author = author;
|
|
190
|
+
}
|
|
191
|
+
if (pack.manifest.homepage) {
|
|
192
|
+
manifest.homepage = pack.manifest.homepage;
|
|
193
|
+
}
|
|
194
|
+
if (pack.manifest.repository) {
|
|
195
|
+
manifest.repository = typeof pack.manifest.repository === "string" ? pack.manifest.repository : pack.manifest.repository.url;
|
|
196
|
+
}
|
|
197
|
+
if (pack.manifest.license) {
|
|
198
|
+
manifest.license = pack.manifest.license;
|
|
199
|
+
}
|
|
200
|
+
if (pack.manifest.logo) {
|
|
201
|
+
manifest.logo = pack.manifest.logo;
|
|
146
202
|
}
|
|
147
203
|
if (pack.manifest.tags.length > 0) {
|
|
148
|
-
manifest.
|
|
204
|
+
manifest.keywords = pack.manifest.tags;
|
|
149
205
|
}
|
|
150
206
|
if (pack.rules.length > 0) {
|
|
151
|
-
const rulesDir =
|
|
207
|
+
const rulesDir = join3(pluginDir, "rules");
|
|
152
208
|
ensureDir(rulesDir);
|
|
153
|
-
manifest.rules =
|
|
209
|
+
manifest.rules = "rules";
|
|
154
210
|
for (const rule of pack.rules) {
|
|
155
211
|
const cursorMeta = rule.meta.cursor ?? {};
|
|
156
212
|
const fm = {
|
|
@@ -161,70 +217,102 @@ function exportCursorPlugin(pack, outputDir) {
|
|
|
161
217
|
if (globs)
|
|
162
218
|
fm.globs = globs;
|
|
163
219
|
const filename = `${rule.name}.mdc`;
|
|
164
|
-
const filepath =
|
|
220
|
+
const filepath = join3(rulesDir, filename);
|
|
165
221
|
writeFileSync2(filepath, serializeFrontmatter(fm, rule.content));
|
|
166
222
|
filesWritten.push(filepath);
|
|
167
|
-
manifest.rules.push(filename);
|
|
168
223
|
}
|
|
169
224
|
}
|
|
170
225
|
if (pack.agents.length > 0) {
|
|
171
|
-
const agentsDir =
|
|
226
|
+
const agentsDir = join3(pluginDir, "agents");
|
|
172
227
|
ensureDir(agentsDir);
|
|
173
|
-
manifest.agents =
|
|
228
|
+
manifest.agents = "agents";
|
|
174
229
|
for (const agent of pack.agents) {
|
|
175
230
|
const fm = {
|
|
176
231
|
name: agent.name,
|
|
177
232
|
description: agent.meta.description ?? ""
|
|
178
233
|
};
|
|
179
234
|
const filename = `${agent.name}.md`;
|
|
180
|
-
const filepath =
|
|
235
|
+
const filepath = join3(agentsDir, filename);
|
|
181
236
|
writeFileSync2(filepath, serializeFrontmatter(fm, agent.content));
|
|
182
237
|
filesWritten.push(filepath);
|
|
183
|
-
manifest.agents.push(filename);
|
|
184
238
|
}
|
|
185
239
|
}
|
|
186
240
|
if (pack.skills.length > 0) {
|
|
187
|
-
const skillsDir =
|
|
241
|
+
const skillsDir = join3(pluginDir, "skills");
|
|
188
242
|
ensureDir(skillsDir);
|
|
189
|
-
manifest.skills =
|
|
243
|
+
manifest.skills = "skills";
|
|
190
244
|
for (const skill of pack.skills) {
|
|
191
|
-
const skillSubDir =
|
|
245
|
+
const skillSubDir = join3(skillsDir, skill.name);
|
|
192
246
|
ensureDir(skillSubDir);
|
|
193
247
|
const fm = {
|
|
194
248
|
name: skill.name,
|
|
195
249
|
description: skill.meta.description ?? ""
|
|
196
250
|
};
|
|
197
|
-
const filepath =
|
|
251
|
+
const filepath = join3(skillSubDir, "SKILL.md");
|
|
198
252
|
writeFileSync2(filepath, serializeFrontmatter(fm, skill.content));
|
|
199
253
|
filesWritten.push(filepath);
|
|
200
|
-
manifest.skills.push(skill.name);
|
|
201
254
|
}
|
|
202
255
|
}
|
|
203
256
|
if (pack.commands.length > 0) {
|
|
204
|
-
const commandsDir =
|
|
257
|
+
const commandsDir = join3(pluginDir, "commands");
|
|
205
258
|
ensureDir(commandsDir);
|
|
206
|
-
manifest.commands =
|
|
259
|
+
manifest.commands = "commands";
|
|
207
260
|
for (const cmd of pack.commands) {
|
|
261
|
+
const fm = {
|
|
262
|
+
name: cmd.name
|
|
263
|
+
};
|
|
264
|
+
if (cmd.meta.description) {
|
|
265
|
+
fm.description = cmd.meta.description;
|
|
266
|
+
}
|
|
208
267
|
const filename = `${cmd.name}.md`;
|
|
209
|
-
const filepath =
|
|
210
|
-
writeFileSync2(filepath, cmd.content);
|
|
268
|
+
const filepath = join3(commandsDir, filename);
|
|
269
|
+
writeFileSync2(filepath, serializeFrontmatter(fm, cmd.content));
|
|
270
|
+
filesWritten.push(filepath);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (pack.hooks) {
|
|
274
|
+
const events = resolveHooksForTarget(pack.hooks, "cursor");
|
|
275
|
+
if (Object.keys(events).length > 0) {
|
|
276
|
+
const hooksDir = join3(pluginDir, "hooks");
|
|
277
|
+
ensureDir(hooksDir);
|
|
278
|
+
const filepath = join3(hooksDir, "hooks.json");
|
|
279
|
+
writeFileSync2(filepath, JSON.stringify({ version: pack.hooks.version ?? 1, hooks: events }, null, 2) + `
|
|
280
|
+
`);
|
|
211
281
|
filesWritten.push(filepath);
|
|
212
|
-
manifest.
|
|
282
|
+
manifest.hooks = "hooks/hooks.json";
|
|
213
283
|
}
|
|
214
284
|
}
|
|
215
285
|
if (pack.mcp && Object.keys(pack.mcp.servers).length > 0) {
|
|
216
|
-
manifest.
|
|
217
|
-
const filepath =
|
|
286
|
+
manifest.mcpServers = ".mcp.json";
|
|
287
|
+
const filepath = join3(pluginDir, ".mcp.json");
|
|
218
288
|
writeFileSync2(filepath, JSON.stringify({ mcpServers: pack.mcp.servers }, null, 2) + `
|
|
219
289
|
`);
|
|
220
290
|
filesWritten.push(filepath);
|
|
221
291
|
}
|
|
222
|
-
const
|
|
292
|
+
const manifestDir = join3(pluginDir, ".cursor-plugin");
|
|
293
|
+
ensureDir(manifestDir);
|
|
294
|
+
const manifestPath = join3(manifestDir, "plugin.json");
|
|
223
295
|
writeFileSync2(manifestPath, JSON.stringify(manifest, null, 2) + `
|
|
224
296
|
`);
|
|
225
297
|
filesWritten.push(manifestPath);
|
|
226
298
|
return { outputDir: pluginDir, filesWritten, manifest };
|
|
227
299
|
}
|
|
300
|
+
function normalizeCursorPluginName(name) {
|
|
301
|
+
const normalized = name.toLowerCase().replace(/[^a-z0-9.-]+/g, "-").replace(/-+/g, "-").replace(/^[^a-z0-9]+/, "").replace(/[^a-z0-9]+$/, "");
|
|
302
|
+
return normalized.length > 0 ? normalized : "agentpacks-plugin";
|
|
303
|
+
}
|
|
304
|
+
function toCursorPluginAuthor(author) {
|
|
305
|
+
if (!author) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
if (typeof author === "string") {
|
|
309
|
+
return { name: author };
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
name: author.name,
|
|
313
|
+
...author.email ? { email: author.email } : {}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
228
316
|
export {
|
|
229
317
|
exportCursorPlugin
|
|
230
318
|
};
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,13 @@ var PackManifestSchema = z.object({
|
|
|
49
49
|
z.string(),
|
|
50
50
|
z.object({ name: z.string(), email: z.string().optional() })
|
|
51
51
|
]).optional(),
|
|
52
|
+
homepage: z.string().optional(),
|
|
53
|
+
repository: z.union([
|
|
54
|
+
z.string(),
|
|
55
|
+
z.object({ url: z.string(), type: z.string().optional() })
|
|
56
|
+
]).optional(),
|
|
57
|
+
license: z.string().optional(),
|
|
58
|
+
logo: z.string().optional(),
|
|
52
59
|
tags: z.array(z.string()).default([]),
|
|
53
60
|
dependencies: z.array(z.string()).default([]),
|
|
54
61
|
conflicts: z.array(z.string()).default([]),
|
|
@@ -1790,6 +1797,28 @@ class CursorTarget extends BaseTarget {
|
|
|
1790
1797
|
filesWritten.push(filepath);
|
|
1791
1798
|
}
|
|
1792
1799
|
}
|
|
1800
|
+
if (effective.includes("hooks")) {
|
|
1801
|
+
const hooksFilepath = resolve8(cursorDir, "hooks.json");
|
|
1802
|
+
if (deleteExisting) {
|
|
1803
|
+
removeIfExists(hooksFilepath);
|
|
1804
|
+
filesDeleted.push(hooksFilepath);
|
|
1805
|
+
}
|
|
1806
|
+
const mergedHooks = {};
|
|
1807
|
+
for (const hookSet of features.hooks) {
|
|
1808
|
+
const events = resolveHooksForTarget(hookSet, TARGET_ID2);
|
|
1809
|
+
for (const [event, entries] of Object.entries(events)) {
|
|
1810
|
+
if (!mergedHooks[event]) {
|
|
1811
|
+
mergedHooks[event] = [];
|
|
1812
|
+
}
|
|
1813
|
+
mergedHooks[event].push(...entries);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
if (Object.keys(mergedHooks).length > 0) {
|
|
1817
|
+
const hooksVersion = features.hooks.find((h) => h.version !== undefined)?.version ?? 1;
|
|
1818
|
+
writeGeneratedJson(hooksFilepath, { version: hooksVersion, hooks: mergedHooks }, { header: false });
|
|
1819
|
+
filesWritten.push(hooksFilepath);
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1793
1822
|
if (effective.includes("mcp")) {
|
|
1794
1823
|
const mcpEntries = Object.entries(features.mcpServers);
|
|
1795
1824
|
if (mcpEntries.length > 0) {
|
|
@@ -2657,23 +2686,41 @@ import { resolve as resolve15, join as join17 } from "path";
|
|
|
2657
2686
|
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
2658
2687
|
function exportCursorPlugin(pack, outputDir) {
|
|
2659
2688
|
const filesWritten = [];
|
|
2660
|
-
const
|
|
2689
|
+
const pluginName = normalizeCursorPluginName(pack.manifest.name);
|
|
2690
|
+
const pluginDir = resolve15(outputDir, pluginName);
|
|
2661
2691
|
mkdirSync4(pluginDir, { recursive: true });
|
|
2662
2692
|
const manifest = {
|
|
2663
|
-
name:
|
|
2664
|
-
version: pack.manifest.version,
|
|
2665
|
-
description: pack.manifest.description
|
|
2693
|
+
name: pluginName
|
|
2666
2694
|
};
|
|
2667
|
-
if (pack.manifest.
|
|
2668
|
-
manifest.
|
|
2695
|
+
if (pack.manifest.version) {
|
|
2696
|
+
manifest.version = pack.manifest.version;
|
|
2697
|
+
}
|
|
2698
|
+
if (pack.manifest.description) {
|
|
2699
|
+
manifest.description = pack.manifest.description;
|
|
2700
|
+
}
|
|
2701
|
+
const author = toCursorPluginAuthor(pack.manifest.author);
|
|
2702
|
+
if (author) {
|
|
2703
|
+
manifest.author = author;
|
|
2704
|
+
}
|
|
2705
|
+
if (pack.manifest.homepage) {
|
|
2706
|
+
manifest.homepage = pack.manifest.homepage;
|
|
2707
|
+
}
|
|
2708
|
+
if (pack.manifest.repository) {
|
|
2709
|
+
manifest.repository = typeof pack.manifest.repository === "string" ? pack.manifest.repository : pack.manifest.repository.url;
|
|
2710
|
+
}
|
|
2711
|
+
if (pack.manifest.license) {
|
|
2712
|
+
manifest.license = pack.manifest.license;
|
|
2713
|
+
}
|
|
2714
|
+
if (pack.manifest.logo) {
|
|
2715
|
+
manifest.logo = pack.manifest.logo;
|
|
2669
2716
|
}
|
|
2670
2717
|
if (pack.manifest.tags.length > 0) {
|
|
2671
|
-
manifest.
|
|
2718
|
+
manifest.keywords = pack.manifest.tags;
|
|
2672
2719
|
}
|
|
2673
2720
|
if (pack.rules.length > 0) {
|
|
2674
2721
|
const rulesDir = join17(pluginDir, "rules");
|
|
2675
2722
|
ensureDir(rulesDir);
|
|
2676
|
-
manifest.rules =
|
|
2723
|
+
manifest.rules = "rules";
|
|
2677
2724
|
for (const rule of pack.rules) {
|
|
2678
2725
|
const cursorMeta = rule.meta.cursor ?? {};
|
|
2679
2726
|
const fm = {
|
|
@@ -2687,13 +2734,12 @@ function exportCursorPlugin(pack, outputDir) {
|
|
|
2687
2734
|
const filepath = join17(rulesDir, filename);
|
|
2688
2735
|
writeFileSync4(filepath, serializeFrontmatter(fm, rule.content));
|
|
2689
2736
|
filesWritten.push(filepath);
|
|
2690
|
-
manifest.rules.push(filename);
|
|
2691
2737
|
}
|
|
2692
2738
|
}
|
|
2693
2739
|
if (pack.agents.length > 0) {
|
|
2694
2740
|
const agentsDir = join17(pluginDir, "agents");
|
|
2695
2741
|
ensureDir(agentsDir);
|
|
2696
|
-
manifest.agents =
|
|
2742
|
+
manifest.agents = "agents";
|
|
2697
2743
|
for (const agent of pack.agents) {
|
|
2698
2744
|
const fm = {
|
|
2699
2745
|
name: agent.name,
|
|
@@ -2703,13 +2749,12 @@ function exportCursorPlugin(pack, outputDir) {
|
|
|
2703
2749
|
const filepath = join17(agentsDir, filename);
|
|
2704
2750
|
writeFileSync4(filepath, serializeFrontmatter(fm, agent.content));
|
|
2705
2751
|
filesWritten.push(filepath);
|
|
2706
|
-
manifest.agents.push(filename);
|
|
2707
2752
|
}
|
|
2708
2753
|
}
|
|
2709
2754
|
if (pack.skills.length > 0) {
|
|
2710
2755
|
const skillsDir = join17(pluginDir, "skills");
|
|
2711
2756
|
ensureDir(skillsDir);
|
|
2712
|
-
manifest.skills =
|
|
2757
|
+
manifest.skills = "skills";
|
|
2713
2758
|
for (const skill of pack.skills) {
|
|
2714
2759
|
const skillSubDir = join17(skillsDir, skill.name);
|
|
2715
2760
|
ensureDir(skillSubDir);
|
|
@@ -2720,34 +2765,68 @@ function exportCursorPlugin(pack, outputDir) {
|
|
|
2720
2765
|
const filepath = join17(skillSubDir, "SKILL.md");
|
|
2721
2766
|
writeFileSync4(filepath, serializeFrontmatter(fm, skill.content));
|
|
2722
2767
|
filesWritten.push(filepath);
|
|
2723
|
-
manifest.skills.push(skill.name);
|
|
2724
2768
|
}
|
|
2725
2769
|
}
|
|
2726
2770
|
if (pack.commands.length > 0) {
|
|
2727
2771
|
const commandsDir = join17(pluginDir, "commands");
|
|
2728
2772
|
ensureDir(commandsDir);
|
|
2729
|
-
manifest.commands =
|
|
2773
|
+
manifest.commands = "commands";
|
|
2730
2774
|
for (const cmd of pack.commands) {
|
|
2775
|
+
const fm = {
|
|
2776
|
+
name: cmd.name
|
|
2777
|
+
};
|
|
2778
|
+
if (cmd.meta.description) {
|
|
2779
|
+
fm.description = cmd.meta.description;
|
|
2780
|
+
}
|
|
2731
2781
|
const filename = `${cmd.name}.md`;
|
|
2732
2782
|
const filepath = join17(commandsDir, filename);
|
|
2733
|
-
writeFileSync4(filepath, cmd.content);
|
|
2783
|
+
writeFileSync4(filepath, serializeFrontmatter(fm, cmd.content));
|
|
2784
|
+
filesWritten.push(filepath);
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
if (pack.hooks) {
|
|
2788
|
+
const events = resolveHooksForTarget(pack.hooks, "cursor");
|
|
2789
|
+
if (Object.keys(events).length > 0) {
|
|
2790
|
+
const hooksDir = join17(pluginDir, "hooks");
|
|
2791
|
+
ensureDir(hooksDir);
|
|
2792
|
+
const filepath = join17(hooksDir, "hooks.json");
|
|
2793
|
+
writeFileSync4(filepath, JSON.stringify({ version: pack.hooks.version ?? 1, hooks: events }, null, 2) + `
|
|
2794
|
+
`);
|
|
2734
2795
|
filesWritten.push(filepath);
|
|
2735
|
-
manifest.
|
|
2796
|
+
manifest.hooks = "hooks/hooks.json";
|
|
2736
2797
|
}
|
|
2737
2798
|
}
|
|
2738
2799
|
if (pack.mcp && Object.keys(pack.mcp.servers).length > 0) {
|
|
2739
|
-
manifest.
|
|
2740
|
-
const filepath = join17(pluginDir, "mcp.json");
|
|
2800
|
+
manifest.mcpServers = ".mcp.json";
|
|
2801
|
+
const filepath = join17(pluginDir, ".mcp.json");
|
|
2741
2802
|
writeFileSync4(filepath, JSON.stringify({ mcpServers: pack.mcp.servers }, null, 2) + `
|
|
2742
2803
|
`);
|
|
2743
2804
|
filesWritten.push(filepath);
|
|
2744
2805
|
}
|
|
2745
|
-
const
|
|
2806
|
+
const manifestDir = join17(pluginDir, ".cursor-plugin");
|
|
2807
|
+
ensureDir(manifestDir);
|
|
2808
|
+
const manifestPath = join17(manifestDir, "plugin.json");
|
|
2746
2809
|
writeFileSync4(manifestPath, JSON.stringify(manifest, null, 2) + `
|
|
2747
2810
|
`);
|
|
2748
2811
|
filesWritten.push(manifestPath);
|
|
2749
2812
|
return { outputDir: pluginDir, filesWritten, manifest };
|
|
2750
2813
|
}
|
|
2814
|
+
function normalizeCursorPluginName(name) {
|
|
2815
|
+
const normalized = name.toLowerCase().replace(/[^a-z0-9.-]+/g, "-").replace(/-+/g, "-").replace(/^[^a-z0-9]+/, "").replace(/[^a-z0-9]+$/, "");
|
|
2816
|
+
return normalized.length > 0 ? normalized : "agentpacks-plugin";
|
|
2817
|
+
}
|
|
2818
|
+
function toCursorPluginAuthor(author) {
|
|
2819
|
+
if (!author) {
|
|
2820
|
+
return null;
|
|
2821
|
+
}
|
|
2822
|
+
if (typeof author === "string") {
|
|
2823
|
+
return { name: author };
|
|
2824
|
+
}
|
|
2825
|
+
return {
|
|
2826
|
+
name: author.name,
|
|
2827
|
+
...author.email ? { email: author.email } : {}
|
|
2828
|
+
};
|
|
2829
|
+
}
|
|
2751
2830
|
|
|
2752
2831
|
// src/importers/rulesync.ts
|
|
2753
2832
|
import { existsSync as existsSync10, readFileSync as readFileSync10, copyFileSync, writeFileSync as writeFileSync5 } from "fs";
|