agentpacks 1.7.13 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +48 -3658
- package/dist/cli/export-cmd.js +7 -1027
- package/dist/cli/generate.js +39 -2731
- package/dist/cli/import-cmd.js +19 -770
- package/dist/cli/info.js +4 -231
- package/dist/cli/init.js +9 -185
- package/dist/cli/install.js +4 -902
- package/dist/cli/login.js +6 -201
- package/dist/cli/models-explain.js +14 -1266
- package/dist/cli/pack/create.js +4 -146
- package/dist/cli/pack/enable.js +2 -65
- package/dist/cli/pack/list.js +5 -893
- package/dist/cli/pack/validate.js +4 -642
- package/dist/cli/publish.js +8 -679
- package/dist/cli/search.js +4 -209
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.js +1 -145
- package/dist/core/dependency-resolver.js +1 -126
- package/dist/core/feature-merger.js +3 -398
- package/dist/core/index.js +5 -1129
- package/dist/core/lockfile.js +2 -43
- package/dist/core/metarepo.js +1 -183
- package/dist/core/pack-loader.js +4 -841
- package/dist/core/profile-resolver.js +1 -110
- package/dist/exporters/cursor-plugin.js +6 -404
- package/dist/exporters/index.js +6 -404
- package/dist/features/agents.js +3 -161
- package/dist/features/commands.js +3 -161
- package/dist/features/hooks.js +3 -153
- package/dist/features/ignore.js +2 -43
- package/dist/features/index.js +4 -629
- package/dist/features/mcp.js +3 -143
- package/dist/features/models.js +3 -292
- package/dist/features/plugins.js +3 -139
- package/dist/features/rules.d.ts +0 -1
- package/dist/features/rules.js +3 -169
- package/dist/features/skills.js +3 -228
- package/dist/importers/claude-code.js +6 -195
- package/dist/importers/cursor.js +5 -355
- package/dist/importers/opencode.js +6 -346
- package/dist/importers/rulesync.js +5 -365
- package/dist/index.js +89 -4934
- package/dist/node/api.js +48 -3659
- package/dist/node/cli/export-cmd.js +7 -1028
- package/dist/node/cli/generate.js +39 -2732
- package/dist/node/cli/import-cmd.js +19 -771
- package/dist/node/cli/info.js +4 -232
- package/dist/node/cli/init.js +9 -186
- package/dist/node/cli/install.js +4 -903
- package/dist/node/cli/login.js +6 -202
- package/dist/node/cli/models-explain.js +14 -1267
- package/dist/node/cli/pack/create.js +4 -147
- package/dist/node/cli/pack/enable.js +2 -66
- package/dist/node/cli/pack/list.js +5 -894
- package/dist/node/cli/pack/validate.js +4 -643
- package/dist/node/cli/publish.js +8 -680
- package/dist/node/cli/search.js +4 -210
- package/dist/node/core/config.js +1 -146
- package/dist/node/core/dependency-resolver.js +1 -127
- package/dist/node/core/feature-merger.js +3 -399
- package/dist/node/core/index.js +5 -1130
- package/dist/node/core/lockfile.js +2 -44
- package/dist/node/core/metarepo.js +1 -184
- package/dist/node/core/pack-loader.js +4 -842
- package/dist/node/core/profile-resolver.js +1 -111
- package/dist/node/exporters/cursor-plugin.js +6 -405
- package/dist/node/exporters/index.js +6 -405
- package/dist/node/features/agents.js +3 -162
- package/dist/node/features/commands.js +3 -162
- package/dist/node/features/hooks.js +3 -154
- package/dist/node/features/ignore.js +2 -44
- package/dist/node/features/index.js +4 -630
- package/dist/node/features/mcp.js +3 -144
- package/dist/node/features/models.js +3 -293
- package/dist/node/features/plugins.js +3 -140
- package/dist/node/features/rules.js +3 -170
- package/dist/node/features/skills.js +3 -229
- package/dist/node/importers/claude-code.js +6 -196
- package/dist/node/importers/cursor.js +5 -356
- package/dist/node/importers/opencode.js +6 -347
- package/dist/node/importers/rulesync.js +5 -366
- package/dist/node/index.js +89 -4935
- package/dist/node/sources/git-ref.js +1 -56
- package/dist/node/sources/git.js +2 -222
- package/dist/node/sources/index.js +4 -714
- package/dist/node/sources/local.js +1 -24
- package/dist/node/sources/npm-ref.js +1 -56
- package/dist/node/sources/npm.js +2 -184
- package/dist/node/sources/registry-ref.js +1 -37
- package/dist/node/sources/registry.js +4 -355
- package/dist/node/targets/additional-targets.js +6 -587
- package/dist/node/targets/base-target.js +1 -23
- package/dist/node/targets/claude-code.js +6 -714
- package/dist/node/targets/codex-cli.js +3 -324
- package/dist/node/targets/copilot.js +5 -603
- package/dist/node/targets/cursor.js +6 -700
- package/dist/node/targets/gemini-cli.js +10 -319
- package/dist/node/targets/generic-md-target.js +6 -478
- package/dist/node/targets/index.js +32 -1873
- package/dist/node/targets/mistral-vibe.js +7 -661
- package/dist/node/targets/opencode.js +13 -723
- package/dist/node/targets/registry.js +32 -1864
- package/dist/node/utils/credentials.js +3 -38
- package/dist/node/utils/diff.js +5 -132
- package/dist/node/utils/filesystem.js +3 -124
- package/dist/node/utils/frontmatter.js +1 -24
- package/dist/node/utils/global.js +1 -53
- package/dist/node/utils/markdown.js +3 -30
- package/dist/node/utils/model-allowlist.js +1 -126
- package/dist/node/utils/model-guidance.js +2 -78
- package/dist/node/utils/registry-client.js +1 -142
- package/dist/node/utils/tarball.js +1 -49
- package/dist/sources/git-ref.js +1 -55
- package/dist/sources/git.js +2 -221
- package/dist/sources/index.js +4 -713
- package/dist/sources/local.js +1 -23
- package/dist/sources/npm-ref.js +1 -55
- package/dist/sources/npm.js +2 -183
- package/dist/sources/registry-ref.js +1 -36
- package/dist/sources/registry.js +4 -354
- package/dist/targets/additional-targets.js +6 -586
- package/dist/targets/base-target.js +1 -22
- package/dist/targets/claude-code.js +6 -713
- package/dist/targets/codex-cli.js +3 -323
- package/dist/targets/copilot.js +5 -602
- package/dist/targets/cursor.js +6 -699
- package/dist/targets/gemini-cli.js +10 -318
- package/dist/targets/generic-md-target.js +6 -477
- package/dist/targets/index.d.ts +0 -1
- package/dist/targets/index.js +32 -1872
- package/dist/targets/mistral-vibe.js +7 -660
- package/dist/targets/opencode.js +13 -722
- package/dist/targets/registry.js +32 -1863
- package/dist/utils/credentials.js +3 -37
- package/dist/utils/diff.js +5 -131
- package/dist/utils/filesystem.js +3 -123
- package/dist/utils/frontmatter.js +1 -23
- package/dist/utils/global.js +1 -52
- package/dist/utils/markdown.js +3 -29
- package/dist/utils/model-allowlist.js +1 -125
- package/dist/utils/model-guidance.js +2 -77
- package/dist/utils/registry-client.js +1 -141
- package/dist/utils/tarball.js +1 -48
- package/package.json +4 -16
- package/dist/node/targets/agents-md.js +0 -211
- package/dist/targets/agents-md.d.ts +0 -13
- package/dist/targets/agents-md.js +0 -211
package/dist/node/cli/install.js
CHANGED
|
@@ -1,903 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { existsSync, readFileSync } from "fs";
|
|
6
|
-
import { parse as parseJsonc } from "jsonc-parser";
|
|
7
|
-
import { resolve } from "path";
|
|
8
|
-
import { z } from "zod";
|
|
9
|
-
var TARGET_IDS = [
|
|
10
|
-
"opencode",
|
|
11
|
-
"cursor",
|
|
12
|
-
"claudecode",
|
|
13
|
-
"codexcli",
|
|
14
|
-
"mistralvibe",
|
|
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
|
-
homepage: z.string().optional(),
|
|
53
|
-
repository: z.union([
|
|
54
|
-
z.string(),
|
|
55
|
-
z.object({ url: z.string(), type: z.string().optional() })
|
|
56
|
-
]).optional(),
|
|
57
|
-
license: z.string().optional(),
|
|
58
|
-
logo: z.string().optional(),
|
|
59
|
-
tags: z.array(z.string()).default([]),
|
|
60
|
-
dependencies: z.array(z.string()).default([]),
|
|
61
|
-
conflicts: z.array(z.string()).default([]),
|
|
62
|
-
targets: z.union([z.literal("*"), z.array(z.string())]).default("*"),
|
|
63
|
-
features: z.union([z.literal("*"), z.array(z.string())]).default("*")
|
|
64
|
-
});
|
|
65
|
-
var FeaturesSchema = z.union([
|
|
66
|
-
z.literal("*"),
|
|
67
|
-
z.array(z.string()),
|
|
68
|
-
z.record(z.string(), z.union([z.literal("*"), z.array(z.string())]))
|
|
69
|
-
]);
|
|
70
|
-
var WorkspaceConfigSchema = z.object({
|
|
71
|
-
$schema: z.string().optional(),
|
|
72
|
-
packs: z.array(z.string()).default(["./packs/default"]),
|
|
73
|
-
disabled: z.array(z.string()).default([]),
|
|
74
|
-
targets: z.union([z.literal("*"), z.array(z.string())]).default("*"),
|
|
75
|
-
features: FeaturesSchema.default("*"),
|
|
76
|
-
mode: z.enum(REPO_MODES).default("repo"),
|
|
77
|
-
baseDirs: z.array(z.string()).default(["."]),
|
|
78
|
-
global: z.boolean().default(false),
|
|
79
|
-
delete: z.boolean().default(true),
|
|
80
|
-
verbose: z.boolean().default(false),
|
|
81
|
-
silent: z.boolean().default(false),
|
|
82
|
-
overrides: z.record(z.string(), z.record(z.string(), z.string())).default({}),
|
|
83
|
-
sources: z.array(z.object({
|
|
84
|
-
source: z.string(),
|
|
85
|
-
packs: z.array(z.string()).optional(),
|
|
86
|
-
skills: z.array(z.string()).optional()
|
|
87
|
-
})).default([]),
|
|
88
|
-
modelProfile: z.string().optional()
|
|
89
|
-
});
|
|
90
|
-
var CONFIG_FILES = ["agentpacks.local.jsonc", "agentpacks.jsonc"];
|
|
91
|
-
function loadWorkspaceConfig(projectRoot) {
|
|
92
|
-
for (const filename of CONFIG_FILES) {
|
|
93
|
-
const filepath = resolve(projectRoot, filename);
|
|
94
|
-
if (existsSync(filepath)) {
|
|
95
|
-
const raw = readFileSync(filepath, "utf-8");
|
|
96
|
-
const parsed = parseJsonc(raw);
|
|
97
|
-
return WorkspaceConfigSchema.parse(parsed);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return WorkspaceConfigSchema.parse({});
|
|
101
|
-
}
|
|
102
|
-
function loadPackManifest(packDir) {
|
|
103
|
-
const filepath = resolve(packDir, "pack.json");
|
|
104
|
-
if (!existsSync(filepath)) {
|
|
105
|
-
const dirName = packDir.split("/").pop() ?? "unknown";
|
|
106
|
-
return PackManifestSchema.parse({ name: dirName });
|
|
107
|
-
}
|
|
108
|
-
const raw = readFileSync(filepath, "utf-8");
|
|
109
|
-
const parsed = JSON.parse(raw);
|
|
110
|
-
return PackManifestSchema.parse(parsed);
|
|
111
|
-
}
|
|
112
|
-
function resolveFeatures(config, targetId) {
|
|
113
|
-
const { features } = config;
|
|
114
|
-
if (features === "*") {
|
|
115
|
-
return [...FEATURE_IDS];
|
|
116
|
-
}
|
|
117
|
-
if (Array.isArray(features)) {
|
|
118
|
-
if (features.includes("*"))
|
|
119
|
-
return [...FEATURE_IDS];
|
|
120
|
-
return features.filter((f) => FEATURE_IDS.includes(f));
|
|
121
|
-
}
|
|
122
|
-
const targetFeatures = features[targetId];
|
|
123
|
-
if (!targetFeatures)
|
|
124
|
-
return [];
|
|
125
|
-
if (targetFeatures === "*")
|
|
126
|
-
return [...FEATURE_IDS];
|
|
127
|
-
if (Array.isArray(targetFeatures) && targetFeatures.includes("*"))
|
|
128
|
-
return [...FEATURE_IDS];
|
|
129
|
-
return targetFeatures.filter((f) => FEATURE_IDS.includes(f));
|
|
130
|
-
}
|
|
131
|
-
function resolveTargets(config) {
|
|
132
|
-
if (config.targets === "*")
|
|
133
|
-
return [...TARGET_IDS];
|
|
134
|
-
return config.targets;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// src/core/lockfile.ts
|
|
138
|
-
import { createHash } from "crypto";
|
|
139
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
140
|
-
import { resolve as resolve2 } from "path";
|
|
141
|
-
var LOCKFILE_VERSION = 1;
|
|
142
|
-
var LOCKFILE_NAME = "agentpacks.lock";
|
|
143
|
-
function loadLockfile(projectRoot) {
|
|
144
|
-
const filepath = resolve2(projectRoot, LOCKFILE_NAME);
|
|
145
|
-
if (!existsSync2(filepath)) {
|
|
146
|
-
return { lockfileVersion: LOCKFILE_VERSION, sources: {} };
|
|
147
|
-
}
|
|
148
|
-
const raw = readFileSync2(filepath, "utf-8");
|
|
149
|
-
return JSON.parse(raw);
|
|
150
|
-
}
|
|
151
|
-
function saveLockfile(projectRoot, lockfile) {
|
|
152
|
-
const filepath = resolve2(projectRoot, LOCKFILE_NAME);
|
|
153
|
-
writeFileSync(filepath, JSON.stringify(lockfile, null, 2) + `
|
|
154
|
-
`);
|
|
155
|
-
}
|
|
156
|
-
function getLockedSource(lockfile, sourceKey) {
|
|
157
|
-
return lockfile.sources[sourceKey];
|
|
158
|
-
}
|
|
159
|
-
function setLockedSource(lockfile, sourceKey, entry) {
|
|
160
|
-
lockfile.sources[sourceKey] = entry;
|
|
161
|
-
}
|
|
162
|
-
function computeIntegrity(content) {
|
|
163
|
-
const hash = createHash("sha256").update(content).digest("hex");
|
|
164
|
-
return `sha256-${hash}`;
|
|
165
|
-
}
|
|
166
|
-
function isLockfileFrozenValid(lockfile, sourceKeys) {
|
|
167
|
-
const missing = sourceKeys.filter((key) => !(key in lockfile.sources));
|
|
168
|
-
return { valid: missing.length === 0, missing };
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// src/sources/git-ref.ts
|
|
172
|
-
function parseGitSourceRef(source) {
|
|
173
|
-
let s = source;
|
|
174
|
-
if (s.startsWith("github:")) {
|
|
175
|
-
s = s.slice(7);
|
|
176
|
-
}
|
|
177
|
-
let path = "";
|
|
178
|
-
const atIdx = s.indexOf("@");
|
|
179
|
-
const colonIdx = s.indexOf(":", atIdx > -1 ? atIdx : 0);
|
|
180
|
-
if (colonIdx > -1) {
|
|
181
|
-
path = s.slice(colonIdx + 1);
|
|
182
|
-
s = s.slice(0, colonIdx);
|
|
183
|
-
}
|
|
184
|
-
let ref = "main";
|
|
185
|
-
if (atIdx > -1) {
|
|
186
|
-
ref = s.slice(atIdx + 1);
|
|
187
|
-
s = s.slice(0, atIdx);
|
|
188
|
-
}
|
|
189
|
-
const parts = s.split("/");
|
|
190
|
-
if (parts.length < 2) {
|
|
191
|
-
throw new Error(`Invalid git source reference: "${source}". Expected owner/repo format.`);
|
|
192
|
-
}
|
|
193
|
-
const owner = parts[0];
|
|
194
|
-
const repo = parts[1];
|
|
195
|
-
if (!owner || !repo) {
|
|
196
|
-
throw new Error(`Invalid git source reference: "${source}". Expected owner/repo format.`);
|
|
197
|
-
}
|
|
198
|
-
return {
|
|
199
|
-
owner,
|
|
200
|
-
repo,
|
|
201
|
-
ref,
|
|
202
|
-
path: path || ""
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
function isGitPackRef(packRef) {
|
|
206
|
-
if (packRef.startsWith("github:"))
|
|
207
|
-
return true;
|
|
208
|
-
if (packRef.startsWith("./") || packRef.startsWith("../") || packRef.startsWith("/")) {
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
if (packRef.startsWith("@") || packRef.startsWith("npm:"))
|
|
212
|
-
return false;
|
|
213
|
-
const parts = packRef.split("/");
|
|
214
|
-
return parts.length === 2 && !packRef.includes("node_modules");
|
|
215
|
-
}
|
|
216
|
-
function gitSourceKey(parsed) {
|
|
217
|
-
return `${parsed.owner}/${parsed.repo}`;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// src/sources/git.ts
|
|
221
|
-
import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
222
|
-
import { join, resolve as resolve3 } from "path";
|
|
223
|
-
var GITHUB_API = "https://api.github.com";
|
|
224
|
-
function githubHeaders(token) {
|
|
225
|
-
const h = {
|
|
226
|
-
Accept: "application/vnd.github.v3+json",
|
|
227
|
-
"User-Agent": "agentpacks"
|
|
228
|
-
};
|
|
229
|
-
if (token)
|
|
230
|
-
h.Authorization = `token ${token}`;
|
|
231
|
-
return h;
|
|
232
|
-
}
|
|
233
|
-
async function resolveGitRef(parsed, token) {
|
|
234
|
-
const base = `${GITHUB_API}/repos/${parsed.owner}/${parsed.repo}/git/ref`;
|
|
235
|
-
const res = await fetch(`${base}/heads/${parsed.ref}`, {
|
|
236
|
-
headers: githubHeaders(token)
|
|
237
|
-
});
|
|
238
|
-
if (!res.ok) {
|
|
239
|
-
const tagRes = await fetch(`${base}/tags/${parsed.ref}`, {
|
|
240
|
-
headers: githubHeaders(token)
|
|
241
|
-
});
|
|
242
|
-
if (!tagRes.ok) {
|
|
243
|
-
throw new Error(`Could not resolve ref "${parsed.ref}" for ${parsed.owner}/${parsed.repo}: ${res.status}`);
|
|
244
|
-
}
|
|
245
|
-
const tagData = await tagRes.json();
|
|
246
|
-
return tagData.object.sha;
|
|
247
|
-
}
|
|
248
|
-
const data = await res.json();
|
|
249
|
-
return data.object.sha;
|
|
250
|
-
}
|
|
251
|
-
async function fetchGitDirectory(parsed, sha, subpath, token) {
|
|
252
|
-
const path = parsed.path ? `${parsed.path}/${subpath}` : subpath;
|
|
253
|
-
const url = `${GITHUB_API}/repos/${parsed.owner}/${parsed.repo}/contents/${path}?ref=${sha}`;
|
|
254
|
-
const res = await fetch(url, { headers: githubHeaders(token) });
|
|
255
|
-
if (!res.ok)
|
|
256
|
-
return [];
|
|
257
|
-
return await res.json();
|
|
258
|
-
}
|
|
259
|
-
async function fetchGitFile(downloadUrl, token) {
|
|
260
|
-
const headers = { "User-Agent": "agentpacks" };
|
|
261
|
-
if (token)
|
|
262
|
-
headers.Authorization = `token ${token}`;
|
|
263
|
-
const res = await fetch(downloadUrl, { headers });
|
|
264
|
-
if (!res.ok) {
|
|
265
|
-
throw new Error(`Failed to fetch ${downloadUrl}: ${res.status}`);
|
|
266
|
-
}
|
|
267
|
-
return res.text();
|
|
268
|
-
}
|
|
269
|
-
async function fetchAndWriteSubdir(parsed, sha, remotePath, localDir, installed, token) {
|
|
270
|
-
mkdirSync(localDir, { recursive: true });
|
|
271
|
-
const entries = await fetchGitDirectory(parsed, sha, remotePath, token);
|
|
272
|
-
for (const entry of entries) {
|
|
273
|
-
if (entry.type === "file" && entry.download_url) {
|
|
274
|
-
const content = await fetchGitFile(entry.download_url, token);
|
|
275
|
-
const filepath = join(localDir, entry.name);
|
|
276
|
-
writeFileSync2(filepath, content);
|
|
277
|
-
installed.push(filepath);
|
|
278
|
-
} else if (entry.type === "dir") {
|
|
279
|
-
await fetchAndWriteSubdir(parsed, sha, `${remotePath}/${entry.name}`, join(localDir, entry.name), installed, token);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
async function installGitSource(projectRoot, source, lockfile, options = {}) {
|
|
284
|
-
const parsed = parseGitSourceRef(source);
|
|
285
|
-
const sourceKey = gitSourceKey(parsed);
|
|
286
|
-
const installed = [];
|
|
287
|
-
const warnings = [];
|
|
288
|
-
let resolvedSha;
|
|
289
|
-
const locked = getLockedSource(lockfile, sourceKey);
|
|
290
|
-
if (options.frozen && !locked) {
|
|
291
|
-
throw new Error(`Frozen mode: no lockfile entry for source "${sourceKey}".`);
|
|
292
|
-
}
|
|
293
|
-
if (locked && !options.update) {
|
|
294
|
-
resolvedSha = locked.resolvedRef;
|
|
295
|
-
} else {
|
|
296
|
-
resolvedSha = await resolveGitRef(parsed, options.token);
|
|
297
|
-
}
|
|
298
|
-
const basePath = parsed.path || "packs";
|
|
299
|
-
const entries = await fetchGitDirectory(parsed, resolvedSha, basePath, options.token);
|
|
300
|
-
const curatedDir = resolve3(projectRoot, ".agentpacks", ".curated");
|
|
301
|
-
mkdirSync(curatedDir, { recursive: true });
|
|
302
|
-
const newLockEntry = {
|
|
303
|
-
requestedRef: parsed.ref,
|
|
304
|
-
resolvedRef: resolvedSha,
|
|
305
|
-
resolvedAt: new Date().toISOString(),
|
|
306
|
-
skills: {},
|
|
307
|
-
packs: {}
|
|
308
|
-
};
|
|
309
|
-
const packDirs = entries.filter((e) => e.type === "dir");
|
|
310
|
-
for (const packEntry of packDirs) {
|
|
311
|
-
const packName = packEntry.name;
|
|
312
|
-
const packOutDir = resolve3(curatedDir, packName);
|
|
313
|
-
const packFiles = await fetchGitDirectory(parsed, resolvedSha, `${basePath}/${packName}`, options.token);
|
|
314
|
-
mkdirSync(packOutDir, { recursive: true });
|
|
315
|
-
for (const file of packFiles) {
|
|
316
|
-
if (file.type === "file" && file.download_url) {
|
|
317
|
-
const content = await fetchGitFile(file.download_url, options.token);
|
|
318
|
-
writeFileSync2(join(packOutDir, file.name), content);
|
|
319
|
-
installed.push(join(packOutDir, file.name));
|
|
320
|
-
if (newLockEntry.packs) {
|
|
321
|
-
newLockEntry.packs[packName] = {
|
|
322
|
-
integrity: computeIntegrity(content)
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
} else if (file.type === "dir") {
|
|
326
|
-
await fetchAndWriteSubdir(parsed, resolvedSha, `${basePath}/${packName}/${file.name}`, join(packOutDir, file.name), installed, options.token);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
if (packDirs.length === 0) {
|
|
331
|
-
const fileEntries = entries.filter((e) => e.type === "file");
|
|
332
|
-
if (fileEntries.length > 0) {
|
|
333
|
-
const packName = parsed.path.split("/").pop() ?? parsed.repo;
|
|
334
|
-
const packOutDir = resolve3(curatedDir, packName);
|
|
335
|
-
mkdirSync(packOutDir, { recursive: true });
|
|
336
|
-
for (const file of entries) {
|
|
337
|
-
if (file.type === "file" && file.download_url) {
|
|
338
|
-
const content = await fetchGitFile(file.download_url, options.token);
|
|
339
|
-
writeFileSync2(join(packOutDir, file.name), content);
|
|
340
|
-
installed.push(join(packOutDir, file.name));
|
|
341
|
-
} else if (file.type === "dir") {
|
|
342
|
-
await fetchAndWriteSubdir(parsed, resolvedSha, `${basePath}/${file.name}`, join(packOutDir, file.name), installed, options.token);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
setLockedSource(lockfile, sourceKey, newLockEntry);
|
|
348
|
-
return { installed, warnings };
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// src/sources/local.ts
|
|
352
|
-
import { existsSync as existsSync3 } from "fs";
|
|
353
|
-
import { isAbsolute, resolve as resolve4 } from "path";
|
|
354
|
-
function resolveLocalPack(packRef, projectRoot) {
|
|
355
|
-
let resolved;
|
|
356
|
-
if (isAbsolute(packRef)) {
|
|
357
|
-
resolved = packRef;
|
|
358
|
-
} else {
|
|
359
|
-
resolved = resolve4(projectRoot, packRef);
|
|
360
|
-
}
|
|
361
|
-
if (!existsSync3(resolved))
|
|
362
|
-
return null;
|
|
363
|
-
return resolved;
|
|
364
|
-
}
|
|
365
|
-
function isLocalPackRef(packRef) {
|
|
366
|
-
return packRef.startsWith("./") || packRef.startsWith("../") || isAbsolute(packRef);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// src/sources/npm-ref.ts
|
|
370
|
-
function parseNpmSourceRef(source) {
|
|
371
|
-
let s = source;
|
|
372
|
-
if (s.startsWith("npm:")) {
|
|
373
|
-
s = s.slice(4);
|
|
374
|
-
}
|
|
375
|
-
let path = "";
|
|
376
|
-
const pathColonIdx = findPathColon(s);
|
|
377
|
-
if (pathColonIdx > -1) {
|
|
378
|
-
path = s.slice(pathColonIdx + 1);
|
|
379
|
-
s = s.slice(0, pathColonIdx);
|
|
380
|
-
}
|
|
381
|
-
let version = "latest";
|
|
382
|
-
const versionAtIdx = findVersionAt(s);
|
|
383
|
-
if (versionAtIdx > -1) {
|
|
384
|
-
version = s.slice(versionAtIdx + 1);
|
|
385
|
-
s = s.slice(0, versionAtIdx);
|
|
386
|
-
}
|
|
387
|
-
if (!s) {
|
|
388
|
-
throw new Error(`Invalid npm source reference: "${source}". Expected package name.`);
|
|
389
|
-
}
|
|
390
|
-
return { packageName: s, version, path };
|
|
391
|
-
}
|
|
392
|
-
function findPathColon(s) {
|
|
393
|
-
const startAfter = s.startsWith("@") ? s.indexOf("/") + 1 : 0;
|
|
394
|
-
const vAt = findVersionAt(s);
|
|
395
|
-
const searchFrom = vAt > -1 ? vAt : startAfter;
|
|
396
|
-
return s.indexOf(":", searchFrom);
|
|
397
|
-
}
|
|
398
|
-
function findVersionAt(s) {
|
|
399
|
-
if (s.startsWith("@")) {
|
|
400
|
-
const slashIdx = s.indexOf("/");
|
|
401
|
-
if (slashIdx === -1)
|
|
402
|
-
return -1;
|
|
403
|
-
return s.indexOf("@", slashIdx + 1);
|
|
404
|
-
}
|
|
405
|
-
return s.indexOf("@");
|
|
406
|
-
}
|
|
407
|
-
function isNpmPackRef(packRef) {
|
|
408
|
-
if (packRef.startsWith("npm:"))
|
|
409
|
-
return true;
|
|
410
|
-
if (packRef.startsWith("@") && packRef.includes("/"))
|
|
411
|
-
return true;
|
|
412
|
-
return false;
|
|
413
|
-
}
|
|
414
|
-
function npmSourceKey(parsed) {
|
|
415
|
-
return `npm:${parsed.packageName}`;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// src/sources/npm.ts
|
|
419
|
-
import { execSync } from "child_process";
|
|
420
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
421
|
-
import { join as join2, resolve as resolve5 } from "path";
|
|
422
|
-
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
423
|
-
async function resolveNpmVersion(parsed) {
|
|
424
|
-
const url = `${NPM_REGISTRY}/${encodeURIComponent(parsed.packageName)}/${parsed.version}`;
|
|
425
|
-
const res = await fetch(url, {
|
|
426
|
-
headers: { Accept: "application/json" }
|
|
427
|
-
});
|
|
428
|
-
if (!res.ok) {
|
|
429
|
-
throw new Error(`Could not resolve npm package "${parsed.packageName}@${parsed.version}": ${res.status}`);
|
|
430
|
-
}
|
|
431
|
-
const data = await res.json();
|
|
432
|
-
return { version: data.version, tarball: data.dist.tarball };
|
|
433
|
-
}
|
|
434
|
-
async function installNpmSource(projectRoot, source, lockfile, options = {}) {
|
|
435
|
-
const parsed = parseNpmSourceRef(source);
|
|
436
|
-
const sourceKey = npmSourceKey(parsed);
|
|
437
|
-
const installed = [];
|
|
438
|
-
const warnings = [];
|
|
439
|
-
const locked = getLockedSource(lockfile, sourceKey);
|
|
440
|
-
if (options.frozen && !locked) {
|
|
441
|
-
throw new Error(`Frozen mode: no lockfile entry for source "${sourceKey}".`);
|
|
442
|
-
}
|
|
443
|
-
let resolvedVersion;
|
|
444
|
-
if (locked && !options.update) {
|
|
445
|
-
resolvedVersion = locked.resolvedRef;
|
|
446
|
-
} else {
|
|
447
|
-
const resolved = await resolveNpmVersion(parsed);
|
|
448
|
-
resolvedVersion = resolved.version;
|
|
449
|
-
}
|
|
450
|
-
const curatedDir = resolve5(projectRoot, ".agentpacks", ".curated");
|
|
451
|
-
mkdirSync2(curatedDir, { recursive: true });
|
|
452
|
-
extractNpmPack(parsed, resolvedVersion, curatedDir, installed, warnings);
|
|
453
|
-
const newEntry = {
|
|
454
|
-
requestedRef: parsed.version,
|
|
455
|
-
resolvedRef: resolvedVersion,
|
|
456
|
-
resolvedAt: new Date().toISOString(),
|
|
457
|
-
skills: {},
|
|
458
|
-
packs: {}
|
|
459
|
-
};
|
|
460
|
-
setLockedSource(lockfile, sourceKey, newEntry);
|
|
461
|
-
return { installed, warnings };
|
|
462
|
-
}
|
|
463
|
-
function extractNpmPack(parsed, version, curatedDir, installed, warnings) {
|
|
464
|
-
const pkgSpec = `${parsed.packageName}@${version}`;
|
|
465
|
-
const packName = parsed.packageName.replace(/^@/, "").replace(/\//g, "-");
|
|
466
|
-
const packOutDir = resolve5(curatedDir, packName);
|
|
467
|
-
try {
|
|
468
|
-
const tmpDir = resolve5(curatedDir, ".tmp-npm");
|
|
469
|
-
mkdirSync2(tmpDir, { recursive: true });
|
|
470
|
-
execSync(`npm pack ${pkgSpec} --pack-destination "${tmpDir}"`, {
|
|
471
|
-
stdio: "pipe",
|
|
472
|
-
timeout: 30000
|
|
473
|
-
});
|
|
474
|
-
const tgzFiles = readdirSync(tmpDir).filter((f) => f.endsWith(".tgz"));
|
|
475
|
-
if (tgzFiles.length === 0) {
|
|
476
|
-
warnings.push(`No tarball found for ${pkgSpec}`);
|
|
477
|
-
return packOutDir;
|
|
478
|
-
}
|
|
479
|
-
const firstTgz = tgzFiles[0];
|
|
480
|
-
if (!firstTgz) {
|
|
481
|
-
warnings.push(`No tarball found for ${pkgSpec}`);
|
|
482
|
-
return packOutDir;
|
|
483
|
-
}
|
|
484
|
-
const tgzPath = join2(tmpDir, firstTgz);
|
|
485
|
-
mkdirSync2(packOutDir, { recursive: true });
|
|
486
|
-
execSync(`tar xzf "${tgzPath}" -C "${packOutDir}" --strip-components=1`, {
|
|
487
|
-
stdio: "pipe",
|
|
488
|
-
timeout: 15000
|
|
489
|
-
});
|
|
490
|
-
execSync(`rm -rf "${tmpDir}"`, { stdio: "pipe" });
|
|
491
|
-
const subpath = parsed.path || "";
|
|
492
|
-
const targetDir = subpath ? join2(packOutDir, subpath) : packOutDir;
|
|
493
|
-
if (existsSync4(targetDir)) {
|
|
494
|
-
collectFiles(targetDir, installed);
|
|
495
|
-
}
|
|
496
|
-
} catch (err) {
|
|
497
|
-
warnings.push(`Failed to extract npm pack ${pkgSpec}: ${err instanceof Error ? err.message : String(err)}`);
|
|
498
|
-
}
|
|
499
|
-
return packOutDir;
|
|
500
|
-
}
|
|
501
|
-
function collectFiles(dir, out) {
|
|
502
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
503
|
-
for (const entry of entries) {
|
|
504
|
-
const full = join2(dir, entry.name);
|
|
505
|
-
if (entry.isDirectory()) {
|
|
506
|
-
collectFiles(full, out);
|
|
507
|
-
} else {
|
|
508
|
-
out.push(full);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// src/sources/registry-ref.ts
|
|
514
|
-
function parseRegistrySourceRef(source) {
|
|
515
|
-
let s = source;
|
|
516
|
-
if (s.startsWith("registry:")) {
|
|
517
|
-
s = s.slice(9);
|
|
518
|
-
}
|
|
519
|
-
if (!s) {
|
|
520
|
-
throw new Error(`Invalid registry source reference: "${source}". Expected pack name.`);
|
|
521
|
-
}
|
|
522
|
-
let version = "latest";
|
|
523
|
-
const atIdx = s.indexOf("@");
|
|
524
|
-
if (atIdx > 0) {
|
|
525
|
-
version = s.slice(atIdx + 1);
|
|
526
|
-
s = s.slice(0, atIdx);
|
|
527
|
-
}
|
|
528
|
-
if (!s) {
|
|
529
|
-
throw new Error(`Invalid registry source reference: "${source}". Pack name is empty.`);
|
|
530
|
-
}
|
|
531
|
-
if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(s)) {
|
|
532
|
-
throw new Error(`Invalid registry pack name: "${s}". Must be lowercase alphanumeric with hyphens.`);
|
|
533
|
-
}
|
|
534
|
-
return { packName: s, version };
|
|
535
|
-
}
|
|
536
|
-
function isRegistryPackRef(packRef) {
|
|
537
|
-
return packRef.startsWith("registry:");
|
|
538
|
-
}
|
|
539
|
-
function registrySourceKey(parsed) {
|
|
540
|
-
return `registry:${parsed.packName}`;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// src/utils/credentials.ts
|
|
544
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
545
|
-
import { homedir } from "os";
|
|
546
|
-
import { dirname, join as join3 } from "path";
|
|
547
|
-
var CONFIG_DIR = join3(homedir(), ".config", "agentpacks");
|
|
548
|
-
var CREDENTIALS_FILE = join3(CONFIG_DIR, "credentials.json");
|
|
549
|
-
function loadCredentials() {
|
|
550
|
-
if (!existsSync5(CREDENTIALS_FILE)) {
|
|
551
|
-
return { registryUrl: "https://registry.agentpacks.dev" };
|
|
552
|
-
}
|
|
553
|
-
try {
|
|
554
|
-
const raw = readFileSync3(CREDENTIALS_FILE, "utf-8");
|
|
555
|
-
return JSON.parse(raw);
|
|
556
|
-
} catch {
|
|
557
|
-
return { registryUrl: "https://registry.agentpacks.dev" };
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
function saveCredentials(credentials) {
|
|
561
|
-
mkdirSync3(dirname(CREDENTIALS_FILE), { recursive: true });
|
|
562
|
-
writeFileSync3(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2) + `
|
|
563
|
-
`, {
|
|
564
|
-
mode: 384
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
function clearCredentials() {
|
|
568
|
-
if (existsSync5(CREDENTIALS_FILE)) {
|
|
569
|
-
writeFileSync3(CREDENTIALS_FILE, JSON.stringify({ registryUrl: "https://registry.agentpacks.dev" }) + `
|
|
570
|
-
`);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// src/utils/registry-client.ts
|
|
575
|
-
var DEFAULT_REGISTRY_URL = "https://registry.agentpacks.dev";
|
|
576
|
-
function createRegistryClient(config) {
|
|
577
|
-
return new RegistryClient({
|
|
578
|
-
registryUrl: config?.registryUrl ?? DEFAULT_REGISTRY_URL,
|
|
579
|
-
authToken: config?.authToken,
|
|
580
|
-
timeout: config?.timeout ?? 30000
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
class RegistryClient {
|
|
585
|
-
config;
|
|
586
|
-
constructor(config) {
|
|
587
|
-
this.config = {
|
|
588
|
-
registryUrl: config.registryUrl.replace(/\/+$/, ""),
|
|
589
|
-
authToken: config.authToken,
|
|
590
|
-
timeout: config.timeout ?? 30000
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
async search(params) {
|
|
594
|
-
const searchParams = new URLSearchParams;
|
|
595
|
-
if (params.query)
|
|
596
|
-
searchParams.set("q", params.query);
|
|
597
|
-
if (params.tags?.length)
|
|
598
|
-
searchParams.set("tags", params.tags.join(","));
|
|
599
|
-
if (params.targets?.length)
|
|
600
|
-
searchParams.set("targets", params.targets.join(","));
|
|
601
|
-
if (params.features?.length)
|
|
602
|
-
searchParams.set("features", params.features.join(","));
|
|
603
|
-
if (params.author)
|
|
604
|
-
searchParams.set("author", params.author);
|
|
605
|
-
if (params.sort)
|
|
606
|
-
searchParams.set("sort", params.sort);
|
|
607
|
-
if (params.limit)
|
|
608
|
-
searchParams.set("limit", String(params.limit));
|
|
609
|
-
if (params.offset)
|
|
610
|
-
searchParams.set("offset", String(params.offset));
|
|
611
|
-
const url = `${this.config.registryUrl}/packs?${searchParams.toString()}`;
|
|
612
|
-
const res = await this.fetch(url);
|
|
613
|
-
return res;
|
|
614
|
-
}
|
|
615
|
-
async info(packName) {
|
|
616
|
-
const url = `${this.config.registryUrl}/packs/${encodeURIComponent(packName)}`;
|
|
617
|
-
const res = await this.fetch(url);
|
|
618
|
-
return res;
|
|
619
|
-
}
|
|
620
|
-
async download(packName, version = "latest") {
|
|
621
|
-
const url = `${this.config.registryUrl}/packs/${encodeURIComponent(packName)}/versions/${encodeURIComponent(version)}/download`;
|
|
622
|
-
const response = await fetch(url, {
|
|
623
|
-
headers: this.headers(),
|
|
624
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
625
|
-
});
|
|
626
|
-
if (!response.ok) {
|
|
627
|
-
throw new RegistryApiError(response.status, `Failed to download ${packName}@${version}: ${response.statusText}`);
|
|
628
|
-
}
|
|
629
|
-
const integrity = response.headers.get("x-integrity") ?? "";
|
|
630
|
-
const data = await response.arrayBuffer();
|
|
631
|
-
return { data, integrity };
|
|
632
|
-
}
|
|
633
|
-
async publish(tarball, metadata) {
|
|
634
|
-
if (!this.config.authToken) {
|
|
635
|
-
throw new Error("Authentication required. Run `agentpacks login` first.");
|
|
636
|
-
}
|
|
637
|
-
const formData = new FormData;
|
|
638
|
-
formData.append("tarball", new Blob([tarball], { type: "application/gzip" }), `${metadata.name}-${metadata.version}.tgz`);
|
|
639
|
-
formData.append("metadata", JSON.stringify(metadata));
|
|
640
|
-
const url = `${this.config.registryUrl}/packs`;
|
|
641
|
-
const response = await fetch(url, {
|
|
642
|
-
method: "POST",
|
|
643
|
-
headers: {
|
|
644
|
-
Authorization: `Bearer ${this.config.authToken}`
|
|
645
|
-
},
|
|
646
|
-
body: formData,
|
|
647
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
648
|
-
});
|
|
649
|
-
if (!response.ok) {
|
|
650
|
-
const body = await response.text();
|
|
651
|
-
throw new RegistryApiError(response.status, `Publish failed: ${body || response.statusText}`);
|
|
652
|
-
}
|
|
653
|
-
return await response.json();
|
|
654
|
-
}
|
|
655
|
-
async featured(limit) {
|
|
656
|
-
const url = limit ? `${this.config.registryUrl}/featured?limit=${limit}` : `${this.config.registryUrl}/featured`;
|
|
657
|
-
const res = await this.fetch(url);
|
|
658
|
-
return res.packs;
|
|
659
|
-
}
|
|
660
|
-
async tags() {
|
|
661
|
-
const url = `${this.config.registryUrl}/tags`;
|
|
662
|
-
const res = await this.fetch(url);
|
|
663
|
-
return res.tags;
|
|
664
|
-
}
|
|
665
|
-
async stats() {
|
|
666
|
-
const url = `${this.config.registryUrl}/stats`;
|
|
667
|
-
return await this.fetch(url);
|
|
668
|
-
}
|
|
669
|
-
async health() {
|
|
670
|
-
try {
|
|
671
|
-
const url = `${this.config.registryUrl}/health`;
|
|
672
|
-
await this.fetch(url);
|
|
673
|
-
return true;
|
|
674
|
-
} catch {
|
|
675
|
-
return false;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
async fetch(url) {
|
|
679
|
-
const response = await fetch(url, {
|
|
680
|
-
headers: this.headers(),
|
|
681
|
-
signal: AbortSignal.timeout(this.config.timeout)
|
|
682
|
-
});
|
|
683
|
-
if (!response.ok) {
|
|
684
|
-
const body = await response.text();
|
|
685
|
-
throw new RegistryApiError(response.status, body || response.statusText);
|
|
686
|
-
}
|
|
687
|
-
return response.json();
|
|
688
|
-
}
|
|
689
|
-
headers() {
|
|
690
|
-
const h = {
|
|
691
|
-
Accept: "application/json"
|
|
692
|
-
};
|
|
693
|
-
if (this.config.authToken) {
|
|
694
|
-
h["Authorization"] = `Bearer ${this.config.authToken}`;
|
|
695
|
-
}
|
|
696
|
-
return h;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
class RegistryApiError extends Error {
|
|
701
|
-
status;
|
|
702
|
-
constructor(status, message) {
|
|
703
|
-
super(message);
|
|
704
|
-
this.name = "RegistryApiError";
|
|
705
|
-
this.status = status;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
// src/utils/tarball.ts
|
|
710
|
-
import { execSync as execSync2 } from "child_process";
|
|
711
|
-
import { createHash as createHash2 } from "crypto";
|
|
712
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4, rmSync } from "fs";
|
|
713
|
-
import { tmpdir } from "os";
|
|
714
|
-
import { join as join4, resolve as resolve6 } from "path";
|
|
715
|
-
async function createTarball(packDir) {
|
|
716
|
-
const absDir = resolve6(packDir);
|
|
717
|
-
const tmpFile = join4(tmpdir(), `agentpacks-${Date.now()}.tgz`);
|
|
718
|
-
try {
|
|
719
|
-
execSync2(`tar -czf "${tmpFile}" -C "${absDir}" .`, {
|
|
720
|
-
stdio: "pipe"
|
|
721
|
-
});
|
|
722
|
-
const buffer = readFileSync4(tmpFile);
|
|
723
|
-
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
724
|
-
} finally {
|
|
725
|
-
if (existsSync6(tmpFile)) {
|
|
726
|
-
rmSync(tmpFile);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
async function extractTarball(data, targetDir) {
|
|
731
|
-
mkdirSync4(targetDir, { recursive: true });
|
|
732
|
-
const tmpFile = join4(tmpdir(), `agentpacks-${Date.now()}.tgz`);
|
|
733
|
-
try {
|
|
734
|
-
const buffer = Buffer.from(data);
|
|
735
|
-
const { writeFileSync: writeFileSync4 } = await import("fs");
|
|
736
|
-
writeFileSync4(tmpFile, buffer);
|
|
737
|
-
execSync2(`tar -xzf "${tmpFile}" -C "${targetDir}"`, {
|
|
738
|
-
stdio: "pipe"
|
|
739
|
-
});
|
|
740
|
-
} finally {
|
|
741
|
-
if (existsSync6(tmpFile)) {
|
|
742
|
-
rmSync(tmpFile);
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
function computeTarballIntegrity(data) {
|
|
747
|
-
const hash = createHash2("sha256").update(Buffer.from(data)).digest("hex");
|
|
748
|
-
return `sha256-${hash}`;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
// src/sources/registry.ts
|
|
752
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readdirSync as readdirSync2, rmSync as rmSync2 } from "fs";
|
|
753
|
-
import { join as join5, resolve as resolve7 } from "path";
|
|
754
|
-
async function installRegistrySource(projectRoot, source, lockfile, options = {}) {
|
|
755
|
-
const parsed = parseRegistrySourceRef(source);
|
|
756
|
-
const sourceKey = registrySourceKey(parsed);
|
|
757
|
-
const installed = [];
|
|
758
|
-
const warnings = [];
|
|
759
|
-
const locked = getLockedSource(lockfile, sourceKey);
|
|
760
|
-
if (options.frozen && !locked) {
|
|
761
|
-
throw new Error(`Frozen mode: no lockfile entry for source "${sourceKey}".`);
|
|
762
|
-
}
|
|
763
|
-
let targetVersion = parsed.version;
|
|
764
|
-
if (locked && !options.update) {
|
|
765
|
-
targetVersion = locked.resolvedRef;
|
|
766
|
-
} else if (targetVersion === "latest") {
|
|
767
|
-
const clientCfg2 = buildClientConfig(options.registryUrl);
|
|
768
|
-
const client2 = createRegistryClient(clientCfg2);
|
|
769
|
-
const info = await client2.info(parsed.packName);
|
|
770
|
-
targetVersion = info.latestVersion;
|
|
771
|
-
}
|
|
772
|
-
const clientCfg = buildClientConfig(options.registryUrl);
|
|
773
|
-
const client = createRegistryClient(clientCfg);
|
|
774
|
-
const { data } = await client.download(parsed.packName, targetVersion);
|
|
775
|
-
const localIntegrity = computeTarballIntegrity(data);
|
|
776
|
-
if (locked && !options.update && locked.skills?.["__integrity"]) {
|
|
777
|
-
const expectedIntegrity = locked.skills["__integrity"].integrity;
|
|
778
|
-
if (expectedIntegrity && localIntegrity !== expectedIntegrity) {
|
|
779
|
-
throw new Error(`Integrity mismatch for ${parsed.packName}@${targetVersion}. ` + `Expected ${expectedIntegrity}, got ${localIntegrity}.`);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
const curatedDir = resolve7(projectRoot, ".agentpacks", ".curated");
|
|
783
|
-
const packOutDir = resolve7(curatedDir, parsed.packName);
|
|
784
|
-
if (existsSync7(packOutDir)) {
|
|
785
|
-
rmSync2(packOutDir, { recursive: true, force: true });
|
|
786
|
-
}
|
|
787
|
-
mkdirSync5(packOutDir, { recursive: true });
|
|
788
|
-
await extractTarball(data, packOutDir);
|
|
789
|
-
collectFiles2(packOutDir, installed);
|
|
790
|
-
const newEntry = {
|
|
791
|
-
requestedRef: parsed.version,
|
|
792
|
-
resolvedRef: targetVersion,
|
|
793
|
-
resolvedAt: new Date().toISOString(),
|
|
794
|
-
skills: {
|
|
795
|
-
__integrity: { integrity: localIntegrity }
|
|
796
|
-
},
|
|
797
|
-
packs: {
|
|
798
|
-
[parsed.packName]: { integrity: localIntegrity }
|
|
799
|
-
}
|
|
800
|
-
};
|
|
801
|
-
setLockedSource(lockfile, sourceKey, newEntry);
|
|
802
|
-
return { installed, warnings };
|
|
803
|
-
}
|
|
804
|
-
function buildClientConfig(registryUrl) {
|
|
805
|
-
const cfg = {};
|
|
806
|
-
if (registryUrl) {
|
|
807
|
-
cfg.registryUrl = registryUrl;
|
|
808
|
-
}
|
|
809
|
-
try {
|
|
810
|
-
const creds = loadCredentials();
|
|
811
|
-
if (creds?.token) {
|
|
812
|
-
cfg.authToken = creds.token;
|
|
813
|
-
}
|
|
814
|
-
} catch {}
|
|
815
|
-
return cfg;
|
|
816
|
-
}
|
|
817
|
-
function collectFiles2(dir, out) {
|
|
818
|
-
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
819
|
-
for (const entry of entries) {
|
|
820
|
-
const full = join5(dir, entry.name);
|
|
821
|
-
if (entry.isDirectory()) {
|
|
822
|
-
collectFiles2(full, out);
|
|
823
|
-
} else {
|
|
824
|
-
out.push(full);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
// src/cli/install.ts
|
|
830
|
-
import chalk from "chalk";
|
|
831
|
-
async function runInstall(projectRoot, options) {
|
|
832
|
-
const config = loadWorkspaceConfig(projectRoot);
|
|
833
|
-
const lockfile = loadLockfile(projectRoot);
|
|
834
|
-
const verbose = options.verbose ?? config.verbose;
|
|
835
|
-
const remotePacks = config.packs.filter((ref) => isGitPackRef(ref) || isNpmPackRef(ref) || isRegistryPackRef(ref));
|
|
836
|
-
const localPacks = config.packs.filter((ref) => isLocalPackRef(ref));
|
|
837
|
-
if (remotePacks.length === 0) {
|
|
838
|
-
console.log(chalk.dim("No remote packs to install. All packs are local."));
|
|
839
|
-
return;
|
|
840
|
-
}
|
|
841
|
-
if (verbose) {
|
|
842
|
-
console.log(chalk.dim(`Found ${remotePacks.length} remote pack(s) to install`));
|
|
843
|
-
console.log(chalk.dim(` (${localPacks.length} local pack(s) skipped)`));
|
|
844
|
-
}
|
|
845
|
-
if (options.frozen) {
|
|
846
|
-
const sourceKeys = remotePacks.map((ref) => ref);
|
|
847
|
-
const frozenCheck = isLockfileFrozenValid(lockfile, sourceKeys);
|
|
848
|
-
if (!frozenCheck.valid) {
|
|
849
|
-
console.log(chalk.red(`Frozen install failed. Missing lockfile entries: ${frozenCheck.missing.join(", ")}`));
|
|
850
|
-
process.exit(1);
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
let totalInstalled = 0;
|
|
854
|
-
const allWarnings = [];
|
|
855
|
-
for (const packRef of remotePacks) {
|
|
856
|
-
if (verbose) {
|
|
857
|
-
console.log(chalk.dim(` Installing ${packRef}...`));
|
|
858
|
-
}
|
|
859
|
-
try {
|
|
860
|
-
let result;
|
|
861
|
-
if (isRegistryPackRef(packRef)) {
|
|
862
|
-
result = await installRegistrySource(projectRoot, packRef, lockfile, {
|
|
863
|
-
update: options.update,
|
|
864
|
-
frozen: options.frozen
|
|
865
|
-
});
|
|
866
|
-
} else if (isGitPackRef(packRef)) {
|
|
867
|
-
const token = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN ?? undefined;
|
|
868
|
-
result = await installGitSource(projectRoot, packRef, lockfile, {
|
|
869
|
-
update: options.update,
|
|
870
|
-
frozen: options.frozen,
|
|
871
|
-
token
|
|
872
|
-
});
|
|
873
|
-
} else if (isNpmPackRef(packRef)) {
|
|
874
|
-
result = await installNpmSource(projectRoot, packRef, lockfile, {
|
|
875
|
-
update: options.update,
|
|
876
|
-
frozen: options.frozen
|
|
877
|
-
});
|
|
878
|
-
} else {
|
|
879
|
-
continue;
|
|
880
|
-
}
|
|
881
|
-
totalInstalled += result.installed.length;
|
|
882
|
-
allWarnings.push(...result.warnings);
|
|
883
|
-
if (verbose && result.installed.length > 0) {
|
|
884
|
-
console.log(chalk.dim(` ${result.installed.length} file(s) installed`));
|
|
885
|
-
}
|
|
886
|
-
} catch (err) {
|
|
887
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
888
|
-
console.log(chalk.red(` error [${packRef}]: ${msg}`));
|
|
889
|
-
allWarnings.push(`Failed to install ${packRef}: ${msg}`);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
for (const w of allWarnings) {
|
|
893
|
-
console.log(chalk.yellow(` warn: ${w}`));
|
|
894
|
-
}
|
|
895
|
-
saveLockfile(projectRoot, lockfile);
|
|
896
|
-
console.log(chalk.green(`Installed ${totalInstalled} file(s) from ${remotePacks.length} source(s)`));
|
|
897
|
-
if (verbose) {
|
|
898
|
-
console.log(chalk.dim("Lockfile updated: agentpacks.lock"));
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
export {
|
|
902
|
-
runInstall
|
|
903
|
-
};
|
|
1
|
+
import{createRequire as zq}from"node:module";var Sq=zq(import.meta.url);import{existsSync as c,readFileSync as i}from"fs";import{parse as hq}from"jsonc-parser";import{resolve as t}from"path";import{z as $}from"zod";var Rq=["opencode","cursor","claudecode","codexcli","mistralvibe","geminicli","copilot","cline","kilo","roo","qwencode","kiro","factorydroid","antigravity","junie","augmentcode","windsurf","warp","replit","zed"],x=["rules","commands","agents","skills","hooks","plugins","mcp","ignore","models"],gq=["repo","monorepo","metarepo"],l=$.object({name:$.string().min(1),version:$.string().default("1.0.0"),description:$.string().default(""),author:$.union([$.string(),$.object({name:$.string(),email:$.string().optional()})]).optional(),homepage:$.string().optional(),repository:$.union([$.string(),$.object({url:$.string(),type:$.string().optional()})]).optional(),license:$.string().optional(),logo:$.string().optional(),tags:$.array($.string()).default([]),dependencies:$.array($.string()).default([]),conflicts:$.array($.string()).default([]),targets:$.union([$.literal("*"),$.array($.string())]).default("*"),features:$.union([$.literal("*"),$.array($.string())]).default("*")}),yq=$.union([$.literal("*"),$.array($.string()),$.record($.string(),$.union([$.literal("*"),$.array($.string())]))]),p=$.object({$schema:$.string().optional(),packs:$.array($.string()).default(["./packs/default"]),disabled:$.array($.string()).default([]),targets:$.union([$.literal("*"),$.array($.string())]).default("*"),features:yq.default("*"),mode:$.enum(gq).default("repo"),baseDirs:$.array($.string()).default(["."]),global:$.boolean().default(!1),delete:$.boolean().default(!0),verbose:$.boolean().default(!1),silent:$.boolean().default(!1),overrides:$.record($.string(),$.record($.string(),$.string())).default({}),sources:$.array($.object({source:$.string(),packs:$.array($.string()).optional(),skills:$.array($.string()).optional()})).default([]),modelProfile:$.string().optional()}),mq=["agentpacks.local.jsonc","agentpacks.jsonc"];function o(q){for(let Q of mq){let X=t(q,Q);if(c(X)){let Z=i(X,"utf-8"),J=hq(Z);return p.parse(J)}}return p.parse({})}function NQ(q){let Q=t(q,"pack.json");if(!c(Q)){let J=q.split("/").pop()??"unknown";return l.parse({name:J})}let X=i(Q,"utf-8"),Z=JSON.parse(X);return l.parse(Z)}function LQ(q,Q){let{features:X}=q;if(X==="*")return[...x];if(Array.isArray(X)){if(X.includes("*"))return[...x];return X.filter((J)=>x.includes(J))}let Z=X[Q];if(!Z)return[];if(Z==="*")return[...x];if(Array.isArray(Z)&&Z.includes("*"))return[...x];return Z.filter((J)=>x.includes(J))}function CQ(q){if(q.targets==="*")return[...Rq];return q.targets}import{createHash as uq}from"crypto";import{existsSync as kq,readFileSync as fq,writeFileSync as dq}from"fs";import{resolve as a}from"path";var nq=1,s="agentpacks.lock";function r(q){let Q=a(q,s);if(!kq(Q))return{lockfileVersion:nq,sources:{}};let X=fq(Q,"utf-8");return JSON.parse(X)}function e(q,Q){let X=a(q,s);dq(X,JSON.stringify(Q,null,2)+`
|
|
2
|
+
`)}function A(q,Q){return q.sources[Q]}function P(q,Q,X){q.sources[Q]=X}function qq(q){return`sha256-${uq("sha256").update(q).digest("hex")}`}function Qq(q,Q){let X=Q.filter((Z)=>!(Z in q.sources));return{valid:X.length===0,missing:X}}function Xq(q){let Q=q;if(Q.startsWith("github:"))Q=Q.slice(7);let X="",Z=Q.indexOf("@"),J=Q.indexOf(":",Z>-1?Z:0);if(J>-1)X=Q.slice(J+1),Q=Q.slice(0,J);let Y="main";if(Z>-1)Y=Q.slice(Z+1),Q=Q.slice(0,Z);let V=Q.split("/");if(V.length<2)throw Error(`Invalid git source reference: "${q}". Expected owner/repo format.`);let W=V[0],M=V[1];if(!W||!M)throw Error(`Invalid git source reference: "${q}". Expected owner/repo format.`);return{owner:W,repo:M,ref:Y,path:X||""}}function j(q){if(q.startsWith("github:"))return!0;if(q.startsWith("./")||q.startsWith("../")||q.startsWith("/"))return!1;if(q.startsWith("@")||q.startsWith("npm:"))return!1;return q.split("/").length===2&&!q.includes("node_modules")}function Zq(q){return`${q.owner}/${q.repo}`}import{mkdirSync as v,writeFileSync as D}from"fs";import{join as w,resolve as I}from"path";var $q="https://api.github.com";function z(q){let Q={Accept:"application/vnd.github.v3+json","User-Agent":"agentpacks"};if(q)Q.Authorization=`token ${q}`;return Q}async function lq(q,Q){let X=`${$q}/repos/${q.owner}/${q.repo}/git/ref`,Z=await fetch(`${X}/heads/${q.ref}`,{headers:z(Q)});if(!Z.ok){let Y=await fetch(`${X}/tags/${q.ref}`,{headers:z(Q)});if(!Y.ok)throw Error(`Could not resolve ref "${q.ref}" for ${q.owner}/${q.repo}: ${Z.status}`);return(await Y.json()).object.sha}return(await Z.json()).object.sha}async function S(q,Q,X,Z){let J=q.path?`${q.path}/${X}`:X,Y=`${$q}/repos/${q.owner}/${q.repo}/contents/${J}?ref=${Q}`,V=await fetch(Y,{headers:z(Z)});if(!V.ok)return[];return await V.json()}async function h(q,Q){let X={"User-Agent":"agentpacks"};if(Q)X.Authorization=`token ${Q}`;let Z=await fetch(q,{headers:X});if(!Z.ok)throw Error(`Failed to fetch ${q}: ${Z.status}`);return Z.text()}async function R(q,Q,X,Z,J,Y){v(Z,{recursive:!0});let V=await S(q,Q,X,Y);for(let W of V)if(W.type==="file"&&W.download_url){let M=await h(W.download_url,Y),B=w(Z,W.name);D(B,M),J.push(B)}else if(W.type==="dir")await R(q,Q,`${X}/${W.name}`,w(Z,W.name),J,Y)}async function Jq(q,Q,X,Z={}){let J=Xq(Q),Y=Zq(J),V=[],W=[],M,B=A(X,Y);if(Z.frozen&&!B)throw Error(`Frozen mode: no lockfile entry for source "${Y}".`);if(B&&!Z.update)M=B.resolvedRef;else M=await lq(J,Z.token);let H=J.path||"packs",U=await S(J,M,H,Z.token),O=I(q,".agentpacks",".curated");v(O,{recursive:!0});let K={requestedRef:J.ref,resolvedRef:M,resolvedAt:new Date().toISOString(),skills:{},packs:{}},b=U.filter((N)=>N.type==="dir");for(let N of b){let L=N.name,G=I(O,L),T=await S(J,M,`${H}/${L}`,Z.token);v(G,{recursive:!0});for(let _ of T)if(_.type==="file"&&_.download_url){let n=await h(_.download_url,Z.token);if(D(w(G,_.name),n),V.push(w(G,_.name)),K.packs)K.packs[L]={integrity:qq(n)}}else if(_.type==="dir")await R(J,M,`${H}/${L}/${_.name}`,w(G,_.name),V,Z.token)}if(b.length===0){if(U.filter((L)=>L.type==="file").length>0){let L=J.path.split("/").pop()??J.repo,G=I(O,L);v(G,{recursive:!0});for(let T of U)if(T.type==="file"&&T.download_url){let _=await h(T.download_url,Z.token);D(w(G,T.name),_),V.push(w(G,T.name))}else if(T.type==="dir")await R(J,M,`${H}/${T.name}`,w(G,T.name),V,Z.token)}}return P(X,Y,K),{installed:V,warnings:W}}import{existsSync as pq}from"fs";import{isAbsolute as Yq,resolve as cq}from"path";function hQ(q,Q){let X;if(Yq(q))X=q;else X=cq(Q,q);if(!pq(X))return null;return X}function Bq(q){return q.startsWith("./")||q.startsWith("../")||Yq(q)}function Mq(q){let Q=q;if(Q.startsWith("npm:"))Q=Q.slice(4);let X="",Z=iq(Q);if(Z>-1)X=Q.slice(Z+1),Q=Q.slice(0,Z);let J="latest",Y=Wq(Q);if(Y>-1)J=Q.slice(Y+1),Q=Q.slice(0,Y);if(!Q)throw Error(`Invalid npm source reference: "${q}". Expected package name.`);return{packageName:Q,version:J,path:X}}function iq(q){let Q=q.startsWith("@")?q.indexOf("/")+1:0,X=Wq(q),Z=X>-1?X:Q;return q.indexOf(":",Z)}function Wq(q){if(q.startsWith("@")){let Q=q.indexOf("/");if(Q===-1)return-1;return q.indexOf("@",Q+1)}return q.indexOf("@")}function g(q){if(q.startsWith("npm:"))return!0;if(q.startsWith("@")&&q.includes("/"))return!0;return!1}function Hq(q){return`npm:${q.packageName}`}import{execSync as y}from"child_process";import{existsSync as tq,mkdirSync as m,readdirSync as Vq}from"fs";import{join as u,resolve as k}from"path";var oq="https://registry.npmjs.org";async function aq(q){let Q=`${oq}/${encodeURIComponent(q.packageName)}/${q.version}`,X=await fetch(Q,{headers:{Accept:"application/json"}});if(!X.ok)throw Error(`Could not resolve npm package "${q.packageName}@${q.version}": ${X.status}`);let Z=await X.json();return{version:Z.version,tarball:Z.dist.tarball}}async function Uq(q,Q,X,Z={}){let J=Mq(Q),Y=Hq(J),V=[],W=[],M=A(X,Y);if(Z.frozen&&!M)throw Error(`Frozen mode: no lockfile entry for source "${Y}".`);let B;if(M&&!Z.update)B=M.resolvedRef;else B=(await aq(J)).version;let H=k(q,".agentpacks",".curated");m(H,{recursive:!0}),sq(J,B,H,V,W);let U={requestedRef:J.version,resolvedRef:B,resolvedAt:new Date().toISOString(),skills:{},packs:{}};return P(X,Y,U),{installed:V,warnings:W}}function sq(q,Q,X,Z,J){let Y=`${q.packageName}@${Q}`,V=q.packageName.replace(/^@/,"").replace(/\//g,"-"),W=k(X,V);try{let M=k(X,".tmp-npm");m(M,{recursive:!0}),y(`npm pack ${Y} --pack-destination "${M}"`,{stdio:"pipe",timeout:30000});let B=Vq(M).filter((b)=>b.endsWith(".tgz"));if(B.length===0)return J.push(`No tarball found for ${Y}`),W;let H=B[0];if(!H)return J.push(`No tarball found for ${Y}`),W;let U=u(M,H);m(W,{recursive:!0}),y(`tar xzf "${U}" -C "${W}" --strip-components=1`,{stdio:"pipe",timeout:15000}),y(`rm -rf "${M}"`,{stdio:"pipe"});let O=q.path||"",K=O?u(W,O):W;if(tq(K))Gq(K,Z)}catch(M){J.push(`Failed to extract npm pack ${Y}: ${M instanceof Error?M.message:String(M)}`)}return W}function Gq(q,Q){let X=Vq(q,{withFileTypes:!0});for(let Z of X){let J=u(q,Z.name);if(Z.isDirectory())Gq(J,Q);else Q.push(J)}}function Kq(q){let Q=q;if(Q.startsWith("registry:"))Q=Q.slice(9);if(!Q)throw Error(`Invalid registry source reference: "${q}". Expected pack name.`);let X="latest",Z=Q.indexOf("@");if(Z>0)X=Q.slice(Z+1),Q=Q.slice(0,Z);if(!Q)throw Error(`Invalid registry source reference: "${q}". Pack name is empty.`);if(!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(Q))throw Error(`Invalid registry pack name: "${Q}". Must be lowercase alphanumeric with hyphens.`);return{packName:Q,version:X}}function f(q){return q.startsWith("registry:")}function Tq(q){return`registry:${q.packName}`}import{existsSync as _q,mkdirSync as rq,readFileSync as eq,writeFileSync as Oq}from"fs";import{homedir as qQ}from"os";import{dirname as QQ,join as Nq}from"path";var XQ=Nq(qQ(),".config","agentpacks"),E=Nq(XQ,"credentials.json");function Lq(){if(!_q(E))return{registryUrl:"https://registry.agentpacks.dev"};try{let q=eq(E,"utf-8");return JSON.parse(q)}catch{return{registryUrl:"https://registry.agentpacks.dev"}}}function iQ(q){rq(QQ(E),{recursive:!0}),Oq(E,JSON.stringify(q,null,2)+`
|
|
3
|
+
`,{mode:384})}function tQ(){if(_q(E))Oq(E,JSON.stringify({registryUrl:"https://registry.agentpacks.dev"})+`
|
|
4
|
+
`)}function d(q){return new Cq({registryUrl:q?.registryUrl??"https://registry.agentpacks.dev",authToken:q?.authToken,timeout:q?.timeout??30000})}class Cq{config;constructor(q){this.config={registryUrl:q.registryUrl.replace(/\/+$/,""),authToken:q.authToken,timeout:q.timeout??30000}}async search(q){let Q=new URLSearchParams;if(q.query)Q.set("q",q.query);if(q.tags?.length)Q.set("tags",q.tags.join(","));if(q.targets?.length)Q.set("targets",q.targets.join(","));if(q.features?.length)Q.set("features",q.features.join(","));if(q.author)Q.set("author",q.author);if(q.sort)Q.set("sort",q.sort);if(q.limit)Q.set("limit",String(q.limit));if(q.offset)Q.set("offset",String(q.offset));let X=`${this.config.registryUrl}/packs?${Q.toString()}`;return await this.fetch(X)}async info(q){let Q=`${this.config.registryUrl}/packs/${encodeURIComponent(q)}`;return await this.fetch(Q)}async download(q,Q="latest"){let X=`${this.config.registryUrl}/packs/${encodeURIComponent(q)}/versions/${encodeURIComponent(Q)}/download`,Z=await fetch(X,{headers:this.headers(),signal:AbortSignal.timeout(this.config.timeout)});if(!Z.ok)throw new F(Z.status,`Failed to download ${q}@${Q}: ${Z.statusText}`);let J=Z.headers.get("x-integrity")??"";return{data:await Z.arrayBuffer(),integrity:J}}async publish(q,Q){if(!this.config.authToken)throw Error("Authentication required. Run `agentpacks login` first.");let X=new FormData;X.append("tarball",new Blob([q],{type:"application/gzip"}),`${Q.name}-${Q.version}.tgz`),X.append("metadata",JSON.stringify(Q));let Z=`${this.config.registryUrl}/packs`,J=await fetch(Z,{method:"POST",headers:{Authorization:`Bearer ${this.config.authToken}`},body:X,signal:AbortSignal.timeout(this.config.timeout)});if(!J.ok){let Y=await J.text();throw new F(J.status,`Publish failed: ${Y||J.statusText}`)}return await J.json()}async featured(q){let Q=q?`${this.config.registryUrl}/featured?limit=${q}`:`${this.config.registryUrl}/featured`;return(await this.fetch(Q)).packs}async tags(){let q=`${this.config.registryUrl}/tags`;return(await this.fetch(q)).tags}async stats(){let q=`${this.config.registryUrl}/stats`;return await this.fetch(q)}async health(){try{let q=`${this.config.registryUrl}/health`;return await this.fetch(q),!0}catch{return!1}}async fetch(q){let Q=await fetch(q,{headers:this.headers(),signal:AbortSignal.timeout(this.config.timeout)});if(!Q.ok){let X=await Q.text();throw new F(Q.status,X||Q.statusText)}return Q.json()}headers(){let q={Accept:"application/json"};if(this.config.authToken)q.Authorization=`Bearer ${this.config.authToken}`;return q}}class F extends Error{status;constructor(q,Q){super(Q);this.name="RegistryApiError",this.status=q}}import{execSync as wq}from"child_process";import{createHash as ZQ}from"crypto";import{existsSync as bq,mkdirSync as $Q,readFileSync as JQ,rmSync as xq}from"fs";import{tmpdir as Aq}from"os";import{join as Pq,resolve as YQ}from"path";async function XX(q){let Q=YQ(q),X=Pq(Aq(),`agentpacks-${Date.now()}.tgz`);try{wq(`tar -czf "${X}" -C "${Q}" .`,{stdio:"pipe"});let Z=JQ(X);return Z.buffer.slice(Z.byteOffset,Z.byteOffset+Z.byteLength)}finally{if(bq(X))xq(X)}}async function Eq(q,Q){$Q(Q,{recursive:!0});let X=Pq(Aq(),`agentpacks-${Date.now()}.tgz`);try{let Z=Buffer.from(q),{writeFileSync:J}=await import("fs");J(X,Z),wq(`tar -xzf "${X}" -C "${Q}"`,{stdio:"pipe"})}finally{if(bq(X))xq(X)}}function vq(q){return`sha256-${ZQ("sha256").update(Buffer.from(q)).digest("hex")}`}import{existsSync as BQ,mkdirSync as MQ,readdirSync as WQ,rmSync as HQ}from"fs";import{join as VQ,resolve as Fq}from"path";async function Iq(q,Q,X,Z={}){let J=Kq(Q),Y=Tq(J),V=[],W=[],M=A(X,Y);if(Z.frozen&&!M)throw Error(`Frozen mode: no lockfile entry for source "${Y}".`);let B=J.version;if(M&&!Z.update)B=M.resolvedRef;else if(B==="latest"){let G=jq(Z.registryUrl);B=(await d(G).info(J.packName)).latestVersion}let H=jq(Z.registryUrl),U=d(H),{data:O}=await U.download(J.packName,B),K=vq(O);if(M&&!Z.update&&M.skills?.__integrity){let G=M.skills.__integrity.integrity;if(G&&K!==G)throw Error(`Integrity mismatch for ${J.packName}@${B}. Expected ${G}, got ${K}.`)}let b=Fq(q,".agentpacks",".curated"),N=Fq(b,J.packName);if(BQ(N))HQ(N,{recursive:!0,force:!0});MQ(N,{recursive:!0}),await Eq(O,N),Dq(N,V);let L={requestedRef:J.version,resolvedRef:B,resolvedAt:new Date().toISOString(),skills:{__integrity:{integrity:K}},packs:{[J.packName]:{integrity:K}}};return P(X,Y,L),{installed:V,warnings:W}}function jq(q){let Q={};if(q)Q.registryUrl=q;try{let X=Lq();if(X?.token)Q.authToken=X.token}catch{}return Q}function Dq(q,Q){let X=WQ(q,{withFileTypes:!0});for(let Z of X){let J=VQ(q,Z.name);if(Z.isDirectory())Dq(J,Q);else Q.push(J)}}import C from"chalk";async function bX(q,Q){let X=o(q),Z=r(q),J=Q.verbose??X.verbose,Y=X.packs.filter((B)=>j(B)||g(B)||f(B)),V=X.packs.filter((B)=>Bq(B));if(Y.length===0){console.log(C.dim("No remote packs to install. All packs are local."));return}if(J)console.log(C.dim(`Found ${Y.length} remote pack(s) to install`)),console.log(C.dim(` (${V.length} local pack(s) skipped)`));if(Q.frozen){let B=Y.map((U)=>U),H=Qq(Z,B);if(!H.valid)console.log(C.red(`Frozen install failed. Missing lockfile entries: ${H.missing.join(", ")}`)),process.exit(1)}let W=0,M=[];for(let B of Y){if(J)console.log(C.dim(` Installing ${B}...`));try{let H;if(f(B))H=await Iq(q,B,Z,{update:Q.update,frozen:Q.frozen});else if(j(B)){let U=process.env.GITHUB_TOKEN??process.env.GH_TOKEN??void 0;H=await Jq(q,B,Z,{update:Q.update,frozen:Q.frozen,token:U})}else if(g(B))H=await Uq(q,B,Z,{update:Q.update,frozen:Q.frozen});else continue;if(W+=H.installed.length,M.push(...H.warnings),J&&H.installed.length>0)console.log(C.dim(` ${H.installed.length} file(s) installed`))}catch(H){let U=H instanceof Error?H.message:String(H);console.log(C.red(` error [${B}]: ${U}`)),M.push(`Failed to install ${B}: ${U}`)}}for(let B of M)console.log(C.yellow(` warn: ${B}`));if(e(q,Z),console.log(C.green(`Installed ${W} file(s) from ${Y.length} source(s)`)),J)console.log(C.dim("Lockfile updated: agentpacks.lock"))}export{bX as runInstall};
|