@musher-dev/musher-sdk 0.1.1
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/LICENSE +21 -0
- package/README.md +102 -0
- package/dist/index.cjs +2135 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1141 -0
- package/dist/index.d.ts +1141 -0
- package/dist/index.js +2056 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// src/frontmatter.ts
|
|
34
|
+
function parseFrontmatter(text) {
|
|
35
|
+
const match = FRONTMATTER_RE.exec(text);
|
|
36
|
+
if (!match) {
|
|
37
|
+
return { body: text };
|
|
38
|
+
}
|
|
39
|
+
const raw = match[1];
|
|
40
|
+
const body = match[2];
|
|
41
|
+
let name;
|
|
42
|
+
let description;
|
|
43
|
+
for (const line of raw.split("\n")) {
|
|
44
|
+
const fm = FIELD_RE.exec(line.trim());
|
|
45
|
+
if (!fm) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const value = stripQuotes(fm[2].trim());
|
|
49
|
+
if (fm[1] === "name") {
|
|
50
|
+
name = value;
|
|
51
|
+
} else if (fm[1] === "description") {
|
|
52
|
+
description = value;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { name, description, body };
|
|
56
|
+
}
|
|
57
|
+
function stripQuotes(s) {
|
|
58
|
+
if (s.length >= 2) {
|
|
59
|
+
const first = s[0];
|
|
60
|
+
const last = s[s.length - 1];
|
|
61
|
+
if (first === '"' && last === '"' || first === "'" && last === "'") {
|
|
62
|
+
return s.slice(1, -1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return s;
|
|
66
|
+
}
|
|
67
|
+
function extractDescription(skill) {
|
|
68
|
+
const def = skill.definition();
|
|
69
|
+
if (!def) {
|
|
70
|
+
return `Skill: ${skill.name}`;
|
|
71
|
+
}
|
|
72
|
+
const text = def.text();
|
|
73
|
+
const fm = parseFrontmatter(text);
|
|
74
|
+
if (fm.description) {
|
|
75
|
+
return fm.description;
|
|
76
|
+
}
|
|
77
|
+
return text.slice(0, 200).replace(/\n/g, " ").trim() || `Skill: ${skill.name}`;
|
|
78
|
+
}
|
|
79
|
+
var FRONTMATTER_RE, FIELD_RE;
|
|
80
|
+
var init_frontmatter = __esm({
|
|
81
|
+
"src/frontmatter.ts"() {
|
|
82
|
+
"use strict";
|
|
83
|
+
FRONTMATTER_RE = /^---[ \t]*\n([\s\S]*?)---[ \t]*\n?([\s\S]*)$/;
|
|
84
|
+
FIELD_RE = /^(name|description)\s*:\s*(.+)$/;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// src/adapters/openai.ts
|
|
89
|
+
var openai_exports = {};
|
|
90
|
+
__export(openai_exports, {
|
|
91
|
+
exportOpenAIInlineSkill: () => exportOpenAIInlineSkill,
|
|
92
|
+
exportOpenAILocalSkill: () => exportOpenAILocalSkill
|
|
93
|
+
});
|
|
94
|
+
async function exportOpenAILocalSkill(skill, targetDir) {
|
|
95
|
+
const { mkdir: mkdir6, writeFile: writeFile6 } = await import("fs/promises");
|
|
96
|
+
const { join: join7, resolve: resolve5, dirname: dirname5 } = await import("path");
|
|
97
|
+
const skillDir = resolve5(targetDir, skill.name);
|
|
98
|
+
await mkdir6(skillDir, { recursive: true });
|
|
99
|
+
for (const fh of skill.files()) {
|
|
100
|
+
const relativePath = fh.logicalPath.replace(SKILL_PREFIX_RE, "");
|
|
101
|
+
const filePath = join7(skillDir, relativePath);
|
|
102
|
+
await mkdir6(dirname5(filePath), { recursive: true });
|
|
103
|
+
await writeFile6(filePath, fh.bytes());
|
|
104
|
+
}
|
|
105
|
+
const description = extractDescription(skill);
|
|
106
|
+
return { name: skill.name, description, path: skillDir };
|
|
107
|
+
}
|
|
108
|
+
function exportOpenAIInlineSkill(skill) {
|
|
109
|
+
const description = extractDescription(skill);
|
|
110
|
+
const zipBuffer = buildStoreZip(skill);
|
|
111
|
+
const data = zipBuffer.toString("base64");
|
|
112
|
+
return {
|
|
113
|
+
type: "inline",
|
|
114
|
+
name: skill.name,
|
|
115
|
+
description,
|
|
116
|
+
source: { type: "base64", mediaType: "application/zip", data }
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function buildStoreZip(skill) {
|
|
120
|
+
const files = skill.files().map((fh) => {
|
|
121
|
+
const relativePath = fh.logicalPath.replace(SKILL_PREFIX_RE, "");
|
|
122
|
+
const name = `${skill.name}/${relativePath}`;
|
|
123
|
+
return { name, data: Buffer.from(fh.bytes()) };
|
|
124
|
+
});
|
|
125
|
+
const parts = [];
|
|
126
|
+
const centralParts = [];
|
|
127
|
+
let offset = 0;
|
|
128
|
+
for (const file of files) {
|
|
129
|
+
const nameBuffer = Buffer.from(file.name, "utf-8");
|
|
130
|
+
const local = Buffer.alloc(30 + nameBuffer.length);
|
|
131
|
+
local.writeUInt32LE(67324752, 0);
|
|
132
|
+
local.writeUInt16LE(20, 4);
|
|
133
|
+
local.writeUInt16LE(0, 6);
|
|
134
|
+
local.writeUInt16LE(0, 8);
|
|
135
|
+
local.writeUInt16LE(0, 10);
|
|
136
|
+
local.writeUInt16LE(0, 12);
|
|
137
|
+
local.writeUInt32LE(crc32(file.data), 14);
|
|
138
|
+
local.writeUInt32LE(file.data.length, 18);
|
|
139
|
+
local.writeUInt32LE(file.data.length, 22);
|
|
140
|
+
local.writeUInt16LE(nameBuffer.length, 26);
|
|
141
|
+
local.writeUInt16LE(0, 28);
|
|
142
|
+
nameBuffer.copy(local, 30);
|
|
143
|
+
const central = Buffer.alloc(46 + nameBuffer.length);
|
|
144
|
+
central.writeUInt32LE(33639248, 0);
|
|
145
|
+
central.writeUInt16LE(20, 4);
|
|
146
|
+
central.writeUInt16LE(20, 6);
|
|
147
|
+
central.writeUInt16LE(0, 8);
|
|
148
|
+
central.writeUInt16LE(0, 10);
|
|
149
|
+
central.writeUInt16LE(0, 12);
|
|
150
|
+
central.writeUInt16LE(0, 14);
|
|
151
|
+
central.writeUInt32LE(crc32(file.data), 16);
|
|
152
|
+
central.writeUInt32LE(file.data.length, 20);
|
|
153
|
+
central.writeUInt32LE(file.data.length, 24);
|
|
154
|
+
central.writeUInt16LE(nameBuffer.length, 28);
|
|
155
|
+
central.writeUInt16LE(0, 30);
|
|
156
|
+
central.writeUInt16LE(0, 32);
|
|
157
|
+
central.writeUInt16LE(0, 34);
|
|
158
|
+
central.writeUInt16LE(0, 36);
|
|
159
|
+
central.writeUInt32LE(0, 38);
|
|
160
|
+
central.writeUInt32LE(offset, 42);
|
|
161
|
+
nameBuffer.copy(central, 46);
|
|
162
|
+
parts.push(local, file.data);
|
|
163
|
+
centralParts.push(central);
|
|
164
|
+
offset += local.length + file.data.length;
|
|
165
|
+
}
|
|
166
|
+
const centralDirOffset = offset;
|
|
167
|
+
let centralDirSize = 0;
|
|
168
|
+
for (const c of centralParts) {
|
|
169
|
+
centralDirSize += c.length;
|
|
170
|
+
}
|
|
171
|
+
const eocd = Buffer.alloc(22);
|
|
172
|
+
eocd.writeUInt32LE(101010256, 0);
|
|
173
|
+
eocd.writeUInt16LE(0, 4);
|
|
174
|
+
eocd.writeUInt16LE(0, 6);
|
|
175
|
+
eocd.writeUInt16LE(files.length, 8);
|
|
176
|
+
eocd.writeUInt16LE(files.length, 10);
|
|
177
|
+
eocd.writeUInt32LE(centralDirSize, 12);
|
|
178
|
+
eocd.writeUInt32LE(centralDirOffset, 16);
|
|
179
|
+
eocd.writeUInt16LE(0, 20);
|
|
180
|
+
return Buffer.concat([...parts, ...centralParts, eocd]);
|
|
181
|
+
}
|
|
182
|
+
function crc32(data) {
|
|
183
|
+
let crc = 4294967295;
|
|
184
|
+
for (let i = 0; i < data.length; i++) {
|
|
185
|
+
crc ^= data[i];
|
|
186
|
+
for (let j = 0; j < 8; j++) {
|
|
187
|
+
crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return (crc ^ 4294967295) >>> 0;
|
|
191
|
+
}
|
|
192
|
+
var SKILL_PREFIX_RE;
|
|
193
|
+
var init_openai = __esm({
|
|
194
|
+
"src/adapters/openai.ts"() {
|
|
195
|
+
"use strict";
|
|
196
|
+
init_frontmatter();
|
|
197
|
+
SKILL_PREFIX_RE = /^skills\/[^/]+\//;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// src/adapters/claude.ts
|
|
202
|
+
var claude_exports = {};
|
|
203
|
+
__export(claude_exports, {
|
|
204
|
+
exportClaudePlugin: () => exportClaudePlugin,
|
|
205
|
+
installClaudeSkills: () => installClaudeSkills
|
|
206
|
+
});
|
|
207
|
+
async function exportClaudePlugin(source, opts) {
|
|
208
|
+
const bundle = "bundle" in source ? source.bundle : source;
|
|
209
|
+
const name = opts.name ?? bundle.ref.slug;
|
|
210
|
+
const pluginDir = (0, import_node_path.resolve)(opts.targetDir, name);
|
|
211
|
+
await (0, import_promises.mkdir)(pluginDir, { recursive: true });
|
|
212
|
+
const files = source.files();
|
|
213
|
+
for (const fh of files) {
|
|
214
|
+
const filePath = (0, import_node_path.join)(pluginDir, fh.logicalPath);
|
|
215
|
+
await (0, import_promises.mkdir)((0, import_node_path.join)(filePath, ".."), { recursive: true });
|
|
216
|
+
await (0, import_promises.writeFile)(filePath, fh.bytes());
|
|
217
|
+
}
|
|
218
|
+
const metaDir = (0, import_node_path.join)(pluginDir, ".claude-plugin");
|
|
219
|
+
await (0, import_promises.mkdir)(metaDir, { recursive: true });
|
|
220
|
+
const manifest = {
|
|
221
|
+
name,
|
|
222
|
+
description: opts.description ?? "",
|
|
223
|
+
version: bundle.version,
|
|
224
|
+
files: files.map((f) => f.logicalPath)
|
|
225
|
+
};
|
|
226
|
+
await (0, import_promises.writeFile)((0, import_node_path.join)(metaDir, "plugin.json"), JSON.stringify(manifest, null, 2));
|
|
227
|
+
return pluginDir;
|
|
228
|
+
}
|
|
229
|
+
async function installClaudeSkills(bundle, dir, opts) {
|
|
230
|
+
const source = "bundle" in bundle ? bundle.bundle : bundle;
|
|
231
|
+
const skillsDir = (0, import_node_path.resolve)(dir, ".claude", "skills");
|
|
232
|
+
const prefix = opts?.prefix ?? "";
|
|
233
|
+
const written = [];
|
|
234
|
+
const skills = "skills" in bundle && typeof bundle.skills === "function" ? bundle.skills() : source.skills();
|
|
235
|
+
for (const skill of skills) {
|
|
236
|
+
const skillDir = (0, import_node_path.join)(skillsDir, prefix, skill.name);
|
|
237
|
+
await (0, import_promises.mkdir)(skillDir, { recursive: true });
|
|
238
|
+
for (const fh of skill.files()) {
|
|
239
|
+
const relativePath = fh.logicalPath.replace(SKILL_PREFIX_RE2, "");
|
|
240
|
+
const filePath = (0, import_node_path.join)(skillDir, relativePath);
|
|
241
|
+
await (0, import_promises.mkdir)((0, import_node_path.join)(filePath, ".."), { recursive: true });
|
|
242
|
+
await (0, import_promises.writeFile)(filePath, fh.bytes());
|
|
243
|
+
written.push(filePath);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return written;
|
|
247
|
+
}
|
|
248
|
+
var import_promises, import_node_path, SKILL_PREFIX_RE2;
|
|
249
|
+
var init_claude = __esm({
|
|
250
|
+
"src/adapters/claude.ts"() {
|
|
251
|
+
"use strict";
|
|
252
|
+
import_promises = require("fs/promises");
|
|
253
|
+
import_node_path = require("path");
|
|
254
|
+
SKILL_PREFIX_RE2 = /^skills\/[^/]+\//;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// src/adapters/vscode.ts
|
|
259
|
+
var vscode_exports = {};
|
|
260
|
+
__export(vscode_exports, {
|
|
261
|
+
installVSCodeSkills: () => installVSCodeSkills
|
|
262
|
+
});
|
|
263
|
+
async function installVSCodeSkills(source, dir, opts) {
|
|
264
|
+
const bundle = "bundle" in source ? source.bundle : source;
|
|
265
|
+
const subdir = opts?.subdir ?? ".agents/skills";
|
|
266
|
+
const skillsDir = (0, import_node_path2.resolve)(dir, subdir);
|
|
267
|
+
const written = [];
|
|
268
|
+
const skills = "skills" in source && typeof source.skills === "function" ? source.skills() : bundle.skills();
|
|
269
|
+
for (const skill of skills) {
|
|
270
|
+
const skillDir = (0, import_node_path2.join)(skillsDir, skill.name);
|
|
271
|
+
await (0, import_promises2.mkdir)(skillDir, { recursive: true });
|
|
272
|
+
for (const fh of skill.files()) {
|
|
273
|
+
const relativePath = fh.logicalPath.replace(SKILL_PREFIX_RE3, "");
|
|
274
|
+
const filePath = (0, import_node_path2.join)(skillDir, relativePath);
|
|
275
|
+
await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(filePath), { recursive: true });
|
|
276
|
+
await (0, import_promises2.writeFile)(filePath, fh.bytes());
|
|
277
|
+
written.push(filePath);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return written;
|
|
281
|
+
}
|
|
282
|
+
var import_promises2, import_node_path2, SKILL_PREFIX_RE3;
|
|
283
|
+
var init_vscode = __esm({
|
|
284
|
+
"src/adapters/vscode.ts"() {
|
|
285
|
+
"use strict";
|
|
286
|
+
import_promises2 = require("fs/promises");
|
|
287
|
+
import_node_path2 = require("path");
|
|
288
|
+
SKILL_PREFIX_RE3 = /^skills\/[^/]+\//;
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// src/index.ts
|
|
293
|
+
var index_exports = {};
|
|
294
|
+
__export(index_exports, {
|
|
295
|
+
AgentSpecHandle: () => AgentSpecHandle,
|
|
296
|
+
ApiError: () => ApiError,
|
|
297
|
+
AssetDetailOutputSchema: () => AssetDetailOutputSchema,
|
|
298
|
+
AssetSummaryOutputSchema: () => AssetSummaryOutputSchema,
|
|
299
|
+
AssetType: () => AssetType,
|
|
300
|
+
AuthenticationError: () => AuthenticationError,
|
|
301
|
+
Bundle: () => Bundle,
|
|
302
|
+
BundleDetailOutputSchema: () => BundleDetailOutputSchema,
|
|
303
|
+
BundleLayerOutputSchema: () => BundleLayerOutputSchema,
|
|
304
|
+
BundleManifestOutputSchema: () => BundleManifestOutputSchema,
|
|
305
|
+
BundleOutputSchema: () => BundleOutputSchema,
|
|
306
|
+
BundleRef: () => BundleRef,
|
|
307
|
+
BundleResolveOutputSchema: () => BundleResolveOutputSchema,
|
|
308
|
+
BundleSourceType: () => BundleSourceType,
|
|
309
|
+
BundleVersionDetailOutputSchema: () => BundleVersionDetailOutputSchema,
|
|
310
|
+
BundleVersionState: () => BundleVersionState,
|
|
311
|
+
BundleVersionSummaryOutputSchema: () => BundleVersionSummaryOutputSchema,
|
|
312
|
+
BundleVisibility: () => BundleVisibility,
|
|
313
|
+
CacheError: () => CacheError,
|
|
314
|
+
FileHandle: () => FileHandle,
|
|
315
|
+
ForbiddenError: () => ForbiddenError,
|
|
316
|
+
IntegrityError: () => IntegrityError,
|
|
317
|
+
ManifestAssetOutputSchema: () => ManifestAssetOutputSchema,
|
|
318
|
+
ManifestDetailOutputSchema: () => ManifestDetailOutputSchema,
|
|
319
|
+
MushError: () => MushError,
|
|
320
|
+
MusherClient: () => MusherClient,
|
|
321
|
+
NetworkError: () => NetworkError,
|
|
322
|
+
NotFoundError: () => NotFoundError,
|
|
323
|
+
PaginationMetaSchema: () => PaginationMetaSchema,
|
|
324
|
+
PromptHandle: () => PromptHandle,
|
|
325
|
+
RateLimitError: () => RateLimitError,
|
|
326
|
+
SchemaError: () => SchemaError,
|
|
327
|
+
Selection: () => Selection,
|
|
328
|
+
SkillHandle: () => SkillHandle,
|
|
329
|
+
TimeoutError: () => TimeoutError,
|
|
330
|
+
ToolsetHandle: () => ToolsetHandle,
|
|
331
|
+
ValidationError: () => ValidationError,
|
|
332
|
+
configure: () => configure,
|
|
333
|
+
exportClaudePlugin: () => exportClaudePlugin,
|
|
334
|
+
exportOpenAIInlineSkill: () => exportOpenAIInlineSkill,
|
|
335
|
+
exportOpenAILocalSkill: () => exportOpenAILocalSkill,
|
|
336
|
+
extractDescription: () => extractDescription,
|
|
337
|
+
getClient: () => getClient,
|
|
338
|
+
installClaudeSkills: () => installClaudeSkills,
|
|
339
|
+
installVSCodeSkills: () => installVSCodeSkills,
|
|
340
|
+
paginatedSchema: () => paginatedSchema,
|
|
341
|
+
parseFrontmatter: () => parseFrontmatter,
|
|
342
|
+
pull: () => pull,
|
|
343
|
+
resolve: () => resolve4,
|
|
344
|
+
resolveMusherDirs: () => resolveMusherDirs
|
|
345
|
+
});
|
|
346
|
+
module.exports = __toCommonJS(index_exports);
|
|
347
|
+
|
|
348
|
+
// src/client.ts
|
|
349
|
+
var import_node_crypto3 = require("crypto");
|
|
350
|
+
|
|
351
|
+
// src/bundle.ts
|
|
352
|
+
var import_node_crypto = require("crypto");
|
|
353
|
+
var import_promises4 = require("fs/promises");
|
|
354
|
+
var import_node_path4 = require("path");
|
|
355
|
+
|
|
356
|
+
// src/handles/agent-spec-handle.ts
|
|
357
|
+
var AgentSpecHandle = class {
|
|
358
|
+
name;
|
|
359
|
+
_file;
|
|
360
|
+
constructor(name, file) {
|
|
361
|
+
this.name = name;
|
|
362
|
+
this._file = file;
|
|
363
|
+
}
|
|
364
|
+
/** All files belonging to this agent spec (single file). */
|
|
365
|
+
files() {
|
|
366
|
+
return [this._file];
|
|
367
|
+
}
|
|
368
|
+
/** The agent spec content as text. */
|
|
369
|
+
content() {
|
|
370
|
+
return this._file.text();
|
|
371
|
+
}
|
|
372
|
+
/** The underlying file handle. */
|
|
373
|
+
file() {
|
|
374
|
+
return this._file;
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// src/handles/file-handle.ts
|
|
379
|
+
var FileHandle = class {
|
|
380
|
+
logicalPath;
|
|
381
|
+
assetType;
|
|
382
|
+
sha256;
|
|
383
|
+
mediaType;
|
|
384
|
+
sizeBytes;
|
|
385
|
+
_content;
|
|
386
|
+
constructor(logicalPath, assetType, sha256, sizeBytes, content, mediaType) {
|
|
387
|
+
this.logicalPath = logicalPath;
|
|
388
|
+
this.assetType = assetType;
|
|
389
|
+
this.sha256 = sha256;
|
|
390
|
+
this.sizeBytes = sizeBytes;
|
|
391
|
+
this._content = content;
|
|
392
|
+
this.mediaType = mediaType;
|
|
393
|
+
}
|
|
394
|
+
/** Return content as a UTF-8 string. */
|
|
395
|
+
text() {
|
|
396
|
+
return this._content.toString("utf-8");
|
|
397
|
+
}
|
|
398
|
+
/** Return content as a Uint8Array. */
|
|
399
|
+
bytes() {
|
|
400
|
+
return new Uint8Array(this._content.buffer, this._content.byteOffset, this._content.byteLength);
|
|
401
|
+
}
|
|
402
|
+
/** Return content as a ReadableStream. */
|
|
403
|
+
stream() {
|
|
404
|
+
const bytes = this.bytes();
|
|
405
|
+
return new ReadableStream({
|
|
406
|
+
start(controller) {
|
|
407
|
+
controller.enqueue(bytes);
|
|
408
|
+
controller.close();
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// src/handles/prompt-handle.ts
|
|
415
|
+
var PromptHandle = class {
|
|
416
|
+
name;
|
|
417
|
+
_file;
|
|
418
|
+
constructor(name, file) {
|
|
419
|
+
this.name = name;
|
|
420
|
+
this._file = file;
|
|
421
|
+
}
|
|
422
|
+
/** All files belonging to this prompt (single file). */
|
|
423
|
+
files() {
|
|
424
|
+
return [this._file];
|
|
425
|
+
}
|
|
426
|
+
/** The prompt content as text. */
|
|
427
|
+
content() {
|
|
428
|
+
return this._file.text();
|
|
429
|
+
}
|
|
430
|
+
/** The underlying file handle. */
|
|
431
|
+
file() {
|
|
432
|
+
return this._file;
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
// src/handles/skill-handle.ts
|
|
437
|
+
init_frontmatter();
|
|
438
|
+
var SkillHandle = class {
|
|
439
|
+
name;
|
|
440
|
+
_files;
|
|
441
|
+
constructor(name, files) {
|
|
442
|
+
this.name = name;
|
|
443
|
+
this._files = files;
|
|
444
|
+
}
|
|
445
|
+
/** All files belonging to this skill. */
|
|
446
|
+
files() {
|
|
447
|
+
return [...this._files];
|
|
448
|
+
}
|
|
449
|
+
/** The SKILL.md definition file, if present. */
|
|
450
|
+
definition() {
|
|
451
|
+
return this._files.find(
|
|
452
|
+
(f) => f.logicalPath.toLowerCase().endsWith("/skill.md") || f.logicalPath.toLowerCase() === "skill.md"
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
/** Parsed frontmatter from SKILL.md, if present. */
|
|
456
|
+
metadata() {
|
|
457
|
+
const def = this.definition();
|
|
458
|
+
if (!def) {
|
|
459
|
+
return void 0;
|
|
460
|
+
}
|
|
461
|
+
return parseFrontmatter(def.text());
|
|
462
|
+
}
|
|
463
|
+
/** Export as an OpenAI local skill directory. */
|
|
464
|
+
async exportOpenAILocal(targetDir) {
|
|
465
|
+
const { exportOpenAILocalSkill: exportOpenAILocalSkill2 } = await Promise.resolve().then(() => (init_openai(), openai_exports));
|
|
466
|
+
return exportOpenAILocalSkill2(this, targetDir);
|
|
467
|
+
}
|
|
468
|
+
/** Export as an OpenAI inline base64 ZIP skill. */
|
|
469
|
+
async exportOpenAIInline() {
|
|
470
|
+
const { exportOpenAIInlineSkill: exportOpenAIInlineSkill2 } = await Promise.resolve().then(() => (init_openai(), openai_exports));
|
|
471
|
+
return exportOpenAIInlineSkill2(this);
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
// src/handles/toolset-handle.ts
|
|
476
|
+
var ToolsetHandle = class {
|
|
477
|
+
name;
|
|
478
|
+
_file;
|
|
479
|
+
constructor(name, file) {
|
|
480
|
+
this.name = name;
|
|
481
|
+
this._file = file;
|
|
482
|
+
}
|
|
483
|
+
/** All files belonging to this toolset (single file). */
|
|
484
|
+
files() {
|
|
485
|
+
return [this._file];
|
|
486
|
+
}
|
|
487
|
+
/** The toolset content as text. */
|
|
488
|
+
content() {
|
|
489
|
+
return this._file.text();
|
|
490
|
+
}
|
|
491
|
+
/** The underlying file handle. */
|
|
492
|
+
file() {
|
|
493
|
+
return this._file;
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// src/errors.ts
|
|
498
|
+
var MushError = class extends Error {
|
|
499
|
+
constructor(message, options) {
|
|
500
|
+
super(message, options);
|
|
501
|
+
this.name = "MushError";
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
var ApiError = class extends MushError {
|
|
505
|
+
status;
|
|
506
|
+
problem;
|
|
507
|
+
constructor(problem, options) {
|
|
508
|
+
super(problem.detail, options);
|
|
509
|
+
this.name = "ApiError";
|
|
510
|
+
this.status = problem.status;
|
|
511
|
+
this.problem = problem;
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
var NotFoundError = class extends ApiError {
|
|
515
|
+
constructor(problem, options) {
|
|
516
|
+
super(problem, options);
|
|
517
|
+
this.name = "NotFoundError";
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
var AuthenticationError = class extends ApiError {
|
|
521
|
+
constructor(problem, options) {
|
|
522
|
+
super(problem, options);
|
|
523
|
+
this.name = "AuthenticationError";
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
var ForbiddenError = class extends ApiError {
|
|
527
|
+
constructor(problem, options) {
|
|
528
|
+
super(problem, options);
|
|
529
|
+
this.name = "ForbiddenError";
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
var ValidationError = class extends ApiError {
|
|
533
|
+
errors;
|
|
534
|
+
constructor(problem, options) {
|
|
535
|
+
super(problem, options);
|
|
536
|
+
this.name = "ValidationError";
|
|
537
|
+
this.errors = problem.errors;
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
var RateLimitError = class extends ApiError {
|
|
541
|
+
retryAfter;
|
|
542
|
+
constructor(problem, retryAfter, options) {
|
|
543
|
+
super(problem, options);
|
|
544
|
+
this.name = "RateLimitError";
|
|
545
|
+
this.retryAfter = retryAfter;
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
var NetworkError = class extends MushError {
|
|
549
|
+
constructor(message, options) {
|
|
550
|
+
super(message, options);
|
|
551
|
+
this.name = "NetworkError";
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
var TimeoutError = class extends NetworkError {
|
|
555
|
+
constructor(message, options) {
|
|
556
|
+
super(message, options);
|
|
557
|
+
this.name = "TimeoutError";
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
var CacheError = class extends MushError {
|
|
561
|
+
constructor(message, options) {
|
|
562
|
+
super(message, options);
|
|
563
|
+
this.name = "CacheError";
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
var IntegrityError = class extends CacheError {
|
|
567
|
+
constructor(expected, actual, options) {
|
|
568
|
+
super(`SHA256 mismatch: expected ${expected}, got ${actual}`, options);
|
|
569
|
+
this.expected = expected;
|
|
570
|
+
this.actual = actual;
|
|
571
|
+
this.name = "IntegrityError";
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
var SchemaError = class extends MushError {
|
|
575
|
+
constructor(message, options) {
|
|
576
|
+
super(message, options);
|
|
577
|
+
this.name = "SchemaError";
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
// src/ref.ts
|
|
582
|
+
var REF_PATTERN = /^([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)(?::(.+)|@sha256:([a-fA-F0-9]+))?$/;
|
|
583
|
+
var BundleRef = class _BundleRef {
|
|
584
|
+
namespace;
|
|
585
|
+
slug;
|
|
586
|
+
version;
|
|
587
|
+
digest;
|
|
588
|
+
constructor(namespace, slug, version, digest) {
|
|
589
|
+
this.namespace = namespace;
|
|
590
|
+
this.slug = slug;
|
|
591
|
+
this.version = version;
|
|
592
|
+
this.digest = digest;
|
|
593
|
+
}
|
|
594
|
+
/** Parse a ref string into a BundleRef. */
|
|
595
|
+
static parse(ref) {
|
|
596
|
+
const match = ref.match(REF_PATTERN);
|
|
597
|
+
if (!match) {
|
|
598
|
+
throw new MushError(
|
|
599
|
+
`Invalid bundle ref "${ref}": expected "namespace/slug", "namespace/slug:version", or "namespace/slug@sha256:digest"`
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
const [, namespace, slug, version, digest] = match;
|
|
603
|
+
return new _BundleRef(namespace, slug, version, digest);
|
|
604
|
+
}
|
|
605
|
+
/** Return the base ref without version or digest: "namespace/slug". */
|
|
606
|
+
toBaseRef() {
|
|
607
|
+
return `${this.namespace}/${this.slug}`;
|
|
608
|
+
}
|
|
609
|
+
/** Return the full ref string. */
|
|
610
|
+
toString() {
|
|
611
|
+
if (this.digest) {
|
|
612
|
+
return `${this.namespace}/${this.slug}@sha256:${this.digest}`;
|
|
613
|
+
}
|
|
614
|
+
if (this.version) {
|
|
615
|
+
return `${this.namespace}/${this.slug}:${this.version}`;
|
|
616
|
+
}
|
|
617
|
+
return `${this.namespace}/${this.slug}`;
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
// src/selection.ts
|
|
622
|
+
var import_promises3 = require("fs/promises");
|
|
623
|
+
var import_node_path3 = require("path");
|
|
624
|
+
var Selection = class {
|
|
625
|
+
_bundle;
|
|
626
|
+
_filter;
|
|
627
|
+
constructor(bundle, filter) {
|
|
628
|
+
this._bundle = bundle;
|
|
629
|
+
this._filter = filter;
|
|
630
|
+
}
|
|
631
|
+
/** The underlying bundle. */
|
|
632
|
+
get bundle() {
|
|
633
|
+
return this._bundle;
|
|
634
|
+
}
|
|
635
|
+
files() {
|
|
636
|
+
const result = [];
|
|
637
|
+
const seen = /* @__PURE__ */ new Set();
|
|
638
|
+
const addFile = (fh) => {
|
|
639
|
+
if (!seen.has(fh.logicalPath)) {
|
|
640
|
+
seen.add(fh.logicalPath);
|
|
641
|
+
result.push(fh);
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
if (this._filter.skills) {
|
|
645
|
+
for (const name of this._filter.skills) {
|
|
646
|
+
const skill = this._bundle.skills().find((s) => s.name === name);
|
|
647
|
+
if (skill) {
|
|
648
|
+
for (const f of skill.files()) {
|
|
649
|
+
addFile(f);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (this._filter.prompts) {
|
|
655
|
+
for (const name of this._filter.prompts) {
|
|
656
|
+
const prompt = this._bundle.prompts().find((p) => p.name === name);
|
|
657
|
+
if (prompt) {
|
|
658
|
+
for (const f of prompt.files()) {
|
|
659
|
+
addFile(f);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (this._filter.toolsets) {
|
|
665
|
+
for (const name of this._filter.toolsets) {
|
|
666
|
+
const toolset = this._bundle.toolsets().find((t) => t.name === name);
|
|
667
|
+
if (toolset) {
|
|
668
|
+
for (const f of toolset.files()) {
|
|
669
|
+
addFile(f);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
if (this._filter.agentSpecs) {
|
|
675
|
+
for (const name of this._filter.agentSpecs) {
|
|
676
|
+
const spec = this._bundle.agentSpecs().find((a) => a.name === name);
|
|
677
|
+
if (spec) {
|
|
678
|
+
for (const f of spec.files()) {
|
|
679
|
+
addFile(f);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
if (this._filter.paths) {
|
|
685
|
+
for (const path of this._filter.paths) {
|
|
686
|
+
const fh = this._bundle.file(path);
|
|
687
|
+
if (fh) {
|
|
688
|
+
addFile(fh);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return result;
|
|
693
|
+
}
|
|
694
|
+
skills() {
|
|
695
|
+
const names = this._filter.skills;
|
|
696
|
+
if (!names) {
|
|
697
|
+
return [];
|
|
698
|
+
}
|
|
699
|
+
return this._bundle.skills().filter((s) => names.includes(s.name));
|
|
700
|
+
}
|
|
701
|
+
prompts() {
|
|
702
|
+
const names = this._filter.prompts;
|
|
703
|
+
if (!names) {
|
|
704
|
+
return [];
|
|
705
|
+
}
|
|
706
|
+
return this._bundle.prompts().filter((p) => names.includes(p.name));
|
|
707
|
+
}
|
|
708
|
+
toolsets() {
|
|
709
|
+
const names = this._filter.toolsets;
|
|
710
|
+
if (!names) {
|
|
711
|
+
return [];
|
|
712
|
+
}
|
|
713
|
+
return this._bundle.toolsets().filter((t) => names.includes(t.name));
|
|
714
|
+
}
|
|
715
|
+
agentSpecs() {
|
|
716
|
+
const names = this._filter.agentSpecs;
|
|
717
|
+
if (!names) {
|
|
718
|
+
return [];
|
|
719
|
+
}
|
|
720
|
+
return this._bundle.agentSpecs().filter((a) => names.includes(a.name));
|
|
721
|
+
}
|
|
722
|
+
/** Write selected files to targetDir preserving logical paths. */
|
|
723
|
+
async materialize(targetDir) {
|
|
724
|
+
const written = [];
|
|
725
|
+
for (const fh of this.files()) {
|
|
726
|
+
const absPath = (0, import_node_path3.resolve)((0, import_node_path3.join)(targetDir, fh.logicalPath));
|
|
727
|
+
await (0, import_promises3.mkdir)((0, import_node_path3.dirname)(absPath), { recursive: true });
|
|
728
|
+
await (0, import_promises3.writeFile)(absPath, fh.bytes());
|
|
729
|
+
written.push(absPath);
|
|
730
|
+
}
|
|
731
|
+
return written;
|
|
732
|
+
}
|
|
733
|
+
// -- Export adapter convenience methods --
|
|
734
|
+
async exportClaudePlugin(opts) {
|
|
735
|
+
const { exportClaudePlugin: exportClaudePlugin2 } = await Promise.resolve().then(() => (init_claude(), claude_exports));
|
|
736
|
+
return exportClaudePlugin2(this, opts);
|
|
737
|
+
}
|
|
738
|
+
async installClaudeSkills(dir, opts) {
|
|
739
|
+
const { installClaudeSkills: installClaudeSkills2 } = await Promise.resolve().then(() => (init_claude(), claude_exports));
|
|
740
|
+
return installClaudeSkills2(this, dir, opts);
|
|
741
|
+
}
|
|
742
|
+
async installVSCodeSkills(dir, opts) {
|
|
743
|
+
const { installVSCodeSkills: installVSCodeSkills2 } = await Promise.resolve().then(() => (init_vscode(), vscode_exports));
|
|
744
|
+
return installVSCodeSkills2(this, dir, opts);
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
// src/bundle.ts
|
|
749
|
+
var Bundle = class {
|
|
750
|
+
ref;
|
|
751
|
+
version;
|
|
752
|
+
metadata;
|
|
753
|
+
_files;
|
|
754
|
+
_skills;
|
|
755
|
+
_prompts;
|
|
756
|
+
_toolsets;
|
|
757
|
+
_agentSpecs;
|
|
758
|
+
constructor(metadata, contents) {
|
|
759
|
+
this.metadata = metadata;
|
|
760
|
+
this.version = metadata.version;
|
|
761
|
+
this.ref = BundleRef.parse(metadata.ref);
|
|
762
|
+
this._files = /* @__PURE__ */ new Map();
|
|
763
|
+
if (metadata.manifest?.layers) {
|
|
764
|
+
for (const layer of metadata.manifest.layers) {
|
|
765
|
+
const buf = contents.get(layer.logicalPath);
|
|
766
|
+
if (buf) {
|
|
767
|
+
const fh = new FileHandle(
|
|
768
|
+
layer.logicalPath,
|
|
769
|
+
layer.assetType,
|
|
770
|
+
layer.contentSha256,
|
|
771
|
+
layer.sizeBytes,
|
|
772
|
+
buf,
|
|
773
|
+
layer.mediaType ?? void 0
|
|
774
|
+
);
|
|
775
|
+
this._files.set(layer.logicalPath, fh);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
this._skills = /* @__PURE__ */ new Map();
|
|
780
|
+
this._prompts = /* @__PURE__ */ new Map();
|
|
781
|
+
this._toolsets = /* @__PURE__ */ new Map();
|
|
782
|
+
this._agentSpecs = /* @__PURE__ */ new Map();
|
|
783
|
+
const skillGroups = /* @__PURE__ */ new Map();
|
|
784
|
+
for (const fh of this._files.values()) {
|
|
785
|
+
switch (fh.assetType) {
|
|
786
|
+
case "skill": {
|
|
787
|
+
const skillName = extractSkillName(fh.logicalPath);
|
|
788
|
+
if (skillName) {
|
|
789
|
+
let group = skillGroups.get(skillName);
|
|
790
|
+
if (!group) {
|
|
791
|
+
group = [];
|
|
792
|
+
skillGroups.set(skillName, group);
|
|
793
|
+
}
|
|
794
|
+
group.push(fh);
|
|
795
|
+
}
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
case "prompt": {
|
|
799
|
+
const name = baseFileName(fh.logicalPath);
|
|
800
|
+
this._prompts.set(name, new PromptHandle(name, fh));
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
803
|
+
case "tool_config": {
|
|
804
|
+
const name = baseFileName(fh.logicalPath);
|
|
805
|
+
this._toolsets.set(name, new ToolsetHandle(name, fh));
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
808
|
+
case "agent_definition": {
|
|
809
|
+
const name = baseFileName(fh.logicalPath);
|
|
810
|
+
this._agentSpecs.set(name, new AgentSpecHandle(name, fh));
|
|
811
|
+
break;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
for (const [name, files] of skillGroups) {
|
|
816
|
+
this._skills.set(name, new SkillHandle(name, files));
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
// -- File access --
|
|
820
|
+
file(path) {
|
|
821
|
+
return this._files.get(path);
|
|
822
|
+
}
|
|
823
|
+
files() {
|
|
824
|
+
return [...this._files.values()];
|
|
825
|
+
}
|
|
826
|
+
// -- Domain handles --
|
|
827
|
+
skills() {
|
|
828
|
+
return [...this._skills.values()];
|
|
829
|
+
}
|
|
830
|
+
skill(name) {
|
|
831
|
+
const h = this._skills.get(name);
|
|
832
|
+
if (!h) {
|
|
833
|
+
throw new Error(`Skill "${name}" not found in bundle`);
|
|
834
|
+
}
|
|
835
|
+
return h;
|
|
836
|
+
}
|
|
837
|
+
prompts() {
|
|
838
|
+
return [...this._prompts.values()];
|
|
839
|
+
}
|
|
840
|
+
prompt(name) {
|
|
841
|
+
const h = this._prompts.get(name);
|
|
842
|
+
if (!h) {
|
|
843
|
+
throw new Error(`Prompt "${name}" not found in bundle`);
|
|
844
|
+
}
|
|
845
|
+
return h;
|
|
846
|
+
}
|
|
847
|
+
toolsets() {
|
|
848
|
+
return [...this._toolsets.values()];
|
|
849
|
+
}
|
|
850
|
+
toolset(name) {
|
|
851
|
+
const h = this._toolsets.get(name);
|
|
852
|
+
if (!h) {
|
|
853
|
+
throw new Error(`Toolset "${name}" not found in bundle`);
|
|
854
|
+
}
|
|
855
|
+
return h;
|
|
856
|
+
}
|
|
857
|
+
agentSpecs() {
|
|
858
|
+
return [...this._agentSpecs.values()];
|
|
859
|
+
}
|
|
860
|
+
agentSpec(name) {
|
|
861
|
+
const h = this._agentSpecs.get(name);
|
|
862
|
+
if (!h) {
|
|
863
|
+
throw new Error(`AgentSpec "${name}" not found in bundle`);
|
|
864
|
+
}
|
|
865
|
+
return h;
|
|
866
|
+
}
|
|
867
|
+
// -- Filtering --
|
|
868
|
+
select(filter) {
|
|
869
|
+
return new Selection(this, filter);
|
|
870
|
+
}
|
|
871
|
+
// -- Integrity --
|
|
872
|
+
verify() {
|
|
873
|
+
const errors = [];
|
|
874
|
+
for (const fh of this._files.values()) {
|
|
875
|
+
const actual = (0, import_node_crypto.createHash)("sha256").update(fh.bytes()).digest("hex");
|
|
876
|
+
if (actual !== fh.sha256) {
|
|
877
|
+
errors.push({ path: fh.logicalPath, expected: fh.sha256, actual });
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return { ok: errors.length === 0, errors };
|
|
881
|
+
}
|
|
882
|
+
// -- Lockfile --
|
|
883
|
+
async writeLockfile(path) {
|
|
884
|
+
const lock = {
|
|
885
|
+
ref: this.ref.toString(),
|
|
886
|
+
version: this.version,
|
|
887
|
+
files: [...this._files.values()].map((f) => ({
|
|
888
|
+
logicalPath: f.logicalPath,
|
|
889
|
+
sha256: f.sha256,
|
|
890
|
+
sizeBytes: f.sizeBytes
|
|
891
|
+
}))
|
|
892
|
+
};
|
|
893
|
+
await (0, import_promises4.mkdir)((0, import_node_path4.dirname)(path), { recursive: true });
|
|
894
|
+
await (0, import_promises4.writeFile)(path, JSON.stringify(lock, null, 2));
|
|
895
|
+
}
|
|
896
|
+
// -- Export adapter convenience methods --
|
|
897
|
+
async exportClaudePlugin(opts) {
|
|
898
|
+
const { exportClaudePlugin: exportClaudePlugin2 } = await Promise.resolve().then(() => (init_claude(), claude_exports));
|
|
899
|
+
return exportClaudePlugin2(this, opts);
|
|
900
|
+
}
|
|
901
|
+
async installClaudeSkills(dir, opts) {
|
|
902
|
+
const { installClaudeSkills: installClaudeSkills2 } = await Promise.resolve().then(() => (init_claude(), claude_exports));
|
|
903
|
+
return installClaudeSkills2(this, dir, opts);
|
|
904
|
+
}
|
|
905
|
+
async installVSCodeSkills(dir, opts) {
|
|
906
|
+
const { installVSCodeSkills: installVSCodeSkills2 } = await Promise.resolve().then(() => (init_vscode(), vscode_exports));
|
|
907
|
+
return installVSCodeSkills2(this, dir, opts);
|
|
908
|
+
}
|
|
909
|
+
// -- Deprecated compat --
|
|
910
|
+
/** @deprecated Use `file(path)` instead. */
|
|
911
|
+
getAsset(path) {
|
|
912
|
+
const fh = this._files.get(path);
|
|
913
|
+
if (!fh) {
|
|
914
|
+
return void 0;
|
|
915
|
+
}
|
|
916
|
+
return {
|
|
917
|
+
logicalPath: fh.logicalPath,
|
|
918
|
+
assetType: fh.assetType,
|
|
919
|
+
content: fh.text(),
|
|
920
|
+
sha256: fh.sha256,
|
|
921
|
+
mediaType: fh.mediaType
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
/** @deprecated Use `files().filter(...)` instead. */
|
|
925
|
+
getAssetsByType(type) {
|
|
926
|
+
return [...this._files.values()].filter((fh) => fh.assetType === type).map((fh) => ({
|
|
927
|
+
logicalPath: fh.logicalPath,
|
|
928
|
+
assetType: fh.assetType,
|
|
929
|
+
content: fh.text(),
|
|
930
|
+
sha256: fh.sha256,
|
|
931
|
+
mediaType: fh.mediaType
|
|
932
|
+
}));
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
function extractSkillName(logicalPath) {
|
|
936
|
+
if (!logicalPath.startsWith("skills/")) {
|
|
937
|
+
return void 0;
|
|
938
|
+
}
|
|
939
|
+
const rest = logicalPath.slice("skills/".length);
|
|
940
|
+
const slashIdx = rest.indexOf("/");
|
|
941
|
+
if (slashIdx === -1) {
|
|
942
|
+
return void 0;
|
|
943
|
+
}
|
|
944
|
+
const name = rest.slice(0, slashIdx);
|
|
945
|
+
return name || void 0;
|
|
946
|
+
}
|
|
947
|
+
function baseFileName(logicalPath) {
|
|
948
|
+
const parts = logicalPath.split("/");
|
|
949
|
+
const last = parts[parts.length - 1] ?? logicalPath;
|
|
950
|
+
const dotIdx = last.lastIndexOf(".");
|
|
951
|
+
return dotIdx > 0 ? last.slice(0, dotIdx) : last;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// src/cache.ts
|
|
955
|
+
var import_node_crypto2 = require("crypto");
|
|
956
|
+
var import_node_fs = require("fs");
|
|
957
|
+
var import_promises5 = require("fs/promises");
|
|
958
|
+
var import_node_path5 = require("path");
|
|
959
|
+
var JSON_EXT_RE = /\.json$/;
|
|
960
|
+
var CACHEDIR_TAG_CONTENT = `Signature: 8a477f597d28d172789f06886806bc55
|
|
961
|
+
# This file is a cache directory tag created by musher.
|
|
962
|
+
# For information, see https://bford.info/cachedir/spec.html
|
|
963
|
+
`;
|
|
964
|
+
var BundleCache = class {
|
|
965
|
+
constructor(cacheDir, registryUrl, manifestTtlSeconds, refTtlSeconds) {
|
|
966
|
+
this.cacheDir = cacheDir;
|
|
967
|
+
this.manifestTtlSeconds = manifestTtlSeconds;
|
|
968
|
+
this.refTtlSeconds = refTtlSeconds;
|
|
969
|
+
this.hostId = computeHostId(registryUrl);
|
|
970
|
+
}
|
|
971
|
+
hostId;
|
|
972
|
+
// -- Blob storage -------------------------------------------------------------
|
|
973
|
+
blobPath(digest) {
|
|
974
|
+
const prefix = digest.slice(0, 2);
|
|
975
|
+
return (0, import_node_path5.join)(this.cacheDir, "blobs", "sha256", prefix, digest);
|
|
976
|
+
}
|
|
977
|
+
async writeBlob(content) {
|
|
978
|
+
const digest = (0, import_node_crypto2.createHash)("sha256").update(content).digest("hex");
|
|
979
|
+
const target = this.blobPath(digest);
|
|
980
|
+
if ((0, import_node_fs.existsSync)(target)) {
|
|
981
|
+
return digest;
|
|
982
|
+
}
|
|
983
|
+
await this.atomicWrite(target, content);
|
|
984
|
+
return digest;
|
|
985
|
+
}
|
|
986
|
+
// -- Manifest storage ---------------------------------------------------------
|
|
987
|
+
manifestDir(namespace, slug) {
|
|
988
|
+
return (0, import_node_path5.join)(this.cacheDir, "manifests", this.hostId, namespace, slug);
|
|
989
|
+
}
|
|
990
|
+
manifestPath(namespace, slug, version) {
|
|
991
|
+
return (0, import_node_path5.join)(this.manifestDir(namespace, slug), `${version}.json`);
|
|
992
|
+
}
|
|
993
|
+
metaPath(namespace, slug, version) {
|
|
994
|
+
return (0, import_node_path5.join)(this.manifestDir(namespace, slug), `${version}.meta.json`);
|
|
995
|
+
}
|
|
996
|
+
// -- Ref storage --------------------------------------------------------------
|
|
997
|
+
refPath(namespace, slug, ref) {
|
|
998
|
+
return (0, import_node_path5.join)(this.cacheDir, "refs", this.hostId, namespace, slug, `${ref}.json`);
|
|
999
|
+
}
|
|
1000
|
+
/** Cache a ref → version mapping with TTL. */
|
|
1001
|
+
async cacheRef(namespace, slug, ref, version) {
|
|
1002
|
+
const entry = {
|
|
1003
|
+
version,
|
|
1004
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1005
|
+
ttlSeconds: this.refTtlSeconds
|
|
1006
|
+
};
|
|
1007
|
+
const target = this.refPath(namespace, slug, ref);
|
|
1008
|
+
await this.atomicWrite(target, Buffer.from(JSON.stringify(entry, null, 2)));
|
|
1009
|
+
}
|
|
1010
|
+
/** Resolve a cached ref → version if still fresh. Returns null if expired or missing. */
|
|
1011
|
+
async resolveRef(namespace, slug, ref) {
|
|
1012
|
+
try {
|
|
1013
|
+
const raw = await (0, import_promises5.readFile)(this.refPath(namespace, slug, ref), "utf-8");
|
|
1014
|
+
const entry = JSON.parse(raw);
|
|
1015
|
+
const fetchedAt = new Date(entry.fetchedAt).getTime();
|
|
1016
|
+
const ttl = (entry.ttlSeconds ?? this.refTtlSeconds) * 1e3;
|
|
1017
|
+
if (Date.now() - fetchedAt < ttl) {
|
|
1018
|
+
return entry.version;
|
|
1019
|
+
}
|
|
1020
|
+
return null;
|
|
1021
|
+
} catch {
|
|
1022
|
+
return null;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
// -- Freshness ----------------------------------------------------------------
|
|
1026
|
+
/** Check if a cached manifest is still fresh. */
|
|
1027
|
+
async isFresh(namespace, slug, version) {
|
|
1028
|
+
try {
|
|
1029
|
+
const raw = await (0, import_promises5.readFile)(this.metaPath(namespace, slug, version), "utf-8");
|
|
1030
|
+
const meta = JSON.parse(raw);
|
|
1031
|
+
const fetchedAt = new Date(meta.fetchedAt).getTime();
|
|
1032
|
+
const ttl = (meta.ttlSeconds ?? this.manifestTtlSeconds) * 1e3;
|
|
1033
|
+
return Date.now() - fetchedAt < ttl;
|
|
1034
|
+
} catch {
|
|
1035
|
+
return false;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
/** Load only the manifest JSON (no blob content). Returns null if not cached. */
|
|
1039
|
+
async loadManifest(namespace, slug, version) {
|
|
1040
|
+
const mPath = this.manifestPath(namespace, slug, version);
|
|
1041
|
+
if (!(0, import_node_fs.existsSync)(mPath)) {
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
try {
|
|
1045
|
+
const raw = await (0, import_promises5.readFile)(mPath, "utf-8");
|
|
1046
|
+
return JSON.parse(raw);
|
|
1047
|
+
} catch {
|
|
1048
|
+
return null;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
// -- Write --------------------------------------------------------------------
|
|
1052
|
+
/** Write only the manifest and metadata to the cache (no blobs). */
|
|
1053
|
+
async writeManifest(manifest) {
|
|
1054
|
+
try {
|
|
1055
|
+
await this.ensureCacheDirTag();
|
|
1056
|
+
const mPath = this.manifestPath(manifest.namespace, manifest.slug, manifest.version);
|
|
1057
|
+
await this.atomicWrite(mPath, Buffer.from(JSON.stringify(manifest, null, 2)));
|
|
1058
|
+
const meta = {
|
|
1059
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1060
|
+
ttlSeconds: this.manifestTtlSeconds,
|
|
1061
|
+
ociDigest: manifest.ociDigest ?? void 0
|
|
1062
|
+
};
|
|
1063
|
+
const metPath = this.metaPath(manifest.namespace, manifest.slug, manifest.version);
|
|
1064
|
+
await this.atomicWrite(metPath, Buffer.from(JSON.stringify(meta, null, 2)));
|
|
1065
|
+
} catch (error) {
|
|
1066
|
+
throw new CacheError(
|
|
1067
|
+
`Failed to write manifest cache: ${error instanceof Error ? error.message : String(error)}`,
|
|
1068
|
+
{ cause: error instanceof Error ? error : void 0 }
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
/** Write a resolved bundle and its assets to the cache. */
|
|
1073
|
+
async write(manifest, assets) {
|
|
1074
|
+
try {
|
|
1075
|
+
await this.ensureCacheDirTag();
|
|
1076
|
+
for (const [, content] of assets) {
|
|
1077
|
+
const buf = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
|
|
1078
|
+
await this.writeBlob(buf);
|
|
1079
|
+
}
|
|
1080
|
+
await this.writeManifest(manifest);
|
|
1081
|
+
return {
|
|
1082
|
+
ref: manifest.ref,
|
|
1083
|
+
version: manifest.version,
|
|
1084
|
+
cacheDir: this.manifestDir(manifest.namespace, manifest.slug),
|
|
1085
|
+
manifest
|
|
1086
|
+
};
|
|
1087
|
+
} catch (error) {
|
|
1088
|
+
throw new CacheError(
|
|
1089
|
+
`Failed to write cache: ${error instanceof Error ? error.message : String(error)}`,
|
|
1090
|
+
{ cause: error instanceof Error ? error : void 0 }
|
|
1091
|
+
);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
// -- Load ---------------------------------------------------------------------
|
|
1095
|
+
/** Load a cached bundle from disk, verifying SHA256 integrity. Returns a Bundle. */
|
|
1096
|
+
async load(namespace, slug, version) {
|
|
1097
|
+
const mPath = this.manifestPath(namespace, slug, version);
|
|
1098
|
+
if (!(0, import_node_fs.existsSync)(mPath)) {
|
|
1099
|
+
return null;
|
|
1100
|
+
}
|
|
1101
|
+
try {
|
|
1102
|
+
const raw = await (0, import_promises5.readFile)(mPath, "utf-8");
|
|
1103
|
+
const manifest = JSON.parse(raw);
|
|
1104
|
+
const contents = /* @__PURE__ */ new Map();
|
|
1105
|
+
if (manifest.manifest?.layers) {
|
|
1106
|
+
for (const layer of manifest.manifest.layers) {
|
|
1107
|
+
const buf = await (0, import_promises5.readFile)(this.blobPath(layer.contentSha256));
|
|
1108
|
+
const hash = (0, import_node_crypto2.createHash)("sha256").update(buf).digest("hex");
|
|
1109
|
+
if (hash !== layer.contentSha256) {
|
|
1110
|
+
throw new IntegrityError(layer.contentSha256, hash);
|
|
1111
|
+
}
|
|
1112
|
+
contents.set(layer.logicalPath, buf);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
return new Bundle(manifest, contents);
|
|
1116
|
+
} catch (error) {
|
|
1117
|
+
if (error instanceof IntegrityError) {
|
|
1118
|
+
throw error;
|
|
1119
|
+
}
|
|
1120
|
+
throw new CacheError(
|
|
1121
|
+
`Failed to load cache: ${error instanceof Error ? error.message : String(error)}`,
|
|
1122
|
+
{ cause: error instanceof Error ? error : void 0 }
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
// -- Cleanup ------------------------------------------------------------------
|
|
1127
|
+
/** Remove expired cache entries and garbage-collect unreferenced blobs. */
|
|
1128
|
+
async clean() {
|
|
1129
|
+
try {
|
|
1130
|
+
const referencedDigests = /* @__PURE__ */ new Set();
|
|
1131
|
+
await this.cleanManifests(referencedDigests);
|
|
1132
|
+
await this.cleanRefs();
|
|
1133
|
+
await this.gcBlobs(referencedDigests);
|
|
1134
|
+
await this.removeLegacy();
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
throw new CacheError(
|
|
1137
|
+
`Failed to clean cache: ${error instanceof Error ? error.message : String(error)}`,
|
|
1138
|
+
{ cause: error instanceof Error ? error : void 0 }
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
/** Remove all cached data. */
|
|
1143
|
+
async purge() {
|
|
1144
|
+
try {
|
|
1145
|
+
const dirs = ["manifests", "refs", "blobs", "temp", "bundles"];
|
|
1146
|
+
for (const dir of dirs) {
|
|
1147
|
+
const p = (0, import_node_path5.join)(this.cacheDir, dir);
|
|
1148
|
+
if ((0, import_node_fs.existsSync)(p)) {
|
|
1149
|
+
await (0, import_promises5.rm)(p, { recursive: true, force: true });
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
} catch (error) {
|
|
1153
|
+
throw new CacheError(
|
|
1154
|
+
`Failed to purge cache: ${error instanceof Error ? error.message : String(error)}`,
|
|
1155
|
+
{ cause: error instanceof Error ? error : void 0 }
|
|
1156
|
+
);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
// -- Internals ----------------------------------------------------------------
|
|
1160
|
+
/** Atomic write via temp file + rename. */
|
|
1161
|
+
async atomicWrite(targetPath, data) {
|
|
1162
|
+
const tempDir = (0, import_node_path5.join)(this.cacheDir, "temp");
|
|
1163
|
+
await (0, import_promises5.mkdir)(tempDir, { recursive: true });
|
|
1164
|
+
const tempPath = (0, import_node_path5.join)(tempDir, `${(0, import_node_crypto2.randomUUID)()}.tmp`);
|
|
1165
|
+
try {
|
|
1166
|
+
await (0, import_promises5.writeFile)(tempPath, data);
|
|
1167
|
+
await (0, import_promises5.mkdir)((0, import_node_path5.dirname)(targetPath), { recursive: true });
|
|
1168
|
+
try {
|
|
1169
|
+
await (0, import_promises5.rename)(tempPath, targetPath);
|
|
1170
|
+
} catch {
|
|
1171
|
+
try {
|
|
1172
|
+
await (0, import_promises5.unlink)(targetPath);
|
|
1173
|
+
} catch {
|
|
1174
|
+
}
|
|
1175
|
+
await (0, import_promises5.rename)(tempPath, targetPath);
|
|
1176
|
+
}
|
|
1177
|
+
} finally {
|
|
1178
|
+
try {
|
|
1179
|
+
await (0, import_promises5.unlink)(tempPath);
|
|
1180
|
+
} catch {
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
/** Write CACHEDIR.TAG if it doesn't exist. */
|
|
1185
|
+
async ensureCacheDirTag() {
|
|
1186
|
+
const tagPath = (0, import_node_path5.join)(this.cacheDir, "CACHEDIR.TAG");
|
|
1187
|
+
if (!(0, import_node_fs.existsSync)(tagPath)) {
|
|
1188
|
+
await (0, import_promises5.mkdir)(this.cacheDir, { recursive: true });
|
|
1189
|
+
await (0, import_promises5.writeFile)(tagPath, CACHEDIR_TAG_CONTENT);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
/** Walk manifests, remove expired, collect digests from surviving ones. */
|
|
1193
|
+
async cleanManifests(referencedDigests) {
|
|
1194
|
+
const manifestsRoot = (0, import_node_path5.join)(this.cacheDir, "manifests");
|
|
1195
|
+
if (!(0, import_node_fs.existsSync)(manifestsRoot)) {
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
for (const hostId of await safeReaddir(manifestsRoot)) {
|
|
1199
|
+
const hostDir = (0, import_node_path5.join)(manifestsRoot, hostId);
|
|
1200
|
+
if (!await isDir(hostDir)) {
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1203
|
+
for (const ns of await safeReaddir(hostDir)) {
|
|
1204
|
+
const nsDir = (0, import_node_path5.join)(hostDir, ns);
|
|
1205
|
+
if (!await isDir(nsDir)) {
|
|
1206
|
+
continue;
|
|
1207
|
+
}
|
|
1208
|
+
for (const slug of await safeReaddir(nsDir)) {
|
|
1209
|
+
const slugDir = (0, import_node_path5.join)(nsDir, slug);
|
|
1210
|
+
if (!await isDir(slugDir)) {
|
|
1211
|
+
continue;
|
|
1212
|
+
}
|
|
1213
|
+
for (const file of await safeReaddir(slugDir)) {
|
|
1214
|
+
if (!file.endsWith(".json") || file.endsWith(".meta.json")) {
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
const version = file.replace(JSON_EXT_RE, "");
|
|
1218
|
+
const fresh = await this.isFresh(ns, slug, version);
|
|
1219
|
+
if (fresh) {
|
|
1220
|
+
await this.collectDigests((0, import_node_path5.join)(slugDir, file), referencedDigests);
|
|
1221
|
+
} else {
|
|
1222
|
+
await safeRm((0, import_node_path5.join)(slugDir, file));
|
|
1223
|
+
await safeRm((0, import_node_path5.join)(slugDir, `${version}.meta.json`));
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
/** Collect blob digests referenced by a manifest file. */
|
|
1231
|
+
async collectDigests(manifestFile, digests) {
|
|
1232
|
+
try {
|
|
1233
|
+
const raw = await (0, import_promises5.readFile)(manifestFile, "utf-8");
|
|
1234
|
+
const manifest = JSON.parse(raw);
|
|
1235
|
+
if (manifest.manifest?.layers) {
|
|
1236
|
+
for (const layer of manifest.manifest.layers) {
|
|
1237
|
+
digests.add(layer.contentSha256);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
} catch {
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
/** Walk refs and remove expired entries. */
|
|
1244
|
+
async cleanRefs() {
|
|
1245
|
+
const refsRoot = (0, import_node_path5.join)(this.cacheDir, "refs");
|
|
1246
|
+
if (!(0, import_node_fs.existsSync)(refsRoot)) {
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
for (const hostId of await safeReaddir(refsRoot)) {
|
|
1250
|
+
const hostDir = (0, import_node_path5.join)(refsRoot, hostId);
|
|
1251
|
+
if (!await isDir(hostDir)) {
|
|
1252
|
+
continue;
|
|
1253
|
+
}
|
|
1254
|
+
for (const ns of await safeReaddir(hostDir)) {
|
|
1255
|
+
const nsDir = (0, import_node_path5.join)(hostDir, ns);
|
|
1256
|
+
if (!await isDir(nsDir)) {
|
|
1257
|
+
continue;
|
|
1258
|
+
}
|
|
1259
|
+
for (const slug of await safeReaddir(nsDir)) {
|
|
1260
|
+
const slugDir = (0, import_node_path5.join)(nsDir, slug);
|
|
1261
|
+
if (!await isDir(slugDir)) {
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
for (const file of await safeReaddir(slugDir)) {
|
|
1265
|
+
if (!file.endsWith(".json")) {
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
const ref = file.replace(JSON_EXT_RE, "");
|
|
1269
|
+
const version = await this.resolveRef(ns, slug, ref);
|
|
1270
|
+
if (version === null) {
|
|
1271
|
+
await safeRm((0, import_node_path5.join)(slugDir, file));
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
/** Remove blobs not referenced by any surviving manifest. */
|
|
1279
|
+
async gcBlobs(referencedDigests) {
|
|
1280
|
+
const blobsRoot = (0, import_node_path5.join)(this.cacheDir, "blobs", "sha256");
|
|
1281
|
+
if (!(0, import_node_fs.existsSync)(blobsRoot)) {
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
for (const prefix of await safeReaddir(blobsRoot)) {
|
|
1285
|
+
const prefixDir = (0, import_node_path5.join)(blobsRoot, prefix);
|
|
1286
|
+
if (!await isDir(prefixDir)) {
|
|
1287
|
+
continue;
|
|
1288
|
+
}
|
|
1289
|
+
for (const digest of await safeReaddir(prefixDir)) {
|
|
1290
|
+
if (!referencedDigests.has(digest)) {
|
|
1291
|
+
await safeRm((0, import_node_path5.join)(prefixDir, digest));
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
/** Remove legacy bundles/ directory if present. */
|
|
1297
|
+
async removeLegacy() {
|
|
1298
|
+
const legacyDir = (0, import_node_path5.join)(this.cacheDir, "bundles");
|
|
1299
|
+
if ((0, import_node_fs.existsSync)(legacyDir)) {
|
|
1300
|
+
await (0, import_promises5.rm)(legacyDir, { recursive: true, force: true });
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
};
|
|
1304
|
+
function computeHostId(registryUrl) {
|
|
1305
|
+
try {
|
|
1306
|
+
const url = new URL(registryUrl);
|
|
1307
|
+
return url.host.replace(/[:/]/g, "_");
|
|
1308
|
+
} catch {
|
|
1309
|
+
return registryUrl.replace(/[:/]/g, "_");
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
async function isDir(path) {
|
|
1313
|
+
try {
|
|
1314
|
+
return (await (0, import_promises5.stat)(path)).isDirectory();
|
|
1315
|
+
} catch {
|
|
1316
|
+
return false;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
async function safeReaddir(path) {
|
|
1320
|
+
try {
|
|
1321
|
+
return await (0, import_promises5.readdir)(path);
|
|
1322
|
+
} catch {
|
|
1323
|
+
return [];
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
async function safeRm(path) {
|
|
1327
|
+
try {
|
|
1328
|
+
await (0, import_promises5.unlink)(path);
|
|
1329
|
+
} catch {
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// src/config.ts
|
|
1334
|
+
var import_node_fs2 = require("fs");
|
|
1335
|
+
var import_node_path7 = require("path");
|
|
1336
|
+
|
|
1337
|
+
// src/keyring.ts
|
|
1338
|
+
var import_node_child_process = require("child_process");
|
|
1339
|
+
var ACCOUNT = "api-key";
|
|
1340
|
+
function serviceName(host) {
|
|
1341
|
+
return `musher/${host}`;
|
|
1342
|
+
}
|
|
1343
|
+
function tryKeyringLookup(service) {
|
|
1344
|
+
try {
|
|
1345
|
+
const platform = process.platform;
|
|
1346
|
+
if (platform === "darwin") {
|
|
1347
|
+
const result = (0, import_node_child_process.execFileSync)(
|
|
1348
|
+
"security",
|
|
1349
|
+
["find-generic-password", "-s", service, "-a", ACCOUNT, "-w"],
|
|
1350
|
+
{
|
|
1351
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1352
|
+
timeout: 5e3
|
|
1353
|
+
}
|
|
1354
|
+
);
|
|
1355
|
+
return result.toString("utf-8").trim() || void 0;
|
|
1356
|
+
}
|
|
1357
|
+
if (platform === "linux") {
|
|
1358
|
+
const result = (0, import_node_child_process.execFileSync)(
|
|
1359
|
+
"secret-tool",
|
|
1360
|
+
["lookup", "service", service, "username", ACCOUNT],
|
|
1361
|
+
{
|
|
1362
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1363
|
+
timeout: 5e3
|
|
1364
|
+
}
|
|
1365
|
+
);
|
|
1366
|
+
return result.toString("utf-8").trim() || void 0;
|
|
1367
|
+
}
|
|
1368
|
+
if (platform === "win32") {
|
|
1369
|
+
const result = (0, import_node_child_process.execFileSync)(
|
|
1370
|
+
"powershell.exe",
|
|
1371
|
+
[
|
|
1372
|
+
"-NoProfile",
|
|
1373
|
+
"-NonInteractive",
|
|
1374
|
+
"-Command",
|
|
1375
|
+
`$cred = Get-StoredCredential -Target '${service.replace(/'/g, "''")}'; if ($cred) { $cred.GetNetworkCredential().Password }`
|
|
1376
|
+
],
|
|
1377
|
+
{
|
|
1378
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1379
|
+
timeout: 5e3
|
|
1380
|
+
}
|
|
1381
|
+
);
|
|
1382
|
+
return result.toString("utf-8").trim() || void 0;
|
|
1383
|
+
}
|
|
1384
|
+
return void 0;
|
|
1385
|
+
} catch {
|
|
1386
|
+
return void 0;
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
function readKeyring(host = "api.musher.dev") {
|
|
1390
|
+
return tryKeyringLookup(serviceName(host));
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
// src/paths.ts
|
|
1394
|
+
var import_node_os = require("os");
|
|
1395
|
+
var import_node_path6 = require("path");
|
|
1396
|
+
var APP_NAME = "musher";
|
|
1397
|
+
function env(name) {
|
|
1398
|
+
const value = process.env[name];
|
|
1399
|
+
return value || void 0;
|
|
1400
|
+
}
|
|
1401
|
+
function absEnv(name) {
|
|
1402
|
+
const value = env(name);
|
|
1403
|
+
if (value && (0, import_node_path6.isAbsolute)(value)) {
|
|
1404
|
+
return value;
|
|
1405
|
+
}
|
|
1406
|
+
return void 0;
|
|
1407
|
+
}
|
|
1408
|
+
function resolveDir(envKey, subdir, platformDefault) {
|
|
1409
|
+
const perDir = absEnv(envKey);
|
|
1410
|
+
if (perDir) {
|
|
1411
|
+
return perDir;
|
|
1412
|
+
}
|
|
1413
|
+
const umbrella = absEnv("MUSHER_HOME");
|
|
1414
|
+
if (umbrella) {
|
|
1415
|
+
return (0, import_node_path6.join)(umbrella, subdir);
|
|
1416
|
+
}
|
|
1417
|
+
return platformDefault();
|
|
1418
|
+
}
|
|
1419
|
+
function xdgDefault(xdgVar, fallbackSuffix) {
|
|
1420
|
+
const xdg = absEnv(xdgVar);
|
|
1421
|
+
if (xdg) {
|
|
1422
|
+
return (0, import_node_path6.join)(xdg, APP_NAME);
|
|
1423
|
+
}
|
|
1424
|
+
return (0, import_node_path6.join)((0, import_node_os.homedir)(), fallbackSuffix, APP_NAME);
|
|
1425
|
+
}
|
|
1426
|
+
function linuxDirs() {
|
|
1427
|
+
return {
|
|
1428
|
+
cache: resolveDir("MUSHER_CACHE_HOME", "cache", () => xdgDefault("XDG_CACHE_HOME", ".cache")),
|
|
1429
|
+
config: resolveDir(
|
|
1430
|
+
"MUSHER_CONFIG_HOME",
|
|
1431
|
+
"config",
|
|
1432
|
+
() => xdgDefault("XDG_CONFIG_HOME", ".config")
|
|
1433
|
+
),
|
|
1434
|
+
data: resolveDir(
|
|
1435
|
+
"MUSHER_DATA_HOME",
|
|
1436
|
+
"data",
|
|
1437
|
+
() => xdgDefault("XDG_DATA_HOME", (0, import_node_path6.join)(".local", "share"))
|
|
1438
|
+
),
|
|
1439
|
+
state: resolveDir(
|
|
1440
|
+
"MUSHER_STATE_HOME",
|
|
1441
|
+
"state",
|
|
1442
|
+
() => xdgDefault("XDG_STATE_HOME", (0, import_node_path6.join)(".local", "state"))
|
|
1443
|
+
),
|
|
1444
|
+
runtime: resolveDir("MUSHER_RUNTIME_DIR", "runtime", () => {
|
|
1445
|
+
const xdg = absEnv("XDG_RUNTIME_DIR");
|
|
1446
|
+
if (xdg) {
|
|
1447
|
+
return (0, import_node_path6.join)(xdg, APP_NAME);
|
|
1448
|
+
}
|
|
1449
|
+
return (0, import_node_path6.join)((0, import_node_os.tmpdir)(), APP_NAME, "run");
|
|
1450
|
+
})
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
function darwinDirs() {
|
|
1454
|
+
const home = (0, import_node_os.homedir)();
|
|
1455
|
+
const appSupport = (0, import_node_path6.join)(home, "Library", "Application Support", APP_NAME);
|
|
1456
|
+
return {
|
|
1457
|
+
cache: resolveDir(
|
|
1458
|
+
"MUSHER_CACHE_HOME",
|
|
1459
|
+
"cache",
|
|
1460
|
+
() => (0, import_node_path6.join)(home, "Library", "Caches", APP_NAME)
|
|
1461
|
+
),
|
|
1462
|
+
config: resolveDir("MUSHER_CONFIG_HOME", "config", () => (0, import_node_path6.join)(appSupport, "config")),
|
|
1463
|
+
data: resolveDir("MUSHER_DATA_HOME", "data", () => (0, import_node_path6.join)(appSupport, "data")),
|
|
1464
|
+
state: resolveDir("MUSHER_STATE_HOME", "state", () => (0, import_node_path6.join)(appSupport, "state")),
|
|
1465
|
+
runtime: resolveDir("MUSHER_RUNTIME_DIR", "runtime", () => (0, import_node_path6.join)((0, import_node_os.tmpdir)(), APP_NAME, "run"))
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
function win32Dirs() {
|
|
1469
|
+
const localAppData = env("LOCALAPPDATA") ?? (0, import_node_path6.join)((0, import_node_os.homedir)(), "AppData", "Local");
|
|
1470
|
+
const base = (0, import_node_path6.join)(localAppData, APP_NAME);
|
|
1471
|
+
return {
|
|
1472
|
+
cache: resolveDir("MUSHER_CACHE_HOME", "cache", () => (0, import_node_path6.join)(base, "cache")),
|
|
1473
|
+
config: resolveDir("MUSHER_CONFIG_HOME", "config", () => (0, import_node_path6.join)(base, "config")),
|
|
1474
|
+
data: resolveDir("MUSHER_DATA_HOME", "data", () => (0, import_node_path6.join)(base, "data")),
|
|
1475
|
+
state: resolveDir("MUSHER_STATE_HOME", "state", () => (0, import_node_path6.join)(base, "state")),
|
|
1476
|
+
runtime: resolveDir("MUSHER_RUNTIME_DIR", "runtime", () => (0, import_node_path6.join)((0, import_node_os.tmpdir)(), APP_NAME, "run"))
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
function resolveMusherDirs() {
|
|
1480
|
+
switch (process.platform) {
|
|
1481
|
+
case "darwin":
|
|
1482
|
+
return darwinDirs();
|
|
1483
|
+
case "win32":
|
|
1484
|
+
return win32Dirs();
|
|
1485
|
+
default:
|
|
1486
|
+
return linuxDirs();
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
// src/config.ts
|
|
1491
|
+
var DEFAULT_BASE_URL = "https://api.musher.dev";
|
|
1492
|
+
var DEFAULT_MANIFEST_TTL = 86400;
|
|
1493
|
+
var DEFAULT_REF_TTL = 300;
|
|
1494
|
+
var DEFAULT_TIMEOUT = 6e4;
|
|
1495
|
+
var DEFAULT_RETRIES = 3;
|
|
1496
|
+
function computeHostId2(host) {
|
|
1497
|
+
return host.replace(/[:/]/g, "_");
|
|
1498
|
+
}
|
|
1499
|
+
function readApiKeyFile(dataDir, host = "api.musher.dev") {
|
|
1500
|
+
try {
|
|
1501
|
+
const dir = dataDir ?? resolveMusherDirs().data;
|
|
1502
|
+
const filePath = (0, import_node_path7.join)(dir, "credentials", computeHostId2(host), "api-key");
|
|
1503
|
+
const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8").trim();
|
|
1504
|
+
if (!content) {
|
|
1505
|
+
return void 0;
|
|
1506
|
+
}
|
|
1507
|
+
if (process.platform !== "win32") {
|
|
1508
|
+
const mode = (0, import_node_fs2.statSync)(filePath).mode;
|
|
1509
|
+
if (mode & 63) {
|
|
1510
|
+
process.emitWarning(
|
|
1511
|
+
`Ignoring ${filePath}: file permissions are too open (must not be readable by group or others). Run: chmod 600 ${filePath}`,
|
|
1512
|
+
"MusherSecurityWarning"
|
|
1513
|
+
);
|
|
1514
|
+
return void 0;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
return content;
|
|
1518
|
+
} catch {
|
|
1519
|
+
return void 0;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
function env2(name) {
|
|
1523
|
+
const value = process.env[name];
|
|
1524
|
+
return value || void 0;
|
|
1525
|
+
}
|
|
1526
|
+
function resolveConfig(config) {
|
|
1527
|
+
const dirs = resolveMusherDirs();
|
|
1528
|
+
const configDir = config?.configDir ?? dirs.config;
|
|
1529
|
+
const baseUrl = config?.baseUrl ?? env2("MUSHER_API_URL") ?? DEFAULT_BASE_URL;
|
|
1530
|
+
let keyringHost;
|
|
1531
|
+
try {
|
|
1532
|
+
keyringHost = new URL(baseUrl).host;
|
|
1533
|
+
} catch {
|
|
1534
|
+
keyringHost = "api.musher.dev";
|
|
1535
|
+
}
|
|
1536
|
+
return {
|
|
1537
|
+
baseUrl,
|
|
1538
|
+
apiKey: config?.apiKey ?? env2("MUSHER_API_KEY") ?? readKeyring(keyringHost) ?? readApiKeyFile(dirs.data, keyringHost),
|
|
1539
|
+
cacheDir: config?.cacheDir ?? dirs.cache,
|
|
1540
|
+
configDir,
|
|
1541
|
+
manifestTtlSeconds: config?.manifestTtlSeconds ?? DEFAULT_MANIFEST_TTL,
|
|
1542
|
+
refTtlSeconds: config?.refTtlSeconds ?? DEFAULT_REF_TTL,
|
|
1543
|
+
timeout: config?.timeout ?? DEFAULT_TIMEOUT,
|
|
1544
|
+
retries: config?.retries ?? DEFAULT_RETRIES
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// src/http.ts
|
|
1549
|
+
var TRAILING_SLASH_RE = /\/$/;
|
|
1550
|
+
var HttpTransport = class {
|
|
1551
|
+
constructor(config) {
|
|
1552
|
+
this.config = config;
|
|
1553
|
+
}
|
|
1554
|
+
async request(method, path, schema, options) {
|
|
1555
|
+
const url = this.buildUrl(path, options?.params);
|
|
1556
|
+
const headers = this.buildHeaders();
|
|
1557
|
+
let lastError;
|
|
1558
|
+
for (let attempt = 0; attempt <= this.config.retries; attempt++) {
|
|
1559
|
+
try {
|
|
1560
|
+
const init = { method, headers };
|
|
1561
|
+
if (options?.body) {
|
|
1562
|
+
init.body = JSON.stringify(options.body);
|
|
1563
|
+
}
|
|
1564
|
+
const response = await this.fetchWithTimeout(url, init);
|
|
1565
|
+
if (!response.ok) {
|
|
1566
|
+
const error = await this.mapError(response);
|
|
1567
|
+
if (response.status === 429 || response.status >= 500) {
|
|
1568
|
+
lastError = error;
|
|
1569
|
+
if (attempt < this.config.retries) {
|
|
1570
|
+
await this.backoff(attempt, error);
|
|
1571
|
+
continue;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
throw error;
|
|
1575
|
+
}
|
|
1576
|
+
const json = await response.json();
|
|
1577
|
+
return this.parse(schema, json);
|
|
1578
|
+
} catch (error) {
|
|
1579
|
+
if (error instanceof ApiError) {
|
|
1580
|
+
throw error;
|
|
1581
|
+
}
|
|
1582
|
+
if (error instanceof SchemaError) {
|
|
1583
|
+
throw error;
|
|
1584
|
+
}
|
|
1585
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
1586
|
+
if (attempt < this.config.retries) {
|
|
1587
|
+
await this.backoff(attempt);
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
throw lastError ?? new NetworkError("Request failed after retries");
|
|
1592
|
+
}
|
|
1593
|
+
buildUrl(path, params) {
|
|
1594
|
+
const base = this.config.baseUrl.replace(TRAILING_SLASH_RE, "");
|
|
1595
|
+
const url = new URL(`${base}${path}`);
|
|
1596
|
+
if (params) {
|
|
1597
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1598
|
+
if (value !== void 0) {
|
|
1599
|
+
url.searchParams.set(key, String(value));
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
return url.toString();
|
|
1604
|
+
}
|
|
1605
|
+
buildHeaders() {
|
|
1606
|
+
const headers = {
|
|
1607
|
+
"Content-Type": "application/json",
|
|
1608
|
+
Accept: "application/json"
|
|
1609
|
+
};
|
|
1610
|
+
if (this.config.apiKey) {
|
|
1611
|
+
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
1612
|
+
}
|
|
1613
|
+
return headers;
|
|
1614
|
+
}
|
|
1615
|
+
async fetchWithTimeout(url, init) {
|
|
1616
|
+
const controller = new AbortController();
|
|
1617
|
+
const timer = setTimeout(() => controller.abort(), this.config.timeout);
|
|
1618
|
+
try {
|
|
1619
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
1620
|
+
} catch (error) {
|
|
1621
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
1622
|
+
throw new TimeoutError(`Request timed out after ${this.config.timeout}ms`);
|
|
1623
|
+
}
|
|
1624
|
+
throw new NetworkError(error instanceof Error ? error.message : "Network request failed", {
|
|
1625
|
+
cause: error instanceof Error ? error : void 0
|
|
1626
|
+
});
|
|
1627
|
+
} finally {
|
|
1628
|
+
clearTimeout(timer);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
async mapError(response) {
|
|
1632
|
+
let problem;
|
|
1633
|
+
try {
|
|
1634
|
+
const body = await response.json();
|
|
1635
|
+
problem = {
|
|
1636
|
+
type: body.type ?? "about:blank",
|
|
1637
|
+
title: body.title ?? response.statusText,
|
|
1638
|
+
status: response.status,
|
|
1639
|
+
detail: body.detail ?? response.statusText,
|
|
1640
|
+
instance: body.instance,
|
|
1641
|
+
traceId: body.traceId
|
|
1642
|
+
};
|
|
1643
|
+
} catch {
|
|
1644
|
+
problem = {
|
|
1645
|
+
type: "about:blank",
|
|
1646
|
+
title: response.statusText,
|
|
1647
|
+
status: response.status,
|
|
1648
|
+
detail: response.statusText
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
switch (response.status) {
|
|
1652
|
+
case 401:
|
|
1653
|
+
return new AuthenticationError(problem);
|
|
1654
|
+
case 403:
|
|
1655
|
+
return new ForbiddenError(problem);
|
|
1656
|
+
case 404:
|
|
1657
|
+
return new NotFoundError(problem);
|
|
1658
|
+
case 422:
|
|
1659
|
+
return new ValidationError(
|
|
1660
|
+
problem
|
|
1661
|
+
);
|
|
1662
|
+
case 429: {
|
|
1663
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
1664
|
+
return new RateLimitError(
|
|
1665
|
+
problem,
|
|
1666
|
+
retryAfter ? Number.parseInt(retryAfter, 10) : void 0
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
default:
|
|
1670
|
+
return new ApiError(problem);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
parse(schema, data) {
|
|
1674
|
+
const result = schema.safeParse(data);
|
|
1675
|
+
if (!result.success) {
|
|
1676
|
+
throw new SchemaError(`API response validation failed: ${result.error.message}`);
|
|
1677
|
+
}
|
|
1678
|
+
return result.data;
|
|
1679
|
+
}
|
|
1680
|
+
async backoff(attempt, error) {
|
|
1681
|
+
let delay = Math.min(1e3 * 2 ** attempt, 1e4);
|
|
1682
|
+
if (error instanceof RateLimitError && error.retryAfter) {
|
|
1683
|
+
delay = error.retryAfter * 1e3;
|
|
1684
|
+
}
|
|
1685
|
+
delay += Math.random() * 500;
|
|
1686
|
+
await new Promise((resolve5) => setTimeout(resolve5, delay));
|
|
1687
|
+
}
|
|
1688
|
+
};
|
|
1689
|
+
|
|
1690
|
+
// src/schemas/asset.ts
|
|
1691
|
+
var import_zod = require("zod");
|
|
1692
|
+
var AssetSummaryOutputSchema = import_zod.z.object({
|
|
1693
|
+
id: import_zod.z.string().uuid(),
|
|
1694
|
+
bundleId: import_zod.z.string().uuid(),
|
|
1695
|
+
assetType: import_zod.z.string(),
|
|
1696
|
+
logicalPath: import_zod.z.string(),
|
|
1697
|
+
contentSha256: import_zod.z.string(),
|
|
1698
|
+
contentSizeBytes: import_zod.z.number().int().nullable().optional(),
|
|
1699
|
+
mediaType: import_zod.z.string().nullable().optional(),
|
|
1700
|
+
createdAt: import_zod.z.string().datetime(),
|
|
1701
|
+
updatedAt: import_zod.z.string().datetime().nullable().optional()
|
|
1702
|
+
});
|
|
1703
|
+
var AssetDetailOutputSchema = AssetSummaryOutputSchema.extend({
|
|
1704
|
+
contentText: import_zod.z.string().nullable().optional()
|
|
1705
|
+
});
|
|
1706
|
+
|
|
1707
|
+
// src/schemas/bundle.ts
|
|
1708
|
+
var import_zod3 = require("zod");
|
|
1709
|
+
|
|
1710
|
+
// src/schemas/common.ts
|
|
1711
|
+
var import_zod2 = require("zod");
|
|
1712
|
+
var BundleVisibility = import_zod2.z.enum(["private", "public"]);
|
|
1713
|
+
var BundleVersionState = import_zod2.z.enum(["published", "yanked"]);
|
|
1714
|
+
var AssetType = import_zod2.z.enum([
|
|
1715
|
+
"agent_definition",
|
|
1716
|
+
"skill",
|
|
1717
|
+
"tool_config",
|
|
1718
|
+
"prompt",
|
|
1719
|
+
"config",
|
|
1720
|
+
"other"
|
|
1721
|
+
]);
|
|
1722
|
+
var BundleSourceType = import_zod2.z.enum(["console", "registry"]);
|
|
1723
|
+
var PaginationMetaSchema = import_zod2.z.object({
|
|
1724
|
+
nextCursor: import_zod2.z.string().nullable(),
|
|
1725
|
+
hasMore: import_zod2.z.boolean()
|
|
1726
|
+
});
|
|
1727
|
+
function paginatedSchema(itemSchema) {
|
|
1728
|
+
return import_zod2.z.object({
|
|
1729
|
+
data: import_zod2.z.array(itemSchema),
|
|
1730
|
+
meta: PaginationMetaSchema
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
// src/schemas/bundle.ts
|
|
1735
|
+
var BundleOutputSchema = import_zod3.z.object({
|
|
1736
|
+
id: import_zod3.z.string().uuid(),
|
|
1737
|
+
namespace: import_zod3.z.string(),
|
|
1738
|
+
slug: import_zod3.z.string(),
|
|
1739
|
+
ref: import_zod3.z.string(),
|
|
1740
|
+
name: import_zod3.z.string(),
|
|
1741
|
+
description: import_zod3.z.string().nullable().optional(),
|
|
1742
|
+
visibility: BundleVisibility,
|
|
1743
|
+
sourceType: BundleSourceType,
|
|
1744
|
+
readmeFormat: import_zod3.z.string().nullable().optional(),
|
|
1745
|
+
createdAt: import_zod3.z.string().datetime(),
|
|
1746
|
+
updatedAt: import_zod3.z.string().datetime().nullable().optional()
|
|
1747
|
+
});
|
|
1748
|
+
var BundleDetailOutputSchema = BundleOutputSchema.extend({
|
|
1749
|
+
readmeContent: import_zod3.z.string().nullable().optional(),
|
|
1750
|
+
latestVersion: import_zod3.z.string().nullable().optional(),
|
|
1751
|
+
versionCount: import_zod3.z.number().int(),
|
|
1752
|
+
assetCount: import_zod3.z.number().int()
|
|
1753
|
+
});
|
|
1754
|
+
|
|
1755
|
+
// src/schemas/resolve.ts
|
|
1756
|
+
var import_zod4 = require("zod");
|
|
1757
|
+
var BundleLayerOutputSchema = import_zod4.z.object({
|
|
1758
|
+
assetId: import_zod4.z.string(),
|
|
1759
|
+
logicalPath: import_zod4.z.string(),
|
|
1760
|
+
assetType: import_zod4.z.string(),
|
|
1761
|
+
contentSha256: import_zod4.z.string(),
|
|
1762
|
+
sizeBytes: import_zod4.z.number().int(),
|
|
1763
|
+
mediaType: import_zod4.z.string().nullable().optional()
|
|
1764
|
+
});
|
|
1765
|
+
var BundleManifestOutputSchema = import_zod4.z.object({
|
|
1766
|
+
layers: import_zod4.z.array(BundleLayerOutputSchema)
|
|
1767
|
+
});
|
|
1768
|
+
var BundleResolveOutputSchema = import_zod4.z.object({
|
|
1769
|
+
bundleId: import_zod4.z.string().uuid(),
|
|
1770
|
+
versionId: import_zod4.z.string().uuid(),
|
|
1771
|
+
namespace: import_zod4.z.string(),
|
|
1772
|
+
slug: import_zod4.z.string(),
|
|
1773
|
+
ref: import_zod4.z.string(),
|
|
1774
|
+
version: import_zod4.z.string(),
|
|
1775
|
+
sourceType: BundleSourceType,
|
|
1776
|
+
ociRef: import_zod4.z.string().nullable().optional(),
|
|
1777
|
+
ociDigest: import_zod4.z.string().nullable().optional(),
|
|
1778
|
+
state: BundleVersionState,
|
|
1779
|
+
manifest: BundleManifestOutputSchema.nullable().optional()
|
|
1780
|
+
});
|
|
1781
|
+
|
|
1782
|
+
// src/schemas/version.ts
|
|
1783
|
+
var import_zod5 = require("zod");
|
|
1784
|
+
var BundleVersionSummaryOutputSchema = import_zod5.z.object({
|
|
1785
|
+
id: import_zod5.z.string().uuid(),
|
|
1786
|
+
bundleId: import_zod5.z.string().uuid(),
|
|
1787
|
+
version: import_zod5.z.string(),
|
|
1788
|
+
state: BundleVersionState,
|
|
1789
|
+
ociRef: import_zod5.z.string().nullable().optional(),
|
|
1790
|
+
ociDigest: import_zod5.z.string().nullable().optional(),
|
|
1791
|
+
publishedBy: import_zod5.z.string().nullable().optional(),
|
|
1792
|
+
yankedBy: import_zod5.z.string().nullable().optional(),
|
|
1793
|
+
yankedAt: import_zod5.z.string().datetime().nullable().optional(),
|
|
1794
|
+
yankReason: import_zod5.z.string().nullable().optional(),
|
|
1795
|
+
createdAt: import_zod5.z.string().datetime()
|
|
1796
|
+
});
|
|
1797
|
+
var ManifestAssetOutputSchema = import_zod5.z.object({
|
|
1798
|
+
assetId: import_zod5.z.string(),
|
|
1799
|
+
logicalPath: import_zod5.z.string(),
|
|
1800
|
+
assetType: import_zod5.z.string(),
|
|
1801
|
+
contentSha256: import_zod5.z.string(),
|
|
1802
|
+
sizeBytes: import_zod5.z.number().int(),
|
|
1803
|
+
mediaType: import_zod5.z.string().nullable().optional()
|
|
1804
|
+
});
|
|
1805
|
+
var ManifestDetailOutputSchema = import_zod5.z.object({
|
|
1806
|
+
namespace: import_zod5.z.string(),
|
|
1807
|
+
bundleSlug: import_zod5.z.string(),
|
|
1808
|
+
version: import_zod5.z.string(),
|
|
1809
|
+
assets: import_zod5.z.array(ManifestAssetOutputSchema)
|
|
1810
|
+
});
|
|
1811
|
+
var BundleVersionDetailOutputSchema = import_zod5.z.object({
|
|
1812
|
+
id: import_zod5.z.string().uuid(),
|
|
1813
|
+
bundleId: import_zod5.z.string().uuid(),
|
|
1814
|
+
version: import_zod5.z.string(),
|
|
1815
|
+
state: BundleVersionState,
|
|
1816
|
+
ociRef: import_zod5.z.string().nullable().optional(),
|
|
1817
|
+
ociDigest: import_zod5.z.string().nullable().optional(),
|
|
1818
|
+
manifest: ManifestDetailOutputSchema.nullable().optional(),
|
|
1819
|
+
publishedBy: import_zod5.z.string().nullable().optional(),
|
|
1820
|
+
yankedBy: import_zod5.z.string().nullable().optional(),
|
|
1821
|
+
yankedAt: import_zod5.z.string().datetime().nullable().optional(),
|
|
1822
|
+
yankReason: import_zod5.z.string().nullable().optional(),
|
|
1823
|
+
createdAt: import_zod5.z.string().datetime()
|
|
1824
|
+
});
|
|
1825
|
+
|
|
1826
|
+
// src/resources/bundles.ts
|
|
1827
|
+
var BundlesResource = class {
|
|
1828
|
+
constructor(http) {
|
|
1829
|
+
this.http = http;
|
|
1830
|
+
}
|
|
1831
|
+
async get(namespace, bundle) {
|
|
1832
|
+
return this.http.request(
|
|
1833
|
+
"GET",
|
|
1834
|
+
`/v1/namespaces/${enc(namespace)}/bundles/${enc(bundle)}`,
|
|
1835
|
+
BundleDetailOutputSchema
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
async list(namespace, params) {
|
|
1839
|
+
return this.http.request(
|
|
1840
|
+
"GET",
|
|
1841
|
+
`/v1/namespaces/${enc(namespace)}/bundles`,
|
|
1842
|
+
paginatedSchema(BundleOutputSchema),
|
|
1843
|
+
{
|
|
1844
|
+
params: {
|
|
1845
|
+
cursor: params?.cursor,
|
|
1846
|
+
limit: params?.limit
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
);
|
|
1850
|
+
}
|
|
1851
|
+
async resolve(namespace, bundle, version, digest) {
|
|
1852
|
+
const params = {};
|
|
1853
|
+
if (version) {
|
|
1854
|
+
params["version"] = version;
|
|
1855
|
+
}
|
|
1856
|
+
if (digest) {
|
|
1857
|
+
params["digest"] = digest;
|
|
1858
|
+
}
|
|
1859
|
+
const hasParams = Object.keys(params).length > 0;
|
|
1860
|
+
return this.http.request(
|
|
1861
|
+
"GET",
|
|
1862
|
+
`/v1/namespaces/${enc(namespace)}/bundles/${enc(bundle)}:resolve`,
|
|
1863
|
+
BundleResolveOutputSchema,
|
|
1864
|
+
hasParams ? { params } : void 0
|
|
1865
|
+
);
|
|
1866
|
+
}
|
|
1867
|
+
async listVersions(namespace, bundle, params) {
|
|
1868
|
+
return this.http.request(
|
|
1869
|
+
"GET",
|
|
1870
|
+
`/v1/namespaces/${enc(namespace)}/bundles/${enc(bundle)}/versions`,
|
|
1871
|
+
paginatedSchema(BundleVersionSummaryOutputSchema),
|
|
1872
|
+
{
|
|
1873
|
+
params: {
|
|
1874
|
+
cursor: params?.cursor,
|
|
1875
|
+
limit: params?.limit
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
);
|
|
1879
|
+
}
|
|
1880
|
+
async getVersion(namespace, bundle, version) {
|
|
1881
|
+
return this.http.request(
|
|
1882
|
+
"GET",
|
|
1883
|
+
`/v1/namespaces/${enc(namespace)}/bundles/${enc(bundle)}/versions/${enc(version)}`,
|
|
1884
|
+
BundleVersionDetailOutputSchema
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
async listAssets(namespace, bundle, params) {
|
|
1888
|
+
return this.http.request(
|
|
1889
|
+
"GET",
|
|
1890
|
+
`/v1/namespaces/${enc(namespace)}/bundles/${enc(bundle)}/assets`,
|
|
1891
|
+
paginatedSchema(AssetSummaryOutputSchema),
|
|
1892
|
+
{
|
|
1893
|
+
params: {
|
|
1894
|
+
cursor: params?.cursor,
|
|
1895
|
+
limit: params?.limit
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
);
|
|
1899
|
+
}
|
|
1900
|
+
async getAsset(namespace, bundle, assetId, version) {
|
|
1901
|
+
return this.http.request(
|
|
1902
|
+
"GET",
|
|
1903
|
+
`/v1/namespaces/${enc(namespace)}/bundles/${enc(bundle)}/assets/${enc(assetId)}`,
|
|
1904
|
+
AssetDetailOutputSchema,
|
|
1905
|
+
{ params: { version } }
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
function enc(value) {
|
|
1910
|
+
return encodeURIComponent(value);
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
// src/client.ts
|
|
1914
|
+
var _loadDeprecationWarned = false;
|
|
1915
|
+
var MusherClient = class {
|
|
1916
|
+
bundles;
|
|
1917
|
+
_cache;
|
|
1918
|
+
_http;
|
|
1919
|
+
constructor(config) {
|
|
1920
|
+
const resolved = resolveConfig(config);
|
|
1921
|
+
this._http = new HttpTransport(resolved);
|
|
1922
|
+
this._cache = new BundleCache(
|
|
1923
|
+
resolved.cacheDir,
|
|
1924
|
+
resolved.baseUrl,
|
|
1925
|
+
resolved.manifestTtlSeconds,
|
|
1926
|
+
resolved.refTtlSeconds
|
|
1927
|
+
);
|
|
1928
|
+
this.bundles = new BundlesResource(this._http);
|
|
1929
|
+
}
|
|
1930
|
+
/**
|
|
1931
|
+
* Resolve a bundle via the API, download all assets, and write to disk cache.
|
|
1932
|
+
* Returns a Bundle object.
|
|
1933
|
+
*
|
|
1934
|
+
* @param ref - Bundle reference (e.g. "namespace/slug", "namespace/slug:version").
|
|
1935
|
+
* @param version - Optional semver constraint. Defaults to latest.
|
|
1936
|
+
*/
|
|
1937
|
+
async pull(ref, version) {
|
|
1938
|
+
const parsed = BundleRef.parse(ref);
|
|
1939
|
+
const resolvedVersion = version ?? parsed.version;
|
|
1940
|
+
const resolved = await this.bundles.resolve(
|
|
1941
|
+
parsed.namespace,
|
|
1942
|
+
parsed.slug,
|
|
1943
|
+
resolvedVersion,
|
|
1944
|
+
parsed.digest
|
|
1945
|
+
);
|
|
1946
|
+
const assets = /* @__PURE__ */ new Map();
|
|
1947
|
+
if (resolved.manifest?.layers) {
|
|
1948
|
+
for (const layer of resolved.manifest.layers) {
|
|
1949
|
+
const asset = await this.bundles.getAsset(
|
|
1950
|
+
parsed.namespace,
|
|
1951
|
+
parsed.slug,
|
|
1952
|
+
layer.assetId,
|
|
1953
|
+
resolved.version
|
|
1954
|
+
);
|
|
1955
|
+
if (asset.contentText != null) {
|
|
1956
|
+
const buf = Buffer.from(asset.contentText, "utf-8");
|
|
1957
|
+
const hash = (0, import_node_crypto3.createHash)("sha256").update(buf).digest("hex");
|
|
1958
|
+
if (hash !== layer.contentSha256) {
|
|
1959
|
+
throw new IntegrityError(layer.contentSha256, hash);
|
|
1960
|
+
}
|
|
1961
|
+
assets.set(layer.logicalPath, buf);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
await this._cache.write(resolved, assets);
|
|
1966
|
+
if (!parsed.digest) {
|
|
1967
|
+
const refAlias = resolvedVersion ?? "latest";
|
|
1968
|
+
await this._cache.cacheRef(parsed.namespace, parsed.slug, refAlias, resolved.version);
|
|
1969
|
+
}
|
|
1970
|
+
return new Bundle(resolved, assets);
|
|
1971
|
+
}
|
|
1972
|
+
/**
|
|
1973
|
+
* Resolve bundle metadata without downloading content.
|
|
1974
|
+
* Checks the manifest cache (with TTL) before calling the API.
|
|
1975
|
+
*
|
|
1976
|
+
* @param ref - Bundle reference.
|
|
1977
|
+
* @param version - Optional semver constraint.
|
|
1978
|
+
*/
|
|
1979
|
+
async resolve(ref, version) {
|
|
1980
|
+
const parsed = BundleRef.parse(ref);
|
|
1981
|
+
let resolvedVersion = version ?? parsed.version;
|
|
1982
|
+
if (!(resolvedVersion || parsed.digest)) {
|
|
1983
|
+
const cachedVersion = await this._cache.resolveRef(parsed.namespace, parsed.slug, "latest");
|
|
1984
|
+
if (cachedVersion) {
|
|
1985
|
+
resolvedVersion = cachedVersion;
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
if (resolvedVersion) {
|
|
1989
|
+
const fresh = await this._cache.isFresh(parsed.namespace, parsed.slug, resolvedVersion);
|
|
1990
|
+
if (fresh) {
|
|
1991
|
+
const manifest = await this._cache.loadManifest(
|
|
1992
|
+
parsed.namespace,
|
|
1993
|
+
parsed.slug,
|
|
1994
|
+
resolvedVersion
|
|
1995
|
+
);
|
|
1996
|
+
if (manifest) {
|
|
1997
|
+
return manifest;
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
const resolved = await this.bundles.resolve(
|
|
2002
|
+
parsed.namespace,
|
|
2003
|
+
parsed.slug,
|
|
2004
|
+
resolvedVersion,
|
|
2005
|
+
parsed.digest
|
|
2006
|
+
);
|
|
2007
|
+
await this._cache.writeManifest(resolved);
|
|
2008
|
+
if (!parsed.digest) {
|
|
2009
|
+
const refAlias = resolvedVersion ?? "latest";
|
|
2010
|
+
await this._cache.cacheRef(parsed.namespace, parsed.slug, refAlias, resolved.version);
|
|
2011
|
+
}
|
|
2012
|
+
return resolved;
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* @deprecated Use `pull()` instead. This method will be removed in a future version.
|
|
2016
|
+
*
|
|
2017
|
+
* Load a bundle into memory. Checks cache first (TTL-aware), pulls if stale.
|
|
2018
|
+
*/
|
|
2019
|
+
async load(ref, version) {
|
|
2020
|
+
if (!_loadDeprecationWarned) {
|
|
2021
|
+
_loadDeprecationWarned = true;
|
|
2022
|
+
process.emitWarning(
|
|
2023
|
+
"MusherClient.load() is deprecated. Use pull() instead.",
|
|
2024
|
+
"DeprecationWarning"
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
const parsed = BundleRef.parse(ref);
|
|
2028
|
+
let resolvedVersion = version ?? parsed.version;
|
|
2029
|
+
if (!(resolvedVersion || parsed.digest)) {
|
|
2030
|
+
const cachedVersion = await this._cache.resolveRef(parsed.namespace, parsed.slug, "latest");
|
|
2031
|
+
if (cachedVersion) {
|
|
2032
|
+
resolvedVersion = cachedVersion;
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
if (resolvedVersion) {
|
|
2036
|
+
const fresh = await this._cache.isFresh(parsed.namespace, parsed.slug, resolvedVersion);
|
|
2037
|
+
if (fresh) {
|
|
2038
|
+
const loaded = await this._cache.load(parsed.namespace, parsed.slug, resolvedVersion);
|
|
2039
|
+
if (loaded) {
|
|
2040
|
+
return loaded;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
return this.pull(ref, version);
|
|
2045
|
+
}
|
|
2046
|
+
/** Cache management utilities. */
|
|
2047
|
+
cache = {
|
|
2048
|
+
/** Remove expired cache entries and garbage-collect unreferenced blobs. */
|
|
2049
|
+
clean: () => this._cache.clean(),
|
|
2050
|
+
/** Remove all cached data. */
|
|
2051
|
+
purge: () => this._cache.purge()
|
|
2052
|
+
};
|
|
2053
|
+
};
|
|
2054
|
+
|
|
2055
|
+
// src/index.ts
|
|
2056
|
+
init_frontmatter();
|
|
2057
|
+
|
|
2058
|
+
// src/adapters/index.ts
|
|
2059
|
+
init_claude();
|
|
2060
|
+
init_openai();
|
|
2061
|
+
init_vscode();
|
|
2062
|
+
|
|
2063
|
+
// src/convenience.ts
|
|
2064
|
+
var _config;
|
|
2065
|
+
var _client;
|
|
2066
|
+
function configure(config) {
|
|
2067
|
+
_config = config;
|
|
2068
|
+
_client = void 0;
|
|
2069
|
+
}
|
|
2070
|
+
function getClient() {
|
|
2071
|
+
if (!_client) {
|
|
2072
|
+
_client = new MusherClient(_config);
|
|
2073
|
+
}
|
|
2074
|
+
return _client;
|
|
2075
|
+
}
|
|
2076
|
+
async function pull(ref, version) {
|
|
2077
|
+
return getClient().pull(ref, version);
|
|
2078
|
+
}
|
|
2079
|
+
async function resolve4(ref, version) {
|
|
2080
|
+
return getClient().resolve(ref, version);
|
|
2081
|
+
}
|
|
2082
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2083
|
+
0 && (module.exports = {
|
|
2084
|
+
AgentSpecHandle,
|
|
2085
|
+
ApiError,
|
|
2086
|
+
AssetDetailOutputSchema,
|
|
2087
|
+
AssetSummaryOutputSchema,
|
|
2088
|
+
AssetType,
|
|
2089
|
+
AuthenticationError,
|
|
2090
|
+
Bundle,
|
|
2091
|
+
BundleDetailOutputSchema,
|
|
2092
|
+
BundleLayerOutputSchema,
|
|
2093
|
+
BundleManifestOutputSchema,
|
|
2094
|
+
BundleOutputSchema,
|
|
2095
|
+
BundleRef,
|
|
2096
|
+
BundleResolveOutputSchema,
|
|
2097
|
+
BundleSourceType,
|
|
2098
|
+
BundleVersionDetailOutputSchema,
|
|
2099
|
+
BundleVersionState,
|
|
2100
|
+
BundleVersionSummaryOutputSchema,
|
|
2101
|
+
BundleVisibility,
|
|
2102
|
+
CacheError,
|
|
2103
|
+
FileHandle,
|
|
2104
|
+
ForbiddenError,
|
|
2105
|
+
IntegrityError,
|
|
2106
|
+
ManifestAssetOutputSchema,
|
|
2107
|
+
ManifestDetailOutputSchema,
|
|
2108
|
+
MushError,
|
|
2109
|
+
MusherClient,
|
|
2110
|
+
NetworkError,
|
|
2111
|
+
NotFoundError,
|
|
2112
|
+
PaginationMetaSchema,
|
|
2113
|
+
PromptHandle,
|
|
2114
|
+
RateLimitError,
|
|
2115
|
+
SchemaError,
|
|
2116
|
+
Selection,
|
|
2117
|
+
SkillHandle,
|
|
2118
|
+
TimeoutError,
|
|
2119
|
+
ToolsetHandle,
|
|
2120
|
+
ValidationError,
|
|
2121
|
+
configure,
|
|
2122
|
+
exportClaudePlugin,
|
|
2123
|
+
exportOpenAIInlineSkill,
|
|
2124
|
+
exportOpenAILocalSkill,
|
|
2125
|
+
extractDescription,
|
|
2126
|
+
getClient,
|
|
2127
|
+
installClaudeSkills,
|
|
2128
|
+
installVSCodeSkills,
|
|
2129
|
+
paginatedSchema,
|
|
2130
|
+
parseFrontmatter,
|
|
2131
|
+
pull,
|
|
2132
|
+
resolve,
|
|
2133
|
+
resolveMusherDirs
|
|
2134
|
+
});
|
|
2135
|
+
//# sourceMappingURL=index.cjs.map
|