agentpacks 0.3.0 → 0.4.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 +168 -8
- package/dist/api.d.ts +2 -0
- package/dist/api.js +929 -409
- package/dist/cli/export-cmd.js +281 -149
- package/dist/cli/generate.js +740 -247
- package/dist/cli/import-cmd.js +57 -85
- package/dist/cli/info.d.ts +4 -0
- package/dist/cli/info.js +232 -0
- package/dist/cli/init.js +8 -36
- package/dist/cli/install.js +414 -129
- package/dist/cli/login.d.ts +9 -0
- package/dist/cli/login.js +202 -0
- package/dist/cli/models-explain.d.ts +16 -0
- package/dist/cli/models-explain.js +1205 -0
- package/dist/cli/pack/create.js +4 -32
- package/dist/cli/pack/enable.js +1 -29
- package/dist/cli/pack/list.js +266 -134
- package/dist/cli/pack/validate.js +274 -127
- package/dist/cli/publish.d.ts +8 -0
- package/dist/cli/publish.js +672 -0
- package/dist/cli/search.d.ts +12 -0
- package/dist/cli/search.js +210 -0
- package/dist/core/config.d.ts +2 -1
- package/dist/core/config.js +74 -117
- package/dist/core/dependency-resolver.js +4 -28
- package/dist/core/feature-merger.d.ts +7 -0
- package/dist/core/feature-merger.js +289 -29
- package/dist/core/index.js +283 -140
- package/dist/core/lockfile.js +0 -28
- package/dist/core/metarepo.js +74 -116
- package/dist/core/pack-loader.d.ts +2 -0
- package/dist/core/pack-loader.js +266 -133
- package/dist/core/profile-resolver.d.ts +75 -0
- package/dist/core/profile-resolver.js +111 -0
- package/dist/exporters/cursor-plugin.js +4 -32
- package/dist/exporters/index.js +4 -32
- package/dist/features/agents.d.ts +5 -0
- package/dist/features/agents.js +2 -30
- package/dist/features/commands.js +2 -30
- package/dist/features/hooks.js +2 -30
- package/dist/features/ignore.js +0 -28
- package/dist/features/index.d.ts +1 -0
- package/dist/features/index.js +176 -31
- package/dist/features/mcp.js +2 -30
- package/dist/features/models.d.ts +167 -0
- package/dist/features/models.js +293 -0
- package/dist/features/plugins.js +2 -30
- package/dist/features/rules.js +2 -30
- package/dist/features/skills.js +2 -30
- package/dist/importers/claude-code.js +10 -38
- package/dist/importers/cursor.js +15 -43
- package/dist/importers/opencode.js +16 -44
- package/dist/importers/rulesync.js +22 -50
- package/dist/index.js +1710 -538
- package/dist/node/api.js +929 -409
- package/dist/node/cli/export-cmd.js +281 -149
- package/dist/node/cli/generate.js +740 -247
- package/dist/node/cli/import-cmd.js +57 -85
- package/dist/node/cli/info.js +232 -0
- package/dist/node/cli/init.js +8 -36
- package/dist/node/cli/install.js +414 -129
- package/dist/node/cli/login.js +202 -0
- package/dist/node/cli/models-explain.js +1205 -0
- package/dist/node/cli/pack/create.js +4 -32
- package/dist/node/cli/pack/enable.js +1 -29
- package/dist/node/cli/pack/list.js +266 -134
- package/dist/node/cli/pack/validate.js +274 -127
- package/dist/node/cli/publish.js +672 -0
- package/dist/node/cli/search.js +210 -0
- package/dist/node/core/config.js +74 -117
- package/dist/node/core/dependency-resolver.js +4 -28
- package/dist/node/core/feature-merger.js +289 -29
- package/dist/node/core/index.js +283 -140
- package/dist/node/core/lockfile.js +0 -28
- package/dist/node/core/metarepo.js +74 -116
- package/dist/node/core/pack-loader.js +266 -133
- package/dist/node/core/profile-resolver.js +111 -0
- package/dist/node/exporters/cursor-plugin.js +4 -32
- package/dist/node/exporters/index.js +4 -32
- package/dist/node/features/agents.js +2 -30
- package/dist/node/features/commands.js +2 -30
- package/dist/node/features/hooks.js +2 -30
- package/dist/node/features/ignore.js +0 -28
- package/dist/node/features/index.js +176 -31
- package/dist/node/features/mcp.js +2 -30
- package/dist/node/features/models.js +293 -0
- package/dist/node/features/plugins.js +2 -30
- package/dist/node/features/rules.js +2 -30
- package/dist/node/features/skills.js +2 -30
- package/dist/node/importers/claude-code.js +10 -38
- package/dist/node/importers/cursor.js +15 -43
- package/dist/node/importers/opencode.js +16 -44
- package/dist/node/importers/rulesync.js +22 -50
- package/dist/node/index.js +1710 -538
- package/dist/node/sources/git-ref.js +7 -30
- package/dist/node/sources/git.js +7 -30
- package/dist/node/sources/index.js +337 -39
- package/dist/node/sources/local.js +0 -28
- package/dist/node/sources/npm-ref.js +0 -28
- package/dist/node/sources/npm.js +10 -37
- package/dist/node/sources/registry-ref.js +37 -0
- package/dist/node/sources/registry.js +355 -0
- package/dist/node/targets/additional-targets.js +196 -37
- package/dist/node/targets/agents-md.js +5 -33
- package/dist/node/targets/base-target.js +0 -28
- package/dist/node/targets/claude-code.js +211 -41
- package/dist/node/targets/codex-cli.js +7 -35
- package/dist/node/targets/copilot.js +202 -41
- package/dist/node/targets/cursor.js +188 -40
- package/dist/node/targets/gemini-cli.js +10 -38
- package/dist/node/targets/generic-md-target.js +196 -37
- package/dist/node/targets/index.js +414 -106
- package/dist/node/targets/opencode.js +171 -51
- package/dist/node/targets/registry.js +414 -106
- package/dist/node/utils/credentials.js +38 -0
- package/dist/node/utils/diff.js +22 -34
- package/dist/node/utils/filesystem.js +2 -30
- package/dist/node/utils/frontmatter.js +0 -28
- package/dist/node/utils/global.js +3 -31
- package/dist/node/utils/markdown.js +0 -28
- package/dist/node/utils/model-allowlist.js +110 -0
- package/dist/node/utils/model-guidance.js +78 -0
- package/dist/node/utils/registry-client.js +142 -0
- package/dist/node/utils/tarball.js +49 -0
- package/dist/sources/git-ref.js +7 -30
- package/dist/sources/git.d.ts +2 -2
- package/dist/sources/git.js +7 -30
- package/dist/sources/index.d.ts +2 -0
- package/dist/sources/index.js +337 -39
- package/dist/sources/local.js +0 -28
- package/dist/sources/npm-ref.js +0 -28
- package/dist/sources/npm.js +10 -37
- package/dist/sources/registry-ref.d.ts +30 -0
- package/dist/sources/registry-ref.js +37 -0
- package/dist/sources/registry.d.ts +18 -0
- package/dist/sources/registry.js +355 -0
- package/dist/targets/additional-targets.js +196 -37
- package/dist/targets/agents-md.js +5 -33
- package/dist/targets/base-target.d.ts +2 -0
- package/dist/targets/base-target.js +0 -28
- package/dist/targets/claude-code.js +211 -41
- package/dist/targets/codex-cli.js +7 -35
- package/dist/targets/copilot.js +202 -41
- package/dist/targets/cursor.js +188 -40
- package/dist/targets/gemini-cli.js +10 -38
- package/dist/targets/generic-md-target.js +196 -37
- package/dist/targets/index.js +414 -106
- package/dist/targets/opencode.js +171 -51
- package/dist/targets/registry.js +414 -106
- package/dist/utils/credentials.d.ts +19 -0
- package/dist/utils/credentials.js +38 -0
- package/dist/utils/diff.js +22 -34
- package/dist/utils/filesystem.js +2 -30
- package/dist/utils/frontmatter.js +0 -28
- package/dist/utils/global.js +3 -31
- package/dist/utils/markdown.js +0 -28
- package/dist/utils/model-allowlist.d.ts +39 -0
- package/dist/utils/model-allowlist.js +110 -0
- package/dist/utils/model-guidance.d.ts +6 -0
- package/dist/utils/model-guidance.js +78 -0
- package/dist/utils/registry-client.d.ts +141 -0
- package/dist/utils/registry-client.js +142 -0
- package/dist/utils/tarball.d.ts +13 -0
- package/dist/utils/tarball.js +49 -0
- package/package.json +171 -5
- package/templates/pack/models.json +38 -0
package/dist/node/index.js
CHANGED
|
@@ -1,52 +1,86 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
8
|
-
var __toCommonJS = (from) => {
|
|
9
|
-
var entry = __moduleCache.get(from), desc;
|
|
10
|
-
if (entry)
|
|
11
|
-
return entry;
|
|
12
|
-
entry = __defProp({}, "__esModule", { value: true });
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
14
|
-
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
15
|
-
get: () => from[key],
|
|
16
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
-
}));
|
|
18
|
-
__moduleCache.set(from, entry);
|
|
19
|
-
return entry;
|
|
20
|
-
};
|
|
21
|
-
var __export = (target, all) => {
|
|
22
|
-
for (var name in all)
|
|
23
|
-
__defProp(target, name, {
|
|
24
|
-
get: all[name],
|
|
25
|
-
enumerable: true,
|
|
26
|
-
configurable: true,
|
|
27
|
-
set: (newValue) => all[name] = () => newValue
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
31
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
32
4
|
|
|
33
5
|
// src/core/config.ts
|
|
34
|
-
var exports_config = {};
|
|
35
|
-
__export(exports_config, {
|
|
36
|
-
resolveTargets: () => resolveTargets,
|
|
37
|
-
resolveFeatures: () => resolveFeatures,
|
|
38
|
-
loadWorkspaceConfig: () => loadWorkspaceConfig,
|
|
39
|
-
loadPackManifest: () => loadPackManifest,
|
|
40
|
-
WorkspaceConfigSchema: () => WorkspaceConfigSchema,
|
|
41
|
-
TARGET_IDS: () => TARGET_IDS,
|
|
42
|
-
REPO_MODES: () => REPO_MODES,
|
|
43
|
-
PackManifestSchema: () => PackManifestSchema,
|
|
44
|
-
FEATURE_IDS: () => FEATURE_IDS
|
|
45
|
-
});
|
|
46
6
|
import { z } from "zod";
|
|
47
7
|
import { readFileSync, existsSync } from "fs";
|
|
48
8
|
import { resolve } from "path";
|
|
49
9
|
import { parse as parseJsonc } from "jsonc-parser";
|
|
10
|
+
var TARGET_IDS = [
|
|
11
|
+
"opencode",
|
|
12
|
+
"cursor",
|
|
13
|
+
"claudecode",
|
|
14
|
+
"codexcli",
|
|
15
|
+
"geminicli",
|
|
16
|
+
"copilot",
|
|
17
|
+
"agentsmd",
|
|
18
|
+
"cline",
|
|
19
|
+
"kilo",
|
|
20
|
+
"roo",
|
|
21
|
+
"qwencode",
|
|
22
|
+
"kiro",
|
|
23
|
+
"factorydroid",
|
|
24
|
+
"antigravity",
|
|
25
|
+
"junie",
|
|
26
|
+
"augmentcode",
|
|
27
|
+
"windsurf",
|
|
28
|
+
"warp",
|
|
29
|
+
"replit",
|
|
30
|
+
"zed"
|
|
31
|
+
];
|
|
32
|
+
var FEATURE_IDS = [
|
|
33
|
+
"rules",
|
|
34
|
+
"commands",
|
|
35
|
+
"agents",
|
|
36
|
+
"skills",
|
|
37
|
+
"hooks",
|
|
38
|
+
"plugins",
|
|
39
|
+
"mcp",
|
|
40
|
+
"ignore",
|
|
41
|
+
"models"
|
|
42
|
+
];
|
|
43
|
+
var REPO_MODES = ["repo", "monorepo", "metarepo"];
|
|
44
|
+
var PackManifestSchema = z.object({
|
|
45
|
+
name: z.string().min(1),
|
|
46
|
+
version: z.string().default("1.0.0"),
|
|
47
|
+
description: z.string().default(""),
|
|
48
|
+
author: z.union([
|
|
49
|
+
z.string(),
|
|
50
|
+
z.object({ name: z.string(), email: z.string().optional() })
|
|
51
|
+
]).optional(),
|
|
52
|
+
tags: z.array(z.string()).default([]),
|
|
53
|
+
dependencies: z.array(z.string()).default([]),
|
|
54
|
+
conflicts: z.array(z.string()).default([]),
|
|
55
|
+
targets: z.union([z.literal("*"), z.array(z.string())]).default("*"),
|
|
56
|
+
features: z.union([z.literal("*"), z.array(z.string())]).default("*")
|
|
57
|
+
});
|
|
58
|
+
var FeaturesSchema = z.union([
|
|
59
|
+
z.literal("*"),
|
|
60
|
+
z.array(z.string()),
|
|
61
|
+
z.record(z.string(), z.union([z.literal("*"), z.array(z.string())]))
|
|
62
|
+
]);
|
|
63
|
+
var WorkspaceConfigSchema = z.object({
|
|
64
|
+
$schema: z.string().optional(),
|
|
65
|
+
packs: z.array(z.string()).default(["./packs/default"]),
|
|
66
|
+
disabled: z.array(z.string()).default([]),
|
|
67
|
+
targets: z.union([z.literal("*"), z.array(z.string())]).default("*"),
|
|
68
|
+
features: FeaturesSchema.default("*"),
|
|
69
|
+
mode: z.enum(REPO_MODES).default("repo"),
|
|
70
|
+
baseDirs: z.array(z.string()).default(["."]),
|
|
71
|
+
global: z.boolean().default(false),
|
|
72
|
+
delete: z.boolean().default(true),
|
|
73
|
+
verbose: z.boolean().default(false),
|
|
74
|
+
silent: z.boolean().default(false),
|
|
75
|
+
overrides: z.record(z.string(), z.record(z.string(), z.string())).default({}),
|
|
76
|
+
sources: z.array(z.object({
|
|
77
|
+
source: z.string(),
|
|
78
|
+
packs: z.array(z.string()).optional(),
|
|
79
|
+
skills: z.array(z.string()).optional()
|
|
80
|
+
})).default([]),
|
|
81
|
+
modelProfile: z.string().optional()
|
|
82
|
+
});
|
|
83
|
+
var CONFIG_FILES = ["agentpacks.local.jsonc", "agentpacks.jsonc"];
|
|
50
84
|
function loadWorkspaceConfig(projectRoot) {
|
|
51
85
|
for (const filename of CONFIG_FILES) {
|
|
52
86
|
const filepath = resolve(projectRoot, filename);
|
|
@@ -92,81 +126,6 @@ function resolveTargets(config) {
|
|
|
92
126
|
return [...TARGET_IDS];
|
|
93
127
|
return config.targets;
|
|
94
128
|
}
|
|
95
|
-
var TARGET_IDS, FEATURE_IDS, REPO_MODES, PackManifestSchema, FeaturesSchema, WorkspaceConfigSchema, CONFIG_FILES;
|
|
96
|
-
var init_config = __esm(() => {
|
|
97
|
-
TARGET_IDS = [
|
|
98
|
-
"opencode",
|
|
99
|
-
"cursor",
|
|
100
|
-
"claudecode",
|
|
101
|
-
"codexcli",
|
|
102
|
-
"geminicli",
|
|
103
|
-
"copilot",
|
|
104
|
-
"agentsmd",
|
|
105
|
-
"cline",
|
|
106
|
-
"kilo",
|
|
107
|
-
"roo",
|
|
108
|
-
"qwencode",
|
|
109
|
-
"kiro",
|
|
110
|
-
"factorydroid",
|
|
111
|
-
"antigravity",
|
|
112
|
-
"junie",
|
|
113
|
-
"augmentcode",
|
|
114
|
-
"windsurf",
|
|
115
|
-
"warp",
|
|
116
|
-
"replit",
|
|
117
|
-
"zed"
|
|
118
|
-
];
|
|
119
|
-
FEATURE_IDS = [
|
|
120
|
-
"rules",
|
|
121
|
-
"commands",
|
|
122
|
-
"agents",
|
|
123
|
-
"skills",
|
|
124
|
-
"hooks",
|
|
125
|
-
"plugins",
|
|
126
|
-
"mcp",
|
|
127
|
-
"ignore"
|
|
128
|
-
];
|
|
129
|
-
REPO_MODES = ["repo", "monorepo", "metarepo"];
|
|
130
|
-
PackManifestSchema = z.object({
|
|
131
|
-
name: z.string().min(1),
|
|
132
|
-
version: z.string().default("1.0.0"),
|
|
133
|
-
description: z.string().default(""),
|
|
134
|
-
author: z.union([
|
|
135
|
-
z.string(),
|
|
136
|
-
z.object({ name: z.string(), email: z.string().optional() })
|
|
137
|
-
]).optional(),
|
|
138
|
-
tags: z.array(z.string()).default([]),
|
|
139
|
-
dependencies: z.array(z.string()).default([]),
|
|
140
|
-
conflicts: z.array(z.string()).default([]),
|
|
141
|
-
targets: z.union([z.literal("*"), z.array(z.string())]).default("*"),
|
|
142
|
-
features: z.union([z.literal("*"), z.array(z.string())]).default("*")
|
|
143
|
-
});
|
|
144
|
-
FeaturesSchema = z.union([
|
|
145
|
-
z.literal("*"),
|
|
146
|
-
z.array(z.string()),
|
|
147
|
-
z.record(z.string(), z.union([z.literal("*"), z.array(z.string())]))
|
|
148
|
-
]);
|
|
149
|
-
WorkspaceConfigSchema = z.object({
|
|
150
|
-
$schema: z.string().optional(),
|
|
151
|
-
packs: z.array(z.string()).default(["./packs/default"]),
|
|
152
|
-
disabled: z.array(z.string()).default([]),
|
|
153
|
-
targets: z.union([z.literal("*"), z.array(z.string())]).default("*"),
|
|
154
|
-
features: FeaturesSchema.default("*"),
|
|
155
|
-
mode: z.enum(REPO_MODES).default("repo"),
|
|
156
|
-
baseDirs: z.array(z.string()).default(["."]),
|
|
157
|
-
global: z.boolean().default(false),
|
|
158
|
-
delete: z.boolean().default(true),
|
|
159
|
-
verbose: z.boolean().default(false),
|
|
160
|
-
silent: z.boolean().default(false),
|
|
161
|
-
overrides: z.record(z.string(), z.record(z.string(), z.string())).default({}),
|
|
162
|
-
sources: z.array(z.object({
|
|
163
|
-
source: z.string(),
|
|
164
|
-
packs: z.array(z.string()).optional(),
|
|
165
|
-
skills: z.array(z.string()).optional()
|
|
166
|
-
})).default([])
|
|
167
|
-
});
|
|
168
|
-
CONFIG_FILES = ["agentpacks.local.jsonc", "agentpacks.jsonc"];
|
|
169
|
-
});
|
|
170
129
|
|
|
171
130
|
// src/utils/filesystem.ts
|
|
172
131
|
import {
|
|
@@ -175,10 +134,10 @@ import {
|
|
|
175
134
|
readFileSync as readFileSync2,
|
|
176
135
|
writeFileSync,
|
|
177
136
|
readdirSync,
|
|
137
|
+
rmSync,
|
|
178
138
|
statSync
|
|
179
139
|
} from "fs";
|
|
180
140
|
import { dirname, relative, join } from "path";
|
|
181
|
-
import { removeSync } from "fs-extra";
|
|
182
141
|
var GENERATED_HEADER_MD = "<!-- Generated by agentpacks. DO NOT EDIT. -->";
|
|
183
142
|
var GENERATED_HEADER_JSON = "// Generated by agentpacks. DO NOT EDIT.";
|
|
184
143
|
var GENERATED_HEADER_JS = "// Generated by agentpacks. DO NOT EDIT.";
|
|
@@ -219,7 +178,7 @@ function ensureDir(dirPath) {
|
|
|
219
178
|
}
|
|
220
179
|
function removeIfExists(targetPath) {
|
|
221
180
|
if (existsSync2(targetPath)) {
|
|
222
|
-
|
|
181
|
+
rmSync(targetPath, { recursive: true, force: true });
|
|
223
182
|
}
|
|
224
183
|
}
|
|
225
184
|
function listFiles(dirPath, options = {}) {
|
|
@@ -545,10 +504,178 @@ function mergeIgnorePatterns(configs) {
|
|
|
545
504
|
return result;
|
|
546
505
|
}
|
|
547
506
|
|
|
507
|
+
// src/features/models.ts
|
|
508
|
+
import { join as join7 } from "path";
|
|
509
|
+
import { z as z2 } from "zod";
|
|
510
|
+
var SECRET_PATTERNS = [
|
|
511
|
+
/["']api[_-]?key["']\s*:/i,
|
|
512
|
+
/["']apiKey["']\s*:/i,
|
|
513
|
+
/["']secret["']\s*:/i,
|
|
514
|
+
/["']password["']\s*:/i,
|
|
515
|
+
/["'](?:auth_token|access_token|bearer_token)["']\s*:/i,
|
|
516
|
+
/["']private[_-]?key["']\s*:/i,
|
|
517
|
+
/-----BEGIN\s+(RSA|EC|DSA|OPENSSH|PGP)\s+PRIVATE\s+KEY-----/,
|
|
518
|
+
/sk-[a-zA-Z0-9]{20,}/,
|
|
519
|
+
/Bearer\s+[a-zA-Z0-9._-]{20,}/
|
|
520
|
+
];
|
|
521
|
+
var AgentModelSchema = z2.object({
|
|
522
|
+
model: z2.string(),
|
|
523
|
+
temperature: z2.number().min(0).max(2).optional(),
|
|
524
|
+
top_p: z2.number().min(0).max(1).optional()
|
|
525
|
+
});
|
|
526
|
+
var ModelProfileSchema = z2.object({
|
|
527
|
+
extends: z2.string().optional(),
|
|
528
|
+
description: z2.string().optional(),
|
|
529
|
+
default: z2.string().optional(),
|
|
530
|
+
small: z2.string().optional(),
|
|
531
|
+
agents: z2.record(z2.string(), AgentModelSchema).optional()
|
|
532
|
+
});
|
|
533
|
+
var RoutingConditionSchema = z2.object({
|
|
534
|
+
complexity: z2.enum(["low", "medium", "high", "critical"]).optional().describe("Task complexity level"),
|
|
535
|
+
urgency: z2.enum(["low", "normal", "high"]).optional().describe("Time sensitivity"),
|
|
536
|
+
budget: z2.enum(["minimal", "standard", "premium"]).optional().describe("Cost/token budget tier"),
|
|
537
|
+
contextWindowNeed: z2.enum(["small", "medium", "large", "max"]).optional().describe("Required context window size"),
|
|
538
|
+
toolUseIntensity: z2.enum(["none", "light", "heavy"]).optional().describe("Expected tool/function calling intensity")
|
|
539
|
+
});
|
|
540
|
+
var RoutingRuleSchema = z2.object({
|
|
541
|
+
when: z2.record(z2.string(), z2.string()),
|
|
542
|
+
use: z2.string(),
|
|
543
|
+
description: z2.string().optional(),
|
|
544
|
+
priority: z2.number().optional()
|
|
545
|
+
});
|
|
546
|
+
var ProviderModelSchema = z2.object({
|
|
547
|
+
options: z2.record(z2.string(), z2.unknown()).optional(),
|
|
548
|
+
variants: z2.record(z2.string(), z2.record(z2.string(), z2.unknown())).optional()
|
|
549
|
+
});
|
|
550
|
+
var ProviderConfigSchema = z2.object({
|
|
551
|
+
options: z2.record(z2.string(), z2.unknown()).optional(),
|
|
552
|
+
models: z2.record(z2.string(), ProviderModelSchema).optional()
|
|
553
|
+
});
|
|
554
|
+
var ModelsSchema = z2.object({
|
|
555
|
+
default: z2.string().optional(),
|
|
556
|
+
small: z2.string().optional(),
|
|
557
|
+
agents: z2.record(z2.string(), AgentModelSchema).optional(),
|
|
558
|
+
profiles: z2.record(z2.string(), ModelProfileSchema).optional(),
|
|
559
|
+
providers: z2.record(z2.string(), ProviderConfigSchema).optional(),
|
|
560
|
+
routing: z2.array(RoutingRuleSchema).optional(),
|
|
561
|
+
overrides: z2.record(z2.string(), z2.object({
|
|
562
|
+
default: z2.string().optional(),
|
|
563
|
+
small: z2.string().optional(),
|
|
564
|
+
agents: z2.record(z2.string(), AgentModelSchema).optional()
|
|
565
|
+
})).optional()
|
|
566
|
+
});
|
|
567
|
+
function parseModels(packDir, packName) {
|
|
568
|
+
const modelsPath = join7(packDir, "models.json");
|
|
569
|
+
const raw = readJsonOrNull(modelsPath);
|
|
570
|
+
if (!raw)
|
|
571
|
+
return null;
|
|
572
|
+
const parsed = ModelsSchema.parse(raw);
|
|
573
|
+
return {
|
|
574
|
+
packName,
|
|
575
|
+
sourcePath: modelsPath,
|
|
576
|
+
config: parsed
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
function mergeModelsConfigs(configs) {
|
|
580
|
+
const warnings = [];
|
|
581
|
+
const result = {};
|
|
582
|
+
for (const entry of configs) {
|
|
583
|
+
const { config, packName } = entry;
|
|
584
|
+
if (config.default !== undefined && result.default === undefined) {
|
|
585
|
+
result.default = config.default;
|
|
586
|
+
} else if (config.default !== undefined && result.default !== undefined) {
|
|
587
|
+
warnings.push(`Models "default" from pack "${packName}" skipped (already defined).`);
|
|
588
|
+
}
|
|
589
|
+
if (config.small !== undefined && result.small === undefined) {
|
|
590
|
+
result.small = config.small;
|
|
591
|
+
} else if (config.small !== undefined && result.small !== undefined) {
|
|
592
|
+
warnings.push(`Models "small" from pack "${packName}" skipped (already defined).`);
|
|
593
|
+
}
|
|
594
|
+
if (config.agents) {
|
|
595
|
+
if (!result.agents)
|
|
596
|
+
result.agents = {};
|
|
597
|
+
for (const [name, assignment] of Object.entries(config.agents)) {
|
|
598
|
+
if (name in result.agents) {
|
|
599
|
+
warnings.push(`Models agent "${name}" from pack "${packName}" skipped (already defined).`);
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
result.agents[name] = assignment;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
if (config.profiles) {
|
|
606
|
+
if (!result.profiles)
|
|
607
|
+
result.profiles = {};
|
|
608
|
+
for (const [name, profile] of Object.entries(config.profiles)) {
|
|
609
|
+
if (name in result.profiles) {
|
|
610
|
+
warnings.push(`Models profile "${name}" from pack "${packName}" skipped (already defined).`);
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
result.profiles[name] = profile;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
if (config.providers) {
|
|
617
|
+
if (!result.providers)
|
|
618
|
+
result.providers = {};
|
|
619
|
+
for (const [providerName, providerConfig] of Object.entries(config.providers)) {
|
|
620
|
+
if (!(providerName in result.providers)) {
|
|
621
|
+
result.providers[providerName] = providerConfig;
|
|
622
|
+
} else {
|
|
623
|
+
const existing = result.providers[providerName];
|
|
624
|
+
if (!existing) {
|
|
625
|
+
result.providers[providerName] = providerConfig;
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
if (providerConfig.options) {
|
|
629
|
+
existing.options = {
|
|
630
|
+
...providerConfig.options,
|
|
631
|
+
...existing.options
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
if (providerConfig.models) {
|
|
635
|
+
if (!existing.models)
|
|
636
|
+
existing.models = {};
|
|
637
|
+
for (const [modelName, modelConfig] of Object.entries(providerConfig.models)) {
|
|
638
|
+
if (!(modelName in existing.models)) {
|
|
639
|
+
existing.models[modelName] = modelConfig;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (config.routing) {
|
|
647
|
+
if (!result.routing)
|
|
648
|
+
result.routing = [];
|
|
649
|
+
result.routing.push(...config.routing);
|
|
650
|
+
}
|
|
651
|
+
if (config.overrides) {
|
|
652
|
+
if (!result.overrides)
|
|
653
|
+
result.overrides = {};
|
|
654
|
+
for (const [targetId, override] of Object.entries(config.overrides)) {
|
|
655
|
+
if (targetId in result.overrides) {
|
|
656
|
+
warnings.push(`Models override for target "${targetId}" from pack "${packName}" skipped (already defined).`);
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
result.overrides[targetId] = override;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return { config: result, warnings };
|
|
664
|
+
}
|
|
665
|
+
function scanModelsForSecrets(config) {
|
|
666
|
+
const warnings = [];
|
|
667
|
+
const json = JSON.stringify(config);
|
|
668
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
669
|
+
if (pattern.test(json)) {
|
|
670
|
+
warnings.push(`Potential secret detected in models.json matching pattern: ${pattern.source}`);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return warnings;
|
|
674
|
+
}
|
|
675
|
+
|
|
548
676
|
// src/core/pack-loader.ts
|
|
549
|
-
init_config();
|
|
550
677
|
import { existsSync as existsSync6 } from "fs";
|
|
551
|
-
import { resolve as
|
|
678
|
+
import { resolve as resolve2, isAbsolute } from "path";
|
|
552
679
|
class PackLoader {
|
|
553
680
|
projectRoot;
|
|
554
681
|
config;
|
|
@@ -581,10 +708,10 @@ class PackLoader {
|
|
|
581
708
|
}
|
|
582
709
|
loadPack(packDir, manifest) {
|
|
583
710
|
const name = manifest.name;
|
|
584
|
-
const rulesDir =
|
|
585
|
-
const commandsDir =
|
|
586
|
-
const agentsDir =
|
|
587
|
-
const skillsDir =
|
|
711
|
+
const rulesDir = resolve2(packDir, "rules");
|
|
712
|
+
const commandsDir = resolve2(packDir, "commands");
|
|
713
|
+
const agentsDir = resolve2(packDir, "agents");
|
|
714
|
+
const skillsDir = resolve2(packDir, "skills");
|
|
588
715
|
return {
|
|
589
716
|
manifest,
|
|
590
717
|
directory: packDir,
|
|
@@ -595,23 +722,25 @@ class PackLoader {
|
|
|
595
722
|
hooks: parseHooks(packDir, name),
|
|
596
723
|
plugins: parsePlugins(packDir, name),
|
|
597
724
|
mcp: parseMcp(packDir, name),
|
|
598
|
-
ignore: parseIgnore(packDir, name)
|
|
725
|
+
ignore: parseIgnore(packDir, name),
|
|
726
|
+
models: parseModels(packDir, name)
|
|
599
727
|
};
|
|
600
728
|
}
|
|
601
729
|
loadForBaseDir(baseDir) {
|
|
602
|
-
const baseDirRoot =
|
|
603
|
-
const localConfigPath =
|
|
730
|
+
const baseDirRoot = resolve2(this.projectRoot, baseDir);
|
|
731
|
+
const localConfigPath = resolve2(baseDirRoot, "agentpacks.jsonc");
|
|
604
732
|
if (!existsSync6(localConfigPath)) {
|
|
605
733
|
return { packs: [], warnings: [] };
|
|
606
734
|
}
|
|
607
|
-
const
|
|
608
|
-
const localConfig = loadWorkspaceConfig2(baseDirRoot);
|
|
735
|
+
const localConfig = loadWorkspaceConfig(baseDirRoot);
|
|
609
736
|
const loader = new PackLoader(baseDirRoot, localConfig);
|
|
610
737
|
return loader.loadAll();
|
|
611
738
|
}
|
|
612
739
|
resolveCuratedPack(packRef) {
|
|
613
|
-
const curatedDir =
|
|
740
|
+
const curatedDir = resolve2(this.projectRoot, ".agentpacks", ".curated");
|
|
614
741
|
let packName = packRef;
|
|
742
|
+
if (packName.startsWith("registry:"))
|
|
743
|
+
packName = packName.slice(9);
|
|
615
744
|
if (packName.startsWith("npm:"))
|
|
616
745
|
packName = packName.slice(4);
|
|
617
746
|
if (packName.startsWith("github:"))
|
|
@@ -622,24 +751,28 @@ class PackLoader {
|
|
|
622
751
|
const parts = packName.split("/");
|
|
623
752
|
packName = packName.includes("@") ? parts.join("-") : parts[parts.length - 1] ?? packName;
|
|
624
753
|
}
|
|
625
|
-
|
|
626
|
-
|
|
754
|
+
const withoutVersion = packName.split("@")[0] ?? packName;
|
|
755
|
+
packName = withoutVersion.split(":")[0] ?? withoutVersion;
|
|
756
|
+
const resolved = resolve2(curatedDir, packName);
|
|
627
757
|
return existsSync6(resolved) ? resolved : null;
|
|
628
758
|
}
|
|
629
759
|
resolvePackPath(packRef) {
|
|
630
760
|
if (packRef.startsWith("./") || packRef.startsWith("../")) {
|
|
631
|
-
return
|
|
761
|
+
return resolve2(this.projectRoot, packRef);
|
|
632
762
|
}
|
|
633
763
|
if (isAbsolute(packRef)) {
|
|
634
764
|
return packRef;
|
|
635
765
|
}
|
|
766
|
+
if (packRef.startsWith("registry:")) {
|
|
767
|
+
return this.resolveCuratedPack(packRef);
|
|
768
|
+
}
|
|
636
769
|
if (packRef.startsWith("@") || packRef.startsWith("npm:") || !packRef.includes("/")) {
|
|
637
770
|
return this.resolveCuratedPack(packRef);
|
|
638
771
|
}
|
|
639
772
|
if (packRef.startsWith("github:") || packRef.includes("/")) {
|
|
640
773
|
return this.resolveCuratedPack(packRef);
|
|
641
774
|
}
|
|
642
|
-
return
|
|
775
|
+
return resolve2(this.projectRoot, packRef);
|
|
643
776
|
}
|
|
644
777
|
}
|
|
645
778
|
|
|
@@ -660,7 +793,8 @@ class FeatureMerger {
|
|
|
660
793
|
hooks: this.mergeHooks(),
|
|
661
794
|
plugins: this.mergePlugins(),
|
|
662
795
|
mcpServers: this.mergeMcp(),
|
|
663
|
-
ignorePatterns: this.mergeIgnore()
|
|
796
|
+
ignorePatterns: this.mergeIgnore(),
|
|
797
|
+
models: this.mergeModels()
|
|
664
798
|
};
|
|
665
799
|
return { features, warnings: this.warnings };
|
|
666
800
|
}
|
|
@@ -747,16 +881,24 @@ class FeatureMerger {
|
|
|
747
881
|
}
|
|
748
882
|
return result;
|
|
749
883
|
}
|
|
884
|
+
mergeModels() {
|
|
885
|
+
const configs = this.packs.map((p) => p.models).filter((m) => m != null);
|
|
886
|
+
if (configs.length === 0)
|
|
887
|
+
return null;
|
|
888
|
+
const { config, warnings } = mergeModelsConfigs(configs);
|
|
889
|
+
this.warnings.push(...warnings);
|
|
890
|
+
return config;
|
|
891
|
+
}
|
|
750
892
|
}
|
|
751
893
|
|
|
752
894
|
// src/core/lockfile.ts
|
|
753
895
|
import { existsSync as existsSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync2 } from "fs";
|
|
754
|
-
import { resolve as
|
|
896
|
+
import { resolve as resolve3 } from "path";
|
|
755
897
|
import { createHash } from "crypto";
|
|
756
898
|
var LOCKFILE_VERSION = 1;
|
|
757
899
|
var LOCKFILE_NAME = "agentpacks.lock";
|
|
758
900
|
function loadLockfile(projectRoot) {
|
|
759
|
-
const filepath =
|
|
901
|
+
const filepath = resolve3(projectRoot, LOCKFILE_NAME);
|
|
760
902
|
if (!existsSync7(filepath)) {
|
|
761
903
|
return { lockfileVersion: LOCKFILE_VERSION, sources: {} };
|
|
762
904
|
}
|
|
@@ -764,7 +906,7 @@ function loadLockfile(projectRoot) {
|
|
|
764
906
|
return JSON.parse(raw);
|
|
765
907
|
}
|
|
766
908
|
function saveLockfile(projectRoot, lockfile) {
|
|
767
|
-
const filepath =
|
|
909
|
+
const filepath = resolve3(projectRoot, LOCKFILE_NAME);
|
|
768
910
|
writeFileSync2(filepath, JSON.stringify(lockfile, null, 2) + `
|
|
769
911
|
`);
|
|
770
912
|
}
|
|
@@ -783,15 +925,119 @@ function isLockfileFrozenValid(lockfile, sourceKeys) {
|
|
|
783
925
|
return { valid: missing.length === 0, missing };
|
|
784
926
|
}
|
|
785
927
|
|
|
928
|
+
// src/core/profile-resolver.ts
|
|
929
|
+
function resolveModels(merged, modelProfile, targetId) {
|
|
930
|
+
let defaultModel = merged.default;
|
|
931
|
+
let smallModel = merged.small;
|
|
932
|
+
let agents = { ...merged.agents };
|
|
933
|
+
if (modelProfile && merged.profiles?.[modelProfile]) {
|
|
934
|
+
const resolvedProfile = resolveProfileInheritance(modelProfile, merged.profiles);
|
|
935
|
+
if (resolvedProfile.default)
|
|
936
|
+
defaultModel = resolvedProfile.default;
|
|
937
|
+
if (resolvedProfile.small)
|
|
938
|
+
smallModel = resolvedProfile.small;
|
|
939
|
+
if (resolvedProfile.agents) {
|
|
940
|
+
agents = { ...agents, ...resolvedProfile.agents };
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
if (targetId) {
|
|
944
|
+
const targetOverride = merged.overrides?.[targetId];
|
|
945
|
+
if (targetOverride) {
|
|
946
|
+
if (targetOverride.default)
|
|
947
|
+
defaultModel = targetOverride.default;
|
|
948
|
+
if (targetOverride.small)
|
|
949
|
+
smallModel = targetOverride.small;
|
|
950
|
+
if (targetOverride.agents) {
|
|
951
|
+
agents = { ...agents, ...targetOverride.agents };
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
const providers = {};
|
|
956
|
+
if (merged.providers) {
|
|
957
|
+
for (const [name, config] of Object.entries(merged.providers)) {
|
|
958
|
+
providers[name] = {
|
|
959
|
+
...config.options ? { options: config.options } : {},
|
|
960
|
+
...config.models ? { models: config.models } : {}
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
const profileNames = Object.keys(merged.profiles ?? {});
|
|
965
|
+
const profiles = {};
|
|
966
|
+
if (merged.profiles) {
|
|
967
|
+
for (const [name, profile] of Object.entries(merged.profiles)) {
|
|
968
|
+
profiles[name] = {
|
|
969
|
+
description: profile.description,
|
|
970
|
+
default: profile.default,
|
|
971
|
+
small: profile.small
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
return {
|
|
976
|
+
default: defaultModel,
|
|
977
|
+
small: smallModel,
|
|
978
|
+
agents,
|
|
979
|
+
providers,
|
|
980
|
+
routing: merged.routing ?? [],
|
|
981
|
+
profileNames,
|
|
982
|
+
activeProfile: modelProfile,
|
|
983
|
+
profiles
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
function resolveAgentModel(resolved, agentName, frontmatterModel) {
|
|
987
|
+
const fromModels = resolved.agents[agentName];
|
|
988
|
+
if (fromModels) {
|
|
989
|
+
return {
|
|
990
|
+
model: fromModels.model,
|
|
991
|
+
temperature: fromModels.temperature,
|
|
992
|
+
top_p: fromModels.top_p
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
if (frontmatterModel) {
|
|
996
|
+
return { model: frontmatterModel };
|
|
997
|
+
}
|
|
998
|
+
return {};
|
|
999
|
+
}
|
|
1000
|
+
function resolveProfileInheritance(profileName, profiles) {
|
|
1001
|
+
const visited = new Set;
|
|
1002
|
+
return resolveProfileChain(profileName, profiles, visited, 0);
|
|
1003
|
+
}
|
|
1004
|
+
var MAX_INHERITANCE_DEPTH = 10;
|
|
1005
|
+
function resolveProfileChain(name, profiles, visited, depth) {
|
|
1006
|
+
if (depth > MAX_INHERITANCE_DEPTH) {
|
|
1007
|
+
throw new Error(`Profile inheritance too deep (max ${MAX_INHERITANCE_DEPTH}): ${name}`);
|
|
1008
|
+
}
|
|
1009
|
+
if (visited.has(name)) {
|
|
1010
|
+
throw new Error(`Circular profile inheritance detected: ${[...visited, name].join(" → ")}`);
|
|
1011
|
+
}
|
|
1012
|
+
const profile = profiles[name];
|
|
1013
|
+
if (!profile) {
|
|
1014
|
+
throw new Error(`Profile "${name}" not found`);
|
|
1015
|
+
}
|
|
1016
|
+
visited.add(name);
|
|
1017
|
+
if (!profile.extends) {
|
|
1018
|
+
return { ...profile };
|
|
1019
|
+
}
|
|
1020
|
+
const parent = resolveProfileChain(profile.extends, profiles, visited, depth + 1);
|
|
1021
|
+
return {
|
|
1022
|
+
description: profile.description ?? parent.description,
|
|
1023
|
+
default: profile.default ?? parent.default,
|
|
1024
|
+
small: profile.small ?? parent.small,
|
|
1025
|
+
agents: {
|
|
1026
|
+
...parent.agents,
|
|
1027
|
+
...profile.agents
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
|
|
786
1032
|
// src/sources/local.ts
|
|
787
1033
|
import { existsSync as existsSync8 } from "fs";
|
|
788
|
-
import { resolve as
|
|
1034
|
+
import { resolve as resolve4, isAbsolute as isAbsolute2 } from "path";
|
|
789
1035
|
function resolveLocalPack(packRef, projectRoot) {
|
|
790
1036
|
let resolved;
|
|
791
1037
|
if (isAbsolute2(packRef)) {
|
|
792
1038
|
resolved = packRef;
|
|
793
1039
|
} else {
|
|
794
|
-
resolved =
|
|
1040
|
+
resolved = resolve4(projectRoot, packRef);
|
|
795
1041
|
}
|
|
796
1042
|
if (!existsSync8(resolved))
|
|
797
1043
|
return null;
|
|
@@ -823,9 +1069,14 @@ function parseGitSourceRef(source) {
|
|
|
823
1069
|
if (parts.length < 2) {
|
|
824
1070
|
throw new Error(`Invalid git source reference: "${source}". Expected owner/repo format.`);
|
|
825
1071
|
}
|
|
1072
|
+
const owner = parts[0];
|
|
1073
|
+
const repo = parts[1];
|
|
1074
|
+
if (!owner || !repo) {
|
|
1075
|
+
throw new Error(`Invalid git source reference: "${source}". Expected owner/repo format.`);
|
|
1076
|
+
}
|
|
826
1077
|
return {
|
|
827
|
-
owner
|
|
828
|
-
repo
|
|
1078
|
+
owner,
|
|
1079
|
+
repo,
|
|
829
1080
|
ref,
|
|
830
1081
|
path: path || ""
|
|
831
1082
|
};
|
|
@@ -894,9 +1145,39 @@ function npmSourceKey(parsed) {
|
|
|
894
1145
|
return `npm:${parsed.packageName}`;
|
|
895
1146
|
}
|
|
896
1147
|
|
|
1148
|
+
// src/sources/registry-ref.ts
|
|
1149
|
+
function parseRegistrySourceRef(source) {
|
|
1150
|
+
let s = source;
|
|
1151
|
+
if (s.startsWith("registry:")) {
|
|
1152
|
+
s = s.slice(9);
|
|
1153
|
+
}
|
|
1154
|
+
if (!s) {
|
|
1155
|
+
throw new Error(`Invalid registry source reference: "${source}". Expected pack name.`);
|
|
1156
|
+
}
|
|
1157
|
+
let version = "latest";
|
|
1158
|
+
const atIdx = s.indexOf("@");
|
|
1159
|
+
if (atIdx > 0) {
|
|
1160
|
+
version = s.slice(atIdx + 1);
|
|
1161
|
+
s = s.slice(0, atIdx);
|
|
1162
|
+
}
|
|
1163
|
+
if (!s) {
|
|
1164
|
+
throw new Error(`Invalid registry source reference: "${source}". Pack name is empty.`);
|
|
1165
|
+
}
|
|
1166
|
+
if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(s)) {
|
|
1167
|
+
throw new Error(`Invalid registry pack name: "${s}". Must be lowercase alphanumeric with hyphens.`);
|
|
1168
|
+
}
|
|
1169
|
+
return { packName: s, version };
|
|
1170
|
+
}
|
|
1171
|
+
function isRegistryPackRef(packRef) {
|
|
1172
|
+
return packRef.startsWith("registry:");
|
|
1173
|
+
}
|
|
1174
|
+
function registrySourceKey(parsed) {
|
|
1175
|
+
return `registry:${parsed.packName}`;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
897
1178
|
// src/sources/git.ts
|
|
898
1179
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
899
|
-
import { resolve as
|
|
1180
|
+
import { resolve as resolve5, join as join8 } from "path";
|
|
900
1181
|
var GITHUB_API = "https://api.github.com";
|
|
901
1182
|
function githubHeaders(token) {
|
|
902
1183
|
const h = {
|
|
@@ -949,11 +1230,11 @@ async function fetchAndWriteSubdir(parsed, sha, remotePath, localDir, installed,
|
|
|
949
1230
|
for (const entry of entries) {
|
|
950
1231
|
if (entry.type === "file" && entry.download_url) {
|
|
951
1232
|
const content = await fetchGitFile(entry.download_url, token);
|
|
952
|
-
const filepath =
|
|
1233
|
+
const filepath = join8(localDir, entry.name);
|
|
953
1234
|
writeFileSync3(filepath, content);
|
|
954
1235
|
installed.push(filepath);
|
|
955
1236
|
} else if (entry.type === "dir") {
|
|
956
|
-
await fetchAndWriteSubdir(parsed, sha, `${remotePath}/${entry.name}`,
|
|
1237
|
+
await fetchAndWriteSubdir(parsed, sha, `${remotePath}/${entry.name}`, join8(localDir, entry.name), installed, token);
|
|
957
1238
|
}
|
|
958
1239
|
}
|
|
959
1240
|
}
|
|
@@ -974,7 +1255,7 @@ async function installGitSource(projectRoot, source, lockfile, options = {}) {
|
|
|
974
1255
|
}
|
|
975
1256
|
const basePath = parsed.path || "packs";
|
|
976
1257
|
const entries = await fetchGitDirectory(parsed, resolvedSha, basePath, options.token);
|
|
977
|
-
const curatedDir =
|
|
1258
|
+
const curatedDir = resolve5(projectRoot, ".agentpacks", ".curated");
|
|
978
1259
|
mkdirSync2(curatedDir, { recursive: true });
|
|
979
1260
|
const newLockEntry = {
|
|
980
1261
|
requestedRef: parsed.ref,
|
|
@@ -986,21 +1267,21 @@ async function installGitSource(projectRoot, source, lockfile, options = {}) {
|
|
|
986
1267
|
const packDirs = entries.filter((e) => e.type === "dir");
|
|
987
1268
|
for (const packEntry of packDirs) {
|
|
988
1269
|
const packName = packEntry.name;
|
|
989
|
-
const packOutDir =
|
|
1270
|
+
const packOutDir = resolve5(curatedDir, packName);
|
|
990
1271
|
const packFiles = await fetchGitDirectory(parsed, resolvedSha, `${basePath}/${packName}`, options.token);
|
|
991
1272
|
mkdirSync2(packOutDir, { recursive: true });
|
|
992
1273
|
for (const file of packFiles) {
|
|
993
1274
|
if (file.type === "file" && file.download_url) {
|
|
994
1275
|
const content = await fetchGitFile(file.download_url, options.token);
|
|
995
|
-
writeFileSync3(
|
|
996
|
-
installed.push(
|
|
1276
|
+
writeFileSync3(join8(packOutDir, file.name), content);
|
|
1277
|
+
installed.push(join8(packOutDir, file.name));
|
|
997
1278
|
if (newLockEntry.packs) {
|
|
998
1279
|
newLockEntry.packs[packName] = {
|
|
999
1280
|
integrity: computeIntegrity(content)
|
|
1000
1281
|
};
|
|
1001
1282
|
}
|
|
1002
1283
|
} else if (file.type === "dir") {
|
|
1003
|
-
await fetchAndWriteSubdir(parsed, resolvedSha, `${basePath}/${packName}/${file.name}`,
|
|
1284
|
+
await fetchAndWriteSubdir(parsed, resolvedSha, `${basePath}/${packName}/${file.name}`, join8(packOutDir, file.name), installed, options.token);
|
|
1004
1285
|
}
|
|
1005
1286
|
}
|
|
1006
1287
|
}
|
|
@@ -1008,15 +1289,15 @@ async function installGitSource(projectRoot, source, lockfile, options = {}) {
|
|
|
1008
1289
|
const fileEntries = entries.filter((e) => e.type === "file");
|
|
1009
1290
|
if (fileEntries.length > 0) {
|
|
1010
1291
|
const packName = parsed.path.split("/").pop() ?? parsed.repo;
|
|
1011
|
-
const packOutDir =
|
|
1292
|
+
const packOutDir = resolve5(curatedDir, packName);
|
|
1012
1293
|
mkdirSync2(packOutDir, { recursive: true });
|
|
1013
1294
|
for (const file of entries) {
|
|
1014
1295
|
if (file.type === "file" && file.download_url) {
|
|
1015
1296
|
const content = await fetchGitFile(file.download_url, options.token);
|
|
1016
|
-
writeFileSync3(
|
|
1017
|
-
installed.push(
|
|
1297
|
+
writeFileSync3(join8(packOutDir, file.name), content);
|
|
1298
|
+
installed.push(join8(packOutDir, file.name));
|
|
1018
1299
|
} else if (file.type === "dir") {
|
|
1019
|
-
await fetchAndWriteSubdir(parsed, resolvedSha, `${basePath}/${file.name}`,
|
|
1300
|
+
await fetchAndWriteSubdir(parsed, resolvedSha, `${basePath}/${file.name}`, join8(packOutDir, file.name), installed, options.token);
|
|
1020
1301
|
}
|
|
1021
1302
|
}
|
|
1022
1303
|
}
|
|
@@ -1026,8 +1307,8 @@ async function installGitSource(projectRoot, source, lockfile, options = {}) {
|
|
|
1026
1307
|
}
|
|
1027
1308
|
|
|
1028
1309
|
// src/sources/npm.ts
|
|
1029
|
-
import { mkdirSync as mkdirSync3, existsSync as existsSync9 } from "fs";
|
|
1030
|
-
import { resolve as
|
|
1310
|
+
import { mkdirSync as mkdirSync3, existsSync as existsSync9, readdirSync as readdirSync2 } from "fs";
|
|
1311
|
+
import { resolve as resolve6, join as join9 } from "path";
|
|
1031
1312
|
import { execSync } from "child_process";
|
|
1032
1313
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
1033
1314
|
async function resolveNpmVersion(parsed) {
|
|
@@ -1051,18 +1332,15 @@ async function installNpmSource(projectRoot, source, lockfile, options = {}) {
|
|
|
1051
1332
|
throw new Error(`Frozen mode: no lockfile entry for source "${sourceKey}".`);
|
|
1052
1333
|
}
|
|
1053
1334
|
let resolvedVersion;
|
|
1054
|
-
let tarballUrl;
|
|
1055
1335
|
if (locked && !options.update) {
|
|
1056
1336
|
resolvedVersion = locked.resolvedRef;
|
|
1057
|
-
tarballUrl = "";
|
|
1058
1337
|
} else {
|
|
1059
1338
|
const resolved = await resolveNpmVersion(parsed);
|
|
1060
1339
|
resolvedVersion = resolved.version;
|
|
1061
|
-
tarballUrl = resolved.tarball;
|
|
1062
1340
|
}
|
|
1063
|
-
const curatedDir =
|
|
1341
|
+
const curatedDir = resolve6(projectRoot, ".agentpacks", ".curated");
|
|
1064
1342
|
mkdirSync3(curatedDir, { recursive: true });
|
|
1065
|
-
|
|
1343
|
+
extractNpmPack(parsed, resolvedVersion, curatedDir, installed, warnings);
|
|
1066
1344
|
const newEntry = {
|
|
1067
1345
|
requestedRef: parsed.version,
|
|
1068
1346
|
resolvedRef: resolvedVersion,
|
|
@@ -1076,20 +1354,25 @@ async function installNpmSource(projectRoot, source, lockfile, options = {}) {
|
|
|
1076
1354
|
function extractNpmPack(parsed, version, curatedDir, installed, warnings) {
|
|
1077
1355
|
const pkgSpec = `${parsed.packageName}@${version}`;
|
|
1078
1356
|
const packName = parsed.packageName.replace(/^@/, "").replace(/\//g, "-");
|
|
1079
|
-
const packOutDir =
|
|
1357
|
+
const packOutDir = resolve6(curatedDir, packName);
|
|
1080
1358
|
try {
|
|
1081
|
-
const tmpDir =
|
|
1359
|
+
const tmpDir = resolve6(curatedDir, ".tmp-npm");
|
|
1082
1360
|
mkdirSync3(tmpDir, { recursive: true });
|
|
1083
1361
|
execSync(`npm pack ${pkgSpec} --pack-destination "${tmpDir}"`, {
|
|
1084
1362
|
stdio: "pipe",
|
|
1085
1363
|
timeout: 30000
|
|
1086
1364
|
});
|
|
1087
|
-
const tgzFiles =
|
|
1365
|
+
const tgzFiles = readdirSync2(tmpDir).filter((f) => f.endsWith(".tgz"));
|
|
1088
1366
|
if (tgzFiles.length === 0) {
|
|
1089
1367
|
warnings.push(`No tarball found for ${pkgSpec}`);
|
|
1090
1368
|
return packOutDir;
|
|
1091
1369
|
}
|
|
1092
|
-
const
|
|
1370
|
+
const firstTgz = tgzFiles[0];
|
|
1371
|
+
if (!firstTgz) {
|
|
1372
|
+
warnings.push(`No tarball found for ${pkgSpec}`);
|
|
1373
|
+
return packOutDir;
|
|
1374
|
+
}
|
|
1375
|
+
const tgzPath = join9(tmpDir, firstTgz);
|
|
1093
1376
|
mkdirSync3(packOutDir, { recursive: true });
|
|
1094
1377
|
execSync(`tar xzf "${tgzPath}" -C "${packOutDir}" --strip-components=1`, {
|
|
1095
1378
|
stdio: "pipe",
|
|
@@ -1097,7 +1380,7 @@ function extractNpmPack(parsed, version, curatedDir, installed, warnings) {
|
|
|
1097
1380
|
});
|
|
1098
1381
|
execSync(`rm -rf "${tmpDir}"`, { stdio: "pipe" });
|
|
1099
1382
|
const subpath = parsed.path || "";
|
|
1100
|
-
const targetDir = subpath ?
|
|
1383
|
+
const targetDir = subpath ? join9(packOutDir, subpath) : packOutDir;
|
|
1101
1384
|
if (existsSync9(targetDir)) {
|
|
1102
1385
|
collectFiles(targetDir, installed);
|
|
1103
1386
|
}
|
|
@@ -1107,10 +1390,9 @@ function extractNpmPack(parsed, version, curatedDir, installed, warnings) {
|
|
|
1107
1390
|
return packOutDir;
|
|
1108
1391
|
}
|
|
1109
1392
|
function collectFiles(dir, out) {
|
|
1110
|
-
const
|
|
1111
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1393
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
1112
1394
|
for (const entry of entries) {
|
|
1113
|
-
const full =
|
|
1395
|
+
const full = join9(dir, entry.name);
|
|
1114
1396
|
if (entry.isDirectory()) {
|
|
1115
1397
|
collectFiles(full, out);
|
|
1116
1398
|
} else {
|
|
@@ -1163,7 +1445,7 @@ ${content}`;
|
|
|
1163
1445
|
}
|
|
1164
1446
|
|
|
1165
1447
|
// src/targets/opencode.ts
|
|
1166
|
-
import { resolve as
|
|
1448
|
+
import { resolve as resolve7, join as join10 } from "path";
|
|
1167
1449
|
var TARGET_ID = "opencode";
|
|
1168
1450
|
|
|
1169
1451
|
class OpenCodeTarget extends BaseTarget {
|
|
@@ -1177,32 +1459,48 @@ class OpenCodeTarget extends BaseTarget {
|
|
|
1177
1459
|
"hooks",
|
|
1178
1460
|
"plugins",
|
|
1179
1461
|
"mcp",
|
|
1180
|
-
"ignore"
|
|
1462
|
+
"ignore",
|
|
1463
|
+
"models"
|
|
1181
1464
|
];
|
|
1182
1465
|
generate(options) {
|
|
1183
1466
|
const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
|
|
1184
|
-
const root =
|
|
1467
|
+
const root = resolve7(projectRoot, baseDir);
|
|
1185
1468
|
const effective = this.getEffectiveFeatures(enabledFeatures);
|
|
1186
1469
|
const filesWritten = [];
|
|
1187
1470
|
const filesDeleted = [];
|
|
1188
1471
|
const warnings = [];
|
|
1189
|
-
const opencodeDir =
|
|
1472
|
+
const opencodeDir = resolve7(root, ".opencode");
|
|
1190
1473
|
if (effective.includes("agents")) {
|
|
1191
|
-
const agentDir =
|
|
1474
|
+
const agentDir = resolve7(opencodeDir, "agent");
|
|
1192
1475
|
if (deleteExisting) {
|
|
1193
1476
|
removeIfExists(agentDir);
|
|
1194
1477
|
filesDeleted.push(agentDir);
|
|
1195
1478
|
}
|
|
1196
1479
|
ensureDir(agentDir);
|
|
1480
|
+
const resolvedModels = features.models ? resolveModels(features.models, options.modelProfile, TARGET_ID) : null;
|
|
1197
1481
|
const agents = features.agents.filter((a) => agentMatchesTarget(a, TARGET_ID));
|
|
1198
1482
|
for (const agent of agents) {
|
|
1199
|
-
const filepath =
|
|
1200
|
-
|
|
1483
|
+
const filepath = join10(agentDir, `${agent.name}.md`);
|
|
1484
|
+
const fm = {};
|
|
1485
|
+
const oc = agent.meta.opencode ?? {};
|
|
1486
|
+
const modelsAgent = resolvedModels?.agents[agent.name];
|
|
1487
|
+
const agentModel = modelsAgent?.model ?? oc.model;
|
|
1488
|
+
const agentTemp = modelsAgent?.temperature ?? oc.temperature;
|
|
1489
|
+
if (agentModel)
|
|
1490
|
+
fm.model = agentModel;
|
|
1491
|
+
if (agentTemp !== undefined)
|
|
1492
|
+
fm.temperature = agentTemp;
|
|
1493
|
+
if (oc.mode)
|
|
1494
|
+
fm.mode = oc.mode;
|
|
1495
|
+
if (oc.top_p !== undefined)
|
|
1496
|
+
fm.top_p = oc.top_p;
|
|
1497
|
+
const content = Object.keys(fm).length > 0 ? serializeFrontmatter(fm, agent.content) : agent.content;
|
|
1498
|
+
writeGeneratedFile(filepath, content);
|
|
1201
1499
|
filesWritten.push(filepath);
|
|
1202
1500
|
}
|
|
1203
1501
|
}
|
|
1204
1502
|
if (effective.includes("skills")) {
|
|
1205
|
-
const skillDir =
|
|
1503
|
+
const skillDir = resolve7(opencodeDir, "skill");
|
|
1206
1504
|
if (deleteExisting) {
|
|
1207
1505
|
removeIfExists(skillDir);
|
|
1208
1506
|
filesDeleted.push(skillDir);
|
|
@@ -1210,15 +1508,15 @@ class OpenCodeTarget extends BaseTarget {
|
|
|
1210
1508
|
ensureDir(skillDir);
|
|
1211
1509
|
const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID));
|
|
1212
1510
|
for (const skill of skills) {
|
|
1213
|
-
const skillSubDir =
|
|
1511
|
+
const skillSubDir = join10(skillDir, skill.name);
|
|
1214
1512
|
ensureDir(skillSubDir);
|
|
1215
|
-
const filepath =
|
|
1513
|
+
const filepath = join10(skillSubDir, "SKILL.md");
|
|
1216
1514
|
writeGeneratedFile(filepath, skill.content);
|
|
1217
1515
|
filesWritten.push(filepath);
|
|
1218
1516
|
}
|
|
1219
1517
|
}
|
|
1220
1518
|
if (effective.includes("commands")) {
|
|
1221
|
-
const cmdDir =
|
|
1519
|
+
const cmdDir = resolve7(opencodeDir, "command");
|
|
1222
1520
|
if (deleteExisting) {
|
|
1223
1521
|
removeIfExists(cmdDir);
|
|
1224
1522
|
filesDeleted.push(cmdDir);
|
|
@@ -1226,19 +1524,19 @@ class OpenCodeTarget extends BaseTarget {
|
|
|
1226
1524
|
ensureDir(cmdDir);
|
|
1227
1525
|
const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID));
|
|
1228
1526
|
for (const cmd of commands) {
|
|
1229
|
-
const filepath =
|
|
1527
|
+
const filepath = join10(cmdDir, `${cmd.name}.md`);
|
|
1230
1528
|
writeGeneratedFile(filepath, cmd.content);
|
|
1231
1529
|
filesWritten.push(filepath);
|
|
1232
1530
|
}
|
|
1233
1531
|
}
|
|
1234
1532
|
if (effective.includes("hooks") || effective.includes("plugins")) {
|
|
1235
|
-
const pluginsDir =
|
|
1533
|
+
const pluginsDir = resolve7(opencodeDir, "plugins");
|
|
1236
1534
|
ensureDir(pluginsDir);
|
|
1237
1535
|
if (effective.includes("hooks")) {
|
|
1238
1536
|
for (const hookSet of features.hooks) {
|
|
1239
1537
|
const events = resolveHooksForTarget(hookSet, TARGET_ID);
|
|
1240
1538
|
if (Object.keys(events).length > 0) {
|
|
1241
|
-
const filepath =
|
|
1539
|
+
const filepath = join10(pluginsDir, `agentpacks-${hookSet.packName}.ts`);
|
|
1242
1540
|
const content = generateOpenCodeHookPlugin(hookSet.packName, events);
|
|
1243
1541
|
writeGeneratedFile(filepath, content, { type: "ts" });
|
|
1244
1542
|
filesWritten.push(filepath);
|
|
@@ -1247,7 +1545,7 @@ class OpenCodeTarget extends BaseTarget {
|
|
|
1247
1545
|
}
|
|
1248
1546
|
if (effective.includes("plugins")) {
|
|
1249
1547
|
for (const plugin of features.plugins) {
|
|
1250
|
-
const filepath =
|
|
1548
|
+
const filepath = join10(pluginsDir, `agentpacks-${plugin.packName}-${plugin.name}.${plugin.extension}`);
|
|
1251
1549
|
writeGeneratedFile(filepath, plugin.content, {
|
|
1252
1550
|
type: plugin.extension
|
|
1253
1551
|
});
|
|
@@ -1255,28 +1553,59 @@ class OpenCodeTarget extends BaseTarget {
|
|
|
1255
1553
|
}
|
|
1256
1554
|
}
|
|
1257
1555
|
}
|
|
1258
|
-
if (effective.includes("mcp")) {
|
|
1259
|
-
const
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1556
|
+
if (effective.includes("mcp") || effective.includes("models")) {
|
|
1557
|
+
const filepath = resolve7(root, "opencode.json");
|
|
1558
|
+
const opencodeConfig = {
|
|
1559
|
+
$schema: "https://opencode.ai/config.json"
|
|
1560
|
+
};
|
|
1561
|
+
if (effective.includes("mcp")) {
|
|
1562
|
+
const mcpEntries = Object.entries(features.mcpServers);
|
|
1563
|
+
if (mcpEntries.length > 0) {
|
|
1564
|
+
opencodeConfig.mcp = buildOpenCodeMcpServers(features.mcpServers);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
if (effective.includes("models") && features.models) {
|
|
1568
|
+
const resolved = resolveModels(features.models, options.modelProfile, TARGET_ID);
|
|
1569
|
+
if (resolved.default)
|
|
1570
|
+
opencodeConfig.model = resolved.default;
|
|
1571
|
+
if (resolved.small)
|
|
1572
|
+
opencodeConfig.small_model = resolved.small;
|
|
1573
|
+
if (Object.keys(resolved.providers).length > 0) {
|
|
1574
|
+
opencodeConfig.provider = resolved.providers;
|
|
1575
|
+
}
|
|
1576
|
+
const agentEntries = Object.entries(resolved.agents);
|
|
1577
|
+
if (agentEntries.length > 0) {
|
|
1578
|
+
const agentConfig = {};
|
|
1579
|
+
for (const [name, assignment] of agentEntries) {
|
|
1580
|
+
const config = { model: assignment.model };
|
|
1581
|
+
if (assignment.temperature !== undefined) {
|
|
1582
|
+
config.temperature = assignment.temperature;
|
|
1583
|
+
}
|
|
1584
|
+
if (assignment.top_p !== undefined) {
|
|
1585
|
+
config.top_p = assignment.top_p;
|
|
1586
|
+
}
|
|
1587
|
+
agentConfig[name] = config;
|
|
1588
|
+
}
|
|
1589
|
+
opencodeConfig.agent = agentConfig;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
if (Object.keys(opencodeConfig).length > 1) {
|
|
1263
1593
|
writeGeneratedJson(filepath, opencodeConfig, { header: false });
|
|
1264
1594
|
filesWritten.push(filepath);
|
|
1265
1595
|
}
|
|
1266
1596
|
}
|
|
1267
1597
|
if (effective.includes("rules")) {
|
|
1268
1598
|
const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID));
|
|
1269
|
-
const rootRules = getRootRules(rules);
|
|
1270
1599
|
const detailRules = getDetailRules(rules);
|
|
1271
1600
|
if (detailRules.length > 0) {
|
|
1272
|
-
const memoriesDir =
|
|
1601
|
+
const memoriesDir = resolve7(opencodeDir, "memories");
|
|
1273
1602
|
if (deleteExisting) {
|
|
1274
1603
|
removeIfExists(memoriesDir);
|
|
1275
1604
|
filesDeleted.push(memoriesDir);
|
|
1276
1605
|
}
|
|
1277
1606
|
ensureDir(memoriesDir);
|
|
1278
1607
|
for (const rule of detailRules) {
|
|
1279
|
-
const filepath =
|
|
1608
|
+
const filepath = join10(memoriesDir, `${rule.name}.md`);
|
|
1280
1609
|
writeGeneratedFile(filepath, rule.content);
|
|
1281
1610
|
filesWritten.push(filepath);
|
|
1282
1611
|
}
|
|
@@ -1285,7 +1614,7 @@ class OpenCodeTarget extends BaseTarget {
|
|
|
1285
1614
|
return this.createResult(filesWritten, filesDeleted, warnings);
|
|
1286
1615
|
}
|
|
1287
1616
|
}
|
|
1288
|
-
function
|
|
1617
|
+
function buildOpenCodeMcpServers(servers) {
|
|
1289
1618
|
const mcp = {};
|
|
1290
1619
|
for (const [name, entry] of Object.entries(servers)) {
|
|
1291
1620
|
if (entry.url) {
|
|
@@ -1305,10 +1634,7 @@ function buildOpenCodeMcp(servers) {
|
|
|
1305
1634
|
};
|
|
1306
1635
|
}
|
|
1307
1636
|
}
|
|
1308
|
-
return
|
|
1309
|
-
$schema: "https://opencode.ai/config.json",
|
|
1310
|
-
mcp
|
|
1311
|
-
};
|
|
1637
|
+
return mcp;
|
|
1312
1638
|
}
|
|
1313
1639
|
function generateOpenCodeHookPlugin(packName, events) {
|
|
1314
1640
|
const identifier = packNameToIdentifier(packName);
|
|
@@ -1355,7 +1681,7 @@ function mapHookEvents(events) {
|
|
|
1355
1681
|
}
|
|
1356
1682
|
|
|
1357
1683
|
// src/targets/cursor.ts
|
|
1358
|
-
import { resolve as
|
|
1684
|
+
import { resolve as resolve8, join as join11 } from "path";
|
|
1359
1685
|
var TARGET_ID2 = "cursor";
|
|
1360
1686
|
|
|
1361
1687
|
class CursorTarget extends BaseTarget {
|
|
@@ -1368,18 +1694,19 @@ class CursorTarget extends BaseTarget {
|
|
|
1368
1694
|
"skills",
|
|
1369
1695
|
"hooks",
|
|
1370
1696
|
"mcp",
|
|
1371
|
-
"ignore"
|
|
1697
|
+
"ignore",
|
|
1698
|
+
"models"
|
|
1372
1699
|
];
|
|
1373
1700
|
generate(options) {
|
|
1374
1701
|
const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
|
|
1375
|
-
const root =
|
|
1702
|
+
const root = resolve8(projectRoot, baseDir);
|
|
1376
1703
|
const effective = this.getEffectiveFeatures(enabledFeatures);
|
|
1377
1704
|
const filesWritten = [];
|
|
1378
1705
|
const filesDeleted = [];
|
|
1379
1706
|
const warnings = [];
|
|
1380
|
-
const cursorDir =
|
|
1707
|
+
const cursorDir = resolve8(root, ".cursor");
|
|
1381
1708
|
if (effective.includes("rules")) {
|
|
1382
|
-
const rulesDir =
|
|
1709
|
+
const rulesDir = resolve8(cursorDir, "rules");
|
|
1383
1710
|
if (deleteExisting) {
|
|
1384
1711
|
removeIfExists(rulesDir);
|
|
1385
1712
|
filesDeleted.push(rulesDir);
|
|
@@ -1396,33 +1723,40 @@ class CursorTarget extends BaseTarget {
|
|
|
1396
1723
|
if (globs) {
|
|
1397
1724
|
frontmatter.globs = globs;
|
|
1398
1725
|
}
|
|
1399
|
-
const filepath =
|
|
1726
|
+
const filepath = join11(rulesDir, `${rule.name}.mdc`);
|
|
1400
1727
|
const content = serializeFrontmatter(frontmatter, rule.content);
|
|
1401
1728
|
writeGeneratedFile(filepath, content);
|
|
1402
1729
|
filesWritten.push(filepath);
|
|
1403
1730
|
}
|
|
1404
1731
|
}
|
|
1405
1732
|
if (effective.includes("agents")) {
|
|
1406
|
-
const agentsDir =
|
|
1733
|
+
const agentsDir = resolve8(cursorDir, "agents");
|
|
1407
1734
|
if (deleteExisting) {
|
|
1408
1735
|
removeIfExists(agentsDir);
|
|
1409
1736
|
filesDeleted.push(agentsDir);
|
|
1410
1737
|
}
|
|
1411
1738
|
ensureDir(agentsDir);
|
|
1739
|
+
const resolvedModels = features.models ? resolveModels(features.models, options.modelProfile, TARGET_ID2) : null;
|
|
1412
1740
|
const agents = features.agents.filter((a) => agentMatchesTarget(a, TARGET_ID2));
|
|
1413
1741
|
for (const agent of agents) {
|
|
1414
1742
|
const frontmatter = {
|
|
1415
1743
|
name: agent.name,
|
|
1416
1744
|
description: agent.meta.description ?? ""
|
|
1417
1745
|
};
|
|
1418
|
-
const
|
|
1746
|
+
const cursorMeta = agent.meta.cursor ?? {};
|
|
1747
|
+
const modelsAgent = resolvedModels?.agents[agent.name];
|
|
1748
|
+
const model = modelsAgent?.model ?? cursorMeta.model;
|
|
1749
|
+
if (model) {
|
|
1750
|
+
frontmatter.model = model;
|
|
1751
|
+
}
|
|
1752
|
+
const filepath = join11(agentsDir, `${agent.name}.md`);
|
|
1419
1753
|
const content = serializeFrontmatter(frontmatter, agent.content);
|
|
1420
1754
|
writeGeneratedFile(filepath, content);
|
|
1421
1755
|
filesWritten.push(filepath);
|
|
1422
1756
|
}
|
|
1423
1757
|
}
|
|
1424
1758
|
if (effective.includes("skills")) {
|
|
1425
|
-
const skillsDir =
|
|
1759
|
+
const skillsDir = resolve8(cursorDir, "skills");
|
|
1426
1760
|
if (deleteExisting) {
|
|
1427
1761
|
removeIfExists(skillsDir);
|
|
1428
1762
|
filesDeleted.push(skillsDir);
|
|
@@ -1430,20 +1764,20 @@ class CursorTarget extends BaseTarget {
|
|
|
1430
1764
|
ensureDir(skillsDir);
|
|
1431
1765
|
const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID2));
|
|
1432
1766
|
for (const skill of skills) {
|
|
1433
|
-
const skillSubDir =
|
|
1767
|
+
const skillSubDir = join11(skillsDir, skill.name);
|
|
1434
1768
|
ensureDir(skillSubDir);
|
|
1435
1769
|
const frontmatter = {
|
|
1436
1770
|
name: skill.name,
|
|
1437
1771
|
description: skill.meta.description ?? ""
|
|
1438
1772
|
};
|
|
1439
|
-
const filepath =
|
|
1773
|
+
const filepath = join11(skillSubDir, "SKILL.md");
|
|
1440
1774
|
const content = serializeFrontmatter(frontmatter, skill.content);
|
|
1441
1775
|
writeGeneratedFile(filepath, content);
|
|
1442
1776
|
filesWritten.push(filepath);
|
|
1443
1777
|
}
|
|
1444
1778
|
}
|
|
1445
1779
|
if (effective.includes("commands")) {
|
|
1446
|
-
const commandsDir =
|
|
1780
|
+
const commandsDir = resolve8(cursorDir, "commands");
|
|
1447
1781
|
if (deleteExisting) {
|
|
1448
1782
|
removeIfExists(commandsDir);
|
|
1449
1783
|
filesDeleted.push(commandsDir);
|
|
@@ -1451,7 +1785,7 @@ class CursorTarget extends BaseTarget {
|
|
|
1451
1785
|
ensureDir(commandsDir);
|
|
1452
1786
|
const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID2));
|
|
1453
1787
|
for (const cmd of commands) {
|
|
1454
|
-
const filepath =
|
|
1788
|
+
const filepath = join11(commandsDir, `${cmd.name}.md`);
|
|
1455
1789
|
writeGeneratedFile(filepath, cmd.content);
|
|
1456
1790
|
filesWritten.push(filepath);
|
|
1457
1791
|
}
|
|
@@ -1460,14 +1794,14 @@ class CursorTarget extends BaseTarget {
|
|
|
1460
1794
|
const mcpEntries = Object.entries(features.mcpServers);
|
|
1461
1795
|
if (mcpEntries.length > 0) {
|
|
1462
1796
|
const mcpConfig = buildCursorMcp(features.mcpServers);
|
|
1463
|
-
const filepath =
|
|
1797
|
+
const filepath = resolve8(cursorDir, "mcp.json");
|
|
1464
1798
|
writeGeneratedJson(filepath, mcpConfig, { header: false });
|
|
1465
1799
|
filesWritten.push(filepath);
|
|
1466
1800
|
}
|
|
1467
1801
|
}
|
|
1468
1802
|
if (effective.includes("ignore")) {
|
|
1469
1803
|
if (features.ignorePatterns.length > 0) {
|
|
1470
|
-
const filepath =
|
|
1804
|
+
const filepath = resolve8(root, ".cursorignore");
|
|
1471
1805
|
const content = features.ignorePatterns.join(`
|
|
1472
1806
|
`) + `
|
|
1473
1807
|
`;
|
|
@@ -1475,6 +1809,17 @@ class CursorTarget extends BaseTarget {
|
|
|
1475
1809
|
filesWritten.push(filepath);
|
|
1476
1810
|
}
|
|
1477
1811
|
}
|
|
1812
|
+
if (effective.includes("models") && features.models) {
|
|
1813
|
+
const resolved = resolveModels(features.models, options.modelProfile, TARGET_ID2);
|
|
1814
|
+
const guidanceContent = buildCursorModelGuidance(resolved);
|
|
1815
|
+
if (guidanceContent) {
|
|
1816
|
+
const rulesDir = resolve8(cursorDir, "rules");
|
|
1817
|
+
ensureDir(rulesDir);
|
|
1818
|
+
const filepath = join11(rulesDir, "model-config.mdc");
|
|
1819
|
+
writeGeneratedFile(filepath, guidanceContent, { header: false });
|
|
1820
|
+
filesWritten.push(filepath);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1478
1823
|
return this.createResult(filesWritten, filesDeleted, warnings);
|
|
1479
1824
|
}
|
|
1480
1825
|
}
|
|
@@ -1493,9 +1838,135 @@ function buildCursorMcp(servers) {
|
|
|
1493
1838
|
}
|
|
1494
1839
|
return { mcpServers };
|
|
1495
1840
|
}
|
|
1841
|
+
function buildCursorModelGuidance(resolved) {
|
|
1842
|
+
if (!resolved.default && !resolved.small && Object.keys(resolved.agents).length === 0) {
|
|
1843
|
+
return null;
|
|
1844
|
+
}
|
|
1845
|
+
const frontmatter = {
|
|
1846
|
+
description: "Model configuration and selection guidelines for this workspace",
|
|
1847
|
+
alwaysApply: true
|
|
1848
|
+
};
|
|
1849
|
+
const lines = [];
|
|
1850
|
+
lines.push("# Model Configuration");
|
|
1851
|
+
lines.push("");
|
|
1852
|
+
lines.push("Use the following model preferences when working in this project.");
|
|
1853
|
+
lines.push("");
|
|
1854
|
+
if (resolved.default || resolved.small) {
|
|
1855
|
+
lines.push("## Default Models");
|
|
1856
|
+
lines.push("");
|
|
1857
|
+
if (resolved.default) {
|
|
1858
|
+
lines.push(`- **Primary model**: ${resolved.default}`);
|
|
1859
|
+
}
|
|
1860
|
+
if (resolved.small) {
|
|
1861
|
+
lines.push(`- **Lightweight tasks** (titles, summaries): ${resolved.small}`);
|
|
1862
|
+
}
|
|
1863
|
+
lines.push("");
|
|
1864
|
+
}
|
|
1865
|
+
const agentEntries = Object.entries(resolved.agents);
|
|
1866
|
+
if (agentEntries.length > 0) {
|
|
1867
|
+
lines.push("## Agent Model Assignments");
|
|
1868
|
+
lines.push("");
|
|
1869
|
+
lines.push("| Agent | Model | Temperature |");
|
|
1870
|
+
lines.push("| --- | --- | --- |");
|
|
1871
|
+
for (const [name, assignment] of agentEntries) {
|
|
1872
|
+
const temp = assignment.temperature !== undefined ? String(assignment.temperature) : "—";
|
|
1873
|
+
lines.push(`| ${name} | ${assignment.model} | ${temp} |`);
|
|
1874
|
+
}
|
|
1875
|
+
lines.push("");
|
|
1876
|
+
}
|
|
1877
|
+
if (Object.keys(resolved.profiles).length > 0) {
|
|
1878
|
+
lines.push("## Available Profiles");
|
|
1879
|
+
lines.push("");
|
|
1880
|
+
lines.push("| Profile | Description | Default Model |");
|
|
1881
|
+
lines.push("| --- | --- | --- |");
|
|
1882
|
+
for (const [name, profile] of Object.entries(resolved.profiles)) {
|
|
1883
|
+
lines.push(`| ${name} | ${profile.description ?? "—"} | ${profile.default ?? "—"} |`);
|
|
1884
|
+
}
|
|
1885
|
+
lines.push("");
|
|
1886
|
+
}
|
|
1887
|
+
if (resolved.activeProfile) {
|
|
1888
|
+
lines.push(`**Active profile**: \`${resolved.activeProfile}\``);
|
|
1889
|
+
lines.push("");
|
|
1890
|
+
}
|
|
1891
|
+
return serializeFrontmatter(frontmatter, lines.join(`
|
|
1892
|
+
`));
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
// src/utils/model-guidance.ts
|
|
1896
|
+
function generateModelGuidanceMarkdown(resolved) {
|
|
1897
|
+
if (!resolved.default && !resolved.small && Object.keys(resolved.agents).length === 0 && Object.keys(resolved.profiles).length === 0) {
|
|
1898
|
+
return null;
|
|
1899
|
+
}
|
|
1900
|
+
const lines = [];
|
|
1901
|
+
lines.push("# Model Configuration");
|
|
1902
|
+
lines.push("");
|
|
1903
|
+
lines.push("Use the following model preferences when working in this project.");
|
|
1904
|
+
lines.push("");
|
|
1905
|
+
if (resolved.default || resolved.small) {
|
|
1906
|
+
lines.push("## Default Models");
|
|
1907
|
+
lines.push("");
|
|
1908
|
+
if (resolved.default) {
|
|
1909
|
+
lines.push(`- **Primary model**: ${resolved.default}`);
|
|
1910
|
+
}
|
|
1911
|
+
if (resolved.small) {
|
|
1912
|
+
lines.push(`- **Lightweight tasks** (titles, summaries): ${resolved.small}`);
|
|
1913
|
+
}
|
|
1914
|
+
lines.push("");
|
|
1915
|
+
}
|
|
1916
|
+
const agentEntries = Object.entries(resolved.agents);
|
|
1917
|
+
if (agentEntries.length > 0) {
|
|
1918
|
+
lines.push("## Agent Model Assignments");
|
|
1919
|
+
lines.push("");
|
|
1920
|
+
lines.push("| Agent | Model | Temperature |");
|
|
1921
|
+
lines.push("| --- | --- | --- |");
|
|
1922
|
+
for (const [name, assignment] of agentEntries) {
|
|
1923
|
+
const temp = assignment.temperature !== undefined ? String(assignment.temperature) : "—";
|
|
1924
|
+
lines.push(`| ${name} | ${assignment.model} | ${temp} |`);
|
|
1925
|
+
}
|
|
1926
|
+
lines.push("");
|
|
1927
|
+
}
|
|
1928
|
+
if (Object.keys(resolved.profiles).length > 0) {
|
|
1929
|
+
lines.push("## Available Profiles");
|
|
1930
|
+
lines.push("");
|
|
1931
|
+
lines.push("| Profile | Description | Default Model |");
|
|
1932
|
+
lines.push("| --- | --- | --- |");
|
|
1933
|
+
for (const [name, profile] of Object.entries(resolved.profiles)) {
|
|
1934
|
+
lines.push(`| ${name} | ${profile.description ?? "—"} | ${profile.default ?? "—"} |`);
|
|
1935
|
+
}
|
|
1936
|
+
lines.push("");
|
|
1937
|
+
}
|
|
1938
|
+
if (resolved.activeProfile) {
|
|
1939
|
+
lines.push(`**Active profile**: \`${resolved.activeProfile}\``);
|
|
1940
|
+
lines.push("");
|
|
1941
|
+
}
|
|
1942
|
+
if (resolved.routing.length > 0) {
|
|
1943
|
+
lines.push("## Task-Aware Routing");
|
|
1944
|
+
lines.push("");
|
|
1945
|
+
lines.push("Select the appropriate profile based on the task context:");
|
|
1946
|
+
lines.push("");
|
|
1947
|
+
lines.push("| Condition | Profile | Description |");
|
|
1948
|
+
lines.push("| --- | --- | --- |");
|
|
1949
|
+
for (const rule of resolved.routing) {
|
|
1950
|
+
const conditions = Object.entries(rule.when).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
1951
|
+
const desc = rule.description ?? "—";
|
|
1952
|
+
lines.push(`| ${conditions} | ${rule.use} | ${desc} |`);
|
|
1953
|
+
}
|
|
1954
|
+
lines.push("");
|
|
1955
|
+
lines.push("### Condition Reference");
|
|
1956
|
+
lines.push("");
|
|
1957
|
+
lines.push("- **complexity**: low | medium | high | critical");
|
|
1958
|
+
lines.push("- **urgency**: low | normal | high");
|
|
1959
|
+
lines.push("- **budget**: minimal | standard | premium");
|
|
1960
|
+
lines.push("- **contextWindowNeed**: small | medium | large | max");
|
|
1961
|
+
lines.push("- **toolUseIntensity**: none | light | heavy");
|
|
1962
|
+
lines.push("");
|
|
1963
|
+
}
|
|
1964
|
+
return lines.join(`
|
|
1965
|
+
`);
|
|
1966
|
+
}
|
|
1496
1967
|
|
|
1497
1968
|
// src/targets/claude-code.ts
|
|
1498
|
-
import { resolve as
|
|
1969
|
+
import { resolve as resolve9, join as join12 } from "path";
|
|
1499
1970
|
var TARGET_ID3 = "claudecode";
|
|
1500
1971
|
|
|
1501
1972
|
class ClaudeCodeTarget extends BaseTarget {
|
|
@@ -1508,18 +1979,19 @@ class ClaudeCodeTarget extends BaseTarget {
|
|
|
1508
1979
|
"skills",
|
|
1509
1980
|
"hooks",
|
|
1510
1981
|
"mcp",
|
|
1511
|
-
"ignore"
|
|
1982
|
+
"ignore",
|
|
1983
|
+
"models"
|
|
1512
1984
|
];
|
|
1513
1985
|
generate(options) {
|
|
1514
1986
|
const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
|
|
1515
|
-
const root =
|
|
1987
|
+
const root = resolve9(projectRoot, baseDir);
|
|
1516
1988
|
const effective = this.getEffectiveFeatures(enabledFeatures);
|
|
1517
1989
|
const filesWritten = [];
|
|
1518
1990
|
const filesDeleted = [];
|
|
1519
1991
|
const warnings = [];
|
|
1520
|
-
const claudeDir =
|
|
1992
|
+
const claudeDir = resolve9(root, ".claude");
|
|
1521
1993
|
if (effective.includes("rules")) {
|
|
1522
|
-
const rulesDir =
|
|
1994
|
+
const rulesDir = resolve9(claudeDir, "rules");
|
|
1523
1995
|
if (deleteExisting) {
|
|
1524
1996
|
removeIfExists(rulesDir);
|
|
1525
1997
|
filesDeleted.push(rulesDir);
|
|
@@ -1532,32 +2004,41 @@ class ClaudeCodeTarget extends BaseTarget {
|
|
|
1532
2004
|
const claudeMd = rootRules.map((r) => r.content).join(`
|
|
1533
2005
|
|
|
1534
2006
|
`);
|
|
1535
|
-
const filepath =
|
|
2007
|
+
const filepath = resolve9(claudeDir, "CLAUDE.md");
|
|
1536
2008
|
writeGeneratedFile(filepath, claudeMd);
|
|
1537
2009
|
filesWritten.push(filepath);
|
|
1538
2010
|
}
|
|
1539
2011
|
for (const rule of detailRules) {
|
|
1540
|
-
const filepath =
|
|
2012
|
+
const filepath = join12(rulesDir, `${rule.name}.md`);
|
|
1541
2013
|
writeGeneratedFile(filepath, rule.content);
|
|
1542
2014
|
filesWritten.push(filepath);
|
|
1543
2015
|
}
|
|
1544
2016
|
}
|
|
1545
2017
|
if (effective.includes("agents")) {
|
|
1546
|
-
const agentsDir =
|
|
2018
|
+
const agentsDir = resolve9(claudeDir, "agents");
|
|
1547
2019
|
if (deleteExisting) {
|
|
1548
2020
|
removeIfExists(agentsDir);
|
|
1549
2021
|
filesDeleted.push(agentsDir);
|
|
1550
2022
|
}
|
|
1551
2023
|
ensureDir(agentsDir);
|
|
2024
|
+
const resolvedModels = features.models ? resolveModels(features.models, options.modelProfile, TARGET_ID3) : null;
|
|
1552
2025
|
const agents = features.agents.filter((a) => agentMatchesTarget(a, TARGET_ID3));
|
|
1553
2026
|
for (const agent of agents) {
|
|
1554
|
-
const filepath =
|
|
1555
|
-
|
|
2027
|
+
const filepath = join12(agentsDir, `${agent.name}.md`);
|
|
2028
|
+
const cc = agent.meta.claudecode ?? {};
|
|
2029
|
+
const modelsAgent = resolvedModels?.agents[agent.name];
|
|
2030
|
+
const agentModel = modelsAgent?.model ?? cc.model;
|
|
2031
|
+
let content = agent.content;
|
|
2032
|
+
if (agentModel) {
|
|
2033
|
+
content = `<!-- model: ${agentModel} -->
|
|
2034
|
+
${content}`;
|
|
2035
|
+
}
|
|
2036
|
+
writeGeneratedFile(filepath, content);
|
|
1556
2037
|
filesWritten.push(filepath);
|
|
1557
2038
|
}
|
|
1558
2039
|
}
|
|
1559
2040
|
if (effective.includes("skills")) {
|
|
1560
|
-
const skillsDir =
|
|
2041
|
+
const skillsDir = resolve9(claudeDir, "skills");
|
|
1561
2042
|
if (deleteExisting) {
|
|
1562
2043
|
removeIfExists(skillsDir);
|
|
1563
2044
|
filesDeleted.push(skillsDir);
|
|
@@ -1565,15 +2046,15 @@ class ClaudeCodeTarget extends BaseTarget {
|
|
|
1565
2046
|
ensureDir(skillsDir);
|
|
1566
2047
|
const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID3));
|
|
1567
2048
|
for (const skill of skills) {
|
|
1568
|
-
const skillSubDir =
|
|
2049
|
+
const skillSubDir = join12(skillsDir, skill.name);
|
|
1569
2050
|
ensureDir(skillSubDir);
|
|
1570
|
-
const filepath =
|
|
2051
|
+
const filepath = join12(skillSubDir, "SKILL.md");
|
|
1571
2052
|
writeGeneratedFile(filepath, skill.content);
|
|
1572
2053
|
filesWritten.push(filepath);
|
|
1573
2054
|
}
|
|
1574
2055
|
}
|
|
1575
2056
|
if (effective.includes("commands")) {
|
|
1576
|
-
const commandsDir =
|
|
2057
|
+
const commandsDir = resolve9(claudeDir, "commands");
|
|
1577
2058
|
if (deleteExisting) {
|
|
1578
2059
|
removeIfExists(commandsDir);
|
|
1579
2060
|
filesDeleted.push(commandsDir);
|
|
@@ -1581,15 +2062,26 @@ class ClaudeCodeTarget extends BaseTarget {
|
|
|
1581
2062
|
ensureDir(commandsDir);
|
|
1582
2063
|
const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID3));
|
|
1583
2064
|
for (const cmd of commands) {
|
|
1584
|
-
const filepath =
|
|
2065
|
+
const filepath = join12(commandsDir, `${cmd.name}.md`);
|
|
1585
2066
|
writeGeneratedFile(filepath, cmd.content);
|
|
1586
2067
|
filesWritten.push(filepath);
|
|
1587
2068
|
}
|
|
1588
2069
|
}
|
|
2070
|
+
if (effective.includes("models") && features.models) {
|
|
2071
|
+
const resolved = resolveModels(features.models, options.modelProfile, TARGET_ID3);
|
|
2072
|
+
const guidance = generateModelGuidanceMarkdown(resolved);
|
|
2073
|
+
if (guidance) {
|
|
2074
|
+
const rulesDir = resolve9(claudeDir, "rules");
|
|
2075
|
+
ensureDir(rulesDir);
|
|
2076
|
+
const filepath = join12(rulesDir, "model-config.md");
|
|
2077
|
+
writeGeneratedFile(filepath, guidance);
|
|
2078
|
+
filesWritten.push(filepath);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
1589
2081
|
if (effective.includes("hooks") || effective.includes("mcp") || effective.includes("ignore")) {
|
|
1590
2082
|
const settings = buildClaudeSettings(options, effective);
|
|
1591
2083
|
if (Object.keys(settings).length > 0) {
|
|
1592
|
-
const filepath =
|
|
2084
|
+
const filepath = resolve9(claudeDir, "settings.json");
|
|
1593
2085
|
const existing = readJsonOrNull(filepath) ?? {};
|
|
1594
2086
|
const merged = { ...existing, ...settings };
|
|
1595
2087
|
writeGeneratedJson(filepath, merged, { header: false });
|
|
@@ -1646,7 +2138,7 @@ function toPascalCase(str) {
|
|
|
1646
2138
|
}
|
|
1647
2139
|
|
|
1648
2140
|
// src/targets/codex-cli.ts
|
|
1649
|
-
import { resolve as
|
|
2141
|
+
import { resolve as resolve10, join as join13 } from "path";
|
|
1650
2142
|
var TARGET_ID4 = "codexcli";
|
|
1651
2143
|
|
|
1652
2144
|
class CodexCliTarget extends BaseTarget {
|
|
@@ -1655,14 +2147,14 @@ class CodexCliTarget extends BaseTarget {
|
|
|
1655
2147
|
supportedFeatures = ["rules", "skills", "mcp", "hooks"];
|
|
1656
2148
|
generate(options) {
|
|
1657
2149
|
const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
|
|
1658
|
-
const root =
|
|
2150
|
+
const root = resolve10(projectRoot, baseDir);
|
|
1659
2151
|
const effective = this.getEffectiveFeatures(enabledFeatures);
|
|
1660
2152
|
const filesWritten = [];
|
|
1661
2153
|
const filesDeleted = [];
|
|
1662
2154
|
const warnings = [];
|
|
1663
|
-
const codexDir =
|
|
2155
|
+
const codexDir = resolve10(root, ".codex");
|
|
1664
2156
|
if (effective.includes("rules")) {
|
|
1665
|
-
const memoriesDir =
|
|
2157
|
+
const memoriesDir = resolve10(codexDir, "memories");
|
|
1666
2158
|
if (deleteExisting) {
|
|
1667
2159
|
removeIfExists(memoriesDir);
|
|
1668
2160
|
filesDeleted.push(memoriesDir);
|
|
@@ -1670,13 +2162,13 @@ class CodexCliTarget extends BaseTarget {
|
|
|
1670
2162
|
ensureDir(memoriesDir);
|
|
1671
2163
|
const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID4));
|
|
1672
2164
|
for (const rule of rules) {
|
|
1673
|
-
const filepath =
|
|
2165
|
+
const filepath = join13(memoriesDir, `${rule.name}.md`);
|
|
1674
2166
|
writeGeneratedFile(filepath, rule.content);
|
|
1675
2167
|
filesWritten.push(filepath);
|
|
1676
2168
|
}
|
|
1677
2169
|
}
|
|
1678
2170
|
if (effective.includes("skills")) {
|
|
1679
|
-
const skillsDir =
|
|
2171
|
+
const skillsDir = resolve10(codexDir, "skills");
|
|
1680
2172
|
if (deleteExisting) {
|
|
1681
2173
|
removeIfExists(skillsDir);
|
|
1682
2174
|
filesDeleted.push(skillsDir);
|
|
@@ -1684,9 +2176,9 @@ class CodexCliTarget extends BaseTarget {
|
|
|
1684
2176
|
ensureDir(skillsDir);
|
|
1685
2177
|
const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID4));
|
|
1686
2178
|
for (const skill of skills) {
|
|
1687
|
-
const skillSubDir =
|
|
2179
|
+
const skillSubDir = join13(skillsDir, skill.name);
|
|
1688
2180
|
ensureDir(skillSubDir);
|
|
1689
|
-
const filepath =
|
|
2181
|
+
const filepath = join13(skillSubDir, "SKILL.md");
|
|
1690
2182
|
writeGeneratedFile(filepath, skill.content);
|
|
1691
2183
|
filesWritten.push(filepath);
|
|
1692
2184
|
}
|
|
@@ -1696,7 +2188,7 @@ class CodexCliTarget extends BaseTarget {
|
|
|
1696
2188
|
}
|
|
1697
2189
|
|
|
1698
2190
|
// src/targets/gemini-cli.ts
|
|
1699
|
-
import { resolve as
|
|
2191
|
+
import { resolve as resolve11, join as join14 } from "path";
|
|
1700
2192
|
var TARGET_ID5 = "geminicli";
|
|
1701
2193
|
|
|
1702
2194
|
class GeminiCliTarget extends BaseTarget {
|
|
@@ -1712,12 +2204,12 @@ class GeminiCliTarget extends BaseTarget {
|
|
|
1712
2204
|
];
|
|
1713
2205
|
generate(options) {
|
|
1714
2206
|
const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
|
|
1715
|
-
const root =
|
|
2207
|
+
const root = resolve11(projectRoot, baseDir);
|
|
1716
2208
|
const effective = this.getEffectiveFeatures(enabledFeatures);
|
|
1717
2209
|
const filesWritten = [];
|
|
1718
2210
|
const filesDeleted = [];
|
|
1719
2211
|
const warnings = [];
|
|
1720
|
-
const geminiDir =
|
|
2212
|
+
const geminiDir = resolve11(root, ".gemini");
|
|
1721
2213
|
if (effective.includes("rules")) {
|
|
1722
2214
|
const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID5));
|
|
1723
2215
|
const rootRules = getRootRules(rules);
|
|
@@ -1726,26 +2218,26 @@ class GeminiCliTarget extends BaseTarget {
|
|
|
1726
2218
|
const geminiMd = rootRules.map((r) => r.content).join(`
|
|
1727
2219
|
|
|
1728
2220
|
`);
|
|
1729
|
-
const filepath =
|
|
2221
|
+
const filepath = resolve11(root, "GEMINI.md");
|
|
1730
2222
|
writeGeneratedFile(filepath, geminiMd);
|
|
1731
2223
|
filesWritten.push(filepath);
|
|
1732
2224
|
}
|
|
1733
2225
|
if (detailRules.length > 0) {
|
|
1734
|
-
const memoriesDir =
|
|
2226
|
+
const memoriesDir = resolve11(geminiDir, "memories");
|
|
1735
2227
|
if (deleteExisting) {
|
|
1736
2228
|
removeIfExists(memoriesDir);
|
|
1737
2229
|
filesDeleted.push(memoriesDir);
|
|
1738
2230
|
}
|
|
1739
2231
|
ensureDir(memoriesDir);
|
|
1740
2232
|
for (const rule of detailRules) {
|
|
1741
|
-
const filepath =
|
|
2233
|
+
const filepath = join14(memoriesDir, `${rule.name}.md`);
|
|
1742
2234
|
writeGeneratedFile(filepath, rule.content);
|
|
1743
2235
|
filesWritten.push(filepath);
|
|
1744
2236
|
}
|
|
1745
2237
|
}
|
|
1746
2238
|
}
|
|
1747
2239
|
if (effective.includes("commands")) {
|
|
1748
|
-
const commandsDir =
|
|
2240
|
+
const commandsDir = resolve11(geminiDir, "commands");
|
|
1749
2241
|
if (deleteExisting) {
|
|
1750
2242
|
removeIfExists(commandsDir);
|
|
1751
2243
|
filesDeleted.push(commandsDir);
|
|
@@ -1754,7 +2246,7 @@ class GeminiCliTarget extends BaseTarget {
|
|
|
1754
2246
|
const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID5));
|
|
1755
2247
|
for (const cmd of commands) {
|
|
1756
2248
|
const toml = buildGeminiCommand(cmd.name, cmd.meta.description ?? "", cmd.content);
|
|
1757
|
-
const filepath =
|
|
2249
|
+
const filepath = join14(commandsDir, `${cmd.name}.toml`);
|
|
1758
2250
|
writeGeneratedFile(filepath, toml, { type: "md" });
|
|
1759
2251
|
filesWritten.push(filepath);
|
|
1760
2252
|
}
|
|
@@ -1763,14 +2255,14 @@ class GeminiCliTarget extends BaseTarget {
|
|
|
1763
2255
|
const mcpEntries = Object.entries(features.mcpServers);
|
|
1764
2256
|
if (mcpEntries.length > 0) {
|
|
1765
2257
|
const settings = buildGeminiSettings(features.mcpServers);
|
|
1766
|
-
const filepath =
|
|
2258
|
+
const filepath = resolve11(geminiDir, "settings.json");
|
|
1767
2259
|
writeGeneratedJson(filepath, settings, { header: false });
|
|
1768
2260
|
filesWritten.push(filepath);
|
|
1769
2261
|
}
|
|
1770
2262
|
}
|
|
1771
2263
|
if (effective.includes("ignore")) {
|
|
1772
2264
|
if (features.ignorePatterns.length > 0) {
|
|
1773
|
-
const filepath =
|
|
2265
|
+
const filepath = resolve11(root, ".geminiignore");
|
|
1774
2266
|
const content = features.ignorePatterns.join(`
|
|
1775
2267
|
`) + `
|
|
1776
2268
|
`;
|
|
@@ -1809,7 +2301,7 @@ function buildGeminiSettings(servers) {
|
|
|
1809
2301
|
}
|
|
1810
2302
|
|
|
1811
2303
|
// src/targets/copilot.ts
|
|
1812
|
-
import { resolve as
|
|
2304
|
+
import { resolve as resolve12, join as join15 } from "path";
|
|
1813
2305
|
var TARGET_ID6 = "copilot";
|
|
1814
2306
|
|
|
1815
2307
|
class CopilotTarget extends BaseTarget {
|
|
@@ -1821,16 +2313,17 @@ class CopilotTarget extends BaseTarget {
|
|
|
1821
2313
|
"agents",
|
|
1822
2314
|
"skills",
|
|
1823
2315
|
"mcp",
|
|
1824
|
-
"ignore"
|
|
2316
|
+
"ignore",
|
|
2317
|
+
"models"
|
|
1825
2318
|
];
|
|
1826
2319
|
generate(options) {
|
|
1827
2320
|
const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
|
|
1828
|
-
const root =
|
|
2321
|
+
const root = resolve12(projectRoot, baseDir);
|
|
1829
2322
|
const effective = this.getEffectiveFeatures(enabledFeatures);
|
|
1830
2323
|
const filesWritten = [];
|
|
1831
2324
|
const filesDeleted = [];
|
|
1832
2325
|
const warnings = [];
|
|
1833
|
-
const githubDir =
|
|
2326
|
+
const githubDir = resolve12(root, ".github");
|
|
1834
2327
|
if (effective.includes("rules")) {
|
|
1835
2328
|
const rules = features.rules.filter((r) => ruleMatchesTarget(r, TARGET_ID6));
|
|
1836
2329
|
if (rules.length > 0) {
|
|
@@ -1839,15 +2332,15 @@ class CopilotTarget extends BaseTarget {
|
|
|
1839
2332
|
---
|
|
1840
2333
|
|
|
1841
2334
|
`);
|
|
1842
|
-
const filepath =
|
|
2335
|
+
const filepath = resolve12(githubDir, "copilot-instructions.md");
|
|
1843
2336
|
ensureDir(githubDir);
|
|
1844
2337
|
writeGeneratedFile(filepath, combinedContent);
|
|
1845
2338
|
filesWritten.push(filepath);
|
|
1846
2339
|
}
|
|
1847
2340
|
}
|
|
1848
2341
|
if (effective.includes("agents")) {
|
|
1849
|
-
const copilotDir =
|
|
1850
|
-
const agentsDir =
|
|
2342
|
+
const copilotDir = resolve12(githubDir, "copilot");
|
|
2343
|
+
const agentsDir = resolve12(copilotDir, "agents");
|
|
1851
2344
|
if (deleteExisting) {
|
|
1852
2345
|
removeIfExists(agentsDir);
|
|
1853
2346
|
filesDeleted.push(agentsDir);
|
|
@@ -1855,14 +2348,14 @@ class CopilotTarget extends BaseTarget {
|
|
|
1855
2348
|
ensureDir(agentsDir);
|
|
1856
2349
|
const agents = features.agents.filter((a) => agentMatchesTarget(a, TARGET_ID6));
|
|
1857
2350
|
for (const agent of agents) {
|
|
1858
|
-
const filepath =
|
|
2351
|
+
const filepath = join15(agentsDir, `${agent.name}.md`);
|
|
1859
2352
|
writeGeneratedFile(filepath, agent.content);
|
|
1860
2353
|
filesWritten.push(filepath);
|
|
1861
2354
|
}
|
|
1862
2355
|
}
|
|
1863
2356
|
if (effective.includes("skills")) {
|
|
1864
|
-
const copilotDir =
|
|
1865
|
-
const skillsDir =
|
|
2357
|
+
const copilotDir = resolve12(githubDir, "copilot");
|
|
2358
|
+
const skillsDir = resolve12(copilotDir, "skills");
|
|
1866
2359
|
if (deleteExisting) {
|
|
1867
2360
|
removeIfExists(skillsDir);
|
|
1868
2361
|
filesDeleted.push(skillsDir);
|
|
@@ -1870,16 +2363,16 @@ class CopilotTarget extends BaseTarget {
|
|
|
1870
2363
|
ensureDir(skillsDir);
|
|
1871
2364
|
const skills = features.skills.filter((s) => skillMatchesTarget(s, TARGET_ID6));
|
|
1872
2365
|
for (const skill of skills) {
|
|
1873
|
-
const skillSubDir =
|
|
2366
|
+
const skillSubDir = join15(skillsDir, skill.name);
|
|
1874
2367
|
ensureDir(skillSubDir);
|
|
1875
|
-
const filepath =
|
|
2368
|
+
const filepath = join15(skillSubDir, "SKILL.md");
|
|
1876
2369
|
writeGeneratedFile(filepath, skill.content);
|
|
1877
2370
|
filesWritten.push(filepath);
|
|
1878
2371
|
}
|
|
1879
2372
|
}
|
|
1880
2373
|
if (effective.includes("commands")) {
|
|
1881
|
-
const copilotDir =
|
|
1882
|
-
const commandsDir =
|
|
2374
|
+
const copilotDir = resolve12(githubDir, "copilot");
|
|
2375
|
+
const commandsDir = resolve12(copilotDir, "commands");
|
|
1883
2376
|
if (deleteExisting) {
|
|
1884
2377
|
removeIfExists(commandsDir);
|
|
1885
2378
|
filesDeleted.push(commandsDir);
|
|
@@ -1887,25 +2380,36 @@ class CopilotTarget extends BaseTarget {
|
|
|
1887
2380
|
ensureDir(commandsDir);
|
|
1888
2381
|
const commands = features.commands.filter((c) => commandMatchesTarget(c, TARGET_ID6));
|
|
1889
2382
|
for (const cmd of commands) {
|
|
1890
|
-
const filepath =
|
|
2383
|
+
const filepath = join15(commandsDir, `${cmd.name}.md`);
|
|
1891
2384
|
writeGeneratedFile(filepath, cmd.content);
|
|
1892
2385
|
filesWritten.push(filepath);
|
|
1893
2386
|
}
|
|
1894
2387
|
}
|
|
1895
2388
|
if (effective.includes("ignore")) {}
|
|
2389
|
+
if (effective.includes("models") && features.models) {
|
|
2390
|
+
const resolved = resolveModels(features.models, options.modelProfile, TARGET_ID6);
|
|
2391
|
+
const guidance = generateModelGuidanceMarkdown(resolved);
|
|
2392
|
+
if (guidance) {
|
|
2393
|
+
const copilotDir = resolve12(githubDir, "copilot");
|
|
2394
|
+
ensureDir(copilotDir);
|
|
2395
|
+
const filepath = join15(copilotDir, "model-config.md");
|
|
2396
|
+
writeGeneratedFile(filepath, guidance);
|
|
2397
|
+
filesWritten.push(filepath);
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
1896
2400
|
return this.createResult(filesWritten, filesDeleted, warnings);
|
|
1897
2401
|
}
|
|
1898
2402
|
}
|
|
1899
2403
|
|
|
1900
2404
|
// src/targets/agents-md.ts
|
|
1901
|
-
import { resolve as
|
|
2405
|
+
import { resolve as resolve13 } from "path";
|
|
1902
2406
|
class AgentsMdTarget extends BaseTarget {
|
|
1903
2407
|
id = "agentsmd";
|
|
1904
2408
|
name = "AGENTS.md";
|
|
1905
2409
|
supportedFeatures = ["rules"];
|
|
1906
2410
|
generate(options) {
|
|
1907
2411
|
const { projectRoot, baseDir, features } = options;
|
|
1908
|
-
const root =
|
|
2412
|
+
const root = resolve13(projectRoot, baseDir);
|
|
1909
2413
|
const filesWritten = [];
|
|
1910
2414
|
const warnings = [];
|
|
1911
2415
|
const rootRules = getRootRules(features.rules);
|
|
@@ -1917,7 +2421,7 @@ class AgentsMdTarget extends BaseTarget {
|
|
|
1917
2421
|
const content = sections.join(`
|
|
1918
2422
|
|
|
1919
2423
|
`);
|
|
1920
|
-
const filepath =
|
|
2424
|
+
const filepath = resolve13(root, "AGENTS.md");
|
|
1921
2425
|
writeGeneratedFile(filepath, content);
|
|
1922
2426
|
filesWritten.push(filepath);
|
|
1923
2427
|
return this.createResult(filesWritten, [], warnings);
|
|
@@ -1925,7 +2429,7 @@ class AgentsMdTarget extends BaseTarget {
|
|
|
1925
2429
|
}
|
|
1926
2430
|
|
|
1927
2431
|
// src/targets/generic-md-target.ts
|
|
1928
|
-
import { resolve as
|
|
2432
|
+
import { resolve as resolve14, join as join16 } from "path";
|
|
1929
2433
|
function createGenericMdTarget(config) {
|
|
1930
2434
|
return new GenericMdTarget(config);
|
|
1931
2435
|
}
|
|
@@ -1944,16 +2448,16 @@ class GenericMdTarget extends BaseTarget {
|
|
|
1944
2448
|
}
|
|
1945
2449
|
generate(options) {
|
|
1946
2450
|
const { projectRoot, baseDir, features, enabledFeatures, deleteExisting } = options;
|
|
1947
|
-
const root =
|
|
2451
|
+
const root = resolve14(projectRoot, baseDir);
|
|
1948
2452
|
const effective = this.getEffectiveFeatures(enabledFeatures);
|
|
1949
2453
|
const filesWritten = [];
|
|
1950
2454
|
const filesDeleted = [];
|
|
1951
2455
|
const warnings = [];
|
|
1952
|
-
const configDir =
|
|
2456
|
+
const configDir = resolve14(root, this.config.configDir);
|
|
1953
2457
|
const rulesSubDir = this.config.rulesDir ?? "rules";
|
|
1954
2458
|
const ext = this.config.ruleExtension ?? ".md";
|
|
1955
2459
|
if (effective.includes("rules")) {
|
|
1956
|
-
const rulesDir =
|
|
2460
|
+
const rulesDir = resolve14(configDir, rulesSubDir);
|
|
1957
2461
|
if (deleteExisting) {
|
|
1958
2462
|
removeIfExists(rulesDir);
|
|
1959
2463
|
filesDeleted.push(rulesDir);
|
|
@@ -1961,13 +2465,13 @@ class GenericMdTarget extends BaseTarget {
|
|
|
1961
2465
|
ensureDir(rulesDir);
|
|
1962
2466
|
const rules = features.rules.filter((r) => ruleMatchesTarget(r, this.id));
|
|
1963
2467
|
for (const rule of rules) {
|
|
1964
|
-
const filepath =
|
|
2468
|
+
const filepath = join16(rulesDir, `${rule.name}${ext}`);
|
|
1965
2469
|
writeGeneratedFile(filepath, rule.content);
|
|
1966
2470
|
filesWritten.push(filepath);
|
|
1967
2471
|
}
|
|
1968
2472
|
}
|
|
1969
2473
|
if (effective.includes("commands")) {
|
|
1970
|
-
const commandsDir =
|
|
2474
|
+
const commandsDir = resolve14(configDir, "commands");
|
|
1971
2475
|
if (deleteExisting) {
|
|
1972
2476
|
removeIfExists(commandsDir);
|
|
1973
2477
|
filesDeleted.push(commandsDir);
|
|
@@ -1975,7 +2479,7 @@ class GenericMdTarget extends BaseTarget {
|
|
|
1975
2479
|
ensureDir(commandsDir);
|
|
1976
2480
|
const commands = features.commands.filter((c) => commandMatchesTarget(c, this.id));
|
|
1977
2481
|
for (const cmd of commands) {
|
|
1978
|
-
const filepath =
|
|
2482
|
+
const filepath = join16(commandsDir, `${cmd.name}.md`);
|
|
1979
2483
|
writeGeneratedFile(filepath, cmd.content);
|
|
1980
2484
|
filesWritten.push(filepath);
|
|
1981
2485
|
}
|
|
@@ -1984,7 +2488,7 @@ class GenericMdTarget extends BaseTarget {
|
|
|
1984
2488
|
const mcpEntries = Object.entries(features.mcpServers);
|
|
1985
2489
|
if (mcpEntries.length > 0) {
|
|
1986
2490
|
const mcpDir = this.config.mcpInConfigDir ? configDir : root;
|
|
1987
|
-
const filepath =
|
|
2491
|
+
const filepath = resolve14(mcpDir, "mcp.json");
|
|
1988
2492
|
writeGeneratedJson(filepath, { mcpServers: features.mcpServers }, {
|
|
1989
2493
|
header: false
|
|
1990
2494
|
});
|
|
@@ -1993,13 +2497,23 @@ class GenericMdTarget extends BaseTarget {
|
|
|
1993
2497
|
}
|
|
1994
2498
|
if (effective.includes("ignore") && this.config.ignoreFile) {
|
|
1995
2499
|
if (features.ignorePatterns.length > 0) {
|
|
1996
|
-
const filepath =
|
|
2500
|
+
const filepath = resolve14(root, this.config.ignoreFile);
|
|
1997
2501
|
writeGeneratedFile(filepath, features.ignorePatterns.join(`
|
|
1998
2502
|
`) + `
|
|
1999
2503
|
`);
|
|
2000
2504
|
filesWritten.push(filepath);
|
|
2001
2505
|
}
|
|
2002
2506
|
}
|
|
2507
|
+
if (effective.includes("models") && features.models) {
|
|
2508
|
+
const resolved = resolveModels(features.models, options.modelProfile, this.id);
|
|
2509
|
+
const guidance = generateModelGuidanceMarkdown(resolved);
|
|
2510
|
+
if (guidance) {
|
|
2511
|
+
ensureDir(configDir);
|
|
2512
|
+
const filepath = join16(configDir, "model-config.md");
|
|
2513
|
+
writeGeneratedFile(filepath, guidance);
|
|
2514
|
+
filesWritten.push(filepath);
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2003
2517
|
return this.createResult(filesWritten, filesDeleted, warnings);
|
|
2004
2518
|
}
|
|
2005
2519
|
}
|
|
@@ -2139,11 +2653,11 @@ function listTargetIds() {
|
|
|
2139
2653
|
}
|
|
2140
2654
|
|
|
2141
2655
|
// src/exporters/cursor-plugin.ts
|
|
2142
|
-
import { resolve as
|
|
2143
|
-
import { mkdirSync as mkdirSync4, writeFileSync as
|
|
2656
|
+
import { resolve as resolve15, join as join17 } from "path";
|
|
2657
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
2144
2658
|
function exportCursorPlugin(pack, outputDir) {
|
|
2145
2659
|
const filesWritten = [];
|
|
2146
|
-
const pluginDir =
|
|
2660
|
+
const pluginDir = resolve15(outputDir, pack.manifest.name);
|
|
2147
2661
|
mkdirSync4(pluginDir, { recursive: true });
|
|
2148
2662
|
const manifest = {
|
|
2149
2663
|
name: pack.manifest.name,
|
|
@@ -2157,7 +2671,7 @@ function exportCursorPlugin(pack, outputDir) {
|
|
|
2157
2671
|
manifest.tags = pack.manifest.tags;
|
|
2158
2672
|
}
|
|
2159
2673
|
if (pack.rules.length > 0) {
|
|
2160
|
-
const rulesDir =
|
|
2674
|
+
const rulesDir = join17(pluginDir, "rules");
|
|
2161
2675
|
ensureDir(rulesDir);
|
|
2162
2676
|
manifest.rules = [];
|
|
2163
2677
|
for (const rule of pack.rules) {
|
|
@@ -2170,14 +2684,14 @@ function exportCursorPlugin(pack, outputDir) {
|
|
|
2170
2684
|
if (globs)
|
|
2171
2685
|
fm.globs = globs;
|
|
2172
2686
|
const filename = `${rule.name}.mdc`;
|
|
2173
|
-
const filepath =
|
|
2174
|
-
|
|
2687
|
+
const filepath = join17(rulesDir, filename);
|
|
2688
|
+
writeFileSync4(filepath, serializeFrontmatter(fm, rule.content));
|
|
2175
2689
|
filesWritten.push(filepath);
|
|
2176
2690
|
manifest.rules.push(filename);
|
|
2177
2691
|
}
|
|
2178
2692
|
}
|
|
2179
2693
|
if (pack.agents.length > 0) {
|
|
2180
|
-
const agentsDir =
|
|
2694
|
+
const agentsDir = join17(pluginDir, "agents");
|
|
2181
2695
|
ensureDir(agentsDir);
|
|
2182
2696
|
manifest.agents = [];
|
|
2183
2697
|
for (const agent of pack.agents) {
|
|
@@ -2186,61 +2700,61 @@ function exportCursorPlugin(pack, outputDir) {
|
|
|
2186
2700
|
description: agent.meta.description ?? ""
|
|
2187
2701
|
};
|
|
2188
2702
|
const filename = `${agent.name}.md`;
|
|
2189
|
-
const filepath =
|
|
2190
|
-
|
|
2703
|
+
const filepath = join17(agentsDir, filename);
|
|
2704
|
+
writeFileSync4(filepath, serializeFrontmatter(fm, agent.content));
|
|
2191
2705
|
filesWritten.push(filepath);
|
|
2192
2706
|
manifest.agents.push(filename);
|
|
2193
2707
|
}
|
|
2194
2708
|
}
|
|
2195
2709
|
if (pack.skills.length > 0) {
|
|
2196
|
-
const skillsDir =
|
|
2710
|
+
const skillsDir = join17(pluginDir, "skills");
|
|
2197
2711
|
ensureDir(skillsDir);
|
|
2198
2712
|
manifest.skills = [];
|
|
2199
2713
|
for (const skill of pack.skills) {
|
|
2200
|
-
const skillSubDir =
|
|
2714
|
+
const skillSubDir = join17(skillsDir, skill.name);
|
|
2201
2715
|
ensureDir(skillSubDir);
|
|
2202
2716
|
const fm = {
|
|
2203
2717
|
name: skill.name,
|
|
2204
2718
|
description: skill.meta.description ?? ""
|
|
2205
2719
|
};
|
|
2206
|
-
const filepath =
|
|
2207
|
-
|
|
2720
|
+
const filepath = join17(skillSubDir, "SKILL.md");
|
|
2721
|
+
writeFileSync4(filepath, serializeFrontmatter(fm, skill.content));
|
|
2208
2722
|
filesWritten.push(filepath);
|
|
2209
2723
|
manifest.skills.push(skill.name);
|
|
2210
2724
|
}
|
|
2211
2725
|
}
|
|
2212
2726
|
if (pack.commands.length > 0) {
|
|
2213
|
-
const commandsDir =
|
|
2727
|
+
const commandsDir = join17(pluginDir, "commands");
|
|
2214
2728
|
ensureDir(commandsDir);
|
|
2215
2729
|
manifest.commands = [];
|
|
2216
2730
|
for (const cmd of pack.commands) {
|
|
2217
2731
|
const filename = `${cmd.name}.md`;
|
|
2218
|
-
const filepath =
|
|
2219
|
-
|
|
2732
|
+
const filepath = join17(commandsDir, filename);
|
|
2733
|
+
writeFileSync4(filepath, cmd.content);
|
|
2220
2734
|
filesWritten.push(filepath);
|
|
2221
2735
|
manifest.commands.push(filename);
|
|
2222
2736
|
}
|
|
2223
2737
|
}
|
|
2224
2738
|
if (pack.mcp && Object.keys(pack.mcp.servers).length > 0) {
|
|
2225
2739
|
manifest.mcp = true;
|
|
2226
|
-
const filepath =
|
|
2227
|
-
|
|
2740
|
+
const filepath = join17(pluginDir, "mcp.json");
|
|
2741
|
+
writeFileSync4(filepath, JSON.stringify({ mcpServers: pack.mcp.servers }, null, 2) + `
|
|
2228
2742
|
`);
|
|
2229
2743
|
filesWritten.push(filepath);
|
|
2230
2744
|
}
|
|
2231
|
-
const manifestPath =
|
|
2232
|
-
|
|
2745
|
+
const manifestPath = join17(pluginDir, "manifest.json");
|
|
2746
|
+
writeFileSync4(manifestPath, JSON.stringify(manifest, null, 2) + `
|
|
2233
2747
|
`);
|
|
2234
2748
|
filesWritten.push(manifestPath);
|
|
2235
2749
|
return { outputDir: pluginDir, filesWritten, manifest };
|
|
2236
2750
|
}
|
|
2237
2751
|
|
|
2238
2752
|
// src/importers/rulesync.ts
|
|
2239
|
-
import { existsSync as existsSync10, readFileSync as readFileSync10, copyFileSync, writeFileSync as
|
|
2240
|
-
import { resolve as
|
|
2753
|
+
import { existsSync as existsSync10, readFileSync as readFileSync10, copyFileSync, writeFileSync as writeFileSync5 } from "fs";
|
|
2754
|
+
import { resolve as resolve16, join as join18, basename as basename6 } from "path";
|
|
2241
2755
|
import { parse as parseJsonc2 } from "jsonc-parser";
|
|
2242
2756
|
function importFromRulesync(projectRoot, outputPackDir) {
|
|
2243
|
-
const rulesyncDir =
|
|
2757
|
+
const rulesyncDir = resolve16(projectRoot, ".rulesync");
|
|
2244
2758
|
const warnings = [];
|
|
2245
2759
|
const filesImported = [];
|
|
2246
2760
|
if (!existsSync10(rulesyncDir)) {
|
|
@@ -2251,79 +2765,79 @@ function importFromRulesync(projectRoot, outputPackDir) {
|
|
|
2251
2765
|
configGenerated: false
|
|
2252
2766
|
};
|
|
2253
2767
|
}
|
|
2254
|
-
const packDir = outputPackDir ??
|
|
2768
|
+
const packDir = outputPackDir ?? resolve16(projectRoot, "packs", "default");
|
|
2255
2769
|
ensureDir(packDir);
|
|
2256
|
-
const rulesDir =
|
|
2770
|
+
const rulesDir = resolve16(rulesyncDir, "rules");
|
|
2257
2771
|
if (existsSync10(rulesDir)) {
|
|
2258
|
-
const outRulesDir =
|
|
2772
|
+
const outRulesDir = resolve16(packDir, "rules");
|
|
2259
2773
|
ensureDir(outRulesDir);
|
|
2260
2774
|
const files = listFiles(rulesDir, { extension: ".md" });
|
|
2261
2775
|
for (const file of files) {
|
|
2262
|
-
const dest =
|
|
2776
|
+
const dest = join18(outRulesDir, basename6(file));
|
|
2263
2777
|
copyFileSync(file, dest);
|
|
2264
2778
|
filesImported.push(dest);
|
|
2265
2779
|
}
|
|
2266
2780
|
}
|
|
2267
|
-
const commandsDir =
|
|
2781
|
+
const commandsDir = resolve16(rulesyncDir, "commands");
|
|
2268
2782
|
if (existsSync10(commandsDir)) {
|
|
2269
|
-
const outCommandsDir =
|
|
2783
|
+
const outCommandsDir = resolve16(packDir, "commands");
|
|
2270
2784
|
ensureDir(outCommandsDir);
|
|
2271
2785
|
const files = listFiles(commandsDir, { extension: ".md" });
|
|
2272
2786
|
for (const file of files) {
|
|
2273
|
-
const dest =
|
|
2787
|
+
const dest = join18(outCommandsDir, basename6(file));
|
|
2274
2788
|
copyFileSync(file, dest);
|
|
2275
2789
|
filesImported.push(dest);
|
|
2276
2790
|
}
|
|
2277
2791
|
}
|
|
2278
|
-
const subagentsDir =
|
|
2792
|
+
const subagentsDir = resolve16(rulesyncDir, "subagents");
|
|
2279
2793
|
if (existsSync10(subagentsDir)) {
|
|
2280
|
-
const outAgentsDir =
|
|
2794
|
+
const outAgentsDir = resolve16(packDir, "agents");
|
|
2281
2795
|
ensureDir(outAgentsDir);
|
|
2282
2796
|
const files = listFiles(subagentsDir, { extension: ".md" });
|
|
2283
2797
|
for (const file of files) {
|
|
2284
|
-
const dest =
|
|
2798
|
+
const dest = join18(outAgentsDir, basename6(file));
|
|
2285
2799
|
copyFileSync(file, dest);
|
|
2286
2800
|
filesImported.push(dest);
|
|
2287
2801
|
}
|
|
2288
2802
|
}
|
|
2289
|
-
const skillsDir =
|
|
2803
|
+
const skillsDir = resolve16(rulesyncDir, "skills");
|
|
2290
2804
|
if (existsSync10(skillsDir)) {
|
|
2291
|
-
const outSkillsDir =
|
|
2805
|
+
const outSkillsDir = resolve16(packDir, "skills");
|
|
2292
2806
|
ensureDir(outSkillsDir);
|
|
2293
2807
|
const skillDirs = listDirs(skillsDir);
|
|
2294
2808
|
for (const skillDir of skillDirs) {
|
|
2295
2809
|
const skillName = basename6(skillDir);
|
|
2296
2810
|
if (skillName.startsWith("."))
|
|
2297
2811
|
continue;
|
|
2298
|
-
const skillMd =
|
|
2812
|
+
const skillMd = join18(skillDir, "SKILL.md");
|
|
2299
2813
|
if (existsSync10(skillMd)) {
|
|
2300
|
-
const outSkillDir =
|
|
2814
|
+
const outSkillDir = join18(outSkillsDir, skillName);
|
|
2301
2815
|
ensureDir(outSkillDir);
|
|
2302
|
-
copyFileSync(skillMd,
|
|
2303
|
-
filesImported.push(
|
|
2816
|
+
copyFileSync(skillMd, join18(outSkillDir, "SKILL.md"));
|
|
2817
|
+
filesImported.push(join18(outSkillDir, "SKILL.md"));
|
|
2304
2818
|
}
|
|
2305
2819
|
}
|
|
2306
2820
|
}
|
|
2307
|
-
const hooksJson =
|
|
2821
|
+
const hooksJson = resolve16(rulesyncDir, "hooks.json");
|
|
2308
2822
|
if (existsSync10(hooksJson)) {
|
|
2309
|
-
const outHooksDir =
|
|
2823
|
+
const outHooksDir = resolve16(packDir, "hooks");
|
|
2310
2824
|
ensureDir(outHooksDir);
|
|
2311
|
-
copyFileSync(hooksJson,
|
|
2312
|
-
filesImported.push(
|
|
2825
|
+
copyFileSync(hooksJson, join18(outHooksDir, "hooks.json"));
|
|
2826
|
+
filesImported.push(join18(outHooksDir, "hooks.json"));
|
|
2313
2827
|
}
|
|
2314
|
-
const mcpJson =
|
|
2828
|
+
const mcpJson = resolve16(rulesyncDir, "mcp.json");
|
|
2315
2829
|
if (existsSync10(mcpJson)) {
|
|
2316
|
-
copyFileSync(mcpJson,
|
|
2317
|
-
filesImported.push(
|
|
2830
|
+
copyFileSync(mcpJson, join18(packDir, "mcp.json"));
|
|
2831
|
+
filesImported.push(join18(packDir, "mcp.json"));
|
|
2318
2832
|
}
|
|
2319
|
-
const aiIgnore =
|
|
2320
|
-
const rulesyncIgnore =
|
|
2833
|
+
const aiIgnore = resolve16(rulesyncDir, ".aiignore");
|
|
2834
|
+
const rulesyncIgnore = resolve16(projectRoot, ".rulesyncignore");
|
|
2321
2835
|
if (existsSync10(aiIgnore)) {
|
|
2322
|
-
copyFileSync(aiIgnore,
|
|
2323
|
-
filesImported.push(
|
|
2836
|
+
copyFileSync(aiIgnore, join18(packDir, "ignore"));
|
|
2837
|
+
filesImported.push(join18(packDir, "ignore"));
|
|
2324
2838
|
} else if (existsSync10(rulesyncIgnore)) {
|
|
2325
|
-
copyFileSync(rulesyncIgnore,
|
|
2326
|
-
filesImported.push(
|
|
2839
|
+
copyFileSync(rulesyncIgnore, join18(packDir, "ignore"));
|
|
2840
|
+
filesImported.push(join18(packDir, "ignore"));
|
|
2327
2841
|
}
|
|
2328
2842
|
const packJson = {
|
|
2329
2843
|
name: "default",
|
|
@@ -2335,20 +2849,20 @@ function importFromRulesync(projectRoot, outputPackDir) {
|
|
|
2335
2849
|
targets: "*",
|
|
2336
2850
|
features: "*"
|
|
2337
2851
|
};
|
|
2338
|
-
|
|
2852
|
+
writeFileSync5(join18(packDir, "pack.json"), JSON.stringify(packJson, null, 2) + `
|
|
2339
2853
|
`);
|
|
2340
|
-
filesImported.push(
|
|
2854
|
+
filesImported.push(join18(packDir, "pack.json"));
|
|
2341
2855
|
let configGenerated = false;
|
|
2342
|
-
const rulesyncConfig =
|
|
2856
|
+
const rulesyncConfig = resolve16(projectRoot, "rulesync.jsonc");
|
|
2343
2857
|
if (existsSync10(rulesyncConfig)) {
|
|
2344
|
-
const agentpacksConfig = convertRulesyncConfig(rulesyncConfig, packDir
|
|
2345
|
-
const configPath =
|
|
2346
|
-
|
|
2858
|
+
const agentpacksConfig = convertRulesyncConfig(rulesyncConfig, packDir);
|
|
2859
|
+
const configPath = resolve16(projectRoot, "agentpacks.jsonc");
|
|
2860
|
+
writeFileSync5(configPath, agentpacksConfig);
|
|
2347
2861
|
configGenerated = true;
|
|
2348
2862
|
}
|
|
2349
2863
|
return { packDir, filesImported, warnings, configGenerated };
|
|
2350
2864
|
}
|
|
2351
|
-
function convertRulesyncConfig(rulesyncPath,
|
|
2865
|
+
function convertRulesyncConfig(rulesyncPath, _packDir) {
|
|
2352
2866
|
const raw = readFileSync10(rulesyncPath, "utf-8");
|
|
2353
2867
|
const parsed = parseJsonc2(raw);
|
|
2354
2868
|
const targets = parsed.targets ?? ["opencode", "cursor", "claudecode"];
|
|
@@ -2356,7 +2870,7 @@ function convertRulesyncConfig(rulesyncPath, packDir, projectRoot) {
|
|
|
2356
2870
|
const baseDirs = parsed.baseDirs ?? ["."];
|
|
2357
2871
|
const global = parsed.global ?? false;
|
|
2358
2872
|
const deleteVal = parsed.delete ?? true;
|
|
2359
|
-
const relPackDir = "./" +
|
|
2873
|
+
const relPackDir = "./" + join18("packs", "default");
|
|
2360
2874
|
const config = {
|
|
2361
2875
|
$schema: "https://unpkg.com/agentpacks/schema.json",
|
|
2362
2876
|
packs: [relPackDir],
|
|
@@ -2373,10 +2887,10 @@ function convertRulesyncConfig(rulesyncPath, packDir, projectRoot) {
|
|
|
2373
2887
|
}
|
|
2374
2888
|
|
|
2375
2889
|
// src/importers/cursor.ts
|
|
2376
|
-
import { existsSync as existsSync11, readFileSync as readFileSync11, writeFileSync as
|
|
2377
|
-
import { resolve as
|
|
2890
|
+
import { existsSync as existsSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync6, copyFileSync as copyFileSync2 } from "fs";
|
|
2891
|
+
import { resolve as resolve17, join as join19, basename as basename7 } from "path";
|
|
2378
2892
|
function importFromCursor(projectRoot, outputPackDir) {
|
|
2379
|
-
const cursorDir =
|
|
2893
|
+
const cursorDir = resolve17(projectRoot, ".cursor");
|
|
2380
2894
|
const warnings = [];
|
|
2381
2895
|
const filesImported = [];
|
|
2382
2896
|
if (!existsSync11(cursorDir)) {
|
|
@@ -2387,11 +2901,11 @@ function importFromCursor(projectRoot, outputPackDir) {
|
|
|
2387
2901
|
configGenerated: false
|
|
2388
2902
|
};
|
|
2389
2903
|
}
|
|
2390
|
-
const packDir = outputPackDir ??
|
|
2904
|
+
const packDir = outputPackDir ?? resolve17(projectRoot, "packs", "cursor-import");
|
|
2391
2905
|
ensureDir(packDir);
|
|
2392
|
-
const rulesDir =
|
|
2906
|
+
const rulesDir = resolve17(cursorDir, "rules");
|
|
2393
2907
|
if (existsSync11(rulesDir)) {
|
|
2394
|
-
const outRulesDir =
|
|
2908
|
+
const outRulesDir = resolve17(packDir, "rules");
|
|
2395
2909
|
ensureDir(outRulesDir);
|
|
2396
2910
|
const files = listFiles(rulesDir, { extension: ".mdc" });
|
|
2397
2911
|
for (const file of files) {
|
|
@@ -2407,64 +2921,64 @@ function importFromCursor(projectRoot, outputPackDir) {
|
|
|
2407
2921
|
meta.cursor = { ...data };
|
|
2408
2922
|
const mdContent = buildAgentpacksRule(meta, content);
|
|
2409
2923
|
const name = basename7(file, ".mdc");
|
|
2410
|
-
const dest =
|
|
2411
|
-
|
|
2924
|
+
const dest = join19(outRulesDir, `${name}.md`);
|
|
2925
|
+
writeFileSync6(dest, mdContent);
|
|
2412
2926
|
filesImported.push(dest);
|
|
2413
2927
|
}
|
|
2414
2928
|
const mdFiles = listFiles(rulesDir, { extension: ".md" });
|
|
2415
2929
|
for (const file of mdFiles) {
|
|
2416
|
-
const dest =
|
|
2930
|
+
const dest = join19(outRulesDir, basename7(file));
|
|
2417
2931
|
copyFileSync2(file, dest);
|
|
2418
2932
|
filesImported.push(dest);
|
|
2419
2933
|
}
|
|
2420
2934
|
}
|
|
2421
|
-
const agentsDir =
|
|
2935
|
+
const agentsDir = resolve17(cursorDir, "agents");
|
|
2422
2936
|
if (existsSync11(agentsDir)) {
|
|
2423
|
-
const outDir =
|
|
2937
|
+
const outDir = resolve17(packDir, "agents");
|
|
2424
2938
|
ensureDir(outDir);
|
|
2425
2939
|
const files = listFiles(agentsDir, { extension: ".md" });
|
|
2426
2940
|
for (const file of files) {
|
|
2427
|
-
const dest =
|
|
2941
|
+
const dest = join19(outDir, basename7(file));
|
|
2428
2942
|
copyFileSync2(file, dest);
|
|
2429
2943
|
filesImported.push(dest);
|
|
2430
2944
|
}
|
|
2431
2945
|
}
|
|
2432
|
-
const skillsDir =
|
|
2946
|
+
const skillsDir = resolve17(cursorDir, "skills");
|
|
2433
2947
|
if (existsSync11(skillsDir)) {
|
|
2434
|
-
const outDir =
|
|
2948
|
+
const outDir = resolve17(packDir, "skills");
|
|
2435
2949
|
ensureDir(outDir);
|
|
2436
2950
|
const dirs = listDirs(skillsDir);
|
|
2437
2951
|
for (const dir of dirs) {
|
|
2438
2952
|
const name = basename7(dir);
|
|
2439
|
-
const skillMd =
|
|
2953
|
+
const skillMd = join19(dir, "SKILL.md");
|
|
2440
2954
|
if (existsSync11(skillMd)) {
|
|
2441
|
-
const outSkillDir =
|
|
2955
|
+
const outSkillDir = join19(outDir, name);
|
|
2442
2956
|
ensureDir(outSkillDir);
|
|
2443
|
-
copyFileSync2(skillMd,
|
|
2444
|
-
filesImported.push(
|
|
2957
|
+
copyFileSync2(skillMd, join19(outSkillDir, "SKILL.md"));
|
|
2958
|
+
filesImported.push(join19(outSkillDir, "SKILL.md"));
|
|
2445
2959
|
}
|
|
2446
2960
|
}
|
|
2447
2961
|
}
|
|
2448
|
-
const commandsDir =
|
|
2962
|
+
const commandsDir = resolve17(cursorDir, "commands");
|
|
2449
2963
|
if (existsSync11(commandsDir)) {
|
|
2450
|
-
const outDir =
|
|
2964
|
+
const outDir = resolve17(packDir, "commands");
|
|
2451
2965
|
ensureDir(outDir);
|
|
2452
2966
|
const files = listFiles(commandsDir, { extension: ".md" });
|
|
2453
2967
|
for (const file of files) {
|
|
2454
|
-
const dest =
|
|
2968
|
+
const dest = join19(outDir, basename7(file));
|
|
2455
2969
|
copyFileSync2(file, dest);
|
|
2456
2970
|
filesImported.push(dest);
|
|
2457
2971
|
}
|
|
2458
2972
|
}
|
|
2459
|
-
const mcpJson =
|
|
2973
|
+
const mcpJson = resolve17(cursorDir, "mcp.json");
|
|
2460
2974
|
if (existsSync11(mcpJson)) {
|
|
2461
|
-
copyFileSync2(mcpJson,
|
|
2462
|
-
filesImported.push(
|
|
2975
|
+
copyFileSync2(mcpJson, join19(packDir, "mcp.json"));
|
|
2976
|
+
filesImported.push(join19(packDir, "mcp.json"));
|
|
2463
2977
|
}
|
|
2464
|
-
const cursorIgnore =
|
|
2978
|
+
const cursorIgnore = resolve17(projectRoot, ".cursorignore");
|
|
2465
2979
|
if (existsSync11(cursorIgnore)) {
|
|
2466
|
-
copyFileSync2(cursorIgnore,
|
|
2467
|
-
filesImported.push(
|
|
2980
|
+
copyFileSync2(cursorIgnore, join19(packDir, "ignore"));
|
|
2981
|
+
filesImported.push(join19(packDir, "ignore"));
|
|
2468
2982
|
}
|
|
2469
2983
|
writePackJson(packDir, "cursor-import", filesImported);
|
|
2470
2984
|
return { packDir, filesImported, warnings, configGenerated: false };
|
|
@@ -2493,20 +3007,20 @@ function writePackJson(packDir, name, filesImported) {
|
|
|
2493
3007
|
targets: "*",
|
|
2494
3008
|
features: "*"
|
|
2495
3009
|
};
|
|
2496
|
-
const dest =
|
|
2497
|
-
|
|
3010
|
+
const dest = join19(packDir, "pack.json");
|
|
3011
|
+
writeFileSync6(dest, JSON.stringify(packJson, null, 2) + `
|
|
2498
3012
|
`);
|
|
2499
3013
|
filesImported.push(dest);
|
|
2500
3014
|
}
|
|
2501
3015
|
|
|
2502
3016
|
// src/importers/claude-code.ts
|
|
2503
|
-
import { existsSync as existsSync12, readFileSync as readFileSync12, writeFileSync as
|
|
2504
|
-
import { resolve as
|
|
3017
|
+
import { existsSync as existsSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync7, copyFileSync as copyFileSync3 } from "fs";
|
|
3018
|
+
import { resolve as resolve18, join as join20, basename as basename8 } from "path";
|
|
2505
3019
|
function importFromClaudeCode(projectRoot, outputPackDir) {
|
|
2506
3020
|
const warnings = [];
|
|
2507
3021
|
const filesImported = [];
|
|
2508
|
-
const claudeDir =
|
|
2509
|
-
const hasClaudeMd = existsSync12(
|
|
3022
|
+
const claudeDir = resolve18(projectRoot, ".claude");
|
|
3023
|
+
const hasClaudeMd = existsSync12(resolve18(projectRoot, "CLAUDE.md"));
|
|
2510
3024
|
const hasClaudeDir = existsSync12(claudeDir);
|
|
2511
3025
|
if (!hasClaudeMd && !hasClaudeDir) {
|
|
2512
3026
|
return {
|
|
@@ -2516,12 +3030,12 @@ function importFromClaudeCode(projectRoot, outputPackDir) {
|
|
|
2516
3030
|
configGenerated: false
|
|
2517
3031
|
};
|
|
2518
3032
|
}
|
|
2519
|
-
const packDir = outputPackDir ??
|
|
3033
|
+
const packDir = outputPackDir ?? resolve18(projectRoot, "packs", "claude-import");
|
|
2520
3034
|
ensureDir(packDir);
|
|
2521
|
-
const rulesDir =
|
|
3035
|
+
const rulesDir = resolve18(packDir, "rules");
|
|
2522
3036
|
ensureDir(rulesDir);
|
|
2523
3037
|
if (hasClaudeMd) {
|
|
2524
|
-
const raw = readFileSync12(
|
|
3038
|
+
const raw = readFileSync12(resolve18(projectRoot, "CLAUDE.md"), "utf-8");
|
|
2525
3039
|
const ruleContent = [
|
|
2526
3040
|
"---",
|
|
2527
3041
|
"root: true",
|
|
@@ -2531,21 +3045,21 @@ function importFromClaudeCode(projectRoot, outputPackDir) {
|
|
|
2531
3045
|
raw
|
|
2532
3046
|
].join(`
|
|
2533
3047
|
`);
|
|
2534
|
-
const dest =
|
|
2535
|
-
|
|
3048
|
+
const dest = join20(rulesDir, "claude-root.md");
|
|
3049
|
+
writeFileSync7(dest, ruleContent);
|
|
2536
3050
|
filesImported.push(dest);
|
|
2537
3051
|
}
|
|
2538
3052
|
if (hasClaudeDir) {
|
|
2539
|
-
const claudeRulesDir =
|
|
3053
|
+
const claudeRulesDir = resolve18(claudeDir, "rules");
|
|
2540
3054
|
if (existsSync12(claudeRulesDir)) {
|
|
2541
3055
|
const files = listFiles(claudeRulesDir, { extension: ".md" });
|
|
2542
3056
|
for (const file of files) {
|
|
2543
|
-
const dest =
|
|
3057
|
+
const dest = join20(rulesDir, basename8(file));
|
|
2544
3058
|
copyFileSync3(file, dest);
|
|
2545
3059
|
filesImported.push(dest);
|
|
2546
3060
|
}
|
|
2547
3061
|
}
|
|
2548
|
-
const settingsPath =
|
|
3062
|
+
const settingsPath = resolve18(claudeDir, "settings.json");
|
|
2549
3063
|
if (existsSync12(settingsPath)) {
|
|
2550
3064
|
try {
|
|
2551
3065
|
const raw = readFileSync12(settingsPath, "utf-8");
|
|
@@ -2553,8 +3067,8 @@ function importFromClaudeCode(projectRoot, outputPackDir) {
|
|
|
2553
3067
|
const mcpServers = settings.mcpServers ?? settings.mcp_servers;
|
|
2554
3068
|
if (mcpServers && typeof mcpServers === "object") {
|
|
2555
3069
|
const mcpConfig = { servers: mcpServers };
|
|
2556
|
-
const dest =
|
|
2557
|
-
|
|
3070
|
+
const dest = join20(packDir, "mcp.json");
|
|
3071
|
+
writeFileSync7(dest, JSON.stringify(mcpConfig, null, 2) + `
|
|
2558
3072
|
`);
|
|
2559
3073
|
filesImported.push(dest);
|
|
2560
3074
|
}
|
|
@@ -2573,20 +3087,20 @@ function importFromClaudeCode(projectRoot, outputPackDir) {
|
|
|
2573
3087
|
targets: "*",
|
|
2574
3088
|
features: "*"
|
|
2575
3089
|
};
|
|
2576
|
-
const packJsonPath =
|
|
2577
|
-
|
|
3090
|
+
const packJsonPath = join20(packDir, "pack.json");
|
|
3091
|
+
writeFileSync7(packJsonPath, JSON.stringify(packJson, null, 2) + `
|
|
2578
3092
|
`);
|
|
2579
3093
|
filesImported.push(packJsonPath);
|
|
2580
3094
|
return { packDir, filesImported, warnings, configGenerated: false };
|
|
2581
3095
|
}
|
|
2582
3096
|
|
|
2583
3097
|
// src/importers/opencode.ts
|
|
2584
|
-
import { existsSync as existsSync13, readFileSync as readFileSync13, writeFileSync as
|
|
2585
|
-
import { resolve as
|
|
3098
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync8, copyFileSync as copyFileSync4 } from "fs";
|
|
3099
|
+
import { resolve as resolve19, join as join21, basename as basename9 } from "path";
|
|
2586
3100
|
function importFromOpenCode(projectRoot, outputPackDir) {
|
|
2587
3101
|
const warnings = [];
|
|
2588
3102
|
const filesImported = [];
|
|
2589
|
-
const ocDir =
|
|
3103
|
+
const ocDir = resolve19(projectRoot, ".opencode");
|
|
2590
3104
|
if (!existsSync13(ocDir)) {
|
|
2591
3105
|
return {
|
|
2592
3106
|
packDir: "",
|
|
@@ -2595,45 +3109,45 @@ function importFromOpenCode(projectRoot, outputPackDir) {
|
|
|
2595
3109
|
configGenerated: false
|
|
2596
3110
|
};
|
|
2597
3111
|
}
|
|
2598
|
-
const packDir = outputPackDir ??
|
|
3112
|
+
const packDir = outputPackDir ?? resolve19(projectRoot, "packs", "opencode-import");
|
|
2599
3113
|
ensureDir(packDir);
|
|
2600
|
-
importDirMd(
|
|
2601
|
-
importDirMd(
|
|
2602
|
-
importDirMd(
|
|
2603
|
-
const skillDir =
|
|
3114
|
+
importDirMd(resolve19(ocDir, "rules"), resolve19(packDir, "rules"), filesImported);
|
|
3115
|
+
importDirMd(resolve19(ocDir, "commands"), resolve19(packDir, "commands"), filesImported);
|
|
3116
|
+
importDirMd(resolve19(ocDir, "agents"), resolve19(packDir, "agents"), filesImported);
|
|
3117
|
+
const skillDir = resolve19(ocDir, "skill");
|
|
2604
3118
|
if (existsSync13(skillDir)) {
|
|
2605
|
-
const outSkillDir =
|
|
3119
|
+
const outSkillDir = resolve19(packDir, "skills");
|
|
2606
3120
|
ensureDir(outSkillDir);
|
|
2607
3121
|
const dirs = listDirs(skillDir);
|
|
2608
3122
|
for (const dir of dirs) {
|
|
2609
3123
|
const name = basename9(dir);
|
|
2610
3124
|
if (name.startsWith("."))
|
|
2611
3125
|
continue;
|
|
2612
|
-
const skillMd =
|
|
3126
|
+
const skillMd = join21(dir, "SKILL.md");
|
|
2613
3127
|
if (existsSync13(skillMd)) {
|
|
2614
|
-
const outDir =
|
|
3128
|
+
const outDir = join21(outSkillDir, name);
|
|
2615
3129
|
ensureDir(outDir);
|
|
2616
|
-
copyFileSync4(skillMd,
|
|
2617
|
-
filesImported.push(
|
|
3130
|
+
copyFileSync4(skillMd, join21(outDir, "SKILL.md"));
|
|
3131
|
+
filesImported.push(join21(outDir, "SKILL.md"));
|
|
2618
3132
|
}
|
|
2619
3133
|
}
|
|
2620
3134
|
}
|
|
2621
|
-
const pluginsDir =
|
|
3135
|
+
const pluginsDir = resolve19(ocDir, "plugins");
|
|
2622
3136
|
if (existsSync13(pluginsDir)) {
|
|
2623
|
-
const outPluginsDir =
|
|
3137
|
+
const outPluginsDir = resolve19(packDir, "plugins");
|
|
2624
3138
|
ensureDir(outPluginsDir);
|
|
2625
3139
|
const files = listFiles(pluginsDir);
|
|
2626
3140
|
for (const file of files) {
|
|
2627
3141
|
if (file.endsWith(".ts") || file.endsWith(".js")) {
|
|
2628
|
-
const dest2 =
|
|
3142
|
+
const dest2 = join21(outPluginsDir, basename9(file));
|
|
2629
3143
|
copyFileSync4(file, dest2);
|
|
2630
3144
|
filesImported.push(dest2);
|
|
2631
3145
|
}
|
|
2632
3146
|
}
|
|
2633
3147
|
}
|
|
2634
|
-
const agentsMd =
|
|
3148
|
+
const agentsMd = resolve19(projectRoot, "AGENTS.md");
|
|
2635
3149
|
if (existsSync13(agentsMd)) {
|
|
2636
|
-
const outRulesDir =
|
|
3150
|
+
const outRulesDir = resolve19(packDir, "rules");
|
|
2637
3151
|
ensureDir(outRulesDir);
|
|
2638
3152
|
const raw = readFileSync13(agentsMd, "utf-8");
|
|
2639
3153
|
const ruleContent = [
|
|
@@ -2645,19 +3159,19 @@ function importFromOpenCode(projectRoot, outputPackDir) {
|
|
|
2645
3159
|
raw
|
|
2646
3160
|
].join(`
|
|
2647
3161
|
`);
|
|
2648
|
-
const dest2 =
|
|
2649
|
-
|
|
3162
|
+
const dest2 = join21(outRulesDir, "agents-md-root.md");
|
|
3163
|
+
writeFileSync8(dest2, ruleContent);
|
|
2650
3164
|
filesImported.push(dest2);
|
|
2651
3165
|
}
|
|
2652
|
-
const ocJson =
|
|
3166
|
+
const ocJson = resolve19(projectRoot, "opencode.json");
|
|
2653
3167
|
if (existsSync13(ocJson)) {
|
|
2654
3168
|
try {
|
|
2655
3169
|
const raw = readFileSync13(ocJson, "utf-8");
|
|
2656
3170
|
const config = JSON.parse(raw);
|
|
2657
3171
|
const mcpObj = config.mcp;
|
|
2658
3172
|
if (mcpObj) {
|
|
2659
|
-
const dest2 =
|
|
2660
|
-
|
|
3173
|
+
const dest2 = join21(packDir, "mcp.json");
|
|
3174
|
+
writeFileSync8(dest2, JSON.stringify({ servers: mcpObj }, null, 2) + `
|
|
2661
3175
|
`);
|
|
2662
3176
|
filesImported.push(dest2);
|
|
2663
3177
|
}
|
|
@@ -2665,10 +3179,10 @@ function importFromOpenCode(projectRoot, outputPackDir) {
|
|
|
2665
3179
|
warnings.push("Failed to parse opencode.json");
|
|
2666
3180
|
}
|
|
2667
3181
|
}
|
|
2668
|
-
const ocIgnore =
|
|
3182
|
+
const ocIgnore = resolve19(projectRoot, ".opencodeignore");
|
|
2669
3183
|
if (existsSync13(ocIgnore)) {
|
|
2670
|
-
copyFileSync4(ocIgnore,
|
|
2671
|
-
filesImported.push(
|
|
3184
|
+
copyFileSync4(ocIgnore, join21(packDir, "ignore"));
|
|
3185
|
+
filesImported.push(join21(packDir, "ignore"));
|
|
2672
3186
|
}
|
|
2673
3187
|
const packJson = {
|
|
2674
3188
|
name: "opencode-import",
|
|
@@ -2680,8 +3194,8 @@ function importFromOpenCode(projectRoot, outputPackDir) {
|
|
|
2680
3194
|
targets: "*",
|
|
2681
3195
|
features: "*"
|
|
2682
3196
|
};
|
|
2683
|
-
const dest =
|
|
2684
|
-
|
|
3197
|
+
const dest = join21(packDir, "pack.json");
|
|
3198
|
+
writeFileSync8(dest, JSON.stringify(packJson, null, 2) + `
|
|
2685
3199
|
`);
|
|
2686
3200
|
filesImported.push(dest);
|
|
2687
3201
|
return { packDir, filesImported, warnings, configGenerated: false };
|
|
@@ -2692,15 +3206,14 @@ function importDirMd(srcDir, outDir, filesImported) {
|
|
|
2692
3206
|
ensureDir(outDir);
|
|
2693
3207
|
const files = listFiles(srcDir, { extension: ".md" });
|
|
2694
3208
|
for (const file of files) {
|
|
2695
|
-
const dest =
|
|
3209
|
+
const dest = join21(outDir, basename9(file));
|
|
2696
3210
|
copyFileSync4(file, dest);
|
|
2697
3211
|
filesImported.push(dest);
|
|
2698
3212
|
}
|
|
2699
3213
|
}
|
|
2700
3214
|
|
|
2701
3215
|
// src/cli/export-cmd.ts
|
|
2702
|
-
|
|
2703
|
-
import { resolve as resolve21 } from "path";
|
|
3216
|
+
import { resolve as resolve20 } from "path";
|
|
2704
3217
|
import chalk from "chalk";
|
|
2705
3218
|
function runExport(projectRoot, options) {
|
|
2706
3219
|
const config = loadWorkspaceConfig(projectRoot);
|
|
@@ -2719,7 +3232,7 @@ function runExport(projectRoot, options) {
|
|
|
2719
3232
|
console.log(chalk.red(`Pack "${options.pack}" not found.`));
|
|
2720
3233
|
return;
|
|
2721
3234
|
}
|
|
2722
|
-
const outputDir =
|
|
3235
|
+
const outputDir = resolve20(projectRoot, options.output ?? "dist/cursor-plugins");
|
|
2723
3236
|
switch (options.format) {
|
|
2724
3237
|
case "cursor-plugin": {
|
|
2725
3238
|
let totalFiles = 0;
|
|
@@ -2796,14 +3309,29 @@ function findHunks(oldLines, newLines) {
|
|
|
2796
3309
|
let ni = 0;
|
|
2797
3310
|
while (oi < oldLines.length || ni < newLines.length) {
|
|
2798
3311
|
if (oi < oldLines.length && ni < newLines.length && oldLines[oi] === newLines[ni]) {
|
|
2799
|
-
changes.push({
|
|
3312
|
+
changes.push({
|
|
3313
|
+
type: " ",
|
|
3314
|
+
line: oldLines[oi] ?? "",
|
|
3315
|
+
oldIdx: oi,
|
|
3316
|
+
newIdx: ni
|
|
3317
|
+
});
|
|
2800
3318
|
oi++;
|
|
2801
3319
|
ni++;
|
|
2802
|
-
} else if (ni < newLines.length && (oi >= oldLines.length || !newLines.slice(ni).includes(oldLines[oi]))) {
|
|
2803
|
-
changes.push({
|
|
3320
|
+
} else if (ni < newLines.length && (oi >= oldLines.length || !newLines.slice(ni).includes(oldLines[oi] ?? ""))) {
|
|
3321
|
+
changes.push({
|
|
3322
|
+
type: "+",
|
|
3323
|
+
line: newLines[ni] ?? "",
|
|
3324
|
+
oldIdx: oi,
|
|
3325
|
+
newIdx: ni
|
|
3326
|
+
});
|
|
2804
3327
|
ni++;
|
|
2805
3328
|
} else {
|
|
2806
|
-
changes.push({
|
|
3329
|
+
changes.push({
|
|
3330
|
+
type: "-",
|
|
3331
|
+
line: oldLines[oi] ?? "",
|
|
3332
|
+
oldIdx: oi,
|
|
3333
|
+
newIdx: oi
|
|
3334
|
+
});
|
|
2807
3335
|
oi++;
|
|
2808
3336
|
}
|
|
2809
3337
|
}
|
|
@@ -2832,8 +3360,9 @@ function findHunks(oldLines, newLines) {
|
|
|
2832
3360
|
lines: []
|
|
2833
3361
|
};
|
|
2834
3362
|
for (let i = contextStart;i < changes.indexOf(change); i++) {
|
|
2835
|
-
|
|
2836
|
-
|
|
3363
|
+
const entry = changes[i];
|
|
3364
|
+
if (entry?.type === " ") {
|
|
3365
|
+
currentHunk.lines.push(` ${entry.line}`);
|
|
2837
3366
|
currentHunk.oldCount++;
|
|
2838
3367
|
currentHunk.newCount++;
|
|
2839
3368
|
}
|
|
@@ -2853,7 +3382,6 @@ function findHunks(oldLines, newLines) {
|
|
|
2853
3382
|
}
|
|
2854
3383
|
|
|
2855
3384
|
// src/cli/generate.ts
|
|
2856
|
-
init_config();
|
|
2857
3385
|
import { existsSync as existsSync15, readFileSync as readFileSync15 } from "fs";
|
|
2858
3386
|
import chalk2 from "chalk";
|
|
2859
3387
|
function runGenerate(projectRoot, options) {
|
|
@@ -2924,9 +3452,9 @@ function runGenerate(projectRoot, options) {
|
|
|
2924
3452
|
enabledFeatures,
|
|
2925
3453
|
deleteExisting: options.diff ? false : config.delete,
|
|
2926
3454
|
global: config.global,
|
|
2927
|
-
verbose: config.verbose
|
|
3455
|
+
verbose: config.verbose,
|
|
3456
|
+
modelProfile: config.modelProfile
|
|
2928
3457
|
};
|
|
2929
|
-
const preSnapshot = new Map;
|
|
2930
3458
|
try {
|
|
2931
3459
|
const result = target.generate(generateOptions);
|
|
2932
3460
|
allResults.push(result);
|
|
@@ -3055,19 +3583,246 @@ Next steps:`), `
|
|
|
3055
3583
|
2. Run`, chalk3.bold("agentpacks generate"), "to generate tool configs");
|
|
3056
3584
|
}
|
|
3057
3585
|
|
|
3058
|
-
// src/
|
|
3059
|
-
|
|
3060
|
-
|
|
3586
|
+
// src/utils/registry-client.ts
|
|
3587
|
+
var DEFAULT_REGISTRY_URL = "https://registry.agentpacks.dev";
|
|
3588
|
+
function createRegistryClient(config) {
|
|
3589
|
+
return new RegistryClient({
|
|
3590
|
+
registryUrl: config?.registryUrl ?? DEFAULT_REGISTRY_URL,
|
|
3591
|
+
authToken: config?.authToken,
|
|
3592
|
+
timeout: config?.timeout ?? 30000
|
|
3593
|
+
});
|
|
3594
|
+
}
|
|
3595
|
+
|
|
3596
|
+
class RegistryClient {
|
|
3597
|
+
config;
|
|
3598
|
+
constructor(config) {
|
|
3599
|
+
this.config = {
|
|
3600
|
+
registryUrl: config.registryUrl.replace(/\/+$/, ""),
|
|
3601
|
+
authToken: config.authToken,
|
|
3602
|
+
timeout: config.timeout ?? 30000
|
|
3603
|
+
};
|
|
3604
|
+
}
|
|
3605
|
+
async search(params) {
|
|
3606
|
+
const searchParams = new URLSearchParams;
|
|
3607
|
+
if (params.query)
|
|
3608
|
+
searchParams.set("q", params.query);
|
|
3609
|
+
if (params.tags?.length)
|
|
3610
|
+
searchParams.set("tags", params.tags.join(","));
|
|
3611
|
+
if (params.targets?.length)
|
|
3612
|
+
searchParams.set("targets", params.targets.join(","));
|
|
3613
|
+
if (params.features?.length)
|
|
3614
|
+
searchParams.set("features", params.features.join(","));
|
|
3615
|
+
if (params.author)
|
|
3616
|
+
searchParams.set("author", params.author);
|
|
3617
|
+
if (params.sort)
|
|
3618
|
+
searchParams.set("sort", params.sort);
|
|
3619
|
+
if (params.limit)
|
|
3620
|
+
searchParams.set("limit", String(params.limit));
|
|
3621
|
+
if (params.offset)
|
|
3622
|
+
searchParams.set("offset", String(params.offset));
|
|
3623
|
+
const url = `${this.config.registryUrl}/packs?${searchParams.toString()}`;
|
|
3624
|
+
const res = await this.fetch(url);
|
|
3625
|
+
return res;
|
|
3626
|
+
}
|
|
3627
|
+
async info(packName) {
|
|
3628
|
+
const url = `${this.config.registryUrl}/packs/${encodeURIComponent(packName)}`;
|
|
3629
|
+
const res = await this.fetch(url);
|
|
3630
|
+
return res;
|
|
3631
|
+
}
|
|
3632
|
+
async download(packName, version = "latest") {
|
|
3633
|
+
const url = `${this.config.registryUrl}/packs/${encodeURIComponent(packName)}/versions/${encodeURIComponent(version)}/download`;
|
|
3634
|
+
const response = await fetch(url, {
|
|
3635
|
+
headers: this.headers(),
|
|
3636
|
+
signal: AbortSignal.timeout(this.config.timeout)
|
|
3637
|
+
});
|
|
3638
|
+
if (!response.ok) {
|
|
3639
|
+
throw new RegistryApiError(response.status, `Failed to download ${packName}@${version}: ${response.statusText}`);
|
|
3640
|
+
}
|
|
3641
|
+
const integrity = response.headers.get("x-integrity") ?? "";
|
|
3642
|
+
const data = await response.arrayBuffer();
|
|
3643
|
+
return { data, integrity };
|
|
3644
|
+
}
|
|
3645
|
+
async publish(tarball, metadata) {
|
|
3646
|
+
if (!this.config.authToken) {
|
|
3647
|
+
throw new Error("Authentication required. Run `agentpacks login` first.");
|
|
3648
|
+
}
|
|
3649
|
+
const formData = new FormData;
|
|
3650
|
+
formData.append("tarball", new Blob([tarball], { type: "application/gzip" }), `${metadata.name}-${metadata.version}.tgz`);
|
|
3651
|
+
formData.append("metadata", JSON.stringify(metadata));
|
|
3652
|
+
const url = `${this.config.registryUrl}/packs`;
|
|
3653
|
+
const response = await fetch(url, {
|
|
3654
|
+
method: "POST",
|
|
3655
|
+
headers: {
|
|
3656
|
+
Authorization: `Bearer ${this.config.authToken}`
|
|
3657
|
+
},
|
|
3658
|
+
body: formData,
|
|
3659
|
+
signal: AbortSignal.timeout(this.config.timeout)
|
|
3660
|
+
});
|
|
3661
|
+
if (!response.ok) {
|
|
3662
|
+
const body = await response.text();
|
|
3663
|
+
throw new RegistryApiError(response.status, `Publish failed: ${body || response.statusText}`);
|
|
3664
|
+
}
|
|
3665
|
+
return await response.json();
|
|
3666
|
+
}
|
|
3667
|
+
async featured(limit) {
|
|
3668
|
+
const url = limit ? `${this.config.registryUrl}/featured?limit=${limit}` : `${this.config.registryUrl}/featured`;
|
|
3669
|
+
const res = await this.fetch(url);
|
|
3670
|
+
return res.packs;
|
|
3671
|
+
}
|
|
3672
|
+
async tags() {
|
|
3673
|
+
const url = `${this.config.registryUrl}/tags`;
|
|
3674
|
+
const res = await this.fetch(url);
|
|
3675
|
+
return res.tags;
|
|
3676
|
+
}
|
|
3677
|
+
async stats() {
|
|
3678
|
+
const url = `${this.config.registryUrl}/stats`;
|
|
3679
|
+
return await this.fetch(url);
|
|
3680
|
+
}
|
|
3681
|
+
async health() {
|
|
3682
|
+
try {
|
|
3683
|
+
const url = `${this.config.registryUrl}/health`;
|
|
3684
|
+
await this.fetch(url);
|
|
3685
|
+
return true;
|
|
3686
|
+
} catch {
|
|
3687
|
+
return false;
|
|
3688
|
+
}
|
|
3689
|
+
}
|
|
3690
|
+
async fetch(url) {
|
|
3691
|
+
const response = await fetch(url, {
|
|
3692
|
+
headers: this.headers(),
|
|
3693
|
+
signal: AbortSignal.timeout(this.config.timeout)
|
|
3694
|
+
});
|
|
3695
|
+
if (!response.ok) {
|
|
3696
|
+
const body = await response.text();
|
|
3697
|
+
throw new RegistryApiError(response.status, body || response.statusText);
|
|
3698
|
+
}
|
|
3699
|
+
return response.json();
|
|
3700
|
+
}
|
|
3701
|
+
headers() {
|
|
3702
|
+
const h = {
|
|
3703
|
+
Accept: "application/json"
|
|
3704
|
+
};
|
|
3705
|
+
if (this.config.authToken) {
|
|
3706
|
+
h["Authorization"] = `Bearer ${this.config.authToken}`;
|
|
3707
|
+
}
|
|
3708
|
+
return h;
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
|
|
3712
|
+
class RegistryApiError extends Error {
|
|
3713
|
+
status;
|
|
3714
|
+
constructor(status, message) {
|
|
3715
|
+
super(message);
|
|
3716
|
+
this.name = "RegistryApiError";
|
|
3717
|
+
this.status = status;
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3720
|
+
|
|
3721
|
+
// src/utils/credentials.ts
|
|
3722
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16, writeFileSync as writeFileSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
3723
|
+
import { join as join22, dirname as dirname2 } from "path";
|
|
3724
|
+
import { homedir } from "os";
|
|
3725
|
+
var CONFIG_DIR = join22(homedir(), ".config", "agentpacks");
|
|
3726
|
+
var CREDENTIALS_FILE = join22(CONFIG_DIR, "credentials.json");
|
|
3727
|
+
function loadCredentials() {
|
|
3728
|
+
if (!existsSync16(CREDENTIALS_FILE)) {
|
|
3729
|
+
return { registryUrl: "https://registry.agentpacks.dev" };
|
|
3730
|
+
}
|
|
3731
|
+
try {
|
|
3732
|
+
const raw = readFileSync16(CREDENTIALS_FILE, "utf-8");
|
|
3733
|
+
return JSON.parse(raw);
|
|
3734
|
+
} catch {
|
|
3735
|
+
return { registryUrl: "https://registry.agentpacks.dev" };
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
function saveCredentials(credentials) {
|
|
3739
|
+
mkdirSync5(dirname2(CREDENTIALS_FILE), { recursive: true });
|
|
3740
|
+
writeFileSync9(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2) + `
|
|
3741
|
+
`, {
|
|
3742
|
+
mode: 384
|
|
3743
|
+
});
|
|
3744
|
+
}
|
|
3745
|
+
function clearCredentials() {
|
|
3746
|
+
if (existsSync16(CREDENTIALS_FILE)) {
|
|
3747
|
+
writeFileSync9(CREDENTIALS_FILE, JSON.stringify({ registryUrl: "https://registry.agentpacks.dev" }) + `
|
|
3748
|
+
`);
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
// src/cli/info.ts
|
|
3061
3753
|
import chalk4 from "chalk";
|
|
3754
|
+
async function runInfo(packName) {
|
|
3755
|
+
const credentials = loadCredentials();
|
|
3756
|
+
const client = createRegistryClient({
|
|
3757
|
+
registryUrl: credentials.registryUrl,
|
|
3758
|
+
authToken: credentials.token
|
|
3759
|
+
});
|
|
3760
|
+
try {
|
|
3761
|
+
const pack = await client.info(packName);
|
|
3762
|
+
console.log(chalk4.bold(`
|
|
3763
|
+
${pack.displayName}`));
|
|
3764
|
+
console.log(chalk4.dim(` ${pack.name}`));
|
|
3765
|
+
console.log(` ${pack.description}`);
|
|
3766
|
+
console.log();
|
|
3767
|
+
console.log(` ${chalk4.dim("Author:")} ${pack.author}`);
|
|
3768
|
+
console.log(` ${chalk4.dim("License:")} ${pack.license}`);
|
|
3769
|
+
console.log(` ${chalk4.dim("Downloads:")} ${pack.downloads}`);
|
|
3770
|
+
if (pack.homepage) {
|
|
3771
|
+
console.log(` ${chalk4.dim("Homepage:")} ${pack.homepage}`);
|
|
3772
|
+
}
|
|
3773
|
+
if (pack.repository) {
|
|
3774
|
+
console.log(` ${chalk4.dim("Repository:")} ${pack.repository}`);
|
|
3775
|
+
}
|
|
3776
|
+
console.log();
|
|
3777
|
+
if (pack.tags.length > 0) {
|
|
3778
|
+
console.log(` ${chalk4.dim("Tags:")} ${pack.tags.join(", ")}`);
|
|
3779
|
+
}
|
|
3780
|
+
if (pack.targets.length > 0) {
|
|
3781
|
+
console.log(` ${chalk4.dim("Targets:")} ${pack.targets.join(", ")}`);
|
|
3782
|
+
}
|
|
3783
|
+
if (pack.features.length > 0) {
|
|
3784
|
+
console.log(` ${chalk4.dim("Features:")} ${pack.features.join(", ")}`);
|
|
3785
|
+
}
|
|
3786
|
+
console.log();
|
|
3787
|
+
if (pack.versions.length > 0) {
|
|
3788
|
+
console.log(chalk4.bold(" Versions:"));
|
|
3789
|
+
for (const v of pack.versions.slice(0, 10)) {
|
|
3790
|
+
console.log(` ${v.version} — ${v.createdAt} (${v.fileCount} files, ${formatBytes(v.tarballSize)})`);
|
|
3791
|
+
}
|
|
3792
|
+
if (pack.versions.length > 10) {
|
|
3793
|
+
console.log(chalk4.dim(` ... and ${pack.versions.length - 10} more`));
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
console.log();
|
|
3797
|
+
console.log(chalk4.bold(" Install:"));
|
|
3798
|
+
console.log(` registry:${pack.name}`);
|
|
3799
|
+
console.log();
|
|
3800
|
+
} catch (err) {
|
|
3801
|
+
console.log(chalk4.red(`Failed to get pack info: ${err instanceof Error ? err.message : String(err)}`));
|
|
3802
|
+
process.exit(1);
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
function formatBytes(bytes) {
|
|
3806
|
+
if (bytes < 1024)
|
|
3807
|
+
return `${bytes} B`;
|
|
3808
|
+
if (bytes < 1024 * 1024)
|
|
3809
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
3810
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
3811
|
+
}
|
|
3812
|
+
|
|
3813
|
+
// src/cli/init.ts
|
|
3814
|
+
import { existsSync as existsSync17, copyFileSync as copyFileSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
3815
|
+
import { resolve as resolve21, join as join23 } from "path";
|
|
3816
|
+
import chalk5 from "chalk";
|
|
3062
3817
|
function runInit(projectRoot) {
|
|
3063
|
-
const configPath =
|
|
3064
|
-
const packsDir =
|
|
3065
|
-
if (
|
|
3066
|
-
console.log(
|
|
3818
|
+
const configPath = resolve21(projectRoot, "agentpacks.jsonc");
|
|
3819
|
+
const packsDir = resolve21(projectRoot, "packs", "default");
|
|
3820
|
+
if (existsSync17(configPath)) {
|
|
3821
|
+
console.log(chalk5.yellow("agentpacks.jsonc already exists. Skipping config creation."));
|
|
3067
3822
|
} else {
|
|
3068
|
-
const templateDir =
|
|
3069
|
-
const templateConfig =
|
|
3070
|
-
if (
|
|
3823
|
+
const templateDir = resolve21(import.meta.dirname, "..", "..", "templates");
|
|
3824
|
+
const templateConfig = resolve21(templateDir, "workspace", "agentpacks.jsonc");
|
|
3825
|
+
if (existsSync17(templateConfig)) {
|
|
3071
3826
|
copyFileSync5(templateConfig, configPath);
|
|
3072
3827
|
} else {
|
|
3073
3828
|
const config = {
|
|
@@ -3091,16 +3846,16 @@ function runInit(projectRoot) {
|
|
|
3091
3846
|
writeFileSync10(configPath, JSON.stringify(config, null, 2) + `
|
|
3092
3847
|
`);
|
|
3093
3848
|
}
|
|
3094
|
-
console.log(
|
|
3849
|
+
console.log(chalk5.green("Created agentpacks.jsonc"));
|
|
3095
3850
|
}
|
|
3096
|
-
if (
|
|
3097
|
-
console.log(
|
|
3851
|
+
if (existsSync17(packsDir)) {
|
|
3852
|
+
console.log(chalk5.yellow("packs/default/ already exists. Skipping pack scaffold."));
|
|
3098
3853
|
} else {
|
|
3099
3854
|
ensureDir(packsDir);
|
|
3100
|
-
ensureDir(
|
|
3101
|
-
ensureDir(
|
|
3102
|
-
ensureDir(
|
|
3103
|
-
ensureDir(
|
|
3855
|
+
ensureDir(join23(packsDir, "rules"));
|
|
3856
|
+
ensureDir(join23(packsDir, "commands"));
|
|
3857
|
+
ensureDir(join23(packsDir, "agents"));
|
|
3858
|
+
ensureDir(join23(packsDir, "skills"));
|
|
3104
3859
|
const packJson = {
|
|
3105
3860
|
name: "default",
|
|
3106
3861
|
version: "1.0.0",
|
|
@@ -3111,43 +3866,162 @@ function runInit(projectRoot) {
|
|
|
3111
3866
|
targets: "*",
|
|
3112
3867
|
features: "*"
|
|
3113
3868
|
};
|
|
3114
|
-
writeFileSync10(
|
|
3869
|
+
writeFileSync10(join23(packsDir, "pack.json"), JSON.stringify(packJson, null, 2) + `
|
|
3115
3870
|
`);
|
|
3116
|
-
const templateRule =
|
|
3117
|
-
if (
|
|
3118
|
-
copyFileSync5(templateRule,
|
|
3871
|
+
const templateRule = resolve21(import.meta.dirname, "..", "..", "templates", "pack", "rules", "overview.md");
|
|
3872
|
+
if (existsSync17(templateRule)) {
|
|
3873
|
+
copyFileSync5(templateRule, join23(packsDir, "rules", "overview.md"));
|
|
3119
3874
|
}
|
|
3120
|
-
console.log(
|
|
3875
|
+
console.log(chalk5.green("Created packs/default/ with scaffold"));
|
|
3121
3876
|
}
|
|
3122
|
-
console.log(
|
|
3877
|
+
console.log(chalk5.cyan(`
|
|
3123
3878
|
Next steps:`), `
|
|
3124
3879
|
1. Edit packs/default/rules/overview.md with your project guidelines`, `
|
|
3125
|
-
2. Run`,
|
|
3126
|
-
3. Or run`,
|
|
3880
|
+
2. Run`, chalk5.bold("agentpacks generate"), "to generate tool configs", `
|
|
3881
|
+
3. Or run`, chalk5.bold("agentpacks import --from rulesync"), "to migrate from rulesync");
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
// src/utils/tarball.ts
|
|
3885
|
+
import { execSync as execSync2 } from "child_process";
|
|
3886
|
+
import { readFileSync as readFileSync17, existsSync as existsSync18, mkdirSync as mkdirSync6, rmSync as rmSync2 } from "fs";
|
|
3887
|
+
import { join as join24, resolve as resolve22 } from "path";
|
|
3888
|
+
import { createHash as createHash2 } from "crypto";
|
|
3889
|
+
import { tmpdir } from "os";
|
|
3890
|
+
async function createTarball(packDir) {
|
|
3891
|
+
const absDir = resolve22(packDir);
|
|
3892
|
+
const tmpFile = join24(tmpdir(), `agentpacks-${Date.now()}.tgz`);
|
|
3893
|
+
try {
|
|
3894
|
+
execSync2(`tar -czf "${tmpFile}" -C "${absDir}" .`, {
|
|
3895
|
+
stdio: "pipe"
|
|
3896
|
+
});
|
|
3897
|
+
const buffer = readFileSync17(tmpFile);
|
|
3898
|
+
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
3899
|
+
} finally {
|
|
3900
|
+
if (existsSync18(tmpFile)) {
|
|
3901
|
+
rmSync2(tmpFile);
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
async function extractTarball(data, targetDir) {
|
|
3906
|
+
mkdirSync6(targetDir, { recursive: true });
|
|
3907
|
+
const tmpFile = join24(tmpdir(), `agentpacks-${Date.now()}.tgz`);
|
|
3908
|
+
try {
|
|
3909
|
+
const buffer = Buffer.from(data);
|
|
3910
|
+
const { writeFileSync: writeFileSync11 } = await import("fs");
|
|
3911
|
+
writeFileSync11(tmpFile, buffer);
|
|
3912
|
+
execSync2(`tar -xzf "${tmpFile}" -C "${targetDir}"`, {
|
|
3913
|
+
stdio: "pipe"
|
|
3914
|
+
});
|
|
3915
|
+
} finally {
|
|
3916
|
+
if (existsSync18(tmpFile)) {
|
|
3917
|
+
rmSync2(tmpFile);
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
function computeTarballIntegrity(data) {
|
|
3922
|
+
const hash = createHash2("sha256").update(Buffer.from(data)).digest("hex");
|
|
3923
|
+
return `sha256-${hash}`;
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3926
|
+
// src/sources/registry.ts
|
|
3927
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync7, readdirSync as readdirSync3, rmSync as rmSync3 } from "fs";
|
|
3928
|
+
import { resolve as resolve23, join as join25 } from "path";
|
|
3929
|
+
async function installRegistrySource(projectRoot, source, lockfile, options = {}) {
|
|
3930
|
+
const parsed = parseRegistrySourceRef(source);
|
|
3931
|
+
const sourceKey = registrySourceKey(parsed);
|
|
3932
|
+
const installed = [];
|
|
3933
|
+
const warnings = [];
|
|
3934
|
+
const locked = getLockedSource(lockfile, sourceKey);
|
|
3935
|
+
if (options.frozen && !locked) {
|
|
3936
|
+
throw new Error(`Frozen mode: no lockfile entry for source "${sourceKey}".`);
|
|
3937
|
+
}
|
|
3938
|
+
let targetVersion = parsed.version;
|
|
3939
|
+
if (locked && !options.update) {
|
|
3940
|
+
targetVersion = locked.resolvedRef;
|
|
3941
|
+
} else if (targetVersion === "latest") {
|
|
3942
|
+
const clientCfg2 = buildClientConfig(options.registryUrl);
|
|
3943
|
+
const client2 = createRegistryClient(clientCfg2);
|
|
3944
|
+
const info = await client2.info(parsed.packName);
|
|
3945
|
+
targetVersion = info.latestVersion;
|
|
3946
|
+
}
|
|
3947
|
+
const clientCfg = buildClientConfig(options.registryUrl);
|
|
3948
|
+
const client = createRegistryClient(clientCfg);
|
|
3949
|
+
const { data } = await client.download(parsed.packName, targetVersion);
|
|
3950
|
+
const localIntegrity = computeTarballIntegrity(data);
|
|
3951
|
+
if (locked && !options.update && locked.skills?.["__integrity"]) {
|
|
3952
|
+
const expectedIntegrity = locked.skills["__integrity"].integrity;
|
|
3953
|
+
if (expectedIntegrity && localIntegrity !== expectedIntegrity) {
|
|
3954
|
+
throw new Error(`Integrity mismatch for ${parsed.packName}@${targetVersion}. ` + `Expected ${expectedIntegrity}, got ${localIntegrity}.`);
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
const curatedDir = resolve23(projectRoot, ".agentpacks", ".curated");
|
|
3958
|
+
const packOutDir = resolve23(curatedDir, parsed.packName);
|
|
3959
|
+
if (existsSync19(packOutDir)) {
|
|
3960
|
+
rmSync3(packOutDir, { recursive: true, force: true });
|
|
3961
|
+
}
|
|
3962
|
+
mkdirSync7(packOutDir, { recursive: true });
|
|
3963
|
+
await extractTarball(data, packOutDir);
|
|
3964
|
+
collectFiles2(packOutDir, installed);
|
|
3965
|
+
const newEntry = {
|
|
3966
|
+
requestedRef: parsed.version,
|
|
3967
|
+
resolvedRef: targetVersion,
|
|
3968
|
+
resolvedAt: new Date().toISOString(),
|
|
3969
|
+
skills: {
|
|
3970
|
+
__integrity: { integrity: localIntegrity }
|
|
3971
|
+
},
|
|
3972
|
+
packs: {
|
|
3973
|
+
[parsed.packName]: { integrity: localIntegrity }
|
|
3974
|
+
}
|
|
3975
|
+
};
|
|
3976
|
+
setLockedSource(lockfile, sourceKey, newEntry);
|
|
3977
|
+
return { installed, warnings };
|
|
3978
|
+
}
|
|
3979
|
+
function buildClientConfig(registryUrl) {
|
|
3980
|
+
const cfg = {};
|
|
3981
|
+
if (registryUrl) {
|
|
3982
|
+
cfg.registryUrl = registryUrl;
|
|
3983
|
+
}
|
|
3984
|
+
try {
|
|
3985
|
+
const creds = loadCredentials();
|
|
3986
|
+
if (creds?.token) {
|
|
3987
|
+
cfg.authToken = creds.token;
|
|
3988
|
+
}
|
|
3989
|
+
} catch {}
|
|
3990
|
+
return cfg;
|
|
3991
|
+
}
|
|
3992
|
+
function collectFiles2(dir, out) {
|
|
3993
|
+
const entries = readdirSync3(dir, { withFileTypes: true });
|
|
3994
|
+
for (const entry of entries) {
|
|
3995
|
+
const full = join25(dir, entry.name);
|
|
3996
|
+
if (entry.isDirectory()) {
|
|
3997
|
+
collectFiles2(full, out);
|
|
3998
|
+
} else {
|
|
3999
|
+
out.push(full);
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
3127
4002
|
}
|
|
3128
4003
|
|
|
3129
4004
|
// src/cli/install.ts
|
|
3130
|
-
|
|
3131
|
-
import chalk5 from "chalk";
|
|
4005
|
+
import chalk6 from "chalk";
|
|
3132
4006
|
async function runInstall(projectRoot, options) {
|
|
3133
4007
|
const config = loadWorkspaceConfig(projectRoot);
|
|
3134
4008
|
const lockfile = loadLockfile(projectRoot);
|
|
3135
4009
|
const verbose = options.verbose ?? config.verbose;
|
|
3136
|
-
const remotePacks = config.packs.filter((ref) => isGitPackRef(ref) || isNpmPackRef(ref));
|
|
4010
|
+
const remotePacks = config.packs.filter((ref) => isGitPackRef(ref) || isNpmPackRef(ref) || isRegistryPackRef(ref));
|
|
3137
4011
|
const localPacks = config.packs.filter((ref) => isLocalPackRef(ref));
|
|
3138
4012
|
if (remotePacks.length === 0) {
|
|
3139
|
-
console.log(
|
|
4013
|
+
console.log(chalk6.dim("No remote packs to install. All packs are local."));
|
|
3140
4014
|
return;
|
|
3141
4015
|
}
|
|
3142
4016
|
if (verbose) {
|
|
3143
|
-
console.log(
|
|
3144
|
-
console.log(
|
|
4017
|
+
console.log(chalk6.dim(`Found ${remotePacks.length} remote pack(s) to install`));
|
|
4018
|
+
console.log(chalk6.dim(` (${localPacks.length} local pack(s) skipped)`));
|
|
3145
4019
|
}
|
|
3146
4020
|
if (options.frozen) {
|
|
3147
4021
|
const sourceKeys = remotePacks.map((ref) => ref);
|
|
3148
4022
|
const frozenCheck = isLockfileFrozenValid(lockfile, sourceKeys);
|
|
3149
4023
|
if (!frozenCheck.valid) {
|
|
3150
|
-
console.log(
|
|
4024
|
+
console.log(chalk6.red(`Frozen install failed. Missing lockfile entries: ${frozenCheck.missing.join(", ")}`));
|
|
3151
4025
|
process.exit(1);
|
|
3152
4026
|
}
|
|
3153
4027
|
}
|
|
@@ -3155,11 +4029,16 @@ async function runInstall(projectRoot, options) {
|
|
|
3155
4029
|
const allWarnings = [];
|
|
3156
4030
|
for (const packRef of remotePacks) {
|
|
3157
4031
|
if (verbose) {
|
|
3158
|
-
console.log(
|
|
4032
|
+
console.log(chalk6.dim(` Installing ${packRef}...`));
|
|
3159
4033
|
}
|
|
3160
4034
|
try {
|
|
3161
4035
|
let result;
|
|
3162
|
-
if (
|
|
4036
|
+
if (isRegistryPackRef(packRef)) {
|
|
4037
|
+
result = await installRegistrySource(projectRoot, packRef, lockfile, {
|
|
4038
|
+
update: options.update,
|
|
4039
|
+
frozen: options.frozen
|
|
4040
|
+
});
|
|
4041
|
+
} else if (isGitPackRef(packRef)) {
|
|
3163
4042
|
const token = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN ?? undefined;
|
|
3164
4043
|
result = await installGitSource(projectRoot, packRef, lockfile, {
|
|
3165
4044
|
update: options.update,
|
|
@@ -3177,39 +4056,204 @@ async function runInstall(projectRoot, options) {
|
|
|
3177
4056
|
totalInstalled += result.installed.length;
|
|
3178
4057
|
allWarnings.push(...result.warnings);
|
|
3179
4058
|
if (verbose && result.installed.length > 0) {
|
|
3180
|
-
console.log(
|
|
4059
|
+
console.log(chalk6.dim(` ${result.installed.length} file(s) installed`));
|
|
3181
4060
|
}
|
|
3182
4061
|
} catch (err) {
|
|
3183
4062
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3184
|
-
console.log(
|
|
4063
|
+
console.log(chalk6.red(` error [${packRef}]: ${msg}`));
|
|
3185
4064
|
allWarnings.push(`Failed to install ${packRef}: ${msg}`);
|
|
3186
4065
|
}
|
|
3187
4066
|
}
|
|
3188
4067
|
for (const w of allWarnings) {
|
|
3189
|
-
console.log(
|
|
4068
|
+
console.log(chalk6.yellow(` warn: ${w}`));
|
|
3190
4069
|
}
|
|
3191
4070
|
saveLockfile(projectRoot, lockfile);
|
|
3192
|
-
console.log(
|
|
4071
|
+
console.log(chalk6.green(`Installed ${totalInstalled} file(s) from ${remotePacks.length} source(s)`));
|
|
3193
4072
|
if (verbose) {
|
|
3194
|
-
console.log(
|
|
4073
|
+
console.log(chalk6.dim("Lockfile updated: agentpacks.lock"));
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
|
|
4077
|
+
// src/cli/login.ts
|
|
4078
|
+
import chalk7 from "chalk";
|
|
4079
|
+
async function runLogin(options) {
|
|
4080
|
+
const registryUrl = options.registry ?? "https://registry.agentpacks.dev";
|
|
4081
|
+
if (!options.token) {
|
|
4082
|
+
console.log(chalk7.bold(`agentpacks login
|
|
4083
|
+
`));
|
|
4084
|
+
console.log("To authenticate, you need an API token.");
|
|
4085
|
+
console.log(`Get one at: ${chalk7.cyan(`${registryUrl}/account/tokens`)}
|
|
4086
|
+
`);
|
|
4087
|
+
console.log("Then run:");
|
|
4088
|
+
console.log(chalk7.dim(` agentpacks login --token <your-token>
|
|
4089
|
+
`));
|
|
4090
|
+
return;
|
|
4091
|
+
}
|
|
4092
|
+
const client = createRegistryClient({
|
|
4093
|
+
registryUrl,
|
|
4094
|
+
authToken: options.token
|
|
4095
|
+
});
|
|
4096
|
+
const healthy = await client.health();
|
|
4097
|
+
if (!healthy) {
|
|
4098
|
+
console.log(chalk7.yellow(`Warning: Could not reach registry at ${registryUrl}`));
|
|
3195
4099
|
}
|
|
4100
|
+
saveCredentials({
|
|
4101
|
+
registryUrl,
|
|
4102
|
+
token: options.token
|
|
4103
|
+
});
|
|
4104
|
+
console.log(chalk7.green(`Authenticated with ${registryUrl}`));
|
|
4105
|
+
console.log(chalk7.dim("Credentials saved to ~/.config/agentpacks/credentials.json"));
|
|
4106
|
+
}
|
|
4107
|
+
|
|
4108
|
+
// src/cli/models-explain.ts
|
|
4109
|
+
import chalk8 from "chalk";
|
|
4110
|
+
import { resolve as resolve24 } from "path";
|
|
4111
|
+
function runModelsExplain(options) {
|
|
4112
|
+
const projectRoot = resolve24(options.config ?? ".");
|
|
4113
|
+
const config = loadWorkspaceConfig(projectRoot);
|
|
4114
|
+
const loader = new PackLoader(projectRoot, config);
|
|
4115
|
+
const { packs } = loader.loadAll();
|
|
4116
|
+
if (packs.length === 0) {
|
|
4117
|
+
console.log(chalk8.red("No packs loaded. Run `agentpacks init` first."));
|
|
4118
|
+
process.exit(1);
|
|
4119
|
+
}
|
|
4120
|
+
const merger = new FeatureMerger(packs);
|
|
4121
|
+
const { features: merged } = merger.merge();
|
|
4122
|
+
if (!merged.models) {
|
|
4123
|
+
console.log(chalk8.dim("No model configuration found in your packs."));
|
|
4124
|
+
return;
|
|
4125
|
+
}
|
|
4126
|
+
const profile = options.profile;
|
|
4127
|
+
const target = options.target;
|
|
4128
|
+
const resolved = resolveModels(merged.models, profile, target);
|
|
4129
|
+
console.log(chalk8.bold(`
|
|
4130
|
+
\uD83D\uDCCB Model Configuration Summary
|
|
4131
|
+
`));
|
|
4132
|
+
if (resolved.default) {
|
|
4133
|
+
console.log(` ${chalk8.dim("Default model:")} ${chalk8.cyan(resolved.default)}`);
|
|
4134
|
+
}
|
|
4135
|
+
if (resolved.small) {
|
|
4136
|
+
console.log(` ${chalk8.dim("Small model:")} ${chalk8.cyan(resolved.small)}`);
|
|
4137
|
+
}
|
|
4138
|
+
if (resolved.activeProfile) {
|
|
4139
|
+
console.log(` ${chalk8.dim("Active profile:")} ${chalk8.green(resolved.activeProfile)}`);
|
|
4140
|
+
}
|
|
4141
|
+
if (target) {
|
|
4142
|
+
console.log(` ${chalk8.dim("Target:")} ${chalk8.yellow(target)}`);
|
|
4143
|
+
}
|
|
4144
|
+
const agentEntries = Object.entries(resolved.agents);
|
|
4145
|
+
if (agentEntries.length > 0) {
|
|
4146
|
+
console.log(chalk8.bold(`
|
|
4147
|
+
Agent Assignments:`));
|
|
4148
|
+
for (const [name, config2] of agentEntries) {
|
|
4149
|
+
const temp = config2.temperature !== undefined ? ` (temp: ${config2.temperature})` : "";
|
|
4150
|
+
console.log(` ${chalk8.dim("•")} ${name}: ${chalk8.cyan(config2.model)}${chalk8.dim(temp)}`);
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
if (resolved.profileNames.length > 0) {
|
|
4154
|
+
console.log(chalk8.bold(`
|
|
4155
|
+
Available Profiles:`));
|
|
4156
|
+
for (const name of resolved.profileNames) {
|
|
4157
|
+
const profileData = resolved.profiles[name];
|
|
4158
|
+
const desc = profileData?.description ?? "";
|
|
4159
|
+
const active = name === resolved.activeProfile ? chalk8.green(" ← active") : "";
|
|
4160
|
+
console.log(` ${chalk8.dim("•")} ${name}${active}${desc ? chalk8.dim(` — ${desc}`) : ""}`);
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
if (resolved.routing.length > 0) {
|
|
4164
|
+
console.log(chalk8.bold(`
|
|
4165
|
+
Routing Rules:`));
|
|
4166
|
+
for (const rule of resolved.routing) {
|
|
4167
|
+
const conditions = Object.entries(rule.when).map(([k, v]) => `${chalk8.yellow(k)}=${chalk8.cyan(v)}`).join(", ");
|
|
4168
|
+
const desc = rule.description;
|
|
4169
|
+
console.log(` ${chalk8.dim("•")} When ${conditions} → use ${chalk8.green(rule.use)}${desc ? chalk8.dim(` (${desc})`) : ""}`);
|
|
4170
|
+
}
|
|
4171
|
+
if (options.task) {
|
|
4172
|
+
console.log(chalk8.bold(`
|
|
4173
|
+
Task Analysis:`));
|
|
4174
|
+
console.log(` ${chalk8.dim("Task:")} "${options.task}"`);
|
|
4175
|
+
const matched = matchTaskToRouting(options.task, resolved.routing);
|
|
4176
|
+
if (matched) {
|
|
4177
|
+
console.log(` ${chalk8.green("✓")} Matched rule: ${chalk8.green(matched.use)}`);
|
|
4178
|
+
const conditions = Object.entries(matched.when).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
4179
|
+
console.log(` ${chalk8.dim(" Conditions:")} ${conditions}`);
|
|
4180
|
+
} else {
|
|
4181
|
+
console.log(` ${chalk8.yellow("○")} No routing rule matched — using default profile`);
|
|
4182
|
+
}
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
const guidance = generateModelGuidanceMarkdown(resolved);
|
|
4186
|
+
if (guidance) {
|
|
4187
|
+
console.log(chalk8.bold(`
|
|
4188
|
+
Generated Guidance Preview:`));
|
|
4189
|
+
console.log(chalk8.dim(" " + "─".repeat(50)));
|
|
4190
|
+
for (const line of guidance.split(`
|
|
4191
|
+
`).slice(0, 20)) {
|
|
4192
|
+
console.log(` ${chalk8.dim(line)}`);
|
|
4193
|
+
}
|
|
4194
|
+
if (guidance.split(`
|
|
4195
|
+
`).length > 20) {
|
|
4196
|
+
console.log(chalk8.dim(` ... (${guidance.split(`
|
|
4197
|
+
`).length - 20} more lines)`));
|
|
4198
|
+
}
|
|
4199
|
+
}
|
|
4200
|
+
console.log("");
|
|
4201
|
+
}
|
|
4202
|
+
function matchTaskToRouting(task, routing) {
|
|
4203
|
+
const lowerTask = task.toLowerCase();
|
|
4204
|
+
const complexityKeywords = {
|
|
4205
|
+
critical: ["critical", "security", "production", "hotfix"],
|
|
4206
|
+
high: ["refactor", "architecture", "complex", "rewrite", "migrate"],
|
|
4207
|
+
medium: ["feature", "implement", "update", "modify"],
|
|
4208
|
+
low: ["fix", "typo", "comment", "rename", "format"]
|
|
4209
|
+
};
|
|
4210
|
+
const urgencyKeywords = {
|
|
4211
|
+
high: ["urgent", "asap", "emergency", "hotfix", "critical"],
|
|
4212
|
+
normal: ["feature", "implement", "add"],
|
|
4213
|
+
low: ["cleanup", "refactor", "docs", "todo"]
|
|
4214
|
+
};
|
|
4215
|
+
const inferred = {};
|
|
4216
|
+
for (const [level, keywords] of Object.entries(complexityKeywords)) {
|
|
4217
|
+
if (keywords.some((kw) => lowerTask.includes(kw))) {
|
|
4218
|
+
inferred["complexity"] = level;
|
|
4219
|
+
break;
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
for (const [level, keywords] of Object.entries(urgencyKeywords)) {
|
|
4223
|
+
if (keywords.some((kw) => lowerTask.includes(kw))) {
|
|
4224
|
+
inferred["urgency"] = level;
|
|
4225
|
+
break;
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4228
|
+
for (const rule of routing) {
|
|
4229
|
+
const matches = Object.entries(rule.when).every(([key, value]) => {
|
|
4230
|
+
if (inferred[key] === value)
|
|
4231
|
+
return true;
|
|
4232
|
+
if (lowerTask.includes(value.toLowerCase()))
|
|
4233
|
+
return true;
|
|
4234
|
+
return false;
|
|
4235
|
+
});
|
|
4236
|
+
if (matches)
|
|
4237
|
+
return rule;
|
|
4238
|
+
}
|
|
4239
|
+
return null;
|
|
3196
4240
|
}
|
|
3197
4241
|
|
|
3198
4242
|
// src/cli/pack/create.ts
|
|
3199
|
-
import { existsSync as
|
|
3200
|
-
import { resolve as
|
|
3201
|
-
import
|
|
4243
|
+
import { existsSync as existsSync20, writeFileSync as writeFileSync11 } from "fs";
|
|
4244
|
+
import { resolve as resolve25, join as join26 } from "path";
|
|
4245
|
+
import chalk9 from "chalk";
|
|
3202
4246
|
function runPackCreate(projectRoot, name) {
|
|
3203
|
-
const packDir =
|
|
3204
|
-
if (
|
|
3205
|
-
console.log(
|
|
4247
|
+
const packDir = resolve25(projectRoot, "packs", name);
|
|
4248
|
+
if (existsSync20(packDir)) {
|
|
4249
|
+
console.log(chalk9.red(`Pack "${name}" already exists at packs/${name}/`));
|
|
3206
4250
|
return;
|
|
3207
4251
|
}
|
|
3208
4252
|
ensureDir(packDir);
|
|
3209
|
-
ensureDir(
|
|
3210
|
-
ensureDir(
|
|
3211
|
-
ensureDir(
|
|
3212
|
-
ensureDir(
|
|
4253
|
+
ensureDir(join26(packDir, "rules"));
|
|
4254
|
+
ensureDir(join26(packDir, "commands"));
|
|
4255
|
+
ensureDir(join26(packDir, "agents"));
|
|
4256
|
+
ensureDir(join26(packDir, "skills"));
|
|
3213
4257
|
const packJson = {
|
|
3214
4258
|
name,
|
|
3215
4259
|
version: "1.0.0",
|
|
@@ -3220,31 +4264,31 @@ function runPackCreate(projectRoot, name) {
|
|
|
3220
4264
|
targets: "*",
|
|
3221
4265
|
features: "*"
|
|
3222
4266
|
};
|
|
3223
|
-
writeFileSync11(
|
|
4267
|
+
writeFileSync11(join26(packDir, "pack.json"), JSON.stringify(packJson, null, 2) + `
|
|
3224
4268
|
`);
|
|
3225
|
-
console.log(
|
|
3226
|
-
console.log(
|
|
3227
|
-
console.log(
|
|
4269
|
+
console.log(chalk9.green(`Created pack "${name}" at packs/${name}/`));
|
|
4270
|
+
console.log(chalk9.dim(" Add rules, commands, agents, skills, hooks, plugins, mcp.json, or ignore files."));
|
|
4271
|
+
console.log(chalk9.dim(` Then add "${join26("./packs", name)}" to packs[] in agentpacks.jsonc.`));
|
|
3228
4272
|
}
|
|
3229
4273
|
|
|
3230
4274
|
// src/cli/pack/enable.ts
|
|
3231
|
-
import { readFileSync as
|
|
3232
|
-
import { resolve as
|
|
3233
|
-
import
|
|
4275
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync21 } from "fs";
|
|
4276
|
+
import { resolve as resolve26 } from "path";
|
|
4277
|
+
import chalk10 from "chalk";
|
|
3234
4278
|
var CONFIG_FILENAME = "agentpacks.jsonc";
|
|
3235
4279
|
function readConfigRaw(projectRoot) {
|
|
3236
|
-
const filepath =
|
|
3237
|
-
if (!
|
|
4280
|
+
const filepath = resolve26(projectRoot, CONFIG_FILENAME);
|
|
4281
|
+
if (!existsSync21(filepath)) {
|
|
3238
4282
|
throw new Error(`No ${CONFIG_FILENAME} found. Run 'agentpacks init' first.`);
|
|
3239
4283
|
}
|
|
3240
|
-
return
|
|
4284
|
+
return readFileSync18(filepath, "utf-8");
|
|
3241
4285
|
}
|
|
3242
4286
|
function parseDisabledFromRaw(raw) {
|
|
3243
4287
|
const regex = /"disabled"\s*:\s*\[([^\]]*)\]/;
|
|
3244
4288
|
const match = regex.exec(raw);
|
|
3245
4289
|
if (!match)
|
|
3246
4290
|
return { list: [], match: null };
|
|
3247
|
-
const inner = match[1].trim();
|
|
4291
|
+
const inner = (match[1] ?? "").trim();
|
|
3248
4292
|
if (!inner)
|
|
3249
4293
|
return { list: [], match };
|
|
3250
4294
|
const list = inner.split(",").map((s) => s.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
|
|
@@ -3264,47 +4308,46 @@ function runPackDisable(projectRoot, packName) {
|
|
|
3264
4308
|
const raw = readConfigRaw(projectRoot);
|
|
3265
4309
|
const { list, match } = parseDisabledFromRaw(raw);
|
|
3266
4310
|
if (list.includes(packName)) {
|
|
3267
|
-
console.log(
|
|
4311
|
+
console.log(chalk10.dim(`Pack "${packName}" is already disabled.`));
|
|
3268
4312
|
return;
|
|
3269
4313
|
}
|
|
3270
4314
|
list.push(packName);
|
|
3271
4315
|
const updated = writeDisabled(raw, list, match);
|
|
3272
|
-
const filepath =
|
|
4316
|
+
const filepath = resolve26(projectRoot, CONFIG_FILENAME);
|
|
3273
4317
|
writeFileSync12(filepath, updated);
|
|
3274
|
-
console.log(
|
|
3275
|
-
console.log(
|
|
4318
|
+
console.log(chalk10.green(`Disabled pack "${packName}".`));
|
|
4319
|
+
console.log(chalk10.dim("Run 'agentpacks generate' to regenerate configs."));
|
|
3276
4320
|
}
|
|
3277
4321
|
function runPackEnable(projectRoot, packName) {
|
|
3278
4322
|
const raw = readConfigRaw(projectRoot);
|
|
3279
4323
|
const { list, match } = parseDisabledFromRaw(raw);
|
|
3280
4324
|
if (!list.includes(packName)) {
|
|
3281
|
-
console.log(
|
|
4325
|
+
console.log(chalk10.dim(`Pack "${packName}" is not disabled.`));
|
|
3282
4326
|
return;
|
|
3283
4327
|
}
|
|
3284
4328
|
const newList = list.filter((n) => n !== packName);
|
|
3285
4329
|
const updated = writeDisabled(raw, newList, match);
|
|
3286
|
-
const filepath =
|
|
4330
|
+
const filepath = resolve26(projectRoot, CONFIG_FILENAME);
|
|
3287
4331
|
writeFileSync12(filepath, updated);
|
|
3288
|
-
console.log(
|
|
3289
|
-
console.log(
|
|
4332
|
+
console.log(chalk10.green(`Enabled pack "${packName}".`));
|
|
4333
|
+
console.log(chalk10.dim("Run 'agentpacks generate' to regenerate configs."));
|
|
3290
4334
|
}
|
|
3291
4335
|
|
|
3292
4336
|
// src/cli/pack/list.ts
|
|
3293
|
-
|
|
3294
|
-
import chalk8 from "chalk";
|
|
4337
|
+
import chalk11 from "chalk";
|
|
3295
4338
|
function runPackList(projectRoot) {
|
|
3296
4339
|
const config = loadWorkspaceConfig(projectRoot);
|
|
3297
4340
|
const loader = new PackLoader(projectRoot, config);
|
|
3298
4341
|
const { packs, warnings } = loader.loadAll();
|
|
3299
4342
|
const disabledSet = new Set(config.disabled);
|
|
3300
4343
|
for (const w of warnings) {
|
|
3301
|
-
console.log(
|
|
4344
|
+
console.log(chalk11.yellow(` warn: ${w}`));
|
|
3302
4345
|
}
|
|
3303
4346
|
if (packs.length === 0 && config.packs.length === 0) {
|
|
3304
|
-
console.log(
|
|
4347
|
+
console.log(chalk11.dim("No packs configured. Run 'agentpacks init' to get started."));
|
|
3305
4348
|
return;
|
|
3306
4349
|
}
|
|
3307
|
-
console.log(
|
|
4350
|
+
console.log(chalk11.bold(`Active packs:
|
|
3308
4351
|
`));
|
|
3309
4352
|
for (const pack of packs) {
|
|
3310
4353
|
const m = pack.manifest;
|
|
@@ -3325,140 +4368,269 @@ function runPackList(projectRoot) {
|
|
|
3325
4368
|
features.push(`${Object.keys(pack.mcp.servers).length} MCP servers`);
|
|
3326
4369
|
if (pack.ignore)
|
|
3327
4370
|
features.push("ignore");
|
|
3328
|
-
const status = disabledSet.has(m.name) ?
|
|
3329
|
-
console.log(` ${status} ${
|
|
4371
|
+
const status = disabledSet.has(m.name) ? chalk11.red("[disabled]") : chalk11.green("[active]");
|
|
4372
|
+
console.log(` ${status} ${chalk11.bold(m.name)} v${m.version}`);
|
|
3330
4373
|
if (m.description) {
|
|
3331
|
-
console.log(` ${
|
|
4374
|
+
console.log(` ${chalk11.dim(m.description)}`);
|
|
3332
4375
|
}
|
|
3333
4376
|
if (features.length > 0) {
|
|
3334
|
-
console.log(` ${
|
|
4377
|
+
console.log(` ${chalk11.dim(features.join(", "))}`);
|
|
3335
4378
|
}
|
|
3336
4379
|
console.log();
|
|
3337
4380
|
}
|
|
3338
4381
|
for (const ref of config.disabled) {
|
|
3339
4382
|
if (!packs.some((p) => p.manifest.name === ref)) {
|
|
3340
|
-
console.log(` ${
|
|
4383
|
+
console.log(` ${chalk11.red("[disabled]")} ${chalk11.dim(ref)}`);
|
|
3341
4384
|
}
|
|
3342
4385
|
}
|
|
3343
4386
|
}
|
|
3344
4387
|
|
|
3345
4388
|
// src/cli/pack/validate.ts
|
|
3346
|
-
|
|
3347
|
-
import {
|
|
3348
|
-
import
|
|
3349
|
-
import chalk9 from "chalk";
|
|
4389
|
+
import { existsSync as existsSync22 } from "fs";
|
|
4390
|
+
import { resolve as resolve27, join as join27 } from "path";
|
|
4391
|
+
import chalk12 from "chalk";
|
|
3350
4392
|
function runPackValidate(projectRoot) {
|
|
3351
4393
|
const config = loadWorkspaceConfig(projectRoot);
|
|
3352
4394
|
let hasErrors = false;
|
|
3353
4395
|
for (const packRef of config.packs) {
|
|
3354
4396
|
const packDir = resolvePackDir(projectRoot, packRef);
|
|
3355
|
-
console.log(
|
|
4397
|
+
console.log(chalk12.bold(`
|
|
3356
4398
|
Validating pack: ${packRef}`));
|
|
3357
|
-
if (!packDir || !
|
|
3358
|
-
console.log(
|
|
4399
|
+
if (!packDir || !existsSync22(packDir)) {
|
|
4400
|
+
console.log(chalk12.red(` ERROR: Pack directory not found: ${packRef}`));
|
|
3359
4401
|
hasErrors = true;
|
|
3360
4402
|
continue;
|
|
3361
4403
|
}
|
|
3362
|
-
const packJsonPath =
|
|
3363
|
-
if (!
|
|
3364
|
-
console.log(
|
|
4404
|
+
const packJsonPath = resolve27(packDir, "pack.json");
|
|
4405
|
+
if (!existsSync22(packJsonPath)) {
|
|
4406
|
+
console.log(chalk12.yellow(" warn: No pack.json found. Name will be inferred from directory."));
|
|
3365
4407
|
} else {
|
|
3366
4408
|
try {
|
|
3367
4409
|
loadPackManifest(packDir);
|
|
3368
|
-
console.log(
|
|
4410
|
+
console.log(chalk12.green(" pack.json: valid"));
|
|
3369
4411
|
} catch (err) {
|
|
3370
4412
|
const message = err instanceof Error ? err.message : String(err);
|
|
3371
|
-
console.log(
|
|
4413
|
+
console.log(chalk12.red(` ERROR pack.json: ${message}`));
|
|
3372
4414
|
hasErrors = true;
|
|
3373
4415
|
}
|
|
3374
4416
|
}
|
|
3375
4417
|
const subdirs = ["rules", "commands", "agents", "skills"];
|
|
3376
4418
|
for (const sub of subdirs) {
|
|
3377
|
-
const subDir =
|
|
3378
|
-
if (
|
|
4419
|
+
const subDir = join27(packDir, sub);
|
|
4420
|
+
if (existsSync22(subDir)) {
|
|
3379
4421
|
if (sub === "skills") {
|
|
3380
4422
|
const skillDirs = listDirs(subDir);
|
|
3381
4423
|
for (const skillDir of skillDirs) {
|
|
3382
|
-
const skillMd =
|
|
3383
|
-
if (!
|
|
3384
|
-
console.log(
|
|
4424
|
+
const skillMd = join27(skillDir, "SKILL.md");
|
|
4425
|
+
if (!existsSync22(skillMd)) {
|
|
4426
|
+
console.log(chalk12.yellow(` warn: skills/${skillDir.split("/").pop()} missing SKILL.md`));
|
|
3385
4427
|
}
|
|
3386
4428
|
}
|
|
3387
|
-
console.log(
|
|
4429
|
+
console.log(chalk12.green(` ${sub}/: ${skillDirs.length} skill(s)`));
|
|
3388
4430
|
} else {
|
|
3389
4431
|
const files = listFiles(subDir, { extension: ".md" });
|
|
3390
|
-
console.log(
|
|
4432
|
+
console.log(chalk12.green(` ${sub}/: ${files.length} file(s)`));
|
|
3391
4433
|
}
|
|
3392
4434
|
}
|
|
3393
4435
|
}
|
|
3394
4436
|
const optionalFiles = ["mcp.json", "ignore", ".aiignore"];
|
|
3395
4437
|
for (const file of optionalFiles) {
|
|
3396
|
-
if (
|
|
3397
|
-
console.log(
|
|
4438
|
+
if (existsSync22(join27(packDir, file))) {
|
|
4439
|
+
console.log(chalk12.green(` ${file}: present`));
|
|
3398
4440
|
}
|
|
3399
4441
|
}
|
|
3400
|
-
const hooksJson =
|
|
3401
|
-
if (
|
|
3402
|
-
console.log(
|
|
4442
|
+
const hooksJson = join27(packDir, "hooks", "hooks.json");
|
|
4443
|
+
if (existsSync22(hooksJson)) {
|
|
4444
|
+
console.log(chalk12.green(" hooks/hooks.json: present"));
|
|
3403
4445
|
}
|
|
3404
|
-
const pluginsDir =
|
|
3405
|
-
if (
|
|
4446
|
+
const pluginsDir = join27(packDir, "plugins");
|
|
4447
|
+
if (existsSync22(pluginsDir)) {
|
|
3406
4448
|
const pluginFiles = [
|
|
3407
4449
|
...listFiles(pluginsDir, { extension: ".ts" }),
|
|
3408
4450
|
...listFiles(pluginsDir, { extension: ".js" })
|
|
3409
4451
|
];
|
|
3410
|
-
console.log(
|
|
4452
|
+
console.log(chalk12.green(` plugins/: ${pluginFiles.length} file(s)`));
|
|
4453
|
+
}
|
|
4454
|
+
const modelsJsonPath = join27(packDir, "models.json");
|
|
4455
|
+
if (existsSync22(modelsJsonPath)) {
|
|
4456
|
+
try {
|
|
4457
|
+
const parsed = parseModels(packDir, "validate");
|
|
4458
|
+
if (parsed) {
|
|
4459
|
+
console.log(chalk12.green(" models.json: valid"));
|
|
4460
|
+
const secretWarnings = scanModelsForSecrets(parsed.config);
|
|
4461
|
+
if (secretWarnings.length > 0) {
|
|
4462
|
+
for (const w of secretWarnings) {
|
|
4463
|
+
console.log(chalk12.red(` ERROR models.json: ${w}`));
|
|
4464
|
+
}
|
|
4465
|
+
hasErrors = true;
|
|
4466
|
+
}
|
|
4467
|
+
}
|
|
4468
|
+
} catch (err) {
|
|
4469
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4470
|
+
console.log(chalk12.red(` ERROR models.json: ${message}`));
|
|
4471
|
+
hasErrors = true;
|
|
4472
|
+
}
|
|
3411
4473
|
}
|
|
3412
4474
|
}
|
|
3413
4475
|
console.log();
|
|
3414
4476
|
if (hasErrors) {
|
|
3415
|
-
console.log(
|
|
4477
|
+
console.log(chalk12.red("Validation failed with errors."));
|
|
3416
4478
|
process.exit(1);
|
|
3417
4479
|
} else {
|
|
3418
|
-
console.log(
|
|
4480
|
+
console.log(chalk12.green("All packs valid."));
|
|
3419
4481
|
}
|
|
3420
4482
|
}
|
|
3421
4483
|
function resolvePackDir(projectRoot, packRef) {
|
|
3422
4484
|
if (packRef.startsWith("./") || packRef.startsWith("../")) {
|
|
3423
|
-
return
|
|
4485
|
+
return resolve27(projectRoot, packRef);
|
|
4486
|
+
}
|
|
4487
|
+
return resolve27(projectRoot, packRef);
|
|
4488
|
+
}
|
|
4489
|
+
|
|
4490
|
+
// src/cli/publish.ts
|
|
4491
|
+
import { resolve as resolve28 } from "path";
|
|
4492
|
+
import { existsSync as existsSync23 } from "fs";
|
|
4493
|
+
import chalk13 from "chalk";
|
|
4494
|
+
async function runPublish(projectRoot, options) {
|
|
4495
|
+
const credentials = loadCredentials();
|
|
4496
|
+
if (!credentials.token) {
|
|
4497
|
+
console.log(chalk13.red("Not authenticated. Run `agentpacks login` first."));
|
|
4498
|
+
process.exit(1);
|
|
4499
|
+
}
|
|
4500
|
+
const packDir = resolve28(projectRoot);
|
|
4501
|
+
const packJsonPath = resolve28(packDir, "pack.json");
|
|
4502
|
+
if (!existsSync23(packJsonPath)) {
|
|
4503
|
+
console.log(chalk13.red("No pack.json found. Are you in a pack directory?"));
|
|
4504
|
+
process.exit(1);
|
|
4505
|
+
}
|
|
4506
|
+
const manifest = loadPackManifest(packDir);
|
|
4507
|
+
console.log(chalk13.bold(`Publishing ${manifest.name}@${manifest.version}...`));
|
|
4508
|
+
const models = parseModels(packDir, manifest.name);
|
|
4509
|
+
if (models) {
|
|
4510
|
+
const secretWarnings = scanModelsForSecrets(models.config);
|
|
4511
|
+
if (secretWarnings.length > 0) {
|
|
4512
|
+
console.log(chalk13.red(`
|
|
4513
|
+
Blocked: secrets detected in models.json:`));
|
|
4514
|
+
for (const w of secretWarnings) {
|
|
4515
|
+
console.log(chalk13.red(` - ${w}`));
|
|
4516
|
+
}
|
|
4517
|
+
process.exit(1);
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4520
|
+
if (options.verbose)
|
|
4521
|
+
console.log(chalk13.dim(" Creating tarball..."));
|
|
4522
|
+
const tarball = await createTarball(packDir);
|
|
4523
|
+
if (options.verbose)
|
|
4524
|
+
console.log(chalk13.dim(" Uploading..."));
|
|
4525
|
+
const client = createRegistryClient({
|
|
4526
|
+
registryUrl: credentials.registryUrl,
|
|
4527
|
+
authToken: credentials.token
|
|
4528
|
+
});
|
|
4529
|
+
try {
|
|
4530
|
+
const result = await client.publish(tarball, {
|
|
4531
|
+
name: manifest.name,
|
|
4532
|
+
version: manifest.version,
|
|
4533
|
+
manifest
|
|
4534
|
+
});
|
|
4535
|
+
console.log(chalk13.green(`
|
|
4536
|
+
Published ${result.name}@${result.version}`));
|
|
4537
|
+
console.log(chalk13.dim(` integrity: ${result.integrity}`));
|
|
4538
|
+
} catch (err) {
|
|
4539
|
+
console.log(chalk13.red(`
|
|
4540
|
+
Publish failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
4541
|
+
process.exit(1);
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
|
|
4545
|
+
// src/cli/search.ts
|
|
4546
|
+
import chalk14 from "chalk";
|
|
4547
|
+
async function runSearch(query, options) {
|
|
4548
|
+
const credentials = loadCredentials();
|
|
4549
|
+
const client = createRegistryClient({
|
|
4550
|
+
registryUrl: credentials.registryUrl,
|
|
4551
|
+
authToken: credentials.token
|
|
4552
|
+
});
|
|
4553
|
+
try {
|
|
4554
|
+
const { packs, total } = await client.search({
|
|
4555
|
+
query,
|
|
4556
|
+
tags: options.tags?.split(","),
|
|
4557
|
+
targets: options.targets?.split(","),
|
|
4558
|
+
sort: options.sort,
|
|
4559
|
+
limit: options.limit ? Number(options.limit) : 20
|
|
4560
|
+
});
|
|
4561
|
+
if (packs.length === 0) {
|
|
4562
|
+
console.log(chalk14.dim("No packs found."));
|
|
4563
|
+
return;
|
|
4564
|
+
}
|
|
4565
|
+
console.log(chalk14.bold(`Found ${total} pack(s)${query ? ` matching "${query}"` : ""}:
|
|
4566
|
+
`));
|
|
4567
|
+
for (const pack of packs) {
|
|
4568
|
+
const verified = pack.verified ? chalk14.green(" [verified]") : "";
|
|
4569
|
+
const featured = pack.featured ? chalk14.yellow(" [featured]") : "";
|
|
4570
|
+
console.log(` ${chalk14.bold(pack.name)}${verified}${featured}`);
|
|
4571
|
+
console.log(` ${pack.description}`);
|
|
4572
|
+
console.log(chalk14.dim(` v${pack.latestVersion} | ${pack.downloads} downloads | by ${pack.author}`));
|
|
4573
|
+
if (options.verbose && pack.tags.length > 0) {
|
|
4574
|
+
console.log(chalk14.dim(` tags: ${pack.tags.join(", ")}`));
|
|
4575
|
+
}
|
|
4576
|
+
console.log();
|
|
4577
|
+
}
|
|
4578
|
+
} catch (err) {
|
|
4579
|
+
console.log(chalk14.red(`Search failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
4580
|
+
process.exit(1);
|
|
3424
4581
|
}
|
|
3425
|
-
return resolve25(projectRoot, packRef);
|
|
3426
4582
|
}
|
|
3427
4583
|
|
|
3428
4584
|
// src/index.ts
|
|
3429
4585
|
import { Command } from "commander";
|
|
3430
|
-
import { resolve as
|
|
4586
|
+
import { resolve as resolve29 } from "path";
|
|
3431
4587
|
var program = new Command;
|
|
3432
4588
|
program.name("agentpacks").description("Composable AI agent configuration manager. Pack-based rules, commands, skills, hooks, and MCP sync across OpenCode, Cursor, Claude Code, Codex, Gemini, Copilot, and more.").version("0.1.0");
|
|
3433
4589
|
program.command("init").description("Initialize agentpacks in the current project").action(() => {
|
|
3434
|
-
runInit(
|
|
4590
|
+
runInit(resolve29("."));
|
|
3435
4591
|
});
|
|
3436
4592
|
program.command("generate").description("Generate tool configs from active packs").option("-t, --targets <targets>", "Comma-separated target IDs or '*' for all").option("-f, --features <features>", "Comma-separated feature IDs or '*' for all").option("--dry-run", "Preview changes without writing files").option("--diff", "Show diff of what would change").option("-v, --verbose", "Enable verbose logging").action((options) => {
|
|
3437
|
-
runGenerate(
|
|
4593
|
+
runGenerate(resolve29("."), options);
|
|
3438
4594
|
});
|
|
3439
4595
|
program.command("install").description("Install remote packs (git, npm) into local cache").option("--update", "Re-resolve all refs (ignore lockfile)").option("--frozen", "Fail if lockfile is missing or incomplete").option("-v, --verbose", "Enable verbose logging").action(async (options) => {
|
|
3440
|
-
await runInstall(
|
|
4596
|
+
await runInstall(resolve29("."), options);
|
|
3441
4597
|
});
|
|
3442
4598
|
program.command("export").description("Export packs to target-native format (e.g. Cursor plugin)").requiredOption("--format <format>", "Export format (cursor-plugin)").option("-o, --output <dir>", "Output directory").option("--pack <name>", "Export a specific pack only").option("-v, --verbose", "Enable verbose logging").action((options) => {
|
|
3443
|
-
runExport(
|
|
4599
|
+
runExport(resolve29("."), options);
|
|
3444
4600
|
});
|
|
3445
4601
|
program.command("import").description("Import from existing tool configurations").requiredOption("--from <source>", "Import source (rulesync)").option("-o, --output <dir>", "Output pack directory").action((options) => {
|
|
3446
|
-
runImport(
|
|
4602
|
+
runImport(resolve29("."), options);
|
|
4603
|
+
});
|
|
4604
|
+
program.command("search [query]").description("Search for packs in the registry").option("--tags <tags>", "Filter by tags (comma-separated)").option("--targets <targets>", "Filter by targets (comma-separated)").option("--sort <sort>", "Sort by: downloads, updated, name, weekly").option("-l, --limit <limit>", "Max results to show").option("-v, --verbose", "Show additional details").action(async (query, options) => {
|
|
4605
|
+
await runSearch(query ?? "", options);
|
|
4606
|
+
});
|
|
4607
|
+
program.command("info <pack>").description("Show detailed pack information from the registry").action(async (packName) => {
|
|
4608
|
+
await runInfo(packName);
|
|
4609
|
+
});
|
|
4610
|
+
program.command("publish").description("Publish a pack to the registry").option("-v, --verbose", "Enable verbose logging").action(async (options) => {
|
|
4611
|
+
await runPublish(resolve29("."), options);
|
|
4612
|
+
});
|
|
4613
|
+
program.command("login").description("Authenticate with the agentpacks registry").option("--token <token>", "API token").option("--registry <url>", "Registry URL").action(async (options) => {
|
|
4614
|
+
await runLogin(options);
|
|
4615
|
+
});
|
|
4616
|
+
var modelsCmd = program.command("models").description("Model configuration and routing");
|
|
4617
|
+
modelsCmd.command("explain").description("Explain model profile and routing resolution").option("-c, --config <path>", "Path to agentpacks.yaml").option("-p, --profile <name>", "Profile to activate").option("-t, --target <id>", "Target to resolve for").option("--task <description>", "Task description for routing match").action((options) => {
|
|
4618
|
+
runModelsExplain(options);
|
|
3447
4619
|
});
|
|
3448
4620
|
var packCmd = program.command("pack").description("Manage packs");
|
|
3449
4621
|
packCmd.command("create <name>").description("Create a new pack scaffold").action((name) => {
|
|
3450
|
-
runPackCreate(
|
|
4622
|
+
runPackCreate(resolve29("."), name);
|
|
3451
4623
|
});
|
|
3452
4624
|
packCmd.command("list").description("List all configured packs and their status").action(() => {
|
|
3453
|
-
runPackList(
|
|
4625
|
+
runPackList(resolve29("."));
|
|
3454
4626
|
});
|
|
3455
4627
|
packCmd.command("validate").description("Validate all configured packs").action(() => {
|
|
3456
|
-
runPackValidate(
|
|
4628
|
+
runPackValidate(resolve29("."));
|
|
3457
4629
|
});
|
|
3458
4630
|
packCmd.command("enable <name>").description("Enable a previously disabled pack").action((name) => {
|
|
3459
|
-
runPackEnable(
|
|
4631
|
+
runPackEnable(resolve29("."), name);
|
|
3460
4632
|
});
|
|
3461
4633
|
packCmd.command("disable <name>").description("Disable a pack without removing it").action((name) => {
|
|
3462
|
-
runPackDisable(
|
|
4634
|
+
runPackDisable(resolve29("."), name);
|
|
3463
4635
|
});
|
|
3464
4636
|
program.parse();
|