@aipm-registry/cli 0.3.5 → 0.4.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 +185 -1
- package/README.md +52 -13
- package/dist/bin.cjs +534 -146
- package/dist/bin.cjs.map +4 -4
- package/package.json +4 -4
package/dist/bin.cjs
CHANGED
|
@@ -4178,8 +4178,8 @@ var init_manifest = __esm({
|
|
|
4178
4178
|
"use strict";
|
|
4179
4179
|
init_zod();
|
|
4180
4180
|
init_scope_name();
|
|
4181
|
-
AiToolSchema = external_exports.enum(["cursor", "claude", "*"]);
|
|
4182
|
-
ALL_TOOLS = ["cursor", "claude"];
|
|
4181
|
+
AiToolSchema = external_exports.enum(["cursor", "claude", "codex", "*"]);
|
|
4182
|
+
ALL_TOOLS = ["cursor", "claude", "codex"];
|
|
4183
4183
|
PackageExampleSchema = external_exports.object({
|
|
4184
4184
|
title: external_exports.string().trim().min(1).max(80),
|
|
4185
4185
|
description: external_exports.string().trim().min(1).max(240).optional(),
|
|
@@ -4237,7 +4237,7 @@ var init_manifest = __esm({
|
|
|
4237
4237
|
});
|
|
4238
4238
|
|
|
4239
4239
|
// ../../packages/schemas/dist/package-json.js
|
|
4240
|
-
var scopedPackageKey, ProjectPackageJsonSchema;
|
|
4240
|
+
var scopedPackageKey, promptAliasKey, ProjectPackageJsonSchema;
|
|
4241
4241
|
var init_package_json = __esm({
|
|
4242
4242
|
"../../packages/schemas/dist/package-json.js"() {
|
|
4243
4243
|
"use strict";
|
|
@@ -4245,17 +4245,19 @@ var init_package_json = __esm({
|
|
|
4245
4245
|
init_scope_name();
|
|
4246
4246
|
init_manifest();
|
|
4247
4247
|
scopedPackageKey = external_exports.string().regex(SCOPE_NAME_REGEX);
|
|
4248
|
+
promptAliasKey = external_exports.string().trim().min(1).max(120);
|
|
4248
4249
|
ProjectPackageJsonSchema = external_exports.object({
|
|
4249
4250
|
schemaVersion: external_exports.literal("0.1"),
|
|
4250
4251
|
registry: external_exports.string().url(),
|
|
4251
4252
|
preferredTools: external_exports.array(AiToolSchema).optional(),
|
|
4252
|
-
packages: external_exports.record(scopedPackageKey, external_exports.string().min(1))
|
|
4253
|
+
packages: external_exports.record(scopedPackageKey, external_exports.string().min(1)),
|
|
4254
|
+
prompts: external_exports.record(promptAliasKey, external_exports.string().url()).default({})
|
|
4253
4255
|
});
|
|
4254
4256
|
}
|
|
4255
4257
|
});
|
|
4256
4258
|
|
|
4257
4259
|
// ../../packages/schemas/dist/lockfile.js
|
|
4258
|
-
var scopedPackageKey2, InstalledPathsSchema, LockfilePackageEntrySchema, LockfileSchema;
|
|
4260
|
+
var scopedPackageKey2, InstalledPathsSchema, LockfilePromptEntrySchema, LockfilePackageEntrySchema, LockfileSchema;
|
|
4259
4261
|
var init_lockfile = __esm({
|
|
4260
4262
|
"../../packages/schemas/dist/lockfile.js"() {
|
|
4261
4263
|
"use strict";
|
|
@@ -4264,6 +4266,15 @@ var init_lockfile = __esm({
|
|
|
4264
4266
|
init_manifest();
|
|
4265
4267
|
scopedPackageKey2 = external_exports.string().regex(SCOPE_NAME_REGEX);
|
|
4266
4268
|
InstalledPathsSchema = external_exports.record(AiToolSchema, external_exports.array(external_exports.string()));
|
|
4269
|
+
LockfilePromptEntrySchema = external_exports.object({
|
|
4270
|
+
id: external_exports.string().min(1),
|
|
4271
|
+
url: external_exports.string().url(),
|
|
4272
|
+
publisher: external_exports.string().min(1),
|
|
4273
|
+
slug: external_exports.string().min(1),
|
|
4274
|
+
contentHash: external_exports.string().min(1),
|
|
4275
|
+
updatedAt: external_exports.string().min(1),
|
|
4276
|
+
installedPath: external_exports.string().min(1)
|
|
4277
|
+
});
|
|
4267
4278
|
LockfilePackageEntrySchema = external_exports.object({
|
|
4268
4279
|
version: external_exports.string(),
|
|
4269
4280
|
integrity: external_exports.string(),
|
|
@@ -4283,7 +4294,8 @@ var init_lockfile = __esm({
|
|
|
4283
4294
|
});
|
|
4284
4295
|
LockfileSchema = external_exports.object({
|
|
4285
4296
|
schemaVersion: external_exports.literal("0.1"),
|
|
4286
|
-
packages: external_exports.record(scopedPackageKey2, LockfilePackageEntrySchema)
|
|
4297
|
+
packages: external_exports.record(scopedPackageKey2, LockfilePackageEntrySchema),
|
|
4298
|
+
prompts: external_exports.record(external_exports.string().min(1), LockfilePromptEntrySchema).default({})
|
|
4287
4299
|
});
|
|
4288
4300
|
}
|
|
4289
4301
|
});
|
|
@@ -4314,6 +4326,8 @@ async function detectToolsInProject(projectRoot) {
|
|
|
4314
4326
|
detected.push("cursor");
|
|
4315
4327
|
if (await pathExists((0, import_node_path2.join)(projectRoot, ".claude")))
|
|
4316
4328
|
detected.push("claude");
|
|
4329
|
+
if (await pathExists((0, import_node_path2.join)(projectRoot, ".codex")))
|
|
4330
|
+
detected.push("codex");
|
|
4317
4331
|
return detected;
|
|
4318
4332
|
}
|
|
4319
4333
|
function manifestAllowsTool(manifest, tool) {
|
|
@@ -4404,6 +4418,29 @@ var init_dist3 = __esm({
|
|
|
4404
4418
|
}
|
|
4405
4419
|
});
|
|
4406
4420
|
|
|
4421
|
+
// ../../packages/adapter-codex/dist/index.js
|
|
4422
|
+
var import_promises4, import_node_path5, CodexSkillAdapter, codexSkillAdapter;
|
|
4423
|
+
var init_dist4 = __esm({
|
|
4424
|
+
"../../packages/adapter-codex/dist/index.js"() {
|
|
4425
|
+
"use strict";
|
|
4426
|
+
import_promises4 = require("node:fs/promises");
|
|
4427
|
+
import_node_path5 = require("node:path");
|
|
4428
|
+
init_dist();
|
|
4429
|
+
CodexSkillAdapter = class {
|
|
4430
|
+
tool = "codex";
|
|
4431
|
+
async installSkill(input2) {
|
|
4432
|
+
const short = shortNameFromScopeName(input2.packageName);
|
|
4433
|
+
const skillDir = (0, import_node_path5.join)(input2.projectRoot, ".agents", "skills", short);
|
|
4434
|
+
await (0, import_promises4.mkdir)(skillDir, { recursive: true });
|
|
4435
|
+
const filePath = (0, import_node_path5.join)(skillDir, "SKILL.md");
|
|
4436
|
+
await (0, import_promises4.writeFile)(filePath, input2.skillMarkdown, "utf8");
|
|
4437
|
+
return { writtenPaths: [filePath] };
|
|
4438
|
+
}
|
|
4439
|
+
};
|
|
4440
|
+
codexSkillAdapter = new CodexSkillAdapter();
|
|
4441
|
+
}
|
|
4442
|
+
});
|
|
4443
|
+
|
|
4407
4444
|
// ../../packages/engine/dist/install-skill.js
|
|
4408
4445
|
async function installSkillPackage(options) {
|
|
4409
4446
|
const tools = await resolveInstallTools({
|
|
@@ -4413,7 +4450,7 @@ async function installSkillPackage(options) {
|
|
|
4413
4450
|
explicitTarget: options.explicitTarget
|
|
4414
4451
|
});
|
|
4415
4452
|
if (tools.length === 0) {
|
|
4416
|
-
throw new Error("No AI tool detected (.cursor
|
|
4453
|
+
throw new Error("No AI tool detected (.cursor/, .claude/, or .codex/). Use --target cursor|claude|codex|* or set preferredTools in aipm.package.json.");
|
|
4417
4454
|
}
|
|
4418
4455
|
const installed = {};
|
|
4419
4456
|
for (const tool of tools) {
|
|
@@ -4434,10 +4471,12 @@ var init_install_skill = __esm({
|
|
|
4434
4471
|
"use strict";
|
|
4435
4472
|
init_dist2();
|
|
4436
4473
|
init_dist3();
|
|
4474
|
+
init_dist4();
|
|
4437
4475
|
init_detect_tools();
|
|
4438
4476
|
adapters = {
|
|
4439
4477
|
cursor: cursorSkillAdapter,
|
|
4440
|
-
claude: claudeSkillAdapter
|
|
4478
|
+
claude: claudeSkillAdapter,
|
|
4479
|
+
codex: codexSkillAdapter
|
|
4441
4480
|
};
|
|
4442
4481
|
}
|
|
4443
4482
|
});
|
|
@@ -4449,7 +4488,7 @@ __export(dist_exports, {
|
|
|
4449
4488
|
installSkillPackage: () => installSkillPackage,
|
|
4450
4489
|
resolveInstallTools: () => resolveInstallTools
|
|
4451
4490
|
});
|
|
4452
|
-
var
|
|
4491
|
+
var init_dist5 = __esm({
|
|
4453
4492
|
"../../packages/engine/dist/index.js"() {
|
|
4454
4493
|
"use strict";
|
|
4455
4494
|
init_detect_tools();
|
|
@@ -7826,28 +7865,28 @@ function useColor() {
|
|
|
7826
7865
|
var program = new Command();
|
|
7827
7866
|
|
|
7828
7867
|
// src/bin.ts
|
|
7829
|
-
var
|
|
7868
|
+
var import_node_crypto3 = require("node:crypto");
|
|
7830
7869
|
var import_node_child_process4 = require("node:child_process");
|
|
7831
7870
|
var import_node_http = require("node:http");
|
|
7832
|
-
var
|
|
7833
|
-
var
|
|
7871
|
+
var import_promises12 = require("node:fs/promises");
|
|
7872
|
+
var import_node_path15 = require("node:path");
|
|
7834
7873
|
var import_node_process5 = require("node:process");
|
|
7835
7874
|
init_dist();
|
|
7836
|
-
|
|
7875
|
+
init_dist5();
|
|
7837
7876
|
|
|
7838
7877
|
// src/pack.ts
|
|
7839
7878
|
var import_node_child_process2 = require("node:child_process");
|
|
7840
7879
|
var import_node_util3 = require("node:util");
|
|
7841
|
-
var
|
|
7842
|
-
var
|
|
7880
|
+
var import_promises6 = require("node:fs/promises");
|
|
7881
|
+
var import_node_path7 = require("node:path");
|
|
7843
7882
|
var import_node_os = require("node:os");
|
|
7844
7883
|
|
|
7845
7884
|
// src/publish-state.ts
|
|
7846
7885
|
var import_node_crypto = require("node:crypto");
|
|
7847
|
-
var
|
|
7848
|
-
var
|
|
7886
|
+
var import_promises5 = require("node:fs/promises");
|
|
7887
|
+
var import_node_path6 = require("node:path");
|
|
7849
7888
|
init_dist();
|
|
7850
|
-
var STATE_PATH = (0,
|
|
7889
|
+
var STATE_PATH = (0, import_node_path6.join)(".aipm", "publish-state.json");
|
|
7851
7890
|
var IGNORE_FILE = ".aipmignore";
|
|
7852
7891
|
var MAX_PACKAGE_BYTES = 50 * 1024 * 1024;
|
|
7853
7892
|
var EXCLUDED_SEGMENTS = /* @__PURE__ */ new Set([".aipm", ".git", "node_modules", "dist", ".next"]);
|
|
@@ -7862,11 +7901,11 @@ var SECRET_PATTERNS = [
|
|
|
7862
7901
|
/<publishData/i
|
|
7863
7902
|
];
|
|
7864
7903
|
function publishStatePath(root) {
|
|
7865
|
-
return (0,
|
|
7904
|
+
return (0, import_node_path6.join)(root, STATE_PATH);
|
|
7866
7905
|
}
|
|
7867
7906
|
function normalizePublishPath(root, filePath) {
|
|
7868
|
-
const abs = (0,
|
|
7869
|
-
const rel = (0,
|
|
7907
|
+
const abs = (0, import_node_path6.resolve)(root, filePath);
|
|
7908
|
+
const rel = (0, import_node_path6.normalize)((0, import_node_path6.relative)(root, abs)).split(import_node_path6.sep).join("/");
|
|
7870
7909
|
if (!rel || rel === ".") return ".";
|
|
7871
7910
|
if (rel.startsWith("../") || rel === ".." || rel.startsWith("/")) {
|
|
7872
7911
|
throw new Error(`Path is outside the skill folder: ${filePath}`);
|
|
@@ -7883,7 +7922,7 @@ function isExcludedPublishPath(rel) {
|
|
|
7883
7922
|
}
|
|
7884
7923
|
async function readAipmIgnore(root) {
|
|
7885
7924
|
try {
|
|
7886
|
-
const raw = await (0,
|
|
7925
|
+
const raw = await (0, import_promises5.readFile)((0, import_node_path6.join)(root, IGNORE_FILE), "utf8");
|
|
7887
7926
|
return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
7888
7927
|
} catch {
|
|
7889
7928
|
return [];
|
|
@@ -7904,7 +7943,7 @@ async function isIgnoredByAipmIgnore(root, rel) {
|
|
|
7904
7943
|
return rules.some((rule) => matchesIgnoreRule(rel, rule));
|
|
7905
7944
|
}
|
|
7906
7945
|
async function assertNoObviousSecrets(path2, rel) {
|
|
7907
|
-
const data = await (0,
|
|
7946
|
+
const data = await (0, import_promises5.readFile)(path2);
|
|
7908
7947
|
if (data.includes(0)) return;
|
|
7909
7948
|
const text = data.toString("utf8");
|
|
7910
7949
|
if (SECRET_PATTERNS.some((pattern) => pattern.test(text))) {
|
|
@@ -7912,7 +7951,7 @@ async function assertNoObviousSecrets(path2, rel) {
|
|
|
7912
7951
|
}
|
|
7913
7952
|
}
|
|
7914
7953
|
async function fileHash(path2) {
|
|
7915
|
-
const data = await (0,
|
|
7954
|
+
const data = await (0, import_promises5.readFile)(path2);
|
|
7916
7955
|
return {
|
|
7917
7956
|
hash: (0, import_node_crypto.createHash)("sha256").update(data).digest("hex"),
|
|
7918
7957
|
size: data.length
|
|
@@ -7920,7 +7959,7 @@ async function fileHash(path2) {
|
|
|
7920
7959
|
}
|
|
7921
7960
|
async function readPublishState(root) {
|
|
7922
7961
|
try {
|
|
7923
|
-
const raw = await (0,
|
|
7962
|
+
const raw = await (0, import_promises5.readFile)(publishStatePath(root), "utf8");
|
|
7924
7963
|
const parsed = JSON.parse(raw);
|
|
7925
7964
|
return {
|
|
7926
7965
|
schemaVersion: "0.1",
|
|
@@ -7932,18 +7971,18 @@ async function readPublishState(root) {
|
|
|
7932
7971
|
}
|
|
7933
7972
|
async function writePublishState(root, state) {
|
|
7934
7973
|
const path2 = publishStatePath(root);
|
|
7935
|
-
await (0,
|
|
7974
|
+
await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(path2), { recursive: true });
|
|
7936
7975
|
const files = [...state.files].sort((a, b) => a.path.localeCompare(b.path));
|
|
7937
|
-
await (0,
|
|
7976
|
+
await (0, import_promises5.writeFile)(path2, JSON.stringify({ schemaVersion: "0.1", files }, null, 2) + "\n", "utf8");
|
|
7938
7977
|
}
|
|
7939
7978
|
async function expandPublishPath(root, rel) {
|
|
7940
7979
|
if (isExcludedPublishPath(rel)) return [];
|
|
7941
7980
|
if (await isIgnoredByAipmIgnore(root, rel)) return [];
|
|
7942
|
-
const abs = (0,
|
|
7943
|
-
const info = await (0,
|
|
7981
|
+
const abs = (0, import_node_path6.join)(root, rel);
|
|
7982
|
+
const info = await (0, import_promises5.stat)(abs);
|
|
7944
7983
|
if (info.isFile()) return [rel];
|
|
7945
7984
|
if (!info.isDirectory()) return [];
|
|
7946
|
-
const entries = await (0,
|
|
7985
|
+
const entries = await (0, import_promises5.readdir)(abs);
|
|
7947
7986
|
const nested = await Promise.all(
|
|
7948
7987
|
entries.map((entry) => expandPublishPath(root, `${rel === "." ? "" : `${rel}/`}${entry}`))
|
|
7949
7988
|
);
|
|
@@ -7959,7 +7998,7 @@ async function addPublishFiles(root, paths) {
|
|
|
7959
7998
|
for (const rel of files) {
|
|
7960
7999
|
if (isExcludedPublishPath(rel)) continue;
|
|
7961
8000
|
if (await isIgnoredByAipmIgnore(root, rel)) continue;
|
|
7962
|
-
const hashed = await fileHash((0,
|
|
8001
|
+
const hashed = await fileHash((0, import_node_path6.join)(root, rel));
|
|
7963
8002
|
byPath.set(rel, { path: rel, ...hashed });
|
|
7964
8003
|
}
|
|
7965
8004
|
}
|
|
@@ -7978,11 +8017,11 @@ async function removePublishFiles(root, paths) {
|
|
|
7978
8017
|
return next;
|
|
7979
8018
|
}
|
|
7980
8019
|
async function resetPublishState(root) {
|
|
7981
|
-
await (0,
|
|
8020
|
+
await (0, import_promises5.rm)(publishStatePath(root), { force: true });
|
|
7982
8021
|
}
|
|
7983
8022
|
async function readManifest(root) {
|
|
7984
8023
|
try {
|
|
7985
|
-
const raw = await (0,
|
|
8024
|
+
const raw = await (0, import_promises5.readFile)((0, import_node_path6.join)(root, "aipm.manifest.json"), "utf8");
|
|
7986
8025
|
return PackageManifestSchema.parse(JSON.parse(raw));
|
|
7987
8026
|
} catch (error) {
|
|
7988
8027
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
@@ -8015,8 +8054,8 @@ async function validatePublishState(root) {
|
|
|
8015
8054
|
if (await isIgnoredByAipmIgnore(root, entry.path)) {
|
|
8016
8055
|
throw new Error(`Refusing to publish ignored path: ${entry.path}`);
|
|
8017
8056
|
}
|
|
8018
|
-
const abs = (0,
|
|
8019
|
-
const info = await (0,
|
|
8057
|
+
const abs = (0, import_node_path6.join)(root, entry.path);
|
|
8058
|
+
const info = await (0, import_promises5.stat)(abs).catch(() => null);
|
|
8020
8059
|
if (!info?.isFile()) throw new Error(`Staged file is missing: ${entry.path}`);
|
|
8021
8060
|
const hashed = await fileHash(abs);
|
|
8022
8061
|
if (hashed.hash !== entry.hash) {
|
|
@@ -8032,7 +8071,7 @@ async function statusPublishState(root) {
|
|
|
8032
8071
|
const state = await readPublishState(root);
|
|
8033
8072
|
const rows = [];
|
|
8034
8073
|
for (const entry of state.files) {
|
|
8035
|
-
const current = await fileHash((0,
|
|
8074
|
+
const current = await fileHash((0, import_node_path6.join)(root, entry.path)).catch(() => null);
|
|
8036
8075
|
rows.push({ ...entry, changed: !current || current.hash !== entry.hash });
|
|
8037
8076
|
}
|
|
8038
8077
|
return rows;
|
|
@@ -8040,9 +8079,9 @@ async function statusPublishState(root) {
|
|
|
8040
8079
|
async function copyStagedFiles(root, destination) {
|
|
8041
8080
|
const state = await readPublishState(root);
|
|
8042
8081
|
for (const entry of state.files) {
|
|
8043
|
-
const target = (0,
|
|
8044
|
-
await (0,
|
|
8045
|
-
await (0,
|
|
8082
|
+
const target = (0, import_node_path6.join)(destination, entry.path);
|
|
8083
|
+
await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(target), { recursive: true });
|
|
8084
|
+
await (0, import_promises5.cp)((0, import_node_path6.join)(root, entry.path), target);
|
|
8046
8085
|
}
|
|
8047
8086
|
}
|
|
8048
8087
|
|
|
@@ -8056,21 +8095,21 @@ async function packDirectory(dir) {
|
|
|
8056
8095
|
return Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout);
|
|
8057
8096
|
}
|
|
8058
8097
|
async function packStagedFiles(root) {
|
|
8059
|
-
const tempDir = await (0,
|
|
8098
|
+
const tempDir = await (0, import_promises6.mkdtemp)((0, import_node_path7.join)((0, import_node_os.tmpdir)(), "aipm-publish-stage-"));
|
|
8060
8099
|
try {
|
|
8061
8100
|
await copyStagedFiles(root, tempDir);
|
|
8062
8101
|
return await packDirectory(tempDir);
|
|
8063
8102
|
} finally {
|
|
8064
|
-
await (0,
|
|
8103
|
+
await (0, import_promises6.rm)(tempDir, { recursive: true, force: true });
|
|
8065
8104
|
}
|
|
8066
8105
|
}
|
|
8067
8106
|
async function unpackTarballToDirectory(tarball) {
|
|
8068
|
-
const { mkdtemp: mkdtemp2, writeFile:
|
|
8069
|
-
const { join:
|
|
8107
|
+
const { mkdtemp: mkdtemp2, writeFile: writeFile9 } = await import("node:fs/promises");
|
|
8108
|
+
const { join: join15 } = await import("node:path");
|
|
8070
8109
|
const { tmpdir: tmpdir2 } = await import("node:os");
|
|
8071
|
-
const tempDir = await mkdtemp2(
|
|
8072
|
-
const tgzPath =
|
|
8073
|
-
await
|
|
8110
|
+
const tempDir = await mkdtemp2(join15(tmpdir2(), "aipm-install-"));
|
|
8111
|
+
const tgzPath = join15(tempDir, "pkg.tgz");
|
|
8112
|
+
await writeFile9(tgzPath, tarball);
|
|
8074
8113
|
await execFileAsync("tar", ["-xzf", tgzPath, "-C", tempDir]);
|
|
8075
8114
|
return tempDir;
|
|
8076
8115
|
}
|
|
@@ -8229,18 +8268,53 @@ async function recordPackageInstall(registry, name, token) {
|
|
|
8229
8268
|
}
|
|
8230
8269
|
return res.json();
|
|
8231
8270
|
}
|
|
8271
|
+
async function fetchPromptDetail(registry, publisher, slug) {
|
|
8272
|
+
const base = registry.replace(/\/$/, "");
|
|
8273
|
+
const url = `${base}/v1/prompts/${encodeURIComponent(publisher)}/${encodeURIComponent(slug)}`;
|
|
8274
|
+
const res = await registryFetch(url, base);
|
|
8275
|
+
if (!res.ok) throw new Error(`Prompt not found: @${publisher}/${slug} (${res.status})`);
|
|
8276
|
+
return res.json();
|
|
8277
|
+
}
|
|
8278
|
+
async function recordPromptCopy(registry, publisher, slug) {
|
|
8279
|
+
const base = registry.replace(/\/$/, "");
|
|
8280
|
+
const url = `${base}/v1/prompts/${encodeURIComponent(publisher)}/${encodeURIComponent(slug)}/copy`;
|
|
8281
|
+
const res = await registryFetch(url, base, { method: "POST" });
|
|
8282
|
+
if (!res.ok) throw new Error(`Prompt copy recording failed: ${res.status}`);
|
|
8283
|
+
}
|
|
8284
|
+
async function publishPrompt(registry, input2, accessToken, sampleImage) {
|
|
8285
|
+
const base = registry.replace(/\/$/, "");
|
|
8286
|
+
const form = new FormData();
|
|
8287
|
+
form.append("data", JSON.stringify(input2));
|
|
8288
|
+
if (sampleImage) {
|
|
8289
|
+
form.append(
|
|
8290
|
+
"sampleImage",
|
|
8291
|
+
new Blob([sampleImage.data], { type: sampleImage.contentType }),
|
|
8292
|
+
sampleImage.filename
|
|
8293
|
+
);
|
|
8294
|
+
}
|
|
8295
|
+
const res = await registryFetch(`${base}/v1/prompts`, base, {
|
|
8296
|
+
method: "POST",
|
|
8297
|
+
headers: registryAuthHeaders(accessToken),
|
|
8298
|
+
body: form
|
|
8299
|
+
});
|
|
8300
|
+
if (!res.ok) {
|
|
8301
|
+
const error = await res.json().catch(() => ({}));
|
|
8302
|
+
throw new Error(error.error ?? `Prompt publish failed: ${res.status}`);
|
|
8303
|
+
}
|
|
8304
|
+
return res.json();
|
|
8305
|
+
}
|
|
8232
8306
|
|
|
8233
8307
|
// src/auth-store.ts
|
|
8234
|
-
var
|
|
8308
|
+
var import_promises7 = require("node:fs/promises");
|
|
8235
8309
|
var import_node_os2 = require("node:os");
|
|
8236
|
-
var
|
|
8237
|
-
var AUTH_FILE = (0,
|
|
8310
|
+
var import_node_path8 = require("node:path");
|
|
8311
|
+
var AUTH_FILE = (0, import_node_path8.join)((0, import_node_os2.homedir)(), ".aipm", "auth.json");
|
|
8238
8312
|
function normalizeRegistry(registry) {
|
|
8239
8313
|
return registry.replace(/\/$/, "");
|
|
8240
8314
|
}
|
|
8241
8315
|
async function readAuthStore() {
|
|
8242
8316
|
try {
|
|
8243
|
-
const raw = await (0,
|
|
8317
|
+
const raw = await (0, import_promises7.readFile)(AUTH_FILE, "utf8");
|
|
8244
8318
|
const parsed = JSON.parse(raw);
|
|
8245
8319
|
return { registries: parsed.registries ?? {} };
|
|
8246
8320
|
} catch {
|
|
@@ -8248,9 +8322,9 @@ async function readAuthStore() {
|
|
|
8248
8322
|
}
|
|
8249
8323
|
}
|
|
8250
8324
|
async function writeAuthStore(store) {
|
|
8251
|
-
await (0,
|
|
8252
|
-
await (0,
|
|
8253
|
-
await (0,
|
|
8325
|
+
await (0, import_promises7.mkdir)((0, import_node_path8.dirname)(AUTH_FILE), { recursive: true });
|
|
8326
|
+
await (0, import_promises7.writeFile)(AUTH_FILE, JSON.stringify(store, null, 2) + "\n", "utf8");
|
|
8327
|
+
await (0, import_promises7.chmod)(AUTH_FILE, 384).catch(() => void 0);
|
|
8254
8328
|
}
|
|
8255
8329
|
async function getStoredRegistryAuth(registry) {
|
|
8256
8330
|
const store = await readAuthStore();
|
|
@@ -8279,41 +8353,41 @@ function isAccessTokenFresh(auth, skewMs = 6e4) {
|
|
|
8279
8353
|
}
|
|
8280
8354
|
|
|
8281
8355
|
// src/install-one.ts
|
|
8282
|
-
|
|
8283
|
-
var
|
|
8284
|
-
var
|
|
8356
|
+
init_dist5();
|
|
8357
|
+
var import_promises9 = require("node:fs/promises");
|
|
8358
|
+
var import_node_path10 = require("node:path");
|
|
8285
8359
|
|
|
8286
8360
|
// src/project-files.ts
|
|
8287
|
-
var
|
|
8288
|
-
var
|
|
8361
|
+
var import_promises8 = require("node:fs/promises");
|
|
8362
|
+
var import_node_path9 = require("node:path");
|
|
8289
8363
|
init_dist();
|
|
8290
8364
|
var PACKAGE_JSON = "aipm.package.json";
|
|
8291
8365
|
var LOCKFILE = "aipm-lock.json";
|
|
8292
8366
|
async function readProjectPackageJson(projectRoot) {
|
|
8293
8367
|
try {
|
|
8294
|
-
const raw = await (0,
|
|
8368
|
+
const raw = await (0, import_promises8.readFile)((0, import_node_path9.join)(projectRoot, PACKAGE_JSON), "utf8");
|
|
8295
8369
|
return ProjectPackageJsonSchema.parse(JSON.parse(raw));
|
|
8296
8370
|
} catch {
|
|
8297
8371
|
return null;
|
|
8298
8372
|
}
|
|
8299
8373
|
}
|
|
8300
8374
|
async function writeProjectPackageJson(projectRoot, data) {
|
|
8301
|
-
await (0,
|
|
8302
|
-
(0,
|
|
8375
|
+
await (0, import_promises8.writeFile)(
|
|
8376
|
+
(0, import_node_path9.join)(projectRoot, PACKAGE_JSON),
|
|
8303
8377
|
JSON.stringify(data, null, 2) + "\n",
|
|
8304
8378
|
"utf8"
|
|
8305
8379
|
);
|
|
8306
8380
|
}
|
|
8307
8381
|
async function readLockfile(projectRoot) {
|
|
8308
8382
|
try {
|
|
8309
|
-
const raw = await (0,
|
|
8383
|
+
const raw = await (0, import_promises8.readFile)((0, import_node_path9.join)(projectRoot, LOCKFILE), "utf8");
|
|
8310
8384
|
return LockfileSchema.parse(JSON.parse(raw));
|
|
8311
8385
|
} catch {
|
|
8312
8386
|
return null;
|
|
8313
8387
|
}
|
|
8314
8388
|
}
|
|
8315
8389
|
async function writeLockfile(projectRoot, data) {
|
|
8316
|
-
await (0,
|
|
8390
|
+
await (0, import_promises8.writeFile)((0, import_node_path9.join)(projectRoot, LOCKFILE), JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
8317
8391
|
}
|
|
8318
8392
|
function upsertLockEntry(lock, name, entry) {
|
|
8319
8393
|
return {
|
|
@@ -8321,6 +8395,12 @@ function upsertLockEntry(lock, name, entry) {
|
|
|
8321
8395
|
packages: { ...lock.packages, [name]: entry }
|
|
8322
8396
|
};
|
|
8323
8397
|
}
|
|
8398
|
+
function upsertPromptLockEntry(lock, name, entry) {
|
|
8399
|
+
return {
|
|
8400
|
+
...lock,
|
|
8401
|
+
prompts: { ...lock.prompts, [name]: entry }
|
|
8402
|
+
};
|
|
8403
|
+
}
|
|
8324
8404
|
function resolveRegistryUrl(project, flag, fallback) {
|
|
8325
8405
|
const fromEnv = process.env.AIPM_REGISTRY_URL ?? process.env.AIPM_REGISTRY;
|
|
8326
8406
|
if (flag) return flag.replace(/\/$/, "");
|
|
@@ -8331,15 +8411,17 @@ function resolveRegistryUrl(project, flag, fallback) {
|
|
|
8331
8411
|
}
|
|
8332
8412
|
function parseTargetFlag(target) {
|
|
8333
8413
|
if (!target) return void 0;
|
|
8334
|
-
if (target === "cursor" || target === "claude" || target === "*")
|
|
8335
|
-
|
|
8414
|
+
if (target === "cursor" || target === "claude" || target === "codex" || target === "*") {
|
|
8415
|
+
return target;
|
|
8416
|
+
}
|
|
8417
|
+
throw new Error('--target must be "cursor", "claude", "codex", or "*"');
|
|
8336
8418
|
}
|
|
8337
8419
|
function parseTargetsFlag(value) {
|
|
8338
8420
|
const targets = value.split(",").map((target) => target.trim()).filter(Boolean);
|
|
8339
8421
|
if (targets.length === 0) throw new Error("At least one target is required.");
|
|
8340
8422
|
for (const target of targets) {
|
|
8341
|
-
if (target !== "cursor" && target !== "claude" && target !== "*") {
|
|
8342
|
-
throw new Error('--targets must contain only "cursor", "claude", and/or "*"');
|
|
8423
|
+
if (target !== "cursor" && target !== "claude" && target !== "codex" && target !== "*") {
|
|
8424
|
+
throw new Error('--targets must contain only "cursor", "claude", "codex", and/or "*"');
|
|
8343
8425
|
}
|
|
8344
8426
|
}
|
|
8345
8427
|
const unique = [...new Set(targets)];
|
|
@@ -8355,13 +8437,13 @@ async function promptForTool() {
|
|
|
8355
8437
|
try {
|
|
8356
8438
|
while (true) {
|
|
8357
8439
|
const answer = await rl.question(
|
|
8358
|
-
"Which AI tool should this skill be installed for? (cursor/claude): "
|
|
8440
|
+
"Which AI tool should this skill be installed for? (cursor/claude/codex): "
|
|
8359
8441
|
);
|
|
8360
8442
|
const normalized = answer.trim().toLowerCase();
|
|
8361
|
-
if (normalized === "cursor" || normalized === "claude") {
|
|
8443
|
+
if (normalized === "cursor" || normalized === "claude" || normalized === "codex") {
|
|
8362
8444
|
return normalized;
|
|
8363
8445
|
}
|
|
8364
|
-
console.log('Please enter "cursor" or "
|
|
8446
|
+
console.log('Please enter "cursor", "claude", or "codex".');
|
|
8365
8447
|
}
|
|
8366
8448
|
} finally {
|
|
8367
8449
|
rl.close();
|
|
@@ -8380,7 +8462,7 @@ async function promptForConfirmation(question) {
|
|
|
8380
8462
|
|
|
8381
8463
|
// src/install-one.ts
|
|
8382
8464
|
function normalizeRelativePath(path2) {
|
|
8383
|
-
return (0,
|
|
8465
|
+
return (0, import_node_path10.normalize)(path2).split(import_node_path10.sep).join("/");
|
|
8384
8466
|
}
|
|
8385
8467
|
function assertSafeRelativePath(path2) {
|
|
8386
8468
|
const rel = normalizeRelativePath(path2.trim());
|
|
@@ -8391,8 +8473,8 @@ function assertSafeRelativePath(path2) {
|
|
|
8391
8473
|
}
|
|
8392
8474
|
function safeJoin(root, relPath) {
|
|
8393
8475
|
const rel = assertSafeRelativePath(relPath);
|
|
8394
|
-
const target = (0,
|
|
8395
|
-
const fromRoot = normalizeRelativePath((0,
|
|
8476
|
+
const target = (0, import_node_path10.resolve)(root, rel);
|
|
8477
|
+
const fromRoot = normalizeRelativePath((0, import_node_path10.relative)(root, target));
|
|
8396
8478
|
if (fromRoot === ".." || fromRoot.startsWith("../") || fromRoot.startsWith("/")) {
|
|
8397
8479
|
throw new Error(`Unsafe install path: ${relPath}`);
|
|
8398
8480
|
}
|
|
@@ -8403,12 +8485,12 @@ function packageHelperSlug(name) {
|
|
|
8403
8485
|
return `${scope}__${pkg}`;
|
|
8404
8486
|
}
|
|
8405
8487
|
function helperRootFor(configRoot, packageName, version) {
|
|
8406
|
-
const base = (0,
|
|
8407
|
-
return (0,
|
|
8488
|
+
const base = (0, import_node_path10.basename)(configRoot) === ".aipm" ? (0, import_node_path10.join)(configRoot, "helpers") : (0, import_node_path10.join)(configRoot, ".aipm", "helpers");
|
|
8489
|
+
return (0, import_node_path10.join)(base, packageHelperSlug(packageName), version);
|
|
8408
8490
|
}
|
|
8409
8491
|
async function assertSourceFile(packageRoot, relPath) {
|
|
8410
8492
|
const source = safeJoin(packageRoot, relPath);
|
|
8411
|
-
const info = await (0,
|
|
8493
|
+
const info = await (0, import_promises9.stat)(source).catch(() => null);
|
|
8412
8494
|
if (!info?.isFile()) throw new Error(`Package install file not found: ${relPath}`);
|
|
8413
8495
|
return source;
|
|
8414
8496
|
}
|
|
@@ -8416,20 +8498,20 @@ async function copyMainFile(input2) {
|
|
|
8416
8498
|
const source = await assertSourceFile(input2.packageRoot, input2.file.from);
|
|
8417
8499
|
const target = safeJoin(input2.installRoot, input2.file.to);
|
|
8418
8500
|
const overwrite = input2.file.overwrite ?? "fail";
|
|
8419
|
-
const exists = await (0,
|
|
8501
|
+
const exists = await (0, import_promises9.stat)(target).catch(() => null);
|
|
8420
8502
|
if (exists) {
|
|
8421
8503
|
if (overwrite === "skip") return null;
|
|
8422
8504
|
if (overwrite === "fail") throw new Error(`Install target already exists: ${target}`);
|
|
8423
8505
|
}
|
|
8424
|
-
await (0,
|
|
8425
|
-
await (0,
|
|
8506
|
+
await (0, import_promises9.mkdir)((0, import_node_path10.dirname)(target), { recursive: true });
|
|
8507
|
+
await (0, import_promises9.cp)(source, target, { force: overwrite === "replace" });
|
|
8426
8508
|
return target;
|
|
8427
8509
|
}
|
|
8428
8510
|
async function copyHelperFile(input2) {
|
|
8429
8511
|
const source = await assertSourceFile(input2.packageRoot, input2.file.from);
|
|
8430
|
-
const target = safeJoin(input2.helperRoot, input2.file.to ?? (0,
|
|
8431
|
-
await (0,
|
|
8432
|
-
await (0,
|
|
8512
|
+
const target = safeJoin(input2.helperRoot, input2.file.to ?? (0, import_node_path10.basename)(input2.file.from));
|
|
8513
|
+
await (0, import_promises9.mkdir)((0, import_node_path10.dirname)(target), { recursive: true });
|
|
8514
|
+
await (0, import_promises9.cp)(source, target, { force: true });
|
|
8433
8515
|
return target;
|
|
8434
8516
|
}
|
|
8435
8517
|
async function installPackageAssets(options) {
|
|
@@ -8446,7 +8528,7 @@ async function installPackageAssets(options) {
|
|
|
8446
8528
|
}
|
|
8447
8529
|
const helperRoot = helperRootFor(options.configRoot, options.packageName, options.version);
|
|
8448
8530
|
if ((install.helperFiles ?? []).length > 0) {
|
|
8449
|
-
await (0,
|
|
8531
|
+
await (0, import_promises9.rm)(helperRoot, { recursive: true, force: true });
|
|
8450
8532
|
}
|
|
8451
8533
|
for (const file of install.helperFiles ?? []) {
|
|
8452
8534
|
assets.helper.push(await copyHelperFile({ packageRoot: options.packageRoot, helperRoot, file }));
|
|
@@ -8491,7 +8573,7 @@ async function installOnePackage(options) {
|
|
|
8491
8573
|
}
|
|
8492
8574
|
let explicitTarget = options.explicitTarget;
|
|
8493
8575
|
let preferredTools = options.project.preferredTools;
|
|
8494
|
-
const { resolveInstallTools: resolveInstallTools2 } = await Promise.resolve().then(() => (
|
|
8576
|
+
const { resolveInstallTools: resolveInstallTools2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
|
|
8495
8577
|
let tools = await resolveInstallTools2({
|
|
8496
8578
|
projectRoot: installRoot,
|
|
8497
8579
|
manifest,
|
|
@@ -8501,7 +8583,7 @@ async function installOnePackage(options) {
|
|
|
8501
8583
|
if (tools.length === 0) {
|
|
8502
8584
|
if (options.ci) {
|
|
8503
8585
|
throw new Error(
|
|
8504
|
-
"No tool detected. Use --target cursor|claude|* in CI mode."
|
|
8586
|
+
"No tool detected. Use --target cursor|claude|codex|* in CI mode."
|
|
8505
8587
|
);
|
|
8506
8588
|
}
|
|
8507
8589
|
const choice = await promptForTool();
|
|
@@ -8522,7 +8604,7 @@ async function installOnePackage(options) {
|
|
|
8522
8604
|
);
|
|
8523
8605
|
const packageRoot = await unpackTarballToDirectory(tarball);
|
|
8524
8606
|
try {
|
|
8525
|
-
const skillMarkdown = await (0,
|
|
8607
|
+
const skillMarkdown = await (0, import_promises9.readFile)(safeJoin(packageRoot, manifest.entry), "utf8");
|
|
8526
8608
|
const result = await installSkillPackage({
|
|
8527
8609
|
projectRoot: installRoot,
|
|
8528
8610
|
manifest,
|
|
@@ -8540,7 +8622,8 @@ async function installOnePackage(options) {
|
|
|
8540
8622
|
});
|
|
8541
8623
|
const lock = await readLockfile(configRoot) ?? {
|
|
8542
8624
|
schemaVersion: "0.1",
|
|
8543
|
-
packages: {}
|
|
8625
|
+
packages: {},
|
|
8626
|
+
prompts: {}
|
|
8544
8627
|
};
|
|
8545
8628
|
const installed = {};
|
|
8546
8629
|
for (const tool of result.resolvedTools) {
|
|
@@ -8562,23 +8645,23 @@ async function installOnePackage(options) {
|
|
|
8562
8645
|
console.log(`Installed ${options.name}@${options.version} \u2192 ${result.resolvedTools.join(", ")}`);
|
|
8563
8646
|
printPostInstallNotice(options.name, postInstall);
|
|
8564
8647
|
} finally {
|
|
8565
|
-
await (0,
|
|
8648
|
+
await (0, import_promises9.rm)(packageRoot, { recursive: true, force: true });
|
|
8566
8649
|
}
|
|
8567
8650
|
}
|
|
8568
8651
|
|
|
8569
8652
|
// src/doctor.ts
|
|
8570
8653
|
var import_node_child_process3 = require("node:child_process");
|
|
8571
|
-
var
|
|
8572
|
-
var
|
|
8654
|
+
var import_promises10 = require("node:fs/promises");
|
|
8655
|
+
var import_node_path12 = require("node:path");
|
|
8573
8656
|
var import_node_util4 = require("node:util");
|
|
8574
8657
|
|
|
8575
8658
|
// src/project-root.ts
|
|
8576
8659
|
var import_node_os3 = require("node:os");
|
|
8577
|
-
var
|
|
8660
|
+
var import_node_path11 = require("node:path");
|
|
8578
8661
|
var import_node_process3 = require("node:process");
|
|
8579
8662
|
function globalConfigDir(env2 = process.env) {
|
|
8580
8663
|
const fromEnv = env2.AIPM_HOME?.trim();
|
|
8581
|
-
return fromEnv ? fromEnv.replace(/\/$/, "") : (0,
|
|
8664
|
+
return fromEnv ? fromEnv.replace(/\/$/, "") : (0, import_node_path11.join)((0, import_node_os3.homedir)(), ".aipm");
|
|
8582
8665
|
}
|
|
8583
8666
|
function resolveConfigRoot(options = {}) {
|
|
8584
8667
|
return options.global ? globalConfigDir() : (0, import_node_process3.cwd)();
|
|
@@ -8609,11 +8692,11 @@ async function commandOutput(command, args) {
|
|
|
8609
8692
|
}
|
|
8610
8693
|
function npmGlobalBin(prefix) {
|
|
8611
8694
|
if (!prefix) return null;
|
|
8612
|
-
return process.platform === "win32" ? prefix : `${prefix}${
|
|
8695
|
+
return process.platform === "win32" ? prefix : `${prefix}${import_node_path12.sep}bin`;
|
|
8613
8696
|
}
|
|
8614
8697
|
function pathIncludes(pathDir) {
|
|
8615
8698
|
if (!pathDir) return false;
|
|
8616
|
-
return (process.env.PATH ?? "").split(
|
|
8699
|
+
return (process.env.PATH ?? "").split(import_node_path12.delimiter).includes(pathDir);
|
|
8617
8700
|
}
|
|
8618
8701
|
function shellPathHint(binDir) {
|
|
8619
8702
|
if (!binDir) return "Run npm prefix -g and add its bin folder to PATH.";
|
|
@@ -8666,11 +8749,11 @@ async function runDoctor(options) {
|
|
|
8666
8749
|
if (!options.publish) {
|
|
8667
8750
|
const configLabel = options.global ? "Global config" : "Project config";
|
|
8668
8751
|
try {
|
|
8669
|
-
await (0,
|
|
8752
|
+
await (0, import_promises10.access)((0, import_node_path12.join)(configRoot, "aipm.package.json"));
|
|
8670
8753
|
checks.push({
|
|
8671
8754
|
name: configLabel,
|
|
8672
8755
|
ok: true,
|
|
8673
|
-
detail: `${(0,
|
|
8756
|
+
detail: `${(0, import_node_path12.join)(configRoot, "aipm.package.json")} exists (${scopeLabel(scope)}).`
|
|
8674
8757
|
});
|
|
8675
8758
|
} catch {
|
|
8676
8759
|
checks.push({
|
|
@@ -8738,11 +8821,181 @@ async function runDoctor(options) {
|
|
|
8738
8821
|
}
|
|
8739
8822
|
}
|
|
8740
8823
|
|
|
8824
|
+
// src/prompt-install.ts
|
|
8825
|
+
var import_node_crypto2 = require("node:crypto");
|
|
8826
|
+
var import_promises11 = require("node:fs/promises");
|
|
8827
|
+
var import_node_path13 = require("node:path");
|
|
8828
|
+
var PROMPT_SITE_ORIGIN = "https://www.aipm-registry.com";
|
|
8829
|
+
function parsePromptUrl(value) {
|
|
8830
|
+
let url;
|
|
8831
|
+
try {
|
|
8832
|
+
url = new URL(value);
|
|
8833
|
+
} catch {
|
|
8834
|
+
return null;
|
|
8835
|
+
}
|
|
8836
|
+
if (url.origin !== PROMPT_SITE_ORIGIN) return null;
|
|
8837
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
8838
|
+
if (parts.length !== 3 || parts[0] !== "prompts") return null;
|
|
8839
|
+
const publisher = decodeURIComponent(parts[1] ?? "").trim().toLowerCase();
|
|
8840
|
+
const slug = decodeURIComponent(parts[2] ?? "").trim().toLowerCase();
|
|
8841
|
+
if (!publisher || !slug || !/^[a-z0-9][a-z0-9-]*$/.test(publisher) || !/^[a-z0-9][a-z0-9-]*$/.test(slug)) {
|
|
8842
|
+
return null;
|
|
8843
|
+
}
|
|
8844
|
+
return {
|
|
8845
|
+
url: `${PROMPT_SITE_ORIGIN}/prompts/${encodeURIComponent(publisher)}/${encodeURIComponent(slug)}`,
|
|
8846
|
+
publisher,
|
|
8847
|
+
slug,
|
|
8848
|
+
alias: slug
|
|
8849
|
+
};
|
|
8850
|
+
}
|
|
8851
|
+
function promptDirectory(configRoot) {
|
|
8852
|
+
return (0, import_node_path13.basename)(configRoot) === ".aipm" ? (0, import_node_path13.join)(configRoot, "prompts") : (0, import_node_path13.join)(configRoot, ".aipm", "prompts");
|
|
8853
|
+
}
|
|
8854
|
+
function promptSnapshotPath(configRoot, reference) {
|
|
8855
|
+
return (0, import_node_path13.join)(promptDirectory(configRoot), `${reference.publisher}--${reference.slug}.md`);
|
|
8856
|
+
}
|
|
8857
|
+
function canonicalPromptContent(prompt) {
|
|
8858
|
+
return JSON.stringify({
|
|
8859
|
+
promptText: prompt.promptText,
|
|
8860
|
+
variables: prompt.variables,
|
|
8861
|
+
exampleInput: prompt.exampleInput,
|
|
8862
|
+
exampleOutput: prompt.exampleOutput,
|
|
8863
|
+
usageNotes: prompt.usageNotes,
|
|
8864
|
+
license: prompt.license
|
|
8865
|
+
});
|
|
8866
|
+
}
|
|
8867
|
+
function promptContentHash(prompt) {
|
|
8868
|
+
return (0, import_node_crypto2.createHash)("sha256").update(canonicalPromptContent(prompt)).digest("hex");
|
|
8869
|
+
}
|
|
8870
|
+
function section(title, value) {
|
|
8871
|
+
return value?.trim() ? `
|
|
8872
|
+
## ${title}
|
|
8873
|
+
|
|
8874
|
+
${value.trim()}
|
|
8875
|
+
` : "";
|
|
8876
|
+
}
|
|
8877
|
+
function renderPromptMarkdown(prompt, sourceUrl) {
|
|
8878
|
+
const variables = prompt.variables.length ? `
|
|
8879
|
+
## Variables
|
|
8880
|
+
|
|
8881
|
+
${prompt.variables.map(
|
|
8882
|
+
(variable) => `- \`{{${variable.name}}}\`${variable.required ? " \u2014 required" : " \u2014 optional"}: ${variable.description}${variable.example ? ` Example: ${variable.example}` : ""}`
|
|
8883
|
+
).join("\n")}
|
|
8884
|
+
` : "";
|
|
8885
|
+
const publisher = prompt.publisher.org?.name ?? prompt.publisher.user.name ?? `@${prompt.publisher.scope}`;
|
|
8886
|
+
return [
|
|
8887
|
+
`# ${prompt.title}`,
|
|
8888
|
+
"",
|
|
8889
|
+
prompt.summary,
|
|
8890
|
+
"",
|
|
8891
|
+
`- Source: ${sourceUrl}`,
|
|
8892
|
+
`- Publisher: ${publisher} (@${prompt.publisher.scope})`,
|
|
8893
|
+
`- Category: ${prompt.category}`,
|
|
8894
|
+
`- Inputs: ${prompt.inputTypes.join(", ") || "none"}`,
|
|
8895
|
+
`- Outputs: ${prompt.outputTypes.join(", ") || "none"}`,
|
|
8896
|
+
`- Effort: ${prompt.effort}`,
|
|
8897
|
+
`- Language: ${prompt.language}`,
|
|
8898
|
+
`- License: ${prompt.license}`,
|
|
8899
|
+
`- Updated: ${prompt.updatedAt}`,
|
|
8900
|
+
"",
|
|
8901
|
+
"## Prompt",
|
|
8902
|
+
"",
|
|
8903
|
+
prompt.promptText.trim(),
|
|
8904
|
+
variables,
|
|
8905
|
+
section("Example input", prompt.exampleInput),
|
|
8906
|
+
section("Example output", prompt.exampleOutput),
|
|
8907
|
+
section("Usage notes", prompt.usageNotes)
|
|
8908
|
+
].join("\n").replace(/\n{3,}/g, "\n\n").trimEnd().concat("\n");
|
|
8909
|
+
}
|
|
8910
|
+
function emptyLock() {
|
|
8911
|
+
return { schemaVersion: "0.1", packages: {}, prompts: {} };
|
|
8912
|
+
}
|
|
8913
|
+
function installedRelativePath(configRoot, absolutePath) {
|
|
8914
|
+
return (0, import_node_path13.relative)(configRoot, absolutePath).split("\\").join("/");
|
|
8915
|
+
}
|
|
8916
|
+
async function installTrackedPrompt(input2) {
|
|
8917
|
+
const prompt = await fetchPromptDetail(
|
|
8918
|
+
input2.registry,
|
|
8919
|
+
input2.reference.publisher,
|
|
8920
|
+
input2.reference.slug
|
|
8921
|
+
);
|
|
8922
|
+
const canonicalReference = {
|
|
8923
|
+
...input2.reference,
|
|
8924
|
+
publisher: prompt.publisher.scope,
|
|
8925
|
+
slug: prompt.slug,
|
|
8926
|
+
url: `${PROMPT_SITE_ORIGIN}/prompts/${encodeURIComponent(prompt.publisher.scope)}/${encodeURIComponent(prompt.slug)}`
|
|
8927
|
+
};
|
|
8928
|
+
const outputPath = promptSnapshotPath(input2.configRoot, canonicalReference);
|
|
8929
|
+
const contentHash = promptContentHash(prompt);
|
|
8930
|
+
const lock = await readLockfile(input2.configRoot) ?? emptyLock();
|
|
8931
|
+
const existing = lock.prompts[input2.reference.alias];
|
|
8932
|
+
const fileExists = Boolean(await (0, import_promises11.stat)(outputPath).catch(() => null));
|
|
8933
|
+
const changed = !existing || existing.contentHash !== contentHash || !fileExists;
|
|
8934
|
+
if (!input2.updateOnly || changed) {
|
|
8935
|
+
await (0, import_promises11.mkdir)((0, import_node_path13.dirname)(outputPath), { recursive: true });
|
|
8936
|
+
await (0, import_promises11.writeFile)(outputPath, renderPromptMarkdown(prompt, canonicalReference.url), "utf8");
|
|
8937
|
+
}
|
|
8938
|
+
if (input2.track) {
|
|
8939
|
+
const currentUrl = input2.project.prompts[input2.reference.alias];
|
|
8940
|
+
if (currentUrl && currentUrl !== canonicalReference.url) {
|
|
8941
|
+
throw new Error(
|
|
8942
|
+
`Prompt alias "${input2.reference.alias}" already tracks ${currentUrl}. Remove it first or use a unique slug.`
|
|
8943
|
+
);
|
|
8944
|
+
}
|
|
8945
|
+
await writeProjectPackageJson(input2.configRoot, {
|
|
8946
|
+
...input2.project,
|
|
8947
|
+
prompts: { ...input2.project.prompts, [input2.reference.alias]: canonicalReference.url }
|
|
8948
|
+
});
|
|
8949
|
+
}
|
|
8950
|
+
const entry = {
|
|
8951
|
+
id: prompt.id,
|
|
8952
|
+
url: canonicalReference.url,
|
|
8953
|
+
publisher: canonicalReference.publisher,
|
|
8954
|
+
slug: canonicalReference.slug,
|
|
8955
|
+
contentHash,
|
|
8956
|
+
updatedAt: prompt.updatedAt,
|
|
8957
|
+
installedPath: installedRelativePath(input2.configRoot, outputPath)
|
|
8958
|
+
};
|
|
8959
|
+
await writeLockfile(input2.configRoot, upsertPromptLockEntry(lock, input2.reference.alias, entry));
|
|
8960
|
+
if (input2.recordCopy) {
|
|
8961
|
+
await recordPromptCopy(input2.registry, canonicalReference.publisher, canonicalReference.slug).catch(
|
|
8962
|
+
() => void 0
|
|
8963
|
+
);
|
|
8964
|
+
}
|
|
8965
|
+
return { changed, path: outputPath, prompt };
|
|
8966
|
+
}
|
|
8967
|
+
function resolveTrackedPrompt(project, value) {
|
|
8968
|
+
const direct = parsePromptUrl(value);
|
|
8969
|
+
if (direct) {
|
|
8970
|
+
const match = Object.entries(project.prompts).find(([, url2]) => url2 === direct.url);
|
|
8971
|
+
return match ? { ...direct, alias: match[0] } : direct;
|
|
8972
|
+
}
|
|
8973
|
+
const url = project.prompts[value];
|
|
8974
|
+
const parsed = url ? parsePromptUrl(url) : null;
|
|
8975
|
+
return parsed ? { ...parsed, alias: value } : null;
|
|
8976
|
+
}
|
|
8977
|
+
async function readInstalledPrompt(configRoot, entry) {
|
|
8978
|
+
return (0, import_promises11.readFile)((0, import_node_path13.join)(configRoot, entry.installedPath), "utf8");
|
|
8979
|
+
}
|
|
8980
|
+
async function removeTrackedPrompt(input2) {
|
|
8981
|
+
const lock = await readLockfile(input2.configRoot);
|
|
8982
|
+
const entry = lock?.prompts[input2.reference.alias];
|
|
8983
|
+
if (entry) await (0, import_promises11.rm)((0, import_node_path13.join)(input2.configRoot, entry.installedPath), { force: true });
|
|
8984
|
+
const prompts = { ...input2.project.prompts };
|
|
8985
|
+
delete prompts[input2.reference.alias];
|
|
8986
|
+
await writeProjectPackageJson(input2.configRoot, { ...input2.project, prompts });
|
|
8987
|
+
if (lock) {
|
|
8988
|
+
const lockedPrompts = { ...lock.prompts };
|
|
8989
|
+
delete lockedPrompts[input2.reference.alias];
|
|
8990
|
+
await writeLockfile(input2.configRoot, { ...lock, prompts: lockedPrompts });
|
|
8991
|
+
}
|
|
8992
|
+
}
|
|
8993
|
+
|
|
8741
8994
|
// src/version.ts
|
|
8742
8995
|
var import_node_fs2 = require("node:fs");
|
|
8743
|
-
var
|
|
8996
|
+
var import_node_path14 = require("node:path");
|
|
8744
8997
|
function getCliVersion() {
|
|
8745
|
-
const pkgPath = (0,
|
|
8998
|
+
const pkgPath = (0, import_node_path14.join)(__dirname, "..", "package.json");
|
|
8746
8999
|
const pkg = JSON.parse((0, import_node_fs2.readFileSync)(pkgPath, "utf8"));
|
|
8747
9000
|
return pkg.version;
|
|
8748
9001
|
}
|
|
@@ -8831,11 +9084,14 @@ async function notifyCliUpdateIfNeeded(currentVersion, options) {
|
|
|
8831
9084
|
var CLI_VERSION = getCliVersion();
|
|
8832
9085
|
var program2 = new Command();
|
|
8833
9086
|
var DEFAULT_REGISTRY = "https://api.aipm-registry.com";
|
|
8834
|
-
var SITE_URL = "https://aipm-registry.com";
|
|
8835
|
-
var PUBLISH_DOC_URL =
|
|
8836
|
-
var DASHBOARD_URL =
|
|
9087
|
+
var SITE_URL = "https://www.aipm-registry.com";
|
|
9088
|
+
var PUBLISH_DOC_URL = `${SITE_URL}/publish`;
|
|
9089
|
+
var DASHBOARD_URL = `${SITE_URL}/dashboard`;
|
|
8837
9090
|
var GLOBAL_OPTION = "-g, --global";
|
|
8838
9091
|
var GLOBAL_OPTION_DESC = "Use global config (~/.aipm) and install skills under your home directory";
|
|
9092
|
+
var normalizedArgv = process.argv.map(
|
|
9093
|
+
(arg) => arg === "-prompt" ? "--prompt" : arg === "-skill" ? "--skill" : arg
|
|
9094
|
+
);
|
|
8839
9095
|
program2.name("aipm").description("AI package manager").enablePositionalOptions().version(CLI_VERSION, "-v, --version", "output the current version").option("--verbose", "Print extra diagnostic output").option("--quiet", "Reduce non-essential output").addHelpText(
|
|
8840
9096
|
"after",
|
|
8841
9097
|
`
|
|
@@ -8863,6 +9119,10 @@ function packagePageUrl(packageName, version) {
|
|
|
8863
9119
|
const [scope, name] = packageName.replace(/^@/, "").split("/");
|
|
8864
9120
|
return `${SITE_URL}/packages/${encodeURIComponent(scope ?? "")}/${encodeURIComponent(name ?? "")}/${encodeURIComponent(version)}`;
|
|
8865
9121
|
}
|
|
9122
|
+
function packageBadgeMarkdown(packageName, version) {
|
|
9123
|
+
const pageUrl = packagePageUrl(packageName, version);
|
|
9124
|
+
return `[](${pageUrl})`;
|
|
9125
|
+
}
|
|
8866
9126
|
function parsePackageArg(value) {
|
|
8867
9127
|
const match = value.match(/^(@[^@]+)(?:@(.+))?$/);
|
|
8868
9128
|
if (!match) throw new Error("Package must be @scope/name or @scope/name@version");
|
|
@@ -8877,23 +9137,23 @@ function skillFolderName(name) {
|
|
|
8877
9137
|
return folder;
|
|
8878
9138
|
}
|
|
8879
9139
|
async function writeStarterFile(path2, content) {
|
|
8880
|
-
await (0,
|
|
9140
|
+
await (0, import_promises12.writeFile)(path2, content, { encoding: "utf8", flag: "wx" });
|
|
8881
9141
|
}
|
|
8882
9142
|
async function inferEntryFromSource(source, fallback) {
|
|
8883
|
-
const sourceInfo = await (0,
|
|
8884
|
-
if (sourceInfo.isFile()) return (0,
|
|
9143
|
+
const sourceInfo = await (0, import_promises12.stat)(source);
|
|
9144
|
+
if (sourceInfo.isFile()) return (0, import_node_path15.basename)(source);
|
|
8885
9145
|
if (!sourceInfo.isDirectory()) return fallback;
|
|
8886
|
-
const entries = await (0,
|
|
9146
|
+
const entries = await (0, import_promises12.readdir)(source);
|
|
8887
9147
|
if (entries.includes(fallback)) return fallback;
|
|
8888
9148
|
return entries.find((entry) => entry.endsWith(".md")) ?? entries.find((entry) => entry.endsWith(".mdc")) ?? fallback;
|
|
8889
9149
|
}
|
|
8890
9150
|
async function copySourceIntoSkillRoot(source, root, sourceLabel) {
|
|
8891
|
-
const sourceInfo = await (0,
|
|
8892
|
-
await (0,
|
|
9151
|
+
const sourceInfo = await (0, import_promises12.stat)(source);
|
|
9152
|
+
await (0, import_promises12.mkdir)(root, { recursive: true });
|
|
8893
9153
|
if (sourceInfo.isDirectory()) {
|
|
8894
|
-
const entries = await (0,
|
|
9154
|
+
const entries = await (0, import_promises12.readdir)(source);
|
|
8895
9155
|
for (const entry of entries) {
|
|
8896
|
-
await (0,
|
|
9156
|
+
await (0, import_promises12.cp)((0, import_node_path15.join)(source, entry), (0, import_node_path15.join)(root, entry), {
|
|
8897
9157
|
recursive: true,
|
|
8898
9158
|
force: false,
|
|
8899
9159
|
errorOnExist: true
|
|
@@ -8902,7 +9162,7 @@ async function copySourceIntoSkillRoot(source, root, sourceLabel) {
|
|
|
8902
9162
|
return;
|
|
8903
9163
|
}
|
|
8904
9164
|
if (sourceInfo.isFile()) {
|
|
8905
|
-
await (0,
|
|
9165
|
+
await (0, import_promises12.cp)(source, (0, import_node_path15.join)(root, (0, import_node_path15.basename)(source)), { force: false, errorOnExist: true });
|
|
8906
9166
|
return;
|
|
8907
9167
|
}
|
|
8908
9168
|
throw new Error(`Unsupported source path: ${sourceLabel}`);
|
|
@@ -8936,11 +9196,11 @@ function packageDashboardUrl(name) {
|
|
|
8936
9196
|
return `${DASHBOARD_URL}/packages/${name.replace(/^@/, "")}`;
|
|
8937
9197
|
}
|
|
8938
9198
|
function helperRootFromTrackedPath(path2) {
|
|
8939
|
-
const parts = path2.split(
|
|
9199
|
+
const parts = path2.split(import_node_path15.sep).filter(Boolean);
|
|
8940
9200
|
const helpersIndex = parts.lastIndexOf("helpers");
|
|
8941
9201
|
if (helpersIndex === -1 || parts.length <= helpersIndex + 2) return null;
|
|
8942
|
-
const prefix = path2.startsWith(
|
|
8943
|
-
return (0,
|
|
9202
|
+
const prefix = path2.startsWith(import_node_path15.sep) ? import_node_path15.sep : "";
|
|
9203
|
+
return (0, import_node_path15.join)(prefix, ...parts.slice(0, helpersIndex + 3));
|
|
8944
9204
|
}
|
|
8945
9205
|
async function showInstalledPrompt(configRoot, packageArg) {
|
|
8946
9206
|
const { name } = parsePackageArg(packageArg);
|
|
@@ -8953,7 +9213,7 @@ async function showInstalledPrompt(configRoot, packageArg) {
|
|
|
8953
9213
|
if (entry.postInstall.status === "cleaned") {
|
|
8954
9214
|
throw new Error(`Setup helper files were cleaned for ${name}. Reinstall the package to restore them.`);
|
|
8955
9215
|
}
|
|
8956
|
-
const content = await (0,
|
|
9216
|
+
const content = await (0, import_promises12.readFile)(entry.postInstall.promptFile, "utf8").catch(() => {
|
|
8957
9217
|
throw new Error(`Setup prompt file is missing: ${entry.postInstall?.promptFile}`);
|
|
8958
9218
|
});
|
|
8959
9219
|
console.log(`Prompt file: ${entry.postInstall.promptFile}`);
|
|
@@ -8986,9 +9246,9 @@ async function cleanupInstalledHelpers(options) {
|
|
|
8986
9246
|
entry.installedAssets.helper.map((path2) => helperRootFromTrackedPath(path2)).filter((path2) => Boolean(path2))
|
|
8987
9247
|
);
|
|
8988
9248
|
if (roots.size > 0) {
|
|
8989
|
-
for (const root of roots) await (0,
|
|
9249
|
+
for (const root of roots) await (0, import_promises12.rm)(root, { recursive: true, force: true });
|
|
8990
9250
|
} else {
|
|
8991
|
-
for (const helperPath of entry.installedAssets.helper) await (0,
|
|
9251
|
+
for (const helperPath of entry.installedAssets.helper) await (0, import_promises12.rm)(helperPath, { force: true });
|
|
8992
9252
|
}
|
|
8993
9253
|
await writeLockfile(options.configRoot, {
|
|
8994
9254
|
...lock,
|
|
@@ -9011,10 +9271,10 @@ async function openUrl(url) {
|
|
|
9011
9271
|
console.log(`Open: ${url}`);
|
|
9012
9272
|
}
|
|
9013
9273
|
function randomBase64Url(bytes = 32) {
|
|
9014
|
-
return (0,
|
|
9274
|
+
return (0, import_node_crypto3.randomBytes)(bytes).toString("base64url");
|
|
9015
9275
|
}
|
|
9016
9276
|
function sha256Base64Url(value) {
|
|
9017
|
-
return (0,
|
|
9277
|
+
return (0, import_node_crypto3.createHash)("sha256").update(value).digest("base64url");
|
|
9018
9278
|
}
|
|
9019
9279
|
function deviceName() {
|
|
9020
9280
|
return `AIPM CLI on ${process.platform}`;
|
|
@@ -9282,9 +9542,9 @@ function buildStarterQualityMetadata(options) {
|
|
|
9282
9542
|
}
|
|
9283
9543
|
async function initSkill(opts) {
|
|
9284
9544
|
if (!isValidScopeName(opts.name)) throw new Error("Invalid @scope/name");
|
|
9285
|
-
const root = opts.here ? (0, import_node_process5.cwd)() : (0,
|
|
9545
|
+
const root = opts.here ? (0, import_node_process5.cwd)() : (0, import_node_path15.resolve)((0, import_node_process5.cwd)(), opts.dir ?? skillFolderName(opts.name));
|
|
9286
9546
|
const cdTarget = opts.here ? null : opts.dir ?? skillFolderName(opts.name);
|
|
9287
|
-
const source = opts.from ? (0,
|
|
9547
|
+
const source = opts.from ? (0, import_node_path15.resolve)(opts.from) : null;
|
|
9288
9548
|
const entry = source ? await inferEntryFromSource(source, opts.entry) : opts.entry;
|
|
9289
9549
|
const template = parseSkillTemplate(opts.template ?? "blank");
|
|
9290
9550
|
const manifest = PackageManifestSchema.parse({
|
|
@@ -9305,17 +9565,17 @@ async function initSkill(opts) {
|
|
|
9305
9565
|
if (source) {
|
|
9306
9566
|
await copySourceIntoSkillRoot(source, root, source);
|
|
9307
9567
|
} else {
|
|
9308
|
-
await (0,
|
|
9568
|
+
await (0, import_promises12.mkdir)(root, { recursive: true });
|
|
9309
9569
|
}
|
|
9310
|
-
await writeStarterFile((0,
|
|
9570
|
+
await writeStarterFile((0, import_node_path15.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
9311
9571
|
if (!opts.from) {
|
|
9312
9572
|
await writeStarterFile(
|
|
9313
|
-
(0,
|
|
9573
|
+
(0, import_node_path15.join)(root, entry),
|
|
9314
9574
|
SKILL_TEMPLATES[template](opts.name)
|
|
9315
9575
|
);
|
|
9316
9576
|
}
|
|
9317
9577
|
await writeStarterFile(
|
|
9318
|
-
(0,
|
|
9578
|
+
(0, import_node_path15.join)(root, ".aipmignore"),
|
|
9319
9579
|
[
|
|
9320
9580
|
"# Files that should never be published with this skill",
|
|
9321
9581
|
".env*",
|
|
@@ -9333,14 +9593,14 @@ async function initSkill(opts) {
|
|
|
9333
9593
|
""
|
|
9334
9594
|
].join("\n")
|
|
9335
9595
|
);
|
|
9336
|
-
await (0,
|
|
9596
|
+
await (0, import_promises12.mkdir)((0, import_node_path15.join)(root, ".aipm"), { recursive: true });
|
|
9337
9597
|
console.log(`Created ${opts.name} skill folder: ${root}`);
|
|
9338
9598
|
printPublishGuide(
|
|
9339
9599
|
opts.from ? `Copied ${opts.from} into ${root} and created aipm.manifest.json, .aipmignore, and the local publish state folder.` : `Created ${root} with aipm.manifest.json, ${entry}, .aipmignore, and the local publish state folder.`,
|
|
9340
9600
|
cdTarget ? `Run cd ${cdTarget}, edit/review the files, then run aipm publish add .` : "Edit/review the files, then run aipm publish add ."
|
|
9341
9601
|
);
|
|
9342
9602
|
}
|
|
9343
|
-
program2.command("init").description("Create aipm.package.json in the current project or globally").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Default registry URL").option("--target <tool>", "Preferred install target: cursor, claude, or *").action(async (opts) => {
|
|
9603
|
+
program2.command("init").description("Create aipm.package.json in the current project or globally").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Default registry URL").option("--target <tool>", "Preferred install target: cursor, claude, codex, or *").action(async (opts) => {
|
|
9344
9604
|
const scope = { global: opts.global };
|
|
9345
9605
|
const configRoot = resolveConfigRoot(scope);
|
|
9346
9606
|
const existing = await readProjectPackageJson(configRoot);
|
|
@@ -9348,7 +9608,7 @@ program2.command("init").description("Create aipm.package.json in the current pr
|
|
|
9348
9608
|
console.log(`aipm.package.json already exists (${scopeLabel(scope)}).`);
|
|
9349
9609
|
return;
|
|
9350
9610
|
}
|
|
9351
|
-
if (scope.global) await (0,
|
|
9611
|
+
if (scope.global) await (0, import_promises12.mkdir)(configRoot, { recursive: true });
|
|
9352
9612
|
const installRoot = resolveInstallRoot(scope);
|
|
9353
9613
|
const detected = await detectToolsInProject(installRoot);
|
|
9354
9614
|
const parsedTarget = parseTargetFlag(opts.target);
|
|
@@ -9362,7 +9622,8 @@ program2.command("init").description("Create aipm.package.json in the current pr
|
|
|
9362
9622
|
schemaVersion: "0.1",
|
|
9363
9623
|
registry,
|
|
9364
9624
|
preferredTools: preferredTools.length ? preferredTools : void 0,
|
|
9365
|
-
packages: {}
|
|
9625
|
+
packages: {},
|
|
9626
|
+
prompts: {}
|
|
9366
9627
|
});
|
|
9367
9628
|
console.log(`Created aipm.package.json (${scopeLabel(scope)}, registry: ${registry})`);
|
|
9368
9629
|
});
|
|
@@ -9450,14 +9711,27 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
|
|
|
9450
9711
|
console.log(`Auth file: ${data.authFile}`);
|
|
9451
9712
|
console.log(`Publish guide: ${data.publishDoc}`);
|
|
9452
9713
|
});
|
|
9453
|
-
program2.command("add <package>").description("Add
|
|
9454
|
-
const { name, version: requestedVersion } = parsePackageArg(pkgArg);
|
|
9714
|
+
program2.command("add <package-or-prompt>").description("Add a skill package or an AIPM prompt URL").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor, claude, codex, or *").option("--token <token>", "Install token for private packages").option("--ci", "Non-interactive; fail if prompt needed").action(async (pkgArg, opts) => {
|
|
9455
9715
|
const scope = { global: opts.global };
|
|
9456
9716
|
const configRoot = resolveConfigRoot(scope);
|
|
9457
9717
|
const installRoot = resolveInstallRoot(scope);
|
|
9458
9718
|
let project = await readProjectPackageJson(configRoot);
|
|
9459
9719
|
if (!project) throw new Error(initRequiredMessage(scope));
|
|
9460
9720
|
const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
|
|
9721
|
+
const promptReference = parsePromptUrl(pkgArg);
|
|
9722
|
+
if (promptReference) {
|
|
9723
|
+
const result = await installTrackedPrompt({
|
|
9724
|
+
configRoot,
|
|
9725
|
+
registry,
|
|
9726
|
+
project,
|
|
9727
|
+
reference: promptReference,
|
|
9728
|
+
track: true,
|
|
9729
|
+
recordCopy: true
|
|
9730
|
+
});
|
|
9731
|
+
console.log(`Installed prompt ${result.prompt.title} \u2192 ${result.path}`);
|
|
9732
|
+
return;
|
|
9733
|
+
}
|
|
9734
|
+
const { name, version: requestedVersion } = parsePackageArg(pkgArg);
|
|
9461
9735
|
const token = await tokenForRead(registry, opts.token);
|
|
9462
9736
|
const version = requestedVersion ?? project.packages[name] ?? await latestVersionForPackage(registry, name, token);
|
|
9463
9737
|
if (!version) throw new Error("Specify version: aipm add @scope/pkg@1.0.0");
|
|
@@ -9509,7 +9783,7 @@ program2.command("search [query]").description("Search public registry packages"
|
|
|
9509
9783
|
console.log(` ${meta}`);
|
|
9510
9784
|
}
|
|
9511
9785
|
});
|
|
9512
|
-
program2.command("install").description("Install all packages from aipm.package.json").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor, claude, or *").option("--token <token>", "Install token for private packages").option("--ci", "Non-interactive").action(async (opts) => {
|
|
9786
|
+
program2.command("install").description("Install all packages from aipm.package.json").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor, claude, codex, or *").option("--token <token>", "Install token for private packages").option("--ci", "Non-interactive").action(async (opts) => {
|
|
9513
9787
|
const scope = { global: opts.global };
|
|
9514
9788
|
const configRoot = resolveConfigRoot(scope);
|
|
9515
9789
|
const installRoot = resolveInstallRoot(scope);
|
|
@@ -9531,10 +9805,75 @@ program2.command("install").description("Install all packages from aipm.package.
|
|
|
9531
9805
|
token
|
|
9532
9806
|
});
|
|
9533
9807
|
}
|
|
9808
|
+
for (const [alias, url] of Object.entries(project.prompts)) {
|
|
9809
|
+
const reference = parsePromptUrl(url);
|
|
9810
|
+
if (!reference) throw new Error(`Invalid tracked prompt URL for ${alias}: ${url}`);
|
|
9811
|
+
const result = await installTrackedPrompt({
|
|
9812
|
+
configRoot,
|
|
9813
|
+
registry,
|
|
9814
|
+
project,
|
|
9815
|
+
reference: { ...reference, alias },
|
|
9816
|
+
track: false
|
|
9817
|
+
});
|
|
9818
|
+
console.log(`Restored prompt ${result.prompt.title} \u2192 ${result.path}`);
|
|
9819
|
+
}
|
|
9820
|
+
});
|
|
9821
|
+
program2.command("show <package-or-prompt>").description("Show an installed prompt snapshot or tracked skill details").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).action(async (value, opts) => {
|
|
9822
|
+
const configRoot = resolveConfigRoot({ global: opts.global });
|
|
9823
|
+
const project = await readProjectPackageJson(configRoot);
|
|
9824
|
+
if (!project) throw new Error(initRequiredMessage({ global: opts.global }));
|
|
9825
|
+
const reference = resolveTrackedPrompt(project, value);
|
|
9826
|
+
if (reference && project.prompts[reference.alias] === reference.url) {
|
|
9827
|
+
const lock2 = await readLockfile(configRoot);
|
|
9828
|
+
const entry2 = lock2?.prompts[reference.alias];
|
|
9829
|
+
if (!entry2) throw new Error(`Prompt is not installed: ${reference.url}. Run aipm install.`);
|
|
9830
|
+
console.log(await readInstalledPrompt(configRoot, entry2));
|
|
9831
|
+
return;
|
|
9832
|
+
}
|
|
9833
|
+
const { name } = parsePackageArg(value);
|
|
9834
|
+
const lock = await readLockfile(configRoot);
|
|
9835
|
+
const entry = lock?.packages[name];
|
|
9836
|
+
if (!entry) throw new Error(`Package is not installed: ${name}`);
|
|
9837
|
+
console.log(`${name}@${entry.version} [${entry.resolvedTools.join(", ")}]`);
|
|
9534
9838
|
});
|
|
9535
9839
|
program2.command("show-prompt <package>").description("Show the manual setup prompt installed with a package").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).action(async (pkgArg, opts) => {
|
|
9536
9840
|
await showInstalledPrompt(resolveConfigRoot({ global: opts.global }), pkgArg);
|
|
9537
9841
|
});
|
|
9842
|
+
function promptImageContentType(path2) {
|
|
9843
|
+
const extension = (0, import_node_path15.extname)(path2).toLowerCase();
|
|
9844
|
+
if (extension === ".png") return "image/png";
|
|
9845
|
+
if (extension === ".jpg" || extension === ".jpeg") return "image/jpeg";
|
|
9846
|
+
if (extension === ".webp") return "image/webp";
|
|
9847
|
+
throw new Error(`Unsupported prompt sample image: ${path2}`);
|
|
9848
|
+
}
|
|
9849
|
+
var promptCommand = program2.command("prompt").description("Publish prompt listings from structured JSON");
|
|
9850
|
+
promptCommand.command("publish <file>").description("Publish one prompt or a batch of prompts from JSON").option("--registry <url>", "Registry API base URL").option("--yes", "Confirm public publishing without an extra reminder").action(async (file, opts) => {
|
|
9851
|
+
const registry = registryFromEnvOrDefault(opts.registry);
|
|
9852
|
+
const accessToken = await authTokenForRegistry(registry, { throwOnFailure: true });
|
|
9853
|
+
if (!accessToken) throw new Error("Run aipm login before publishing prompts.");
|
|
9854
|
+
const absoluteFile = (0, import_node_path15.resolve)(file);
|
|
9855
|
+
const parsed = JSON.parse(await (0, import_promises12.readFile)(absoluteFile, "utf8"));
|
|
9856
|
+
const rows = Array.isArray(parsed) ? parsed : "prompts" in parsed ? parsed.prompts : [parsed];
|
|
9857
|
+
if (rows.length === 0) throw new Error("Prompt publish file contains no prompts.");
|
|
9858
|
+
if (!opts.yes) {
|
|
9859
|
+
console.log(`Reminder: this will publish ${rows.length} public prompt${rows.length === 1 ? "" : "s"}.`);
|
|
9860
|
+
console.log("Use --yes to skip this reminder in automation.");
|
|
9861
|
+
}
|
|
9862
|
+
for (const row of rows) {
|
|
9863
|
+
const { sampleImagePath, ...input2 } = row;
|
|
9864
|
+
let sampleImage;
|
|
9865
|
+
if (sampleImagePath) {
|
|
9866
|
+
const imagePath = (0, import_node_path15.resolve)((0, import_node_path15.dirname)(absoluteFile), sampleImagePath);
|
|
9867
|
+
sampleImage = {
|
|
9868
|
+
data: await (0, import_promises12.readFile)(imagePath),
|
|
9869
|
+
filename: (0, import_node_path15.basename)(imagePath),
|
|
9870
|
+
contentType: promptImageContentType(imagePath)
|
|
9871
|
+
};
|
|
9872
|
+
}
|
|
9873
|
+
const saved = await publishPrompt(registry, input2, accessToken, sampleImage);
|
|
9874
|
+
console.log(`Published ${saved.title} \u2192 ${SITE_URL}${saved.path}`);
|
|
9875
|
+
}
|
|
9876
|
+
});
|
|
9538
9877
|
program2.command("cleanup <package>").description("Delete temporary helper files installed with a package").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--yes", "Delete helper files without asking for confirmation").action(async (pkgArg, opts) => {
|
|
9539
9878
|
await cleanupInstalledHelpers({
|
|
9540
9879
|
configRoot: resolveConfigRoot({ global: opts.global }),
|
|
@@ -9550,8 +9889,8 @@ var publish = program2.command("publish [dir]").description("Stage, validate, an
|
|
|
9550
9889
|
publish.help();
|
|
9551
9890
|
return;
|
|
9552
9891
|
}
|
|
9553
|
-
const abs = (0,
|
|
9554
|
-
const manifestRaw = await (0,
|
|
9892
|
+
const abs = (0, import_node_path15.resolve)(dir);
|
|
9893
|
+
const manifestRaw = await (0, import_promises12.readFile)((0, import_node_path15.join)(abs, "aipm.manifest.json"), "utf8");
|
|
9555
9894
|
const manifest = PackageManifestSchema.parse(JSON.parse(manifestRaw));
|
|
9556
9895
|
const tarball = await packDirectory(abs);
|
|
9557
9896
|
const registry = registryFromEnvOrDefault(opts.registry);
|
|
@@ -9559,6 +9898,7 @@ var publish = program2.command("publish [dir]").description("Stage, validate, an
|
|
|
9559
9898
|
console.log(`Published ${manifest.name}@${result.version}`);
|
|
9560
9899
|
console.log(`View: ${packagePageUrl(manifest.name, result.version)}`);
|
|
9561
9900
|
console.log(`Install: aipm add ${manifest.name}@${result.version} --target ${manifest.targets[0]} --ci`);
|
|
9901
|
+
console.log(`README badge: ${packageBadgeMarkdown(manifest.name, result.version)}`);
|
|
9562
9902
|
printPublishGuide(
|
|
9563
9903
|
`Published ${manifest.name}@${result.version} from ${abs}.`,
|
|
9564
9904
|
"Share the install command or open the package page to confirm the listing."
|
|
@@ -9684,28 +10024,46 @@ publish.command("push").description("Publish staged files").option("--registry <
|
|
|
9684
10024
|
console.log(`Published ${manifest.name}@${result.version}`);
|
|
9685
10025
|
console.log(`View: ${packagePageUrl(manifest.name, result.version)}`);
|
|
9686
10026
|
console.log(`Install: aipm add ${manifest.name}@${result.version} --target ${manifest.targets[0]} --ci`);
|
|
10027
|
+
console.log(`README badge: ${packageBadgeMarkdown(manifest.name, result.version)}`);
|
|
9687
10028
|
printPublishGuide(
|
|
9688
10029
|
`Published ${manifest.name}@${result.version} to ${registry}.`,
|
|
9689
10030
|
"Open the registry page, test the install command in a clean project, and share the package link."
|
|
9690
10031
|
);
|
|
9691
10032
|
});
|
|
9692
|
-
program2.command("list").description("List
|
|
10033
|
+
program2.command("list").description("List installed skills and prompts from aipm-lock.json").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("-p, --prompt", "List prompts only").option("-s, --skill", "List skills only").action(async (opts) => {
|
|
9693
10034
|
const configRoot = resolveConfigRoot({ global: opts.global });
|
|
9694
10035
|
const lock = await readLockfile(configRoot);
|
|
9695
|
-
|
|
9696
|
-
|
|
10036
|
+
const showSkills = !opts.prompt || Boolean(opts.skill);
|
|
10037
|
+
const showPrompts = !opts.skill || Boolean(opts.prompt);
|
|
10038
|
+
const skillRows = lock ? Object.entries(lock.packages) : [];
|
|
10039
|
+
const promptRows = lock ? Object.entries(lock.prompts) : [];
|
|
10040
|
+
if ((!showSkills || skillRows.length === 0) && (!showPrompts || promptRows.length === 0)) {
|
|
10041
|
+
console.log(opts.prompt && !opts.skill ? "No prompts installed." : opts.skill && !opts.prompt ? "No skills installed." : "No skills or prompts installed.");
|
|
9697
10042
|
return;
|
|
9698
10043
|
}
|
|
9699
|
-
|
|
9700
|
-
|
|
10044
|
+
if (showSkills) {
|
|
10045
|
+
for (const [name, entry] of skillRows) {
|
|
10046
|
+
console.log(`skill ${name}@${entry.version} [${entry.resolvedTools.join(", ")}]`);
|
|
10047
|
+
}
|
|
10048
|
+
}
|
|
10049
|
+
if (showPrompts) {
|
|
10050
|
+
for (const [name, entry] of promptRows) {
|
|
10051
|
+
console.log(`prompt ${name} ${entry.url} ${entry.installedPath}`);
|
|
10052
|
+
}
|
|
9701
10053
|
}
|
|
9702
10054
|
});
|
|
9703
|
-
program2.command("remove <package>").alias("rm").description("Remove a
|
|
9704
|
-
const { name } = parsePackageArg(pkgArg);
|
|
10055
|
+
program2.command("remove <package-or-prompt>").alias("rm").description("Remove a tracked skill or prompt and its installed files").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).action(async (pkgArg, opts) => {
|
|
9705
10056
|
const scope = { global: opts.global };
|
|
9706
10057
|
const configRoot = resolveConfigRoot(scope);
|
|
9707
10058
|
const project = await readProjectPackageJson(configRoot);
|
|
9708
10059
|
if (!project) throw new Error(initRequiredMessage(scope));
|
|
10060
|
+
const promptReference = resolveTrackedPrompt(project, pkgArg);
|
|
10061
|
+
if (promptReference && project.prompts[promptReference.alias] === promptReference.url) {
|
|
10062
|
+
await removeTrackedPrompt({ configRoot, project, reference: promptReference });
|
|
10063
|
+
console.log(`Removed prompt ${promptReference.url} and its local snapshot.`);
|
|
10064
|
+
return;
|
|
10065
|
+
}
|
|
10066
|
+
const { name } = parsePackageArg(pkgArg);
|
|
9709
10067
|
const packages = { ...project.packages };
|
|
9710
10068
|
delete packages[name];
|
|
9711
10069
|
await writeProjectPackageJson(configRoot, { ...project, packages });
|
|
@@ -9718,19 +10076,31 @@ program2.command("remove <package>").alias("rm").description("Remove a package f
|
|
|
9718
10076
|
console.log(`Removed ${name} from AIPM ${scopeLabel(scope)} files.`);
|
|
9719
10077
|
console.log("Adapter-written files are not deleted yet; review your project before committing.");
|
|
9720
10078
|
});
|
|
9721
|
-
program2.command("update [package]").description("Update one installed package, or all installed packages, to the latest registry version").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor, claude, or *").option("--token <token>", "Install token for private packages").option("--ci", "Non-interactive").action(async (pkgArg, opts) => {
|
|
10079
|
+
program2.command("update [package]").description("Update one installed package, or all installed packages, to the latest registry version").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor, claude, codex, or *").option("--token <token>", "Install token for private packages").option("--ci", "Non-interactive").action(async (pkgArg, opts) => {
|
|
9722
10080
|
const scope = { global: opts.global };
|
|
9723
10081
|
const configRoot = resolveConfigRoot(scope);
|
|
9724
10082
|
const installRoot = resolveInstallRoot(scope);
|
|
9725
10083
|
let project = await readProjectPackageJson(configRoot);
|
|
9726
10084
|
if (!project) throw new Error(initRequiredMessage(scope));
|
|
9727
10085
|
const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
|
|
9728
|
-
const
|
|
9729
|
-
|
|
9730
|
-
|
|
9731
|
-
|
|
10086
|
+
const requestedPrompt = pkgArg ? resolveTrackedPrompt(project, pkgArg) : null;
|
|
10087
|
+
if (requestedPrompt) {
|
|
10088
|
+
if (project.prompts[requestedPrompt.alias] !== requestedPrompt.url) {
|
|
10089
|
+
throw new Error(`Prompt is not tracked: ${requestedPrompt.url}`);
|
|
10090
|
+
}
|
|
10091
|
+
const result = await installTrackedPrompt({
|
|
10092
|
+
configRoot,
|
|
10093
|
+
registry,
|
|
10094
|
+
project,
|
|
10095
|
+
reference: requestedPrompt,
|
|
10096
|
+
track: false,
|
|
10097
|
+
updateOnly: true
|
|
10098
|
+
});
|
|
10099
|
+
console.log(result.changed ? `Updated prompt ${result.prompt.title} \u2192 ${result.path}` : `Prompt unchanged: ${result.prompt.title}`);
|
|
9732
10100
|
return;
|
|
9733
10101
|
}
|
|
10102
|
+
const token = await tokenForRead(registry, opts.token);
|
|
10103
|
+
const names = pkgArg ? [parsePackageArg(pkgArg).name] : Object.keys(project.packages);
|
|
9734
10104
|
for (const name of names) {
|
|
9735
10105
|
const version = await latestVersionForPackage(registry, name, token);
|
|
9736
10106
|
project = {
|
|
@@ -9750,9 +10120,27 @@ program2.command("update [package]").description("Update one installed package,
|
|
|
9750
10120
|
token
|
|
9751
10121
|
});
|
|
9752
10122
|
}
|
|
10123
|
+
if (!pkgArg) {
|
|
10124
|
+
for (const [alias, url] of Object.entries(project.prompts)) {
|
|
10125
|
+
const reference = parsePromptUrl(url);
|
|
10126
|
+
if (!reference) throw new Error(`Invalid tracked prompt URL for ${alias}: ${url}`);
|
|
10127
|
+
const result = await installTrackedPrompt({
|
|
10128
|
+
configRoot,
|
|
10129
|
+
registry,
|
|
10130
|
+
project,
|
|
10131
|
+
reference: { ...reference, alias },
|
|
10132
|
+
track: false,
|
|
10133
|
+
updateOnly: true
|
|
10134
|
+
});
|
|
10135
|
+
console.log(result.changed ? `Updated prompt ${result.prompt.title} \u2192 ${result.path}` : `Prompt unchanged: ${result.prompt.title}`);
|
|
10136
|
+
}
|
|
10137
|
+
}
|
|
10138
|
+
if (names.length === 0 && Object.keys(project.prompts).length === 0) {
|
|
10139
|
+
console.log("No skills or prompts configured.");
|
|
10140
|
+
}
|
|
9753
10141
|
});
|
|
9754
10142
|
program2.command("doctor").description("Check PATH, Node, registry, project config, and publish readiness").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Registry base URL").option("--json", "Print machine-readable JSON").option("--publish", "Only show publish-readiness checks").action((opts) => runDoctor(opts));
|
|
9755
|
-
program2.parseAsync(
|
|
10143
|
+
program2.parseAsync(normalizedArgv).catch((err) => {
|
|
9756
10144
|
console.error(err.message);
|
|
9757
10145
|
const message = err.message.toLowerCase();
|
|
9758
10146
|
if (message.includes("token") || message.includes("unauthorized") || message.includes("forbidden")) {
|