agentpacks 1.7.5 → 1.7.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 +69 -742
- package/dist/api.d.ts +15 -15
- package/dist/api.js +2706 -2706
- package/dist/cli/export-cmd.js +364 -364
- package/dist/cli/generate.js +1409 -1409
- package/dist/cli/import-cmd.js +249 -249
- package/dist/cli/info.js +31 -31
- package/dist/cli/init.js +6 -6
- package/dist/cli/install.js +141 -141
- package/dist/cli/login.js +31 -31
- package/dist/cli/models-explain.js +514 -514
- package/dist/cli/pack/create.js +6 -6
- package/dist/cli/pack/enable.js +2 -2
- package/dist/cli/pack/list.js +362 -362
- package/dist/cli/pack/validate.js +119 -119
- package/dist/cli/publish.js +42 -42
- package/dist/cli/search.js +31 -31
- package/dist/core/config.js +3 -3
- package/dist/core/feature-merger.d.ts +5 -5
- package/dist/core/feature-merger.js +4 -4
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +633 -633
- package/dist/core/lockfile.js +1 -1
- package/dist/core/metarepo.js +3 -3
- package/dist/core/pack-loader.d.ts +6 -6
- package/dist/core/pack-loader.js +362 -362
- package/dist/core/profile-resolver.d.ts +1 -1
- package/dist/exporters/cursor-plugin.d.ts +12 -0
- package/dist/exporters/cursor-plugin.js +46 -46
- package/dist/exporters/index.d.ts +1 -1
- package/dist/exporters/index.js +46 -46
- package/dist/features/agents.js +4 -4
- package/dist/features/commands.js +4 -4
- package/dist/features/hooks.js +4 -4
- package/dist/features/index.d.ts +8 -8
- package/dist/features/index.js +350 -350
- package/dist/features/mcp.js +4 -4
- package/dist/features/models.js +4 -4
- package/dist/features/plugins.js +5 -5
- package/dist/features/rules.js +4 -4
- package/dist/features/skills.js +5 -5
- package/dist/importers/claude-code.js +6 -6
- package/dist/importers/cursor.js +7 -7
- package/dist/importers/opencode.js +7 -7
- package/dist/importers/rulesync.js +7 -7
- package/dist/index.js +2674 -2674
- package/dist/node/api.js +2706 -2706
- package/dist/node/cli/export-cmd.js +364 -364
- package/dist/node/cli/generate.js +1409 -1409
- package/dist/node/cli/import-cmd.js +249 -249
- package/dist/node/cli/info.js +31 -31
- package/dist/node/cli/init.js +6 -6
- package/dist/node/cli/install.js +141 -141
- package/dist/node/cli/login.js +31 -31
- package/dist/node/cli/models-explain.js +514 -514
- package/dist/node/cli/pack/create.js +6 -6
- package/dist/node/cli/pack/enable.js +2 -2
- package/dist/node/cli/pack/list.js +362 -362
- package/dist/node/cli/pack/validate.js +119 -119
- package/dist/node/cli/publish.js +42 -42
- package/dist/node/cli/search.js +31 -31
- package/dist/node/core/config.js +3 -3
- package/dist/node/core/feature-merger.js +4 -4
- package/dist/node/core/index.js +633 -633
- package/dist/node/core/lockfile.js +1 -1
- package/dist/node/core/metarepo.js +3 -3
- package/dist/node/core/pack-loader.js +362 -362
- package/dist/node/exporters/cursor-plugin.js +46 -46
- package/dist/node/exporters/index.js +46 -46
- package/dist/node/features/agents.js +4 -4
- package/dist/node/features/commands.js +4 -4
- package/dist/node/features/hooks.js +4 -4
- package/dist/node/features/index.js +350 -350
- package/dist/node/features/mcp.js +4 -4
- package/dist/node/features/models.js +4 -4
- package/dist/node/features/plugins.js +5 -5
- package/dist/node/features/rules.js +4 -4
- package/dist/node/features/skills.js +5 -5
- package/dist/node/importers/claude-code.js +6 -6
- package/dist/node/importers/cursor.js +7 -7
- package/dist/node/importers/opencode.js +7 -7
- package/dist/node/importers/rulesync.js +7 -7
- package/dist/node/index.js +2674 -2674
- package/dist/node/sources/git.js +2 -2
- package/dist/node/sources/index.js +138 -138
- package/dist/node/sources/local.js +1 -1
- package/dist/node/sources/npm.js +3 -3
- package/dist/node/sources/registry.js +35 -35
- package/dist/node/targets/additional-targets.js +43 -43
- package/dist/node/targets/agents-md.js +4 -4
- package/dist/node/targets/claude-code.js +86 -86
- package/dist/node/targets/codex-cli.js +6 -6
- package/dist/node/targets/copilot.js +46 -46
- package/dist/node/targets/cursor.js +68 -68
- package/dist/node/targets/gemini-cli.js +25 -25
- package/dist/node/targets/generic-md-target.js +43 -43
- package/dist/node/targets/index.js +911 -911
- package/dist/node/targets/mistral-vibe.js +46 -46
- package/dist/node/targets/opencode.js +68 -68
- package/dist/node/targets/registry.js +911 -911
- package/dist/node/utils/credentials.js +2 -2
- package/dist/node/utils/filesystem.js +4 -4
- package/dist/node/utils/global.js +1 -1
- package/dist/node/utils/tarball.js +2 -2
- package/dist/sources/git.js +2 -2
- package/dist/sources/index.d.ts +6 -6
- package/dist/sources/index.js +138 -138
- package/dist/sources/local.js +1 -1
- package/dist/sources/npm.d.ts +3 -0
- package/dist/sources/npm.js +3 -3
- package/dist/sources/registry.js +35 -35
- package/dist/targets/additional-targets.js +43 -43
- package/dist/targets/agents-md.js +4 -4
- package/dist/targets/claude-code.js +86 -86
- package/dist/targets/codex-cli.js +6 -6
- package/dist/targets/copilot.js +46 -46
- package/dist/targets/cursor.js +68 -68
- package/dist/targets/gemini-cli.js +25 -25
- package/dist/targets/generic-md-target.js +43 -43
- package/dist/targets/index.d.ts +6 -6
- package/dist/targets/index.js +911 -911
- package/dist/targets/mistral-vibe.js +46 -46
- package/dist/targets/opencode.js +68 -68
- package/dist/targets/registry.js +911 -911
- package/dist/utils/credentials.js +2 -2
- package/dist/utils/filesystem.js +4 -4
- package/dist/utils/global.d.ts +3 -0
- package/dist/utils/global.js +1 -1
- package/dist/utils/tarball.js +2 -2
- package/package.json +5 -5
- package/templates/pack/models.json +36 -36
- package/templates/pack/pack.json +8 -8
- package/templates/workspace/agentpacks.jsonc +24 -24
|
@@ -5,13 +5,13 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
5
5
|
import {
|
|
6
6
|
existsSync,
|
|
7
7
|
mkdirSync,
|
|
8
|
-
readFileSync,
|
|
9
|
-
writeFileSync,
|
|
10
8
|
readdirSync,
|
|
9
|
+
readFileSync,
|
|
11
10
|
rmSync,
|
|
12
|
-
statSync
|
|
11
|
+
statSync,
|
|
12
|
+
writeFileSync
|
|
13
13
|
} from "fs";
|
|
14
|
-
import { dirname,
|
|
14
|
+
import { dirname, join, relative } from "path";
|
|
15
15
|
var GENERATED_HEADER_MD = "<!-- Generated by agentpacks. DO NOT EDIT. -->";
|
|
16
16
|
var GENERATED_HEADER_JSON = "// Generated by agentpacks. DO NOT EDIT.";
|
|
17
17
|
var GENERATED_HEADER_JS = "// Generated by agentpacks. DO NOT EDIT.";
|
|
@@ -111,6 +111,175 @@ function getHeader(type) {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
// src/features/models.ts
|
|
115
|
+
import { join as join2 } from "path";
|
|
116
|
+
import { z } from "zod";
|
|
117
|
+
var SECRET_PATTERNS = [
|
|
118
|
+
/["']api[_-]?key["']\s*:/i,
|
|
119
|
+
/["']apiKey["']\s*:/i,
|
|
120
|
+
/["']secret["']\s*:/i,
|
|
121
|
+
/["']password["']\s*:/i,
|
|
122
|
+
/["'](?:auth_token|access_token|bearer_token)["']\s*:/i,
|
|
123
|
+
/["']private[_-]?key["']\s*:/i,
|
|
124
|
+
/-----BEGIN\s+(RSA|EC|DSA|OPENSSH|PGP)\s+PRIVATE\s+KEY-----/,
|
|
125
|
+
/sk-[a-zA-Z0-9]{20,}/,
|
|
126
|
+
/Bearer\s+[a-zA-Z0-9._-]{20,}/
|
|
127
|
+
];
|
|
128
|
+
var AgentModelSchema = z.object({
|
|
129
|
+
model: z.string(),
|
|
130
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
131
|
+
top_p: z.number().min(0).max(1).optional()
|
|
132
|
+
});
|
|
133
|
+
var ModelProfileSchema = z.object({
|
|
134
|
+
extends: z.string().optional(),
|
|
135
|
+
description: z.string().optional(),
|
|
136
|
+
default: z.string().optional(),
|
|
137
|
+
small: z.string().optional(),
|
|
138
|
+
agents: z.record(z.string(), AgentModelSchema).optional()
|
|
139
|
+
});
|
|
140
|
+
var RoutingConditionSchema = z.object({
|
|
141
|
+
complexity: z.enum(["low", "medium", "high", "critical"]).optional().describe("Task complexity level"),
|
|
142
|
+
urgency: z.enum(["low", "normal", "high"]).optional().describe("Time sensitivity"),
|
|
143
|
+
budget: z.enum(["minimal", "standard", "premium"]).optional().describe("Cost/token budget tier"),
|
|
144
|
+
contextWindowNeed: z.enum(["small", "medium", "large", "max"]).optional().describe("Required context window size"),
|
|
145
|
+
toolUseIntensity: z.enum(["none", "light", "heavy"]).optional().describe("Expected tool/function calling intensity")
|
|
146
|
+
});
|
|
147
|
+
var RoutingRuleSchema = z.object({
|
|
148
|
+
when: z.record(z.string(), z.string()),
|
|
149
|
+
use: z.string(),
|
|
150
|
+
description: z.string().optional(),
|
|
151
|
+
priority: z.number().optional()
|
|
152
|
+
});
|
|
153
|
+
var ProviderModelSchema = z.object({
|
|
154
|
+
options: z.record(z.string(), z.unknown()).optional(),
|
|
155
|
+
variants: z.record(z.string(), z.record(z.string(), z.unknown())).optional()
|
|
156
|
+
});
|
|
157
|
+
var ProviderConfigSchema = z.object({
|
|
158
|
+
options: z.record(z.string(), z.unknown()).optional(),
|
|
159
|
+
models: z.record(z.string(), ProviderModelSchema).optional()
|
|
160
|
+
});
|
|
161
|
+
var ModelsSchema = z.object({
|
|
162
|
+
default: z.string().optional(),
|
|
163
|
+
small: z.string().optional(),
|
|
164
|
+
agents: z.record(z.string(), AgentModelSchema).optional(),
|
|
165
|
+
profiles: z.record(z.string(), ModelProfileSchema).optional(),
|
|
166
|
+
providers: z.record(z.string(), ProviderConfigSchema).optional(),
|
|
167
|
+
routing: z.array(RoutingRuleSchema).optional(),
|
|
168
|
+
overrides: z.record(z.string(), z.object({
|
|
169
|
+
default: z.string().optional(),
|
|
170
|
+
small: z.string().optional(),
|
|
171
|
+
agents: z.record(z.string(), AgentModelSchema).optional()
|
|
172
|
+
})).optional()
|
|
173
|
+
});
|
|
174
|
+
function parseModels(packDir, packName) {
|
|
175
|
+
const modelsPath = join2(packDir, "models.json");
|
|
176
|
+
const raw = readJsonOrNull(modelsPath);
|
|
177
|
+
if (!raw)
|
|
178
|
+
return null;
|
|
179
|
+
const parsed = ModelsSchema.parse(raw);
|
|
180
|
+
return {
|
|
181
|
+
packName,
|
|
182
|
+
sourcePath: modelsPath,
|
|
183
|
+
config: parsed
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function mergeModelsConfigs(configs) {
|
|
187
|
+
const warnings = [];
|
|
188
|
+
const result = {};
|
|
189
|
+
for (const entry of configs) {
|
|
190
|
+
const { config, packName } = entry;
|
|
191
|
+
if (config.default !== undefined && result.default === undefined) {
|
|
192
|
+
result.default = config.default;
|
|
193
|
+
} else if (config.default !== undefined && result.default !== undefined) {
|
|
194
|
+
warnings.push(`Models "default" from pack "${packName}" skipped (already defined).`);
|
|
195
|
+
}
|
|
196
|
+
if (config.small !== undefined && result.small === undefined) {
|
|
197
|
+
result.small = config.small;
|
|
198
|
+
} else if (config.small !== undefined && result.small !== undefined) {
|
|
199
|
+
warnings.push(`Models "small" from pack "${packName}" skipped (already defined).`);
|
|
200
|
+
}
|
|
201
|
+
if (config.agents) {
|
|
202
|
+
if (!result.agents)
|
|
203
|
+
result.agents = {};
|
|
204
|
+
for (const [name, assignment] of Object.entries(config.agents)) {
|
|
205
|
+
if (name in result.agents) {
|
|
206
|
+
warnings.push(`Models agent "${name}" from pack "${packName}" skipped (already defined).`);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
result.agents[name] = assignment;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (config.profiles) {
|
|
213
|
+
if (!result.profiles)
|
|
214
|
+
result.profiles = {};
|
|
215
|
+
for (const [name, profile] of Object.entries(config.profiles)) {
|
|
216
|
+
if (name in result.profiles) {
|
|
217
|
+
warnings.push(`Models profile "${name}" from pack "${packName}" skipped (already defined).`);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
result.profiles[name] = profile;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (config.providers) {
|
|
224
|
+
if (!result.providers)
|
|
225
|
+
result.providers = {};
|
|
226
|
+
for (const [providerName, providerConfig] of Object.entries(config.providers)) {
|
|
227
|
+
if (!(providerName in result.providers)) {
|
|
228
|
+
result.providers[providerName] = providerConfig;
|
|
229
|
+
} else {
|
|
230
|
+
const existing = result.providers[providerName];
|
|
231
|
+
if (!existing) {
|
|
232
|
+
result.providers[providerName] = providerConfig;
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (providerConfig.options) {
|
|
236
|
+
existing.options = {
|
|
237
|
+
...providerConfig.options,
|
|
238
|
+
...existing.options
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
if (providerConfig.models) {
|
|
242
|
+
if (!existing.models)
|
|
243
|
+
existing.models = {};
|
|
244
|
+
for (const [modelName, modelConfig] of Object.entries(providerConfig.models)) {
|
|
245
|
+
if (!(modelName in existing.models)) {
|
|
246
|
+
existing.models[modelName] = modelConfig;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (config.routing) {
|
|
254
|
+
if (!result.routing)
|
|
255
|
+
result.routing = [];
|
|
256
|
+
result.routing.push(...config.routing);
|
|
257
|
+
}
|
|
258
|
+
if (config.overrides) {
|
|
259
|
+
if (!result.overrides)
|
|
260
|
+
result.overrides = {};
|
|
261
|
+
for (const [targetId, override] of Object.entries(config.overrides)) {
|
|
262
|
+
if (targetId in result.overrides) {
|
|
263
|
+
warnings.push(`Models override for target "${targetId}" from pack "${packName}" skipped (already defined).`);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
result.overrides[targetId] = override;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return { config: result, warnings };
|
|
271
|
+
}
|
|
272
|
+
function scanModelsForSecrets(config) {
|
|
273
|
+
const warnings = [];
|
|
274
|
+
const json = JSON.stringify(config);
|
|
275
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
276
|
+
if (pattern.test(json)) {
|
|
277
|
+
warnings.push(`Potential secret detected in models.json matching pattern: ${pattern.source}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return warnings;
|
|
281
|
+
}
|
|
282
|
+
|
|
114
283
|
// src/utils/frontmatter.ts
|
|
115
284
|
import matter from "gray-matter";
|
|
116
285
|
function parseFrontmatter(source) {
|
|
@@ -129,38 +298,32 @@ function serializeFrontmatter(data, content) {
|
|
|
129
298
|
return matter.stringify(content, filtered);
|
|
130
299
|
}
|
|
131
300
|
|
|
132
|
-
// src/features/
|
|
301
|
+
// src/features/agents.ts
|
|
133
302
|
import { readFileSync as readFileSync2 } from "fs";
|
|
134
303
|
import { basename } from "path";
|
|
135
|
-
function
|
|
136
|
-
const files = listFiles(
|
|
137
|
-
return files.map((filepath) =>
|
|
304
|
+
function parseAgents(agentsDir, packName) {
|
|
305
|
+
const files = listFiles(agentsDir, { extension: ".md" });
|
|
306
|
+
return files.map((filepath) => parseAgentFile(filepath, packName));
|
|
138
307
|
}
|
|
139
|
-
function
|
|
308
|
+
function parseAgentFile(filepath, packName) {
|
|
140
309
|
const raw = readFileSync2(filepath, "utf-8");
|
|
141
310
|
const { data, content } = parseFrontmatter(raw);
|
|
142
311
|
return {
|
|
143
|
-
name: basename(filepath, ".md"),
|
|
312
|
+
name: data.name ?? basename(filepath, ".md"),
|
|
144
313
|
sourcePath: filepath,
|
|
145
314
|
packName,
|
|
146
315
|
meta: data,
|
|
147
316
|
content
|
|
148
317
|
};
|
|
149
318
|
}
|
|
150
|
-
function
|
|
151
|
-
const { targets } =
|
|
319
|
+
function agentMatchesTarget(agent, targetId) {
|
|
320
|
+
const { targets } = agent.meta;
|
|
152
321
|
if (!targets || targets === "*")
|
|
153
322
|
return true;
|
|
154
323
|
if (Array.isArray(targets) && targets.includes("*"))
|
|
155
324
|
return true;
|
|
156
325
|
return Array.isArray(targets) && targets.includes(targetId);
|
|
157
326
|
}
|
|
158
|
-
function getRootRules(rules) {
|
|
159
|
-
return rules.filter((r) => r.meta.root === true);
|
|
160
|
-
}
|
|
161
|
-
function getDetailRules(rules) {
|
|
162
|
-
return rules.filter((r) => r.meta.root !== true);
|
|
163
|
-
}
|
|
164
327
|
|
|
165
328
|
// src/features/commands.ts
|
|
166
329
|
import { readFileSync as readFileSync3 } from "fs";
|
|
@@ -189,54 +352,187 @@ function commandMatchesTarget(cmd, targetId) {
|
|
|
189
352
|
return Array.isArray(targets) && targets.includes(targetId);
|
|
190
353
|
}
|
|
191
354
|
|
|
192
|
-
// src/features/
|
|
193
|
-
import {
|
|
194
|
-
|
|
195
|
-
function
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
const
|
|
355
|
+
// src/features/hooks.ts
|
|
356
|
+
import { join as join3 } from "path";
|
|
357
|
+
var TARGET_OVERRIDE_KEYS = ["cursor", "claudecode", "opencode"];
|
|
358
|
+
function parseHooks(packDir, packName) {
|
|
359
|
+
const hooksPath = join3(packDir, "hooks", "hooks.json");
|
|
360
|
+
const raw = readJsonOrNull(hooksPath);
|
|
361
|
+
if (!raw)
|
|
362
|
+
return null;
|
|
363
|
+
const shared = raw.hooks ?? {};
|
|
364
|
+
const targetOverrides = {};
|
|
365
|
+
for (const key of TARGET_OVERRIDE_KEYS) {
|
|
366
|
+
const override = raw[key];
|
|
367
|
+
if (override && typeof override === "object" && "hooks" in override && override.hooks) {
|
|
368
|
+
targetOverrides[key] = override.hooks;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
202
371
|
return {
|
|
203
|
-
name: data.name ?? basename3(filepath, ".md"),
|
|
204
|
-
sourcePath: filepath,
|
|
205
372
|
packName,
|
|
206
|
-
|
|
207
|
-
|
|
373
|
+
sourcePath: hooksPath,
|
|
374
|
+
version: raw.version,
|
|
375
|
+
shared,
|
|
376
|
+
targetOverrides
|
|
208
377
|
};
|
|
209
378
|
}
|
|
210
|
-
function
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
379
|
+
function resolveHooksForTarget(hooks, targetId) {
|
|
380
|
+
const merged = {};
|
|
381
|
+
for (const [event, entries] of Object.entries(hooks.shared)) {
|
|
382
|
+
merged[event] = [...entries];
|
|
383
|
+
}
|
|
384
|
+
const overrides = hooks.targetOverrides[targetId];
|
|
385
|
+
if (overrides) {
|
|
386
|
+
for (const [event, entries] of Object.entries(overrides)) {
|
|
387
|
+
merged[event] = [...merged[event] ?? [], ...entries];
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return merged;
|
|
217
391
|
}
|
|
218
392
|
|
|
219
|
-
// src/features/
|
|
220
|
-
import {
|
|
221
|
-
import {
|
|
222
|
-
var
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
393
|
+
// src/features/ignore.ts
|
|
394
|
+
import { existsSync as existsSync2, readFileSync as readFileSync4 } from "fs";
|
|
395
|
+
import { join as join4 } from "path";
|
|
396
|
+
var IGNORE_FILES = ["ignore", ".aiignore"];
|
|
397
|
+
function parseIgnore(packDir, packName) {
|
|
398
|
+
for (const filename of IGNORE_FILES) {
|
|
399
|
+
const filepath = join4(packDir, filename);
|
|
400
|
+
if (existsSync2(filepath)) {
|
|
401
|
+
const raw = readFileSync4(filepath, "utf-8");
|
|
402
|
+
const patterns = parseIgnoreContent(raw);
|
|
403
|
+
return {
|
|
404
|
+
packName,
|
|
405
|
+
sourcePath: filepath,
|
|
406
|
+
patterns
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
function parseIgnoreContent(content) {
|
|
413
|
+
return content.split(`
|
|
414
|
+
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
415
|
+
}
|
|
416
|
+
function mergeIgnorePatterns(configs) {
|
|
417
|
+
const seen = new Set;
|
|
418
|
+
const result = [];
|
|
419
|
+
for (const config of configs) {
|
|
420
|
+
for (const pattern of config.patterns) {
|
|
421
|
+
if (!seen.has(pattern)) {
|
|
422
|
+
seen.add(pattern);
|
|
423
|
+
result.push(pattern);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return result;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// src/features/mcp.ts
|
|
431
|
+
import { join as join5 } from "path";
|
|
432
|
+
function parseMcp(packDir, packName) {
|
|
433
|
+
const mcpPath = join5(packDir, "mcp.json");
|
|
434
|
+
const raw = readJsonOrNull(mcpPath);
|
|
435
|
+
if (!raw?.mcpServers)
|
|
436
|
+
return null;
|
|
437
|
+
return {
|
|
438
|
+
packName,
|
|
439
|
+
sourcePath: mcpPath,
|
|
440
|
+
servers: raw.mcpServers
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function mergeMcpConfigs(configs) {
|
|
444
|
+
const servers = {};
|
|
445
|
+
const warnings = [];
|
|
446
|
+
for (const config of configs) {
|
|
447
|
+
for (const [name, entry] of Object.entries(config.servers)) {
|
|
448
|
+
if (name in servers) {
|
|
449
|
+
warnings.push(`MCP server "${name}" from pack "${config.packName}" skipped (already defined).`);
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
servers[name] = entry;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return { servers, warnings };
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// src/features/plugins.ts
|
|
459
|
+
import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
|
|
460
|
+
import { basename as basename3, join as join6 } from "path";
|
|
461
|
+
function parsePlugins(packDir, packName) {
|
|
462
|
+
const pluginsDir = join6(packDir, "plugins");
|
|
463
|
+
if (!existsSync3(pluginsDir))
|
|
464
|
+
return [];
|
|
465
|
+
const tsFiles = listFiles(pluginsDir, { extension: ".ts" });
|
|
466
|
+
const jsFiles = listFiles(pluginsDir, { extension: ".js" });
|
|
467
|
+
const allFiles = [...tsFiles, ...jsFiles];
|
|
468
|
+
return allFiles.map((filepath) => parsePluginFile(filepath, packName));
|
|
469
|
+
}
|
|
470
|
+
function parsePluginFile(filepath, packName) {
|
|
471
|
+
const content = readFileSync5(filepath, "utf-8");
|
|
472
|
+
const ext = filepath.endsWith(".ts") ? "ts" : "js";
|
|
473
|
+
return {
|
|
474
|
+
name: basename3(filepath, `.${ext}`),
|
|
475
|
+
sourcePath: filepath,
|
|
476
|
+
packName,
|
|
477
|
+
content,
|
|
478
|
+
extension: ext
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// src/features/rules.ts
|
|
483
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
484
|
+
import { basename as basename4 } from "path";
|
|
485
|
+
function parseRules(rulesDir, packName) {
|
|
486
|
+
const files = listFiles(rulesDir, { extension: ".md" });
|
|
487
|
+
return files.map((filepath) => parseRuleFile(filepath, packName));
|
|
488
|
+
}
|
|
489
|
+
function parseRuleFile(filepath, packName) {
|
|
490
|
+
const raw = readFileSync6(filepath, "utf-8");
|
|
491
|
+
const { data, content } = parseFrontmatter(raw);
|
|
492
|
+
return {
|
|
493
|
+
name: basename4(filepath, ".md"),
|
|
494
|
+
sourcePath: filepath,
|
|
495
|
+
packName,
|
|
496
|
+
meta: data,
|
|
497
|
+
content
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
function ruleMatchesTarget(rule, targetId) {
|
|
501
|
+
const { targets } = rule.meta;
|
|
502
|
+
if (!targets || targets === "*")
|
|
503
|
+
return true;
|
|
504
|
+
if (Array.isArray(targets) && targets.includes("*"))
|
|
505
|
+
return true;
|
|
506
|
+
return Array.isArray(targets) && targets.includes(targetId);
|
|
507
|
+
}
|
|
508
|
+
function getRootRules(rules) {
|
|
509
|
+
return rules.filter((r) => r.meta.root === true);
|
|
510
|
+
}
|
|
511
|
+
function getDetailRules(rules) {
|
|
512
|
+
return rules.filter((r) => r.meta.root !== true);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// src/features/skills.ts
|
|
516
|
+
import { existsSync as existsSync4, readFileSync as readFileSync7 } from "fs";
|
|
517
|
+
import { basename as basename5, join as join7 } from "path";
|
|
518
|
+
var SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
519
|
+
var SKILL_NAME_MAX_LENGTH = 64;
|
|
520
|
+
function parseSkills(skillsDir, packName) {
|
|
521
|
+
const dirs = listDirs(skillsDir);
|
|
522
|
+
const skills = [];
|
|
523
|
+
for (const dir of dirs) {
|
|
524
|
+
const skillMd = join7(dir, "SKILL.md");
|
|
525
|
+
if (existsSync4(skillMd)) {
|
|
526
|
+
skills.push(parseSkillFile(skillMd, dir, packName));
|
|
231
527
|
}
|
|
232
528
|
}
|
|
233
529
|
return skills;
|
|
234
530
|
}
|
|
235
531
|
function parseSkillFile(filepath, skillDir, packName) {
|
|
236
|
-
const raw =
|
|
532
|
+
const raw = readFileSync7(filepath, "utf-8");
|
|
237
533
|
const { data, content } = parseFrontmatter(raw);
|
|
238
534
|
return {
|
|
239
|
-
name: data.name ??
|
|
535
|
+
name: data.name ?? basename5(skillDir),
|
|
240
536
|
sourcePath: filepath,
|
|
241
537
|
sourceDir: skillDir,
|
|
242
538
|
packName,
|
|
@@ -272,7 +568,7 @@ function normalizeImportedSkillMarkdown(source, skillName) {
|
|
|
272
568
|
}
|
|
273
569
|
function validateAgentSkillsFrontmatter(skill) {
|
|
274
570
|
const errors = [];
|
|
275
|
-
const dirName =
|
|
571
|
+
const dirName = basename5(skill.sourceDir);
|
|
276
572
|
const declaredName = skill.meta.name;
|
|
277
573
|
if (typeof declaredName !== "string" || declaredName.trim().length === 0) {
|
|
278
574
|
errors.push('Missing required frontmatter field "name".');
|
|
@@ -305,302 +601,6 @@ function skillMatchesTarget(skill, targetId) {
|
|
|
305
601
|
return true;
|
|
306
602
|
return Array.isArray(targets) && targets.includes(targetId);
|
|
307
603
|
}
|
|
308
|
-
|
|
309
|
-
// src/features/hooks.ts
|
|
310
|
-
import { join as join3 } from "path";
|
|
311
|
-
var TARGET_OVERRIDE_KEYS = ["cursor", "claudecode", "opencode"];
|
|
312
|
-
function parseHooks(packDir, packName) {
|
|
313
|
-
const hooksPath = join3(packDir, "hooks", "hooks.json");
|
|
314
|
-
const raw = readJsonOrNull(hooksPath);
|
|
315
|
-
if (!raw)
|
|
316
|
-
return null;
|
|
317
|
-
const shared = raw.hooks ?? {};
|
|
318
|
-
const targetOverrides = {};
|
|
319
|
-
for (const key of TARGET_OVERRIDE_KEYS) {
|
|
320
|
-
const override = raw[key];
|
|
321
|
-
if (override && typeof override === "object" && "hooks" in override && override.hooks) {
|
|
322
|
-
targetOverrides[key] = override.hooks;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
return {
|
|
326
|
-
packName,
|
|
327
|
-
sourcePath: hooksPath,
|
|
328
|
-
version: raw.version,
|
|
329
|
-
shared,
|
|
330
|
-
targetOverrides
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
function resolveHooksForTarget(hooks, targetId) {
|
|
334
|
-
const merged = {};
|
|
335
|
-
for (const [event, entries] of Object.entries(hooks.shared)) {
|
|
336
|
-
merged[event] = [...entries];
|
|
337
|
-
}
|
|
338
|
-
const overrides = hooks.targetOverrides[targetId];
|
|
339
|
-
if (overrides) {
|
|
340
|
-
for (const [event, entries] of Object.entries(overrides)) {
|
|
341
|
-
merged[event] = [...merged[event] ?? [], ...entries];
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
return merged;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// src/features/plugins.ts
|
|
348
|
-
import { readFileSync as readFileSync6, existsSync as existsSync3 } from "fs";
|
|
349
|
-
import { basename as basename5, join as join4 } from "path";
|
|
350
|
-
function parsePlugins(packDir, packName) {
|
|
351
|
-
const pluginsDir = join4(packDir, "plugins");
|
|
352
|
-
if (!existsSync3(pluginsDir))
|
|
353
|
-
return [];
|
|
354
|
-
const tsFiles = listFiles(pluginsDir, { extension: ".ts" });
|
|
355
|
-
const jsFiles = listFiles(pluginsDir, { extension: ".js" });
|
|
356
|
-
const allFiles = [...tsFiles, ...jsFiles];
|
|
357
|
-
return allFiles.map((filepath) => parsePluginFile(filepath, packName));
|
|
358
|
-
}
|
|
359
|
-
function parsePluginFile(filepath, packName) {
|
|
360
|
-
const content = readFileSync6(filepath, "utf-8");
|
|
361
|
-
const ext = filepath.endsWith(".ts") ? "ts" : "js";
|
|
362
|
-
return {
|
|
363
|
-
name: basename5(filepath, `.${ext}`),
|
|
364
|
-
sourcePath: filepath,
|
|
365
|
-
packName,
|
|
366
|
-
content,
|
|
367
|
-
extension: ext
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// src/features/mcp.ts
|
|
372
|
-
import { join as join5 } from "path";
|
|
373
|
-
function parseMcp(packDir, packName) {
|
|
374
|
-
const mcpPath = join5(packDir, "mcp.json");
|
|
375
|
-
const raw = readJsonOrNull(mcpPath);
|
|
376
|
-
if (!raw?.mcpServers)
|
|
377
|
-
return null;
|
|
378
|
-
return {
|
|
379
|
-
packName,
|
|
380
|
-
sourcePath: mcpPath,
|
|
381
|
-
servers: raw.mcpServers
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
function mergeMcpConfigs(configs) {
|
|
385
|
-
const servers = {};
|
|
386
|
-
const warnings = [];
|
|
387
|
-
for (const config of configs) {
|
|
388
|
-
for (const [name, entry] of Object.entries(config.servers)) {
|
|
389
|
-
if (name in servers) {
|
|
390
|
-
warnings.push(`MCP server "${name}" from pack "${config.packName}" skipped (already defined).`);
|
|
391
|
-
continue;
|
|
392
|
-
}
|
|
393
|
-
servers[name] = entry;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
return { servers, warnings };
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
// src/features/ignore.ts
|
|
400
|
-
import { existsSync as existsSync4, readFileSync as readFileSync7 } from "fs";
|
|
401
|
-
import { join as join6 } from "path";
|
|
402
|
-
var IGNORE_FILES = ["ignore", ".aiignore"];
|
|
403
|
-
function parseIgnore(packDir, packName) {
|
|
404
|
-
for (const filename of IGNORE_FILES) {
|
|
405
|
-
const filepath = join6(packDir, filename);
|
|
406
|
-
if (existsSync4(filepath)) {
|
|
407
|
-
const raw = readFileSync7(filepath, "utf-8");
|
|
408
|
-
const patterns = parseIgnoreContent(raw);
|
|
409
|
-
return {
|
|
410
|
-
packName,
|
|
411
|
-
sourcePath: filepath,
|
|
412
|
-
patterns
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
return null;
|
|
417
|
-
}
|
|
418
|
-
function parseIgnoreContent(content) {
|
|
419
|
-
return content.split(`
|
|
420
|
-
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
421
|
-
}
|
|
422
|
-
function mergeIgnorePatterns(configs) {
|
|
423
|
-
const seen = new Set;
|
|
424
|
-
const result = [];
|
|
425
|
-
for (const config of configs) {
|
|
426
|
-
for (const pattern of config.patterns) {
|
|
427
|
-
if (!seen.has(pattern)) {
|
|
428
|
-
seen.add(pattern);
|
|
429
|
-
result.push(pattern);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
return result;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// src/features/models.ts
|
|
437
|
-
import { join as join7 } from "path";
|
|
438
|
-
import { z } from "zod";
|
|
439
|
-
var SECRET_PATTERNS = [
|
|
440
|
-
/["']api[_-]?key["']\s*:/i,
|
|
441
|
-
/["']apiKey["']\s*:/i,
|
|
442
|
-
/["']secret["']\s*:/i,
|
|
443
|
-
/["']password["']\s*:/i,
|
|
444
|
-
/["'](?:auth_token|access_token|bearer_token)["']\s*:/i,
|
|
445
|
-
/["']private[_-]?key["']\s*:/i,
|
|
446
|
-
/-----BEGIN\s+(RSA|EC|DSA|OPENSSH|PGP)\s+PRIVATE\s+KEY-----/,
|
|
447
|
-
/sk-[a-zA-Z0-9]{20,}/,
|
|
448
|
-
/Bearer\s+[a-zA-Z0-9._-]{20,}/
|
|
449
|
-
];
|
|
450
|
-
var AgentModelSchema = z.object({
|
|
451
|
-
model: z.string(),
|
|
452
|
-
temperature: z.number().min(0).max(2).optional(),
|
|
453
|
-
top_p: z.number().min(0).max(1).optional()
|
|
454
|
-
});
|
|
455
|
-
var ModelProfileSchema = z.object({
|
|
456
|
-
extends: z.string().optional(),
|
|
457
|
-
description: z.string().optional(),
|
|
458
|
-
default: z.string().optional(),
|
|
459
|
-
small: z.string().optional(),
|
|
460
|
-
agents: z.record(z.string(), AgentModelSchema).optional()
|
|
461
|
-
});
|
|
462
|
-
var RoutingConditionSchema = z.object({
|
|
463
|
-
complexity: z.enum(["low", "medium", "high", "critical"]).optional().describe("Task complexity level"),
|
|
464
|
-
urgency: z.enum(["low", "normal", "high"]).optional().describe("Time sensitivity"),
|
|
465
|
-
budget: z.enum(["minimal", "standard", "premium"]).optional().describe("Cost/token budget tier"),
|
|
466
|
-
contextWindowNeed: z.enum(["small", "medium", "large", "max"]).optional().describe("Required context window size"),
|
|
467
|
-
toolUseIntensity: z.enum(["none", "light", "heavy"]).optional().describe("Expected tool/function calling intensity")
|
|
468
|
-
});
|
|
469
|
-
var RoutingRuleSchema = z.object({
|
|
470
|
-
when: z.record(z.string(), z.string()),
|
|
471
|
-
use: z.string(),
|
|
472
|
-
description: z.string().optional(),
|
|
473
|
-
priority: z.number().optional()
|
|
474
|
-
});
|
|
475
|
-
var ProviderModelSchema = z.object({
|
|
476
|
-
options: z.record(z.string(), z.unknown()).optional(),
|
|
477
|
-
variants: z.record(z.string(), z.record(z.string(), z.unknown())).optional()
|
|
478
|
-
});
|
|
479
|
-
var ProviderConfigSchema = z.object({
|
|
480
|
-
options: z.record(z.string(), z.unknown()).optional(),
|
|
481
|
-
models: z.record(z.string(), ProviderModelSchema).optional()
|
|
482
|
-
});
|
|
483
|
-
var ModelsSchema = z.object({
|
|
484
|
-
default: z.string().optional(),
|
|
485
|
-
small: z.string().optional(),
|
|
486
|
-
agents: z.record(z.string(), AgentModelSchema).optional(),
|
|
487
|
-
profiles: z.record(z.string(), ModelProfileSchema).optional(),
|
|
488
|
-
providers: z.record(z.string(), ProviderConfigSchema).optional(),
|
|
489
|
-
routing: z.array(RoutingRuleSchema).optional(),
|
|
490
|
-
overrides: z.record(z.string(), z.object({
|
|
491
|
-
default: z.string().optional(),
|
|
492
|
-
small: z.string().optional(),
|
|
493
|
-
agents: z.record(z.string(), AgentModelSchema).optional()
|
|
494
|
-
})).optional()
|
|
495
|
-
});
|
|
496
|
-
function parseModels(packDir, packName) {
|
|
497
|
-
const modelsPath = join7(packDir, "models.json");
|
|
498
|
-
const raw = readJsonOrNull(modelsPath);
|
|
499
|
-
if (!raw)
|
|
500
|
-
return null;
|
|
501
|
-
const parsed = ModelsSchema.parse(raw);
|
|
502
|
-
return {
|
|
503
|
-
packName,
|
|
504
|
-
sourcePath: modelsPath,
|
|
505
|
-
config: parsed
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
function mergeModelsConfigs(configs) {
|
|
509
|
-
const warnings = [];
|
|
510
|
-
const result = {};
|
|
511
|
-
for (const entry of configs) {
|
|
512
|
-
const { config, packName } = entry;
|
|
513
|
-
if (config.default !== undefined && result.default === undefined) {
|
|
514
|
-
result.default = config.default;
|
|
515
|
-
} else if (config.default !== undefined && result.default !== undefined) {
|
|
516
|
-
warnings.push(`Models "default" from pack "${packName}" skipped (already defined).`);
|
|
517
|
-
}
|
|
518
|
-
if (config.small !== undefined && result.small === undefined) {
|
|
519
|
-
result.small = config.small;
|
|
520
|
-
} else if (config.small !== undefined && result.small !== undefined) {
|
|
521
|
-
warnings.push(`Models "small" from pack "${packName}" skipped (already defined).`);
|
|
522
|
-
}
|
|
523
|
-
if (config.agents) {
|
|
524
|
-
if (!result.agents)
|
|
525
|
-
result.agents = {};
|
|
526
|
-
for (const [name, assignment] of Object.entries(config.agents)) {
|
|
527
|
-
if (name in result.agents) {
|
|
528
|
-
warnings.push(`Models agent "${name}" from pack "${packName}" skipped (already defined).`);
|
|
529
|
-
continue;
|
|
530
|
-
}
|
|
531
|
-
result.agents[name] = assignment;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
if (config.profiles) {
|
|
535
|
-
if (!result.profiles)
|
|
536
|
-
result.profiles = {};
|
|
537
|
-
for (const [name, profile] of Object.entries(config.profiles)) {
|
|
538
|
-
if (name in result.profiles) {
|
|
539
|
-
warnings.push(`Models profile "${name}" from pack "${packName}" skipped (already defined).`);
|
|
540
|
-
continue;
|
|
541
|
-
}
|
|
542
|
-
result.profiles[name] = profile;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
if (config.providers) {
|
|
546
|
-
if (!result.providers)
|
|
547
|
-
result.providers = {};
|
|
548
|
-
for (const [providerName, providerConfig] of Object.entries(config.providers)) {
|
|
549
|
-
if (!(providerName in result.providers)) {
|
|
550
|
-
result.providers[providerName] = providerConfig;
|
|
551
|
-
} else {
|
|
552
|
-
const existing = result.providers[providerName];
|
|
553
|
-
if (!existing) {
|
|
554
|
-
result.providers[providerName] = providerConfig;
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
if (providerConfig.options) {
|
|
558
|
-
existing.options = {
|
|
559
|
-
...providerConfig.options,
|
|
560
|
-
...existing.options
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
if (providerConfig.models) {
|
|
564
|
-
if (!existing.models)
|
|
565
|
-
existing.models = {};
|
|
566
|
-
for (const [modelName, modelConfig] of Object.entries(providerConfig.models)) {
|
|
567
|
-
if (!(modelName in existing.models)) {
|
|
568
|
-
existing.models[modelName] = modelConfig;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
if (config.routing) {
|
|
576
|
-
if (!result.routing)
|
|
577
|
-
result.routing = [];
|
|
578
|
-
result.routing.push(...config.routing);
|
|
579
|
-
}
|
|
580
|
-
if (config.overrides) {
|
|
581
|
-
if (!result.overrides)
|
|
582
|
-
result.overrides = {};
|
|
583
|
-
for (const [targetId, override] of Object.entries(config.overrides)) {
|
|
584
|
-
if (targetId in result.overrides) {
|
|
585
|
-
warnings.push(`Models override for target "${targetId}" from pack "${packName}" skipped (already defined).`);
|
|
586
|
-
continue;
|
|
587
|
-
}
|
|
588
|
-
result.overrides[targetId] = override;
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
return { config: result, warnings };
|
|
593
|
-
}
|
|
594
|
-
function scanModelsForSecrets(config) {
|
|
595
|
-
const warnings = [];
|
|
596
|
-
const json = JSON.stringify(config);
|
|
597
|
-
for (const pattern of SECRET_PATTERNS) {
|
|
598
|
-
if (pattern.test(json)) {
|
|
599
|
-
warnings.push(`Potential secret detected in models.json matching pattern: ${pattern.source}`);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
return warnings;
|
|
603
|
-
}
|
|
604
604
|
export {
|
|
605
605
|
validateAgentSkillsFrontmatter,
|
|
606
606
|
skillMatchesTarget,
|