@prompd/core 0.5.0-beta.14 → 0.5.0-beta.17
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/index.cjs +133 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -35
- package/dist/index.d.ts +52 -35
- package/dist/index.js +133 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3136,12 +3136,35 @@ function isBinaryAsset(name) {
|
|
|
3136
3136
|
const dot = name.lastIndexOf(".");
|
|
3137
3137
|
return dot >= 0 && BINARY_ASSET_EXT.has(name.slice(dot + 1).toLowerCase());
|
|
3138
3138
|
}
|
|
3139
|
+
var MAX_FILE_SIZE_IN_ZIP = 10 * 1024 * 1024;
|
|
3140
|
+
var MAX_TOTAL_EXTRACTED_SIZE = 500 * 1024 * 1024;
|
|
3141
|
+
function isSymlinkEntry(perms) {
|
|
3142
|
+
return typeof perms === "number" && (perms & 61440) === 40960;
|
|
3143
|
+
}
|
|
3139
3144
|
async function extractPdpkg(buffer) {
|
|
3140
3145
|
const zip = await JSZip__default.default.loadAsync(buffer);
|
|
3141
3146
|
const out = /* @__PURE__ */ new Map();
|
|
3147
|
+
let total = 0;
|
|
3142
3148
|
for (const entry of Object.values(zip.files)) {
|
|
3149
|
+
if (entry.name.includes("\0")) {
|
|
3150
|
+
throw new Error(`Security violation: null byte in entry name: ${entry.name}`);
|
|
3151
|
+
}
|
|
3152
|
+
if (entry.name.startsWith("/") || /(^|\/)\.\.(\/|$)/.test(entry.name)) {
|
|
3153
|
+
throw new Error(`Security violation: path traversal in entry: ${entry.name}`);
|
|
3154
|
+
}
|
|
3155
|
+
if (isSymlinkEntry(entry.unixPermissions)) {
|
|
3156
|
+
throw new Error(`Security violation: symlink entry in archive: ${entry.name}`);
|
|
3157
|
+
}
|
|
3143
3158
|
if (entry.dir || isBinaryAsset(entry.name)) continue;
|
|
3144
|
-
|
|
3159
|
+
const bytes = await entry.async("uint8array");
|
|
3160
|
+
if (bytes.length > MAX_FILE_SIZE_IN_ZIP) {
|
|
3161
|
+
throw new Error(`File too large in package: ${entry.name} (${bytes.length} bytes, max ${MAX_FILE_SIZE_IN_ZIP})`);
|
|
3162
|
+
}
|
|
3163
|
+
total += bytes.length;
|
|
3164
|
+
if (total > MAX_TOTAL_EXTRACTED_SIZE) {
|
|
3165
|
+
throw new Error(`Package total decompressed size exceeds limit (${MAX_TOTAL_EXTRACTED_SIZE} bytes). Possible decompression bomb.`);
|
|
3166
|
+
}
|
|
3167
|
+
out.set(entry.name, new TextDecoder().decode(bytes));
|
|
3145
3168
|
}
|
|
3146
3169
|
return out;
|
|
3147
3170
|
}
|
|
@@ -3384,11 +3407,55 @@ function normalizeSegments(p) {
|
|
|
3384
3407
|
}
|
|
3385
3408
|
return out.join("/");
|
|
3386
3409
|
}
|
|
3387
|
-
function
|
|
3410
|
+
function slugify(name) {
|
|
3411
|
+
return name.toLowerCase().replace(/[@/]+/g, "-").replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3412
|
+
}
|
|
3413
|
+
function resolvePackageDir(root, type, name) {
|
|
3388
3414
|
return joinPosix3(root, ".prompd", getInstallDirForType(type), name);
|
|
3389
3415
|
}
|
|
3416
|
+
function resolveInstallDir(root, type, name, version) {
|
|
3417
|
+
return joinPosix3(resolvePackageDir(root, type, name), version);
|
|
3418
|
+
}
|
|
3419
|
+
async function addWorkspaceDependency(store, root, name, version) {
|
|
3420
|
+
if (!store.readFile) return;
|
|
3421
|
+
const manifestPath = joinPosix3(root, "prompd.json");
|
|
3422
|
+
try {
|
|
3423
|
+
const existing = await store.readFile(manifestPath);
|
|
3424
|
+
const manifest = existing && existing.trim() ? JSON.parse(existing) : {};
|
|
3425
|
+
if (!manifest.dependencies || typeof manifest.dependencies !== "object") manifest.dependencies = {};
|
|
3426
|
+
manifest.dependencies[name] = version;
|
|
3427
|
+
await store.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
3428
|
+
} catch {
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
async function removeWorkspaceDependency(store, root, name) {
|
|
3432
|
+
if (!store.readFile) return;
|
|
3433
|
+
const manifestPath = joinPosix3(root, "prompd.json");
|
|
3434
|
+
try {
|
|
3435
|
+
const existing = await store.readFile(manifestPath);
|
|
3436
|
+
if (!existing || !existing.trim()) return;
|
|
3437
|
+
const manifest = JSON.parse(existing);
|
|
3438
|
+
const deps = manifest.dependencies;
|
|
3439
|
+
if (!deps || typeof deps !== "object") return;
|
|
3440
|
+
delete deps[name];
|
|
3441
|
+
await store.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
3442
|
+
} catch {
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
function readManifest(files) {
|
|
3446
|
+
const raw = files.get("manifest.json") ?? files.get("prompd.json");
|
|
3447
|
+
if (!raw) return {};
|
|
3448
|
+
try {
|
|
3449
|
+
return JSON.parse(raw);
|
|
3450
|
+
} catch {
|
|
3451
|
+
return {};
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3390
3454
|
async function installPackage(opts) {
|
|
3391
|
-
|
|
3455
|
+
return installInternal(opts, /* @__PURE__ */ new Set());
|
|
3456
|
+
}
|
|
3457
|
+
async function installInternal(opts, visited) {
|
|
3458
|
+
const { ref, root, store, download, global, tools, deployTool } = opts;
|
|
3392
3459
|
const parsed = parsePackageReference(ref);
|
|
3393
3460
|
const bytes = await download(parsed.name, parsed.version);
|
|
3394
3461
|
if (bytes.length > MAX_PACKAGE_SIZE) {
|
|
@@ -3398,41 +3465,77 @@ async function installPackage(opts) {
|
|
|
3398
3465
|
if (files.size === 0) {
|
|
3399
3466
|
throw new Error(`Package "${parsed.name}" contains no installable files.`);
|
|
3400
3467
|
}
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
const
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
if (
|
|
3409
|
-
|
|
3468
|
+
const m = readManifest(files);
|
|
3469
|
+
const name = typeof m.name === "string" && m.name ? m.name : parsed.name;
|
|
3470
|
+
const version = typeof m.version === "string" && m.version ? m.version : parsed.version;
|
|
3471
|
+
const type = typeof m.type === "string" && isValidPackageType(m.type) ? m.type : opts.type && isValidPackageType(opts.type) ? opts.type : "package";
|
|
3472
|
+
visited.add(name);
|
|
3473
|
+
if (m.dependencies && typeof m.dependencies === "object") {
|
|
3474
|
+
for (const [depName, depVersion] of Object.entries(m.dependencies)) {
|
|
3475
|
+
if (depName === name || visited.has(depName)) continue;
|
|
3476
|
+
await installInternal({ ...opts, ref: `${depName}@${depVersion}`, type: void 0 }, visited);
|
|
3410
3477
|
}
|
|
3411
3478
|
}
|
|
3412
|
-
|
|
3413
|
-
const baseSegments = normalizeSegments(installedPath);
|
|
3414
|
-
await store.removeDir?.(installedPath);
|
|
3479
|
+
let installedPath;
|
|
3415
3480
|
const written = [];
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3481
|
+
if (type === "node-template") {
|
|
3482
|
+
if (!store.writeBytes) {
|
|
3483
|
+
throw new Error("Installing a node-template requires a PackageStore with writeBytes (binary). This host does not support it.");
|
|
3484
|
+
}
|
|
3485
|
+
const dir = joinPosix3(root, ".prompd", getInstallDirForType("node-template"));
|
|
3486
|
+
installedPath = joinPosix3(dir, `${slugify(name)}-${version}.pdpkg`);
|
|
3487
|
+
await store.writeBytes(installedPath, bytes);
|
|
3488
|
+
} else {
|
|
3489
|
+
installedPath = resolveInstallDir(root, type, name, version);
|
|
3490
|
+
const base = normalizeSegments(installedPath);
|
|
3491
|
+
await store.removeDir?.(installedPath);
|
|
3492
|
+
for (const [rel, content] of files) {
|
|
3493
|
+
const dest = joinPosix3(installedPath, rel);
|
|
3494
|
+
if (normalizeSegments(dest) !== base && !normalizeSegments(dest).startsWith(base + "/")) {
|
|
3495
|
+
throw new Error(`Security violation: extracted path escapes install directory: ${rel}`);
|
|
3496
|
+
}
|
|
3497
|
+
await store.writeFile(dest, content);
|
|
3498
|
+
written.push(rel);
|
|
3499
|
+
}
|
|
3500
|
+
await store.writeFile(joinPosix3(installedPath, ".prmdmeta"), JSON.stringify(m, null, 2) + "\n");
|
|
3501
|
+
if (tools && tools.length > 0) {
|
|
3502
|
+
if (type !== "skill") throw new Error(`Tool deploy is only valid for skills, but '${name}' is a ${type}.`);
|
|
3503
|
+
if (!deployTool) throw new Error("tools were requested but no deployTool hook was provided.");
|
|
3504
|
+
for (const tool of tools) await deployTool({ installedPath, name, tool });
|
|
3421
3505
|
}
|
|
3422
|
-
await store.writeFile(dest, content);
|
|
3423
|
-
written.push(rel);
|
|
3424
3506
|
}
|
|
3425
|
-
|
|
3507
|
+
if (!global) await addWorkspaceDependency(store, root, name, version);
|
|
3508
|
+
return { name, version, scope: parsed.scope, type, installedPath, files: written };
|
|
3426
3509
|
}
|
|
3427
3510
|
async function uninstallPackage(opts) {
|
|
3428
|
-
const {
|
|
3429
|
-
if (!store.removeDir)
|
|
3430
|
-
|
|
3511
|
+
const { root, store, global } = opts;
|
|
3512
|
+
if (!store.removeDir) throw new Error("Uninstall requires a PackageStore with removeDir.");
|
|
3513
|
+
const parsed = parsePackageReference(opts.ref);
|
|
3514
|
+
const name = parsed.name;
|
|
3515
|
+
const removed = [];
|
|
3516
|
+
for (const type of ["package", "workflow", "skill", "node-template"]) {
|
|
3517
|
+
if (type === "node-template") {
|
|
3518
|
+
const dir = joinPosix3(root, ".prompd", getInstallDirForType("node-template"));
|
|
3519
|
+
if (!store.readdir || !store.removeFile) continue;
|
|
3520
|
+
try {
|
|
3521
|
+
const prefix = `${slugify(name)}-`;
|
|
3522
|
+
for (const entry of await store.readdir(dir)) {
|
|
3523
|
+
if (entry.startsWith(prefix) && entry.endsWith(".pdpkg")) {
|
|
3524
|
+
const p = joinPosix3(dir, entry);
|
|
3525
|
+
await store.removeFile(p);
|
|
3526
|
+
removed.push(p);
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
} catch {
|
|
3530
|
+
}
|
|
3531
|
+
} else {
|
|
3532
|
+
const dir = resolvePackageDir(root, type, name);
|
|
3533
|
+
await store.removeDir(dir);
|
|
3534
|
+
removed.push(dir);
|
|
3535
|
+
}
|
|
3431
3536
|
}
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
await store.removeDir(installedPath);
|
|
3435
|
-
return { name: parsed.name, scope: parsed.scope, installedPath };
|
|
3537
|
+
if (!global) await removeWorkspaceDependency(store, root, name);
|
|
3538
|
+
return { name, scope: parsed.scope, removed };
|
|
3436
3539
|
}
|
|
3437
3540
|
|
|
3438
3541
|
// src/lib/compiler/index.ts
|