@aipm-registry/cli 0.4.0 → 0.4.3

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/bin.cjs CHANGED
@@ -6,8 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __esm = (fn, res) => function __init() {
10
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
9
+ var __esm = (fn, res, err) => function __init() {
10
+ if (err) throw err[0];
11
+ try {
12
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
13
+ } catch (e) {
14
+ throw err = [e], e;
15
+ }
11
16
  };
12
17
  var __export = (target, all) => {
13
18
  for (var name in all)
@@ -3837,7 +3842,7 @@ var init_types = __esm({
3837
3842
  ...processCreateParams(params)
3838
3843
  });
3839
3844
  };
3840
- BRAND = Symbol("zod_brand");
3845
+ BRAND = /* @__PURE__ */ Symbol("zod_brand");
3841
3846
  ZodBranded = class extends ZodType {
3842
3847
  _parse(input2) {
3843
3848
  const { ctx } = this._processInputParams(input2);
@@ -4011,14 +4016,14 @@ var init_types = __esm({
4011
4016
  onumber = () => numberType().optional();
4012
4017
  oboolean = () => booleanType().optional();
4013
4018
  coerce = {
4014
- string: (arg) => ZodString.create({ ...arg, coerce: true }),
4015
- number: (arg) => ZodNumber.create({ ...arg, coerce: true }),
4016
- boolean: (arg) => ZodBoolean.create({
4019
+ string: ((arg) => ZodString.create({ ...arg, coerce: true })),
4020
+ number: ((arg) => ZodNumber.create({ ...arg, coerce: true })),
4021
+ boolean: ((arg) => ZodBoolean.create({
4017
4022
  ...arg,
4018
4023
  coerce: true
4019
- }),
4020
- bigint: (arg) => ZodBigInt.create({ ...arg, coerce: true }),
4021
- date: (arg) => ZodDate.create({ ...arg, coerce: true })
4024
+ })),
4025
+ bigint: ((arg) => ZodBigInt.create({ ...arg, coerce: true })),
4026
+ date: ((arg) => ZodDate.create({ ...arg, coerce: true }))
4022
4027
  };
4023
4028
  NEVER = INVALID;
4024
4029
  }
@@ -4178,8 +4183,8 @@ var init_manifest = __esm({
4178
4183
  "use strict";
4179
4184
  init_zod();
4180
4185
  init_scope_name();
4181
- AiToolSchema = external_exports.enum(["cursor", "claude", "*"]);
4182
- ALL_TOOLS = ["cursor", "claude"];
4186
+ AiToolSchema = external_exports.enum(["cursor", "claude", "codex", "*"]);
4187
+ ALL_TOOLS = ["cursor", "claude", "codex"];
4183
4188
  PackageExampleSchema = external_exports.object({
4184
4189
  title: external_exports.string().trim().min(1).max(80),
4185
4190
  description: external_exports.string().trim().min(1).max(240).optional(),
@@ -4326,6 +4331,8 @@ async function detectToolsInProject(projectRoot) {
4326
4331
  detected.push("cursor");
4327
4332
  if (await pathExists((0, import_node_path2.join)(projectRoot, ".claude")))
4328
4333
  detected.push("claude");
4334
+ if (await pathExists((0, import_node_path2.join)(projectRoot, ".codex")))
4335
+ detected.push("codex");
4329
4336
  return detected;
4330
4337
  }
4331
4338
  function manifestAllowsTool(manifest, tool) {
@@ -4370,23 +4377,57 @@ var init_detect_tools = __esm({
4370
4377
  }
4371
4378
  });
4372
4379
 
4373
- // ../../packages/adapter-claude/dist/index.js
4374
- var import_promises2, import_node_path3, ClaudeSkillAdapter, claudeSkillAdapter;
4380
+ // ../../packages/adapter-sdk/dist/index.js
4381
+ async function writeSkillDirectory(skillDir, input2) {
4382
+ const entryPath = (0, import_node_path3.join)(skillDir, "SKILL.md");
4383
+ const seen = /* @__PURE__ */ new Set(["skill.md"]);
4384
+ const files = (input2.supportingFiles ?? []).map((file) => {
4385
+ const normalized = (0, import_node_path3.normalize)(file.path);
4386
+ const target = (0, import_node_path3.resolve)(skillDir, normalized);
4387
+ const fromSkillDir = (0, import_node_path3.relative)(skillDir, target);
4388
+ return { file, normalized, target, fromSkillDir, key: fromSkillDir.toLowerCase() };
4389
+ });
4390
+ for (const { file, normalized, fromSkillDir, key } of files) {
4391
+ if (!normalized || normalized === "." || (0, import_node_path3.isAbsolute)(normalized) || fromSkillDir === ".." || fromSkillDir.startsWith(`..${import_node_path3.sep}`) || (0, import_node_path3.isAbsolute)(fromSkillDir) || seen.has(key)) {
4392
+ throw new Error(`Unsafe or duplicate skill supporting file path: ${file.path}`);
4393
+ }
4394
+ seen.add(key);
4395
+ }
4396
+ await (0, import_promises2.mkdir)(skillDir, { recursive: true });
4397
+ await (0, import_promises2.writeFile)(entryPath, input2.skillMarkdown, "utf8");
4398
+ const writtenPaths = [entryPath];
4399
+ for (const { file, target } of files) {
4400
+ await (0, import_promises2.mkdir)((0, import_node_path3.dirname)(target), { recursive: true });
4401
+ await (0, import_promises2.writeFile)(target, file.content);
4402
+ if (file.mode !== void 0)
4403
+ await (0, import_promises2.chmod)(target, file.mode & 511);
4404
+ writtenPaths.push(target);
4405
+ }
4406
+ return { writtenPaths };
4407
+ }
4408
+ var import_promises2, import_node_path3;
4375
4409
  var init_dist2 = __esm({
4376
- "../../packages/adapter-claude/dist/index.js"() {
4410
+ "../../packages/adapter-sdk/dist/index.js"() {
4377
4411
  "use strict";
4378
4412
  import_promises2 = require("node:fs/promises");
4379
4413
  import_node_path3 = require("node:path");
4414
+ }
4415
+ });
4416
+
4417
+ // ../../packages/adapter-claude/dist/index.js
4418
+ var import_node_path4, ClaudeSkillAdapter, claudeSkillAdapter;
4419
+ var init_dist3 = __esm({
4420
+ "../../packages/adapter-claude/dist/index.js"() {
4421
+ "use strict";
4422
+ import_node_path4 = require("node:path");
4423
+ init_dist2();
4380
4424
  init_dist();
4381
4425
  ClaudeSkillAdapter = class {
4382
4426
  tool = "claude";
4383
4427
  async installSkill(input2) {
4384
4428
  const short = shortNameFromScopeName(input2.packageName);
4385
- const skillDir = (0, import_node_path3.join)(input2.projectRoot, ".claude", "aipm", "skills", short);
4386
- await (0, import_promises2.mkdir)(skillDir, { recursive: true });
4387
- const filePath = (0, import_node_path3.join)(skillDir, "SKILL.md");
4388
- await (0, import_promises2.writeFile)(filePath, input2.skillMarkdown, "utf8");
4389
- return { writtenPaths: [filePath] };
4429
+ const skillDir = (0, import_node_path4.join)(input2.projectRoot, ".claude", "skills", short);
4430
+ return writeSkillDirectory(skillDir, input2);
4390
4431
  }
4391
4432
  };
4392
4433
  claudeSkillAdapter = new ClaudeSkillAdapter();
@@ -4394,20 +4435,20 @@ var init_dist2 = __esm({
4394
4435
  });
4395
4436
 
4396
4437
  // ../../packages/adapter-cursor/dist/index.js
4397
- var import_promises3, import_node_path4, CursorSkillAdapter, cursorSkillAdapter;
4398
- var init_dist3 = __esm({
4438
+ var import_promises3, import_node_path5, CursorSkillAdapter, cursorSkillAdapter;
4439
+ var init_dist4 = __esm({
4399
4440
  "../../packages/adapter-cursor/dist/index.js"() {
4400
4441
  "use strict";
4401
4442
  import_promises3 = require("node:fs/promises");
4402
- import_node_path4 = require("node:path");
4443
+ import_node_path5 = require("node:path");
4403
4444
  init_dist();
4404
4445
  CursorSkillAdapter = class {
4405
4446
  tool = "cursor";
4406
4447
  async installSkill(input2) {
4407
4448
  const short = shortNameFromScopeName(input2.packageName);
4408
- const skillsDir = (0, import_node_path4.join)(input2.projectRoot, ".cursor", "aipm", "skills");
4449
+ const skillsDir = (0, import_node_path5.join)(input2.projectRoot, ".cursor", "aipm", "skills");
4409
4450
  await (0, import_promises3.mkdir)(skillsDir, { recursive: true });
4410
- const filePath = (0, import_node_path4.join)(skillsDir, `${short}.md`);
4451
+ const filePath = (0, import_node_path5.join)(skillsDir, `${short}.md`);
4411
4452
  await (0, import_promises3.writeFile)(filePath, input2.skillMarkdown, "utf8");
4412
4453
  return { writtenPaths: [filePath] };
4413
4454
  }
@@ -4416,6 +4457,26 @@ var init_dist3 = __esm({
4416
4457
  }
4417
4458
  });
4418
4459
 
4460
+ // ../../packages/adapter-codex/dist/index.js
4461
+ var import_node_path6, CodexSkillAdapter, codexSkillAdapter;
4462
+ var init_dist5 = __esm({
4463
+ "../../packages/adapter-codex/dist/index.js"() {
4464
+ "use strict";
4465
+ import_node_path6 = require("node:path");
4466
+ init_dist2();
4467
+ init_dist();
4468
+ CodexSkillAdapter = class {
4469
+ tool = "codex";
4470
+ async installSkill(input2) {
4471
+ const short = shortNameFromScopeName(input2.packageName);
4472
+ const skillDir = (0, import_node_path6.join)(input2.projectRoot, ".agents", "skills", short);
4473
+ return writeSkillDirectory(skillDir, input2);
4474
+ }
4475
+ };
4476
+ codexSkillAdapter = new CodexSkillAdapter();
4477
+ }
4478
+ });
4479
+
4419
4480
  // ../../packages/engine/dist/install-skill.js
4420
4481
  async function installSkillPackage(options) {
4421
4482
  const tools = await resolveInstallTools({
@@ -4425,7 +4486,7 @@ async function installSkillPackage(options) {
4425
4486
  explicitTarget: options.explicitTarget
4426
4487
  });
4427
4488
  if (tools.length === 0) {
4428
- throw new Error("No AI tool detected (.cursor/ or .claude/). Use --target cursor|claude|* or set preferredTools in aipm.package.json.");
4489
+ throw new Error("No AI tool detected (.cursor/, .claude/, or .codex/). Use --target cursor|claude|codex|* or set preferredTools in aipm.package.json.");
4429
4490
  }
4430
4491
  const installed = {};
4431
4492
  for (const tool of tools) {
@@ -4434,6 +4495,7 @@ async function installSkillPackage(options) {
4434
4495
  packageName: options.manifest.name,
4435
4496
  version: options.manifest.version,
4436
4497
  skillMarkdown: options.skillMarkdown,
4498
+ supportingFiles: options.supportingFiles,
4437
4499
  projectRoot: options.projectRoot
4438
4500
  });
4439
4501
  installed[tool] = result.writtenPaths;
@@ -4444,12 +4506,14 @@ var adapters;
4444
4506
  var init_install_skill = __esm({
4445
4507
  "../../packages/engine/dist/install-skill.js"() {
4446
4508
  "use strict";
4447
- init_dist2();
4448
4509
  init_dist3();
4510
+ init_dist4();
4511
+ init_dist5();
4449
4512
  init_detect_tools();
4450
4513
  adapters = {
4451
4514
  cursor: cursorSkillAdapter,
4452
- claude: claudeSkillAdapter
4515
+ claude: claudeSkillAdapter,
4516
+ codex: codexSkillAdapter
4453
4517
  };
4454
4518
  }
4455
4519
  });
@@ -4461,7 +4525,7 @@ __export(dist_exports, {
4461
4525
  installSkillPackage: () => installSkillPackage,
4462
4526
  resolveInstallTools: () => resolveInstallTools
4463
4527
  });
4464
- var init_dist4 = __esm({
4528
+ var init_dist6 = __esm({
4465
4529
  "../../packages/engine/dist/index.js"() {
4466
4530
  "use strict";
4467
4531
  init_detect_tools();
@@ -7841,25 +7905,34 @@ var program = new Command();
7841
7905
  var import_node_crypto3 = require("node:crypto");
7842
7906
  var import_node_child_process4 = require("node:child_process");
7843
7907
  var import_node_http = require("node:http");
7844
- var import_promises11 = require("node:fs/promises");
7845
- var import_node_path14 = require("node:path");
7908
+ var import_promises12 = require("node:fs/promises");
7909
+ var import_node_path17 = require("node:path");
7846
7910
  var import_node_process5 = require("node:process");
7847
7911
  init_dist();
7848
- init_dist4();
7912
+ init_dist6();
7849
7913
 
7850
7914
  // src/pack.ts
7851
7915
  var import_node_child_process2 = require("node:child_process");
7852
7916
  var import_node_util3 = require("node:util");
7853
7917
  var import_promises5 = require("node:fs/promises");
7854
- var import_node_path6 = require("node:path");
7918
+ var import_node_path8 = require("node:path");
7855
7919
  var import_node_os = require("node:os");
7856
7920
 
7857
7921
  // src/publish-state.ts
7858
7922
  var import_node_crypto = require("node:crypto");
7859
7923
  var import_promises4 = require("node:fs/promises");
7860
- var import_node_path5 = require("node:path");
7924
+ var import_node_path7 = require("node:path");
7861
7925
  init_dist();
7862
- var STATE_PATH = (0, import_node_path5.join)(".aipm", "publish-state.json");
7926
+
7927
+ // src/recommend-cmd.ts
7928
+ function recommendCmd(command, stream = process.stderr) {
7929
+ const quoted = `"${command}"`;
7930
+ if (!stream.isTTY) return quoted;
7931
+ return `\x1B[36m${quoted}\x1B[39m`;
7932
+ }
7933
+
7934
+ // src/publish-state.ts
7935
+ var STATE_PATH = (0, import_node_path7.join)(".aipm", "publish-state.json");
7863
7936
  var IGNORE_FILE = ".aipmignore";
7864
7937
  var MAX_PACKAGE_BYTES = 50 * 1024 * 1024;
7865
7938
  var EXCLUDED_SEGMENTS = /* @__PURE__ */ new Set([".aipm", ".git", "node_modules", "dist", ".next"]);
@@ -7874,11 +7947,11 @@ var SECRET_PATTERNS = [
7874
7947
  /<publishData/i
7875
7948
  ];
7876
7949
  function publishStatePath(root) {
7877
- return (0, import_node_path5.join)(root, STATE_PATH);
7950
+ return (0, import_node_path7.join)(root, STATE_PATH);
7878
7951
  }
7879
7952
  function normalizePublishPath(root, filePath) {
7880
- const abs = (0, import_node_path5.resolve)(root, filePath);
7881
- const rel = (0, import_node_path5.normalize)((0, import_node_path5.relative)(root, abs)).split(import_node_path5.sep).join("/");
7953
+ const abs = (0, import_node_path7.resolve)(root, filePath);
7954
+ const rel = (0, import_node_path7.normalize)((0, import_node_path7.relative)(root, abs)).split(import_node_path7.sep).join("/");
7882
7955
  if (!rel || rel === ".") return ".";
7883
7956
  if (rel.startsWith("../") || rel === ".." || rel.startsWith("/")) {
7884
7957
  throw new Error(`Path is outside the skill folder: ${filePath}`);
@@ -7895,7 +7968,7 @@ function isExcludedPublishPath(rel) {
7895
7968
  }
7896
7969
  async function readAipmIgnore(root) {
7897
7970
  try {
7898
- const raw = await (0, import_promises4.readFile)((0, import_node_path5.join)(root, IGNORE_FILE), "utf8");
7971
+ const raw = await (0, import_promises4.readFile)((0, import_node_path7.join)(root, IGNORE_FILE), "utf8");
7899
7972
  return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
7900
7973
  } catch {
7901
7974
  return [];
@@ -7944,14 +8017,14 @@ async function readPublishState(root) {
7944
8017
  }
7945
8018
  async function writePublishState(root, state) {
7946
8019
  const path2 = publishStatePath(root);
7947
- await (0, import_promises4.mkdir)((0, import_node_path5.dirname)(path2), { recursive: true });
8020
+ await (0, import_promises4.mkdir)((0, import_node_path7.dirname)(path2), { recursive: true });
7948
8021
  const files = [...state.files].sort((a, b) => a.path.localeCompare(b.path));
7949
8022
  await (0, import_promises4.writeFile)(path2, JSON.stringify({ schemaVersion: "0.1", files }, null, 2) + "\n", "utf8");
7950
8023
  }
7951
8024
  async function expandPublishPath(root, rel) {
7952
8025
  if (isExcludedPublishPath(rel)) return [];
7953
8026
  if (await isIgnoredByAipmIgnore(root, rel)) return [];
7954
- const abs = (0, import_node_path5.join)(root, rel);
8027
+ const abs = (0, import_node_path7.join)(root, rel);
7955
8028
  const info = await (0, import_promises4.stat)(abs);
7956
8029
  if (info.isFile()) return [rel];
7957
8030
  if (!info.isDirectory()) return [];
@@ -7971,7 +8044,7 @@ async function addPublishFiles(root, paths) {
7971
8044
  for (const rel of files) {
7972
8045
  if (isExcludedPublishPath(rel)) continue;
7973
8046
  if (await isIgnoredByAipmIgnore(root, rel)) continue;
7974
- const hashed = await fileHash((0, import_node_path5.join)(root, rel));
8047
+ const hashed = await fileHash((0, import_node_path7.join)(root, rel));
7975
8048
  byPath.set(rel, { path: rel, ...hashed });
7976
8049
  }
7977
8050
  }
@@ -7994,11 +8067,13 @@ async function resetPublishState(root) {
7994
8067
  }
7995
8068
  async function readManifest(root) {
7996
8069
  try {
7997
- const raw = await (0, import_promises4.readFile)((0, import_node_path5.join)(root, "aipm.manifest.json"), "utf8");
8070
+ const raw = await (0, import_promises4.readFile)((0, import_node_path7.join)(root, "aipm.manifest.json"), "utf8");
7998
8071
  return PackageManifestSchema.parse(JSON.parse(raw));
7999
8072
  } catch (error) {
8000
8073
  if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
8001
- throw new Error("No aipm.manifest.json found. Run aipm publish init --name @org/skill.");
8074
+ throw new Error(
8075
+ `No aipm.manifest.json found. Run ${recommendCmd("aipm publish init --name <@org/skill>")}.`
8076
+ );
8002
8077
  }
8003
8078
  throw error;
8004
8079
  }
@@ -8014,7 +8089,9 @@ function installReferencedFiles(manifest) {
8014
8089
  async function validatePublishState(root) {
8015
8090
  const manifest = await readManifest(root);
8016
8091
  const state = await readPublishState(root);
8017
- if (state.files.length === 0) throw new Error("No files staged. Run aipm publish add <files...>.");
8092
+ if (state.files.length === 0) {
8093
+ throw new Error(`No files staged. Run ${recommendCmd("aipm publish add <files...>")}.`);
8094
+ }
8018
8095
  const staged = new Set(state.files.map((entry) => entry.path));
8019
8096
  if (!staged.has("aipm.manifest.json")) throw new Error("aipm.manifest.json must be staged.");
8020
8097
  if (!staged.has(manifest.entry)) throw new Error(`Manifest entry must be staged: ${manifest.entry}`);
@@ -8027,12 +8104,14 @@ async function validatePublishState(root) {
8027
8104
  if (await isIgnoredByAipmIgnore(root, entry.path)) {
8028
8105
  throw new Error(`Refusing to publish ignored path: ${entry.path}`);
8029
8106
  }
8030
- const abs = (0, import_node_path5.join)(root, entry.path);
8107
+ const abs = (0, import_node_path7.join)(root, entry.path);
8031
8108
  const info = await (0, import_promises4.stat)(abs).catch(() => null);
8032
8109
  if (!info?.isFile()) throw new Error(`Staged file is missing: ${entry.path}`);
8033
8110
  const hashed = await fileHash(abs);
8034
8111
  if (hashed.hash !== entry.hash) {
8035
- throw new Error(`Staged file changed after add: ${entry.path}. Run aipm publish add ${entry.path}`);
8112
+ throw new Error(
8113
+ `Staged file changed after add: ${entry.path}. Run ${recommendCmd(`aipm publish add ${entry.path}`)}.`
8114
+ );
8036
8115
  }
8037
8116
  await assertNoObviousSecrets(abs, entry.path);
8038
8117
  size += hashed.size;
@@ -8044,7 +8123,7 @@ async function statusPublishState(root) {
8044
8123
  const state = await readPublishState(root);
8045
8124
  const rows = [];
8046
8125
  for (const entry of state.files) {
8047
- const current = await fileHash((0, import_node_path5.join)(root, entry.path)).catch(() => null);
8126
+ const current = await fileHash((0, import_node_path7.join)(root, entry.path)).catch(() => null);
8048
8127
  rows.push({ ...entry, changed: !current || current.hash !== entry.hash });
8049
8128
  }
8050
8129
  return rows;
@@ -8052,9 +8131,9 @@ async function statusPublishState(root) {
8052
8131
  async function copyStagedFiles(root, destination) {
8053
8132
  const state = await readPublishState(root);
8054
8133
  for (const entry of state.files) {
8055
- const target = (0, import_node_path5.join)(destination, entry.path);
8056
- await (0, import_promises4.mkdir)((0, import_node_path5.dirname)(target), { recursive: true });
8057
- await (0, import_promises4.cp)((0, import_node_path5.join)(root, entry.path), target);
8134
+ const target = (0, import_node_path7.join)(destination, entry.path);
8135
+ await (0, import_promises4.mkdir)((0, import_node_path7.dirname)(target), { recursive: true });
8136
+ await (0, import_promises4.cp)((0, import_node_path7.join)(root, entry.path), target);
8058
8137
  }
8059
8138
  }
8060
8139
 
@@ -8068,7 +8147,7 @@ async function packDirectory(dir) {
8068
8147
  return Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout);
8069
8148
  }
8070
8149
  async function packStagedFiles(root) {
8071
- const tempDir = await (0, import_promises5.mkdtemp)((0, import_node_path6.join)((0, import_node_os.tmpdir)(), "aipm-publish-stage-"));
8150
+ const tempDir = await (0, import_promises5.mkdtemp)((0, import_node_path8.join)((0, import_node_os.tmpdir)(), "aipm-publish-stage-"));
8072
8151
  try {
8073
8152
  await copyStagedFiles(root, tempDir);
8074
8153
  return await packDirectory(tempDir);
@@ -8078,10 +8157,10 @@ async function packStagedFiles(root) {
8078
8157
  }
8079
8158
  async function unpackTarballToDirectory(tarball) {
8080
8159
  const { mkdtemp: mkdtemp2, writeFile: writeFile8 } = await import("node:fs/promises");
8081
- const { join: join14 } = await import("node:path");
8160
+ const { join: join16 } = await import("node:path");
8082
8161
  const { tmpdir: tmpdir2 } = await import("node:os");
8083
- const tempDir = await mkdtemp2(join14(tmpdir2(), "aipm-install-"));
8084
- const tgzPath = join14(tempDir, "pkg.tgz");
8162
+ const tempDir = await mkdtemp2(join16(tmpdir2(), "aipm-install-"));
8163
+ const tgzPath = join16(tempDir, "pkg.tgz");
8085
8164
  await writeFile8(tgzPath, tarball);
8086
8165
  await execFileAsync("tar", ["-xzf", tgzPath, "-C", tempDir]);
8087
8166
  return tempDir;
@@ -8095,7 +8174,7 @@ function registryFetchError(registry, cause) {
8095
8174
  const msg = cause instanceof Error ? cause.message : String(cause);
8096
8175
  if (msg === "fetch failed" || msg.includes("ECONNREFUSED") || msg.includes("ENOTFOUND") || msg.includes("timed out") || msg.includes("aborted")) {
8097
8176
  return new Error(
8098
- `Cannot reach registry at ${registry}. Check your connection or pass --registry <url>.`
8177
+ `Cannot reach registry at ${registry}. Check your connection or pass ${recommendCmd("--registry <url>")}.`
8099
8178
  );
8100
8179
  }
8101
8180
  return new Error(`Registry request failed (${registry}): ${msg}`);
@@ -8116,13 +8195,13 @@ function privateInstallHint(name, status, token) {
8116
8195
  if (status !== 404 || !name.startsWith("@") || token) {
8117
8196
  return `Package not found: ${name} (${status})`;
8118
8197
  }
8119
- return `Package not found: ${name} (${status}). If @org/pkg is private, run aipm login, or set AIPM_TOKEN for CI.`;
8198
+ return `Package not found: ${name} (${status}). If @org/pkg is private, run ${recommendCmd("aipm login")}, or set AIPM_TOKEN for CI.`;
8120
8199
  }
8121
8200
  function publishTokenHint(name, error) {
8122
8201
  if (error === "Publish token required") {
8123
8202
  return [
8124
8203
  `Publish token required for ${name}.`,
8125
- `Generate a fresh 5-minute publish token for ${name} from the package dashboard, then retry with AIPM_TOKEN=<token> aipm publish push --yes.`
8204
+ `Generate a fresh 5-minute publish token for ${name} from the package dashboard, then retry with ${recommendCmd("AIPM_TOKEN=<token> aipm publish push --yes")}.`
8126
8205
  ].join(" ");
8127
8206
  }
8128
8207
  if (error === "Invalid publish token") {
@@ -8280,8 +8359,8 @@ async function publishPrompt(registry, input2, accessToken, sampleImage) {
8280
8359
  // src/auth-store.ts
8281
8360
  var import_promises6 = require("node:fs/promises");
8282
8361
  var import_node_os2 = require("node:os");
8283
- var import_node_path7 = require("node:path");
8284
- var AUTH_FILE = (0, import_node_path7.join)((0, import_node_os2.homedir)(), ".aipm", "auth.json");
8362
+ var import_node_path9 = require("node:path");
8363
+ var AUTH_FILE = (0, import_node_path9.join)((0, import_node_os2.homedir)(), ".aipm", "auth.json");
8285
8364
  function normalizeRegistry(registry) {
8286
8365
  return registry.replace(/\/$/, "");
8287
8366
  }
@@ -8295,7 +8374,7 @@ async function readAuthStore() {
8295
8374
  }
8296
8375
  }
8297
8376
  async function writeAuthStore(store) {
8298
- await (0, import_promises6.mkdir)((0, import_node_path7.dirname)(AUTH_FILE), { recursive: true });
8377
+ await (0, import_promises6.mkdir)((0, import_node_path9.dirname)(AUTH_FILE), { recursive: true });
8299
8378
  await (0, import_promises6.writeFile)(AUTH_FILE, JSON.stringify(store, null, 2) + "\n", "utf8");
8300
8379
  await (0, import_promises6.chmod)(AUTH_FILE, 384).catch(() => void 0);
8301
8380
  }
@@ -8326,19 +8405,19 @@ function isAccessTokenFresh(auth, skewMs = 6e4) {
8326
8405
  }
8327
8406
 
8328
8407
  // src/install-one.ts
8329
- init_dist4();
8408
+ init_dist6();
8330
8409
  var import_promises8 = require("node:fs/promises");
8331
- var import_node_path9 = require("node:path");
8410
+ var import_node_path11 = require("node:path");
8332
8411
 
8333
8412
  // src/project-files.ts
8334
8413
  var import_promises7 = require("node:fs/promises");
8335
- var import_node_path8 = require("node:path");
8414
+ var import_node_path10 = require("node:path");
8336
8415
  init_dist();
8337
8416
  var PACKAGE_JSON = "aipm.package.json";
8338
8417
  var LOCKFILE = "aipm-lock.json";
8339
8418
  async function readProjectPackageJson(projectRoot) {
8340
8419
  try {
8341
- const raw = await (0, import_promises7.readFile)((0, import_node_path8.join)(projectRoot, PACKAGE_JSON), "utf8");
8420
+ const raw = await (0, import_promises7.readFile)((0, import_node_path10.join)(projectRoot, PACKAGE_JSON), "utf8");
8342
8421
  return ProjectPackageJsonSchema.parse(JSON.parse(raw));
8343
8422
  } catch {
8344
8423
  return null;
@@ -8346,21 +8425,21 @@ async function readProjectPackageJson(projectRoot) {
8346
8425
  }
8347
8426
  async function writeProjectPackageJson(projectRoot, data) {
8348
8427
  await (0, import_promises7.writeFile)(
8349
- (0, import_node_path8.join)(projectRoot, PACKAGE_JSON),
8428
+ (0, import_node_path10.join)(projectRoot, PACKAGE_JSON),
8350
8429
  JSON.stringify(data, null, 2) + "\n",
8351
8430
  "utf8"
8352
8431
  );
8353
8432
  }
8354
8433
  async function readLockfile(projectRoot) {
8355
8434
  try {
8356
- const raw = await (0, import_promises7.readFile)((0, import_node_path8.join)(projectRoot, LOCKFILE), "utf8");
8435
+ const raw = await (0, import_promises7.readFile)((0, import_node_path10.join)(projectRoot, LOCKFILE), "utf8");
8357
8436
  return LockfileSchema.parse(JSON.parse(raw));
8358
8437
  } catch {
8359
8438
  return null;
8360
8439
  }
8361
8440
  }
8362
8441
  async function writeLockfile(projectRoot, data) {
8363
- await (0, import_promises7.writeFile)((0, import_node_path8.join)(projectRoot, LOCKFILE), JSON.stringify(data, null, 2) + "\n", "utf8");
8442
+ await (0, import_promises7.writeFile)((0, import_node_path10.join)(projectRoot, LOCKFILE), JSON.stringify(data, null, 2) + "\n", "utf8");
8364
8443
  }
8365
8444
  function upsertLockEntry(lock, name, entry) {
8366
8445
  return {
@@ -8384,15 +8463,17 @@ function resolveRegistryUrl(project, flag, fallback) {
8384
8463
  }
8385
8464
  function parseTargetFlag(target) {
8386
8465
  if (!target) return void 0;
8387
- if (target === "cursor" || target === "claude" || target === "*") return target;
8388
- throw new Error('--target must be "cursor", "claude", or "*"');
8466
+ if (target === "cursor" || target === "claude" || target === "codex" || target === "*") {
8467
+ return target;
8468
+ }
8469
+ throw new Error('--target must be "cursor", "claude", "codex", or "*"');
8389
8470
  }
8390
8471
  function parseTargetsFlag(value) {
8391
8472
  const targets = value.split(",").map((target) => target.trim()).filter(Boolean);
8392
8473
  if (targets.length === 0) throw new Error("At least one target is required.");
8393
8474
  for (const target of targets) {
8394
- if (target !== "cursor" && target !== "claude" && target !== "*") {
8395
- throw new Error('--targets must contain only "cursor", "claude", and/or "*"');
8475
+ if (target !== "cursor" && target !== "claude" && target !== "codex" && target !== "*") {
8476
+ throw new Error('--targets must contain only "cursor", "claude", "codex", and/or "*"');
8396
8477
  }
8397
8478
  }
8398
8479
  const unique = [...new Set(targets)];
@@ -8408,13 +8489,13 @@ async function promptForTool() {
8408
8489
  try {
8409
8490
  while (true) {
8410
8491
  const answer = await rl.question(
8411
- "Which AI tool should this skill be installed for? (cursor/claude): "
8492
+ "Which AI tool should this skill be installed for? (cursor/claude/codex): "
8412
8493
  );
8413
8494
  const normalized = answer.trim().toLowerCase();
8414
- if (normalized === "cursor" || normalized === "claude") {
8495
+ if (normalized === "cursor" || normalized === "claude" || normalized === "codex") {
8415
8496
  return normalized;
8416
8497
  }
8417
- console.log('Please enter "cursor" or "claude".');
8498
+ console.log('Please enter "cursor", "claude", or "codex".');
8418
8499
  }
8419
8500
  } finally {
8420
8501
  rl.close();
@@ -8433,7 +8514,7 @@ async function promptForConfirmation(question) {
8433
8514
 
8434
8515
  // src/install-one.ts
8435
8516
  function normalizeRelativePath(path2) {
8436
- return (0, import_node_path9.normalize)(path2).split(import_node_path9.sep).join("/");
8517
+ return (0, import_node_path11.normalize)(path2).split(import_node_path11.sep).join("/");
8437
8518
  }
8438
8519
  function assertSafeRelativePath(path2) {
8439
8520
  const rel = normalizeRelativePath(path2.trim());
@@ -8444,8 +8525,8 @@ function assertSafeRelativePath(path2) {
8444
8525
  }
8445
8526
  function safeJoin(root, relPath) {
8446
8527
  const rel = assertSafeRelativePath(relPath);
8447
- const target = (0, import_node_path9.resolve)(root, rel);
8448
- const fromRoot = normalizeRelativePath((0, import_node_path9.relative)(root, target));
8528
+ const target = (0, import_node_path11.resolve)(root, rel);
8529
+ const fromRoot = normalizeRelativePath((0, import_node_path11.relative)(root, target));
8449
8530
  if (fromRoot === ".." || fromRoot.startsWith("../") || fromRoot.startsWith("/")) {
8450
8531
  throw new Error(`Unsafe install path: ${relPath}`);
8451
8532
  }
@@ -8456,8 +8537,8 @@ function packageHelperSlug(name) {
8456
8537
  return `${scope}__${pkg}`;
8457
8538
  }
8458
8539
  function helperRootFor(configRoot, packageName, version) {
8459
- const base = (0, import_node_path9.basename)(configRoot) === ".aipm" ? (0, import_node_path9.join)(configRoot, "helpers") : (0, import_node_path9.join)(configRoot, ".aipm", "helpers");
8460
- return (0, import_node_path9.join)(base, packageHelperSlug(packageName), version);
8540
+ const base = (0, import_node_path11.basename)(configRoot) === ".aipm" ? (0, import_node_path11.join)(configRoot, "helpers") : (0, import_node_path11.join)(configRoot, ".aipm", "helpers");
8541
+ return (0, import_node_path11.join)(base, packageHelperSlug(packageName), version);
8461
8542
  }
8462
8543
  async function assertSourceFile(packageRoot, relPath) {
8463
8544
  const source = safeJoin(packageRoot, relPath);
@@ -8465,6 +8546,55 @@ async function assertSourceFile(packageRoot, relPath) {
8465
8546
  if (!info?.isFile()) throw new Error(`Package install file not found: ${relPath}`);
8466
8547
  return source;
8467
8548
  }
8549
+ function installReferencedFiles2(install) {
8550
+ return [
8551
+ ...(install?.mainFiles ?? []).map((file) => file.from),
8552
+ ...(install?.helperFiles ?? []).map((file) => file.from)
8553
+ ];
8554
+ }
8555
+ function isRootLicenseOrNotice(path2) {
8556
+ return !path2.includes("/") && /^(?:licen[cs]e|notice|copying)(?:$|[._-])/i.test(path2);
8557
+ }
8558
+ async function listRegularPackageFiles(root, current = root) {
8559
+ const files = [];
8560
+ for (const entry of await (0, import_promises8.readdir)(current, { withFileTypes: true })) {
8561
+ const absolute = (0, import_node_path11.join)(current, entry.name);
8562
+ if (entry.isDirectory()) {
8563
+ files.push(...await listRegularPackageFiles(root, absolute));
8564
+ } else if (entry.isFile()) {
8565
+ files.push(normalizeRelativePath((0, import_node_path11.relative)(root, absolute)));
8566
+ }
8567
+ }
8568
+ return files;
8569
+ }
8570
+ async function collectSkillSupportingFiles(packageRoot, manifest) {
8571
+ const entry = assertSafeRelativePath(manifest.entry);
8572
+ const entryDirectory = (0, import_node_path11.dirname)(entry);
8573
+ const excluded = /* @__PURE__ */ new Set([
8574
+ entry,
8575
+ "aipm.manifest.json",
8576
+ "pkg.tgz",
8577
+ ...installReferencedFiles2(manifest.install).map(assertSafeRelativePath)
8578
+ ]);
8579
+ const supportingFiles = [];
8580
+ for (const sourcePath of await listRegularPackageFiles(packageRoot)) {
8581
+ if (excluded.has(sourcePath)) continue;
8582
+ const fromEntryDirectory = normalizeRelativePath((0, import_node_path11.relative)(entryDirectory, sourcePath));
8583
+ const isEntrySibling = fromEntryDirectory !== ".." && !fromEntryDirectory.startsWith("../") && !fromEntryDirectory.startsWith("/");
8584
+ if (!isEntrySibling && !isRootLicenseOrNotice(sourcePath)) continue;
8585
+ const destinationPath = isEntrySibling ? fromEntryDirectory : (0, import_node_path11.basename)(sourcePath);
8586
+ if (destinationPath.toLowerCase() === "skill.md") {
8587
+ throw new Error(`Package supporting file conflicts with installed SKILL.md: ${sourcePath}`);
8588
+ }
8589
+ const source = safeJoin(packageRoot, sourcePath);
8590
+ supportingFiles.push({
8591
+ path: destinationPath,
8592
+ content: await (0, import_promises8.readFile)(source),
8593
+ mode: (await (0, import_promises8.stat)(source)).mode
8594
+ });
8595
+ }
8596
+ return supportingFiles.sort((a, b) => a.path.localeCompare(b.path));
8597
+ }
8468
8598
  async function copyMainFile(input2) {
8469
8599
  const source = await assertSourceFile(input2.packageRoot, input2.file.from);
8470
8600
  const target = safeJoin(input2.installRoot, input2.file.to);
@@ -8474,14 +8604,14 @@ async function copyMainFile(input2) {
8474
8604
  if (overwrite === "skip") return null;
8475
8605
  if (overwrite === "fail") throw new Error(`Install target already exists: ${target}`);
8476
8606
  }
8477
- await (0, import_promises8.mkdir)((0, import_node_path9.dirname)(target), { recursive: true });
8607
+ await (0, import_promises8.mkdir)((0, import_node_path11.dirname)(target), { recursive: true });
8478
8608
  await (0, import_promises8.cp)(source, target, { force: overwrite === "replace" });
8479
8609
  return target;
8480
8610
  }
8481
8611
  async function copyHelperFile(input2) {
8482
8612
  const source = await assertSourceFile(input2.packageRoot, input2.file.from);
8483
- const target = safeJoin(input2.helperRoot, input2.file.to ?? (0, import_node_path9.basename)(input2.file.from));
8484
- await (0, import_promises8.mkdir)((0, import_node_path9.dirname)(target), { recursive: true });
8613
+ const target = safeJoin(input2.helperRoot, input2.file.to ?? (0, import_node_path11.basename)(input2.file.from));
8614
+ await (0, import_promises8.mkdir)((0, import_node_path11.dirname)(target), { recursive: true });
8485
8615
  await (0, import_promises8.cp)(source, target, { force: true });
8486
8616
  return target;
8487
8617
  }
@@ -8544,7 +8674,7 @@ async function installOnePackage(options) {
8544
8674
  }
8545
8675
  let explicitTarget = options.explicitTarget;
8546
8676
  let preferredTools = options.project.preferredTools;
8547
- const { resolveInstallTools: resolveInstallTools2 } = await Promise.resolve().then(() => (init_dist4(), dist_exports));
8677
+ const { resolveInstallTools: resolveInstallTools2 } = await Promise.resolve().then(() => (init_dist6(), dist_exports));
8548
8678
  let tools = await resolveInstallTools2({
8549
8679
  projectRoot: installRoot,
8550
8680
  manifest,
@@ -8554,7 +8684,7 @@ async function installOnePackage(options) {
8554
8684
  if (tools.length === 0) {
8555
8685
  if (options.ci) {
8556
8686
  throw new Error(
8557
- "No tool detected. Use --target cursor|claude|* in CI mode."
8687
+ "No tool detected. Use --target cursor|claude|codex|* in CI mode."
8558
8688
  );
8559
8689
  }
8560
8690
  const choice = await promptForTool();
@@ -8576,10 +8706,12 @@ async function installOnePackage(options) {
8576
8706
  const packageRoot = await unpackTarballToDirectory(tarball);
8577
8707
  try {
8578
8708
  const skillMarkdown = await (0, import_promises8.readFile)(safeJoin(packageRoot, manifest.entry), "utf8");
8709
+ const supportingFiles = await collectSkillSupportingFiles(packageRoot, manifest);
8579
8710
  const result = await installSkillPackage({
8580
8711
  projectRoot: installRoot,
8581
8712
  manifest,
8582
8713
  skillMarkdown,
8714
+ supportingFiles,
8583
8715
  preferredTools,
8584
8716
  explicitTarget
8585
8717
  });
@@ -8623,16 +8755,16 @@ async function installOnePackage(options) {
8623
8755
  // src/doctor.ts
8624
8756
  var import_node_child_process3 = require("node:child_process");
8625
8757
  var import_promises9 = require("node:fs/promises");
8626
- var import_node_path11 = require("node:path");
8758
+ var import_node_path13 = require("node:path");
8627
8759
  var import_node_util4 = require("node:util");
8628
8760
 
8629
8761
  // src/project-root.ts
8630
8762
  var import_node_os3 = require("node:os");
8631
- var import_node_path10 = require("node:path");
8763
+ var import_node_path12 = require("node:path");
8632
8764
  var import_node_process3 = require("node:process");
8633
8765
  function globalConfigDir(env2 = process.env) {
8634
8766
  const fromEnv = env2.AIPM_HOME?.trim();
8635
- return fromEnv ? fromEnv.replace(/\/$/, "") : (0, import_node_path10.join)((0, import_node_os3.homedir)(), ".aipm");
8767
+ return fromEnv ? fromEnv.replace(/\/$/, "") : (0, import_node_path12.join)((0, import_node_os3.homedir)(), ".aipm");
8636
8768
  }
8637
8769
  function resolveConfigRoot(options = {}) {
8638
8770
  return options.global ? globalConfigDir() : (0, import_node_process3.cwd)();
@@ -8644,7 +8776,7 @@ function scopeLabel(options) {
8644
8776
  return options.global ? "global" : "project";
8645
8777
  }
8646
8778
  function initRequiredMessage(options) {
8647
- return options.global ? "Run aipm init -g first" : "Run aipm init first";
8779
+ return options.global ? `Run ${recommendCmd("aipm init -g")} first` : `Run ${recommendCmd("aipm init")} first`;
8648
8780
  }
8649
8781
 
8650
8782
  // src/doctor.ts
@@ -8663,11 +8795,11 @@ async function commandOutput(command, args) {
8663
8795
  }
8664
8796
  function npmGlobalBin(prefix) {
8665
8797
  if (!prefix) return null;
8666
- return process.platform === "win32" ? prefix : `${prefix}${import_node_path11.sep}bin`;
8798
+ return process.platform === "win32" ? prefix : `${prefix}${import_node_path13.sep}bin`;
8667
8799
  }
8668
8800
  function pathIncludes(pathDir) {
8669
8801
  if (!pathDir) return false;
8670
- return (process.env.PATH ?? "").split(import_node_path11.delimiter).includes(pathDir);
8802
+ return (process.env.PATH ?? "").split(import_node_path13.delimiter).includes(pathDir);
8671
8803
  }
8672
8804
  function shellPathHint(binDir) {
8673
8805
  if (!binDir) return "Run npm prefix -g and add its bin folder to PATH.";
@@ -8720,11 +8852,11 @@ async function runDoctor(options) {
8720
8852
  if (!options.publish) {
8721
8853
  const configLabel = options.global ? "Global config" : "Project config";
8722
8854
  try {
8723
- await (0, import_promises9.access)((0, import_node_path11.join)(configRoot, "aipm.package.json"));
8855
+ await (0, import_promises9.access)((0, import_node_path13.join)(configRoot, "aipm.package.json"));
8724
8856
  checks.push({
8725
8857
  name: configLabel,
8726
8858
  ok: true,
8727
- detail: `${(0, import_node_path11.join)(configRoot, "aipm.package.json")} exists (${scopeLabel(scope)}).`
8859
+ detail: `${(0, import_node_path13.join)(configRoot, "aipm.package.json")} exists (${scopeLabel(scope)}).`
8728
8860
  });
8729
8861
  } catch {
8730
8862
  checks.push({
@@ -8754,7 +8886,7 @@ async function runDoctor(options) {
8754
8886
  checks.push({
8755
8887
  name: "Publish stage",
8756
8888
  ok: rows.length > 0 && changed.length === 0,
8757
- detail: rows.length === 0 ? "No files staged. Run aipm publish add ." : changed.length > 0 ? `${changed.length} staged file(s) changed after add. Run aipm publish add . again.` : `${rows.length} file(s) staged.`
8889
+ detail: rows.length === 0 ? `No files staged. Run ${recommendCmd("aipm publish add .")}` : changed.length > 0 ? `${changed.length} staged file(s) changed after add. Run ${recommendCmd("aipm publish add .")} again.` : `${rows.length} file(s) staged.`
8758
8890
  });
8759
8891
  } catch (error) {
8760
8892
  checks.push({
@@ -8795,7 +8927,7 @@ async function runDoctor(options) {
8795
8927
  // src/prompt-install.ts
8796
8928
  var import_node_crypto2 = require("node:crypto");
8797
8929
  var import_promises10 = require("node:fs/promises");
8798
- var import_node_path12 = require("node:path");
8930
+ var import_node_path14 = require("node:path");
8799
8931
  var PROMPT_SITE_ORIGIN = "https://www.aipm-registry.com";
8800
8932
  function parsePromptUrl(value) {
8801
8933
  let url;
@@ -8820,10 +8952,10 @@ function parsePromptUrl(value) {
8820
8952
  };
8821
8953
  }
8822
8954
  function promptDirectory(configRoot) {
8823
- return (0, import_node_path12.basename)(configRoot) === ".aipm" ? (0, import_node_path12.join)(configRoot, "prompts") : (0, import_node_path12.join)(configRoot, ".aipm", "prompts");
8955
+ return (0, import_node_path14.basename)(configRoot) === ".aipm" ? (0, import_node_path14.join)(configRoot, "prompts") : (0, import_node_path14.join)(configRoot, ".aipm", "prompts");
8824
8956
  }
8825
8957
  function promptSnapshotPath(configRoot, reference) {
8826
- return (0, import_node_path12.join)(promptDirectory(configRoot), `${reference.publisher}--${reference.slug}.md`);
8958
+ return (0, import_node_path14.join)(promptDirectory(configRoot), `${reference.publisher}--${reference.slug}.md`);
8827
8959
  }
8828
8960
  function canonicalPromptContent(prompt) {
8829
8961
  return JSON.stringify({
@@ -8882,7 +9014,7 @@ function emptyLock() {
8882
9014
  return { schemaVersion: "0.1", packages: {}, prompts: {} };
8883
9015
  }
8884
9016
  function installedRelativePath(configRoot, absolutePath) {
8885
- return (0, import_node_path12.relative)(configRoot, absolutePath).split("\\").join("/");
9017
+ return (0, import_node_path14.relative)(configRoot, absolutePath).split("\\").join("/");
8886
9018
  }
8887
9019
  async function installTrackedPrompt(input2) {
8888
9020
  const prompt = await fetchPromptDetail(
@@ -8903,7 +9035,7 @@ async function installTrackedPrompt(input2) {
8903
9035
  const fileExists = Boolean(await (0, import_promises10.stat)(outputPath).catch(() => null));
8904
9036
  const changed = !existing || existing.contentHash !== contentHash || !fileExists;
8905
9037
  if (!input2.updateOnly || changed) {
8906
- await (0, import_promises10.mkdir)((0, import_node_path12.dirname)(outputPath), { recursive: true });
9038
+ await (0, import_promises10.mkdir)((0, import_node_path14.dirname)(outputPath), { recursive: true });
8907
9039
  await (0, import_promises10.writeFile)(outputPath, renderPromptMarkdown(prompt, canonicalReference.url), "utf8");
8908
9040
  }
8909
9041
  if (input2.track) {
@@ -8946,12 +9078,12 @@ function resolveTrackedPrompt(project, value) {
8946
9078
  return parsed ? { ...parsed, alias: value } : null;
8947
9079
  }
8948
9080
  async function readInstalledPrompt(configRoot, entry) {
8949
- return (0, import_promises10.readFile)((0, import_node_path12.join)(configRoot, entry.installedPath), "utf8");
9081
+ return (0, import_promises10.readFile)((0, import_node_path14.join)(configRoot, entry.installedPath), "utf8");
8950
9082
  }
8951
9083
  async function removeTrackedPrompt(input2) {
8952
9084
  const lock = await readLockfile(input2.configRoot);
8953
9085
  const entry = lock?.prompts[input2.reference.alias];
8954
- if (entry) await (0, import_promises10.rm)((0, import_node_path12.join)(input2.configRoot, entry.installedPath), { force: true });
9086
+ if (entry) await (0, import_promises10.rm)((0, import_node_path14.join)(input2.configRoot, entry.installedPath), { force: true });
8955
9087
  const prompts = { ...input2.project.prompts };
8956
9088
  delete prompts[input2.reference.alias];
8957
9089
  await writeProjectPackageJson(input2.configRoot, { ...input2.project, prompts });
@@ -8962,11 +9094,65 @@ async function removeTrackedPrompt(input2) {
8962
9094
  }
8963
9095
  }
8964
9096
 
9097
+ // src/remove-package.ts
9098
+ var import_promises11 = require("node:fs/promises");
9099
+ var import_node_path15 = require("node:path");
9100
+ function within(root, path2) {
9101
+ const rel = (0, import_node_path15.relative)((0, import_node_path15.resolve)(root), (0, import_node_path15.resolve)(path2));
9102
+ return rel === "" || !rel.startsWith("..") && !(0, import_node_path15.isAbsolute)(rel);
9103
+ }
9104
+ function trackedInstalledPackagePaths(entry) {
9105
+ return [
9106
+ ...Object.values(entry.installed).flat(),
9107
+ ...entry.installedAssets?.main ?? [],
9108
+ ...entry.installedAssets?.helper ?? []
9109
+ ];
9110
+ }
9111
+ async function pruneEmptyParents(path2, roots) {
9112
+ let current = (0, import_node_path15.dirname)(path2);
9113
+ while (roots.some((root) => within(root, current)) && !roots.some((root) => (0, import_node_path15.resolve)(root) === current)) {
9114
+ try {
9115
+ await (0, import_promises11.rmdir)(current);
9116
+ } catch {
9117
+ return;
9118
+ }
9119
+ current = (0, import_node_path15.dirname)(current);
9120
+ }
9121
+ }
9122
+ async function removeInstalledPackageFiles(input2) {
9123
+ const roots = [.../* @__PURE__ */ new Set([(0, import_node_path15.resolve)(input2.configRoot), (0, import_node_path15.resolve)(input2.installRoot)])];
9124
+ const realRoots = await Promise.all(roots.map((root) => (0, import_promises11.realpath)(root).catch(() => root)));
9125
+ const requestedPaths = [...new Set(trackedInstalledPackagePaths(input2.entry).map((path2) => (0, import_node_path15.resolve)(path2)))];
9126
+ const protectedPaths = new Set(
9127
+ (input2.otherEntries ?? []).flatMap(trackedInstalledPackagePaths).map((path2) => (0, import_node_path15.resolve)(path2))
9128
+ );
9129
+ const paths = requestedPaths.filter((path2) => !protectedPaths.has(path2));
9130
+ const unsafe = paths.find((path2) => !roots.some((root) => within(root, path2)));
9131
+ if (unsafe) throw new Error(`Refusing to remove an untrusted path from the lockfile: ${unsafe}`);
9132
+ for (const path2 of paths) {
9133
+ const stat5 = await (0, import_promises11.lstat)(path2).catch(() => null);
9134
+ if (!stat5 || stat5.isSymbolicLink()) continue;
9135
+ const canonicalPath = await (0, import_promises11.realpath)(path2);
9136
+ if (!realRoots.some((root) => within(root, canonicalPath))) {
9137
+ throw new Error(`Refusing to remove a path that resolves outside the install roots: ${path2}`);
9138
+ }
9139
+ }
9140
+ let removed = 0;
9141
+ for (const path2 of paths) {
9142
+ if (await (0, import_promises11.lstat)(path2).catch(() => null)) removed += 1;
9143
+ await (0, import_promises11.rm)(path2, { force: true });
9144
+ }
9145
+ for (const path2 of paths.sort((a, b) => b.length - a.length)) {
9146
+ await pruneEmptyParents(path2, roots);
9147
+ }
9148
+ return { removed, retainedShared: requestedPaths.length - paths.length };
9149
+ }
9150
+
8965
9151
  // src/version.ts
8966
9152
  var import_node_fs2 = require("node:fs");
8967
- var import_node_path13 = require("node:path");
9153
+ var import_node_path16 = require("node:path");
8968
9154
  function getCliVersion() {
8969
- const pkgPath = (0, import_node_path13.join)(__dirname, "..", "package.json");
9155
+ const pkgPath = (0, import_node_path16.join)(__dirname, "..", "package.json");
8970
9156
  const pkg = JSON.parse((0, import_node_fs2.readFileSync)(pkgPath, "utf8"));
8971
9157
  return pkg.version;
8972
9158
  }
@@ -9108,23 +9294,23 @@ function skillFolderName(name) {
9108
9294
  return folder;
9109
9295
  }
9110
9296
  async function writeStarterFile(path2, content) {
9111
- await (0, import_promises11.writeFile)(path2, content, { encoding: "utf8", flag: "wx" });
9297
+ await (0, import_promises12.writeFile)(path2, content, { encoding: "utf8", flag: "wx" });
9112
9298
  }
9113
9299
  async function inferEntryFromSource(source, fallback) {
9114
- const sourceInfo = await (0, import_promises11.stat)(source);
9115
- if (sourceInfo.isFile()) return (0, import_node_path14.basename)(source);
9300
+ const sourceInfo = await (0, import_promises12.stat)(source);
9301
+ if (sourceInfo.isFile()) return (0, import_node_path17.basename)(source);
9116
9302
  if (!sourceInfo.isDirectory()) return fallback;
9117
- const entries = await (0, import_promises11.readdir)(source);
9303
+ const entries = await (0, import_promises12.readdir)(source);
9118
9304
  if (entries.includes(fallback)) return fallback;
9119
9305
  return entries.find((entry) => entry.endsWith(".md")) ?? entries.find((entry) => entry.endsWith(".mdc")) ?? fallback;
9120
9306
  }
9121
9307
  async function copySourceIntoSkillRoot(source, root, sourceLabel) {
9122
- const sourceInfo = await (0, import_promises11.stat)(source);
9123
- await (0, import_promises11.mkdir)(root, { recursive: true });
9308
+ const sourceInfo = await (0, import_promises12.stat)(source);
9309
+ await (0, import_promises12.mkdir)(root, { recursive: true });
9124
9310
  if (sourceInfo.isDirectory()) {
9125
- const entries = await (0, import_promises11.readdir)(source);
9311
+ const entries = await (0, import_promises12.readdir)(source);
9126
9312
  for (const entry of entries) {
9127
- await (0, import_promises11.cp)((0, import_node_path14.join)(source, entry), (0, import_node_path14.join)(root, entry), {
9313
+ await (0, import_promises12.cp)((0, import_node_path17.join)(source, entry), (0, import_node_path17.join)(root, entry), {
9128
9314
  recursive: true,
9129
9315
  force: false,
9130
9316
  errorOnExist: true
@@ -9133,7 +9319,7 @@ async function copySourceIntoSkillRoot(source, root, sourceLabel) {
9133
9319
  return;
9134
9320
  }
9135
9321
  if (sourceInfo.isFile()) {
9136
- await (0, import_promises11.cp)(source, (0, import_node_path14.join)(root, (0, import_node_path14.basename)(source)), { force: false, errorOnExist: true });
9322
+ await (0, import_promises12.cp)(source, (0, import_node_path17.join)(root, (0, import_node_path17.basename)(source)), { force: false, errorOnExist: true });
9137
9323
  return;
9138
9324
  }
9139
9325
  throw new Error(`Unsupported source path: ${sourceLabel}`);
@@ -9167,11 +9353,11 @@ function packageDashboardUrl(name) {
9167
9353
  return `${DASHBOARD_URL}/packages/${name.replace(/^@/, "")}`;
9168
9354
  }
9169
9355
  function helperRootFromTrackedPath(path2) {
9170
- const parts = path2.split(import_node_path14.sep).filter(Boolean);
9356
+ const parts = path2.split(import_node_path17.sep).filter(Boolean);
9171
9357
  const helpersIndex = parts.lastIndexOf("helpers");
9172
9358
  if (helpersIndex === -1 || parts.length <= helpersIndex + 2) return null;
9173
- const prefix = path2.startsWith(import_node_path14.sep) ? import_node_path14.sep : "";
9174
- return (0, import_node_path14.join)(prefix, ...parts.slice(0, helpersIndex + 3));
9359
+ const prefix = path2.startsWith(import_node_path17.sep) ? import_node_path17.sep : "";
9360
+ return (0, import_node_path17.join)(prefix, ...parts.slice(0, helpersIndex + 3));
9175
9361
  }
9176
9362
  async function showInstalledPrompt(configRoot, packageArg) {
9177
9363
  const { name } = parsePackageArg(packageArg);
@@ -9184,7 +9370,7 @@ async function showInstalledPrompt(configRoot, packageArg) {
9184
9370
  if (entry.postInstall.status === "cleaned") {
9185
9371
  throw new Error(`Setup helper files were cleaned for ${name}. Reinstall the package to restore them.`);
9186
9372
  }
9187
- const content = await (0, import_promises11.readFile)(entry.postInstall.promptFile, "utf8").catch(() => {
9373
+ const content = await (0, import_promises12.readFile)(entry.postInstall.promptFile, "utf8").catch(() => {
9188
9374
  throw new Error(`Setup prompt file is missing: ${entry.postInstall?.promptFile}`);
9189
9375
  });
9190
9376
  console.log(`Prompt file: ${entry.postInstall.promptFile}`);
@@ -9217,9 +9403,9 @@ async function cleanupInstalledHelpers(options) {
9217
9403
  entry.installedAssets.helper.map((path2) => helperRootFromTrackedPath(path2)).filter((path2) => Boolean(path2))
9218
9404
  );
9219
9405
  if (roots.size > 0) {
9220
- for (const root of roots) await (0, import_promises11.rm)(root, { recursive: true, force: true });
9406
+ for (const root of roots) await (0, import_promises12.rm)(root, { recursive: true, force: true });
9221
9407
  } else {
9222
- for (const helperPath of entry.installedAssets.helper) await (0, import_promises11.rm)(helperPath, { force: true });
9408
+ for (const helperPath of entry.installedAssets.helper) await (0, import_promises12.rm)(helperPath, { force: true });
9223
9409
  }
9224
9410
  await writeLockfile(options.configRoot, {
9225
9411
  ...lock,
@@ -9264,7 +9450,7 @@ async function authTokenForRegistry(registry, options = {}) {
9264
9450
  return refreshed.accessToken;
9265
9451
  } catch {
9266
9452
  await clearStoredRegistryAuth(registry);
9267
- const message = `CLI login for ${registry} expired or was revoked. Run aipm login to access private packages.`;
9453
+ const message = `CLI login for ${registry} expired or was revoked. Run ${recommendCmd("aipm login")} to access private packages.`;
9268
9454
  if (options.throwOnFailure) throw new Error(message);
9269
9455
  if (!options.quiet) console.warn(`Warning: ${message}`);
9270
9456
  return void 0;
@@ -9513,9 +9699,9 @@ function buildStarterQualityMetadata(options) {
9513
9699
  }
9514
9700
  async function initSkill(opts) {
9515
9701
  if (!isValidScopeName(opts.name)) throw new Error("Invalid @scope/name");
9516
- const root = opts.here ? (0, import_node_process5.cwd)() : (0, import_node_path14.resolve)((0, import_node_process5.cwd)(), opts.dir ?? skillFolderName(opts.name));
9702
+ const root = opts.here ? (0, import_node_process5.cwd)() : (0, import_node_path17.resolve)((0, import_node_process5.cwd)(), opts.dir ?? skillFolderName(opts.name));
9517
9703
  const cdTarget = opts.here ? null : opts.dir ?? skillFolderName(opts.name);
9518
- const source = opts.from ? (0, import_node_path14.resolve)(opts.from) : null;
9704
+ const source = opts.from ? (0, import_node_path17.resolve)(opts.from) : null;
9519
9705
  const entry = source ? await inferEntryFromSource(source, opts.entry) : opts.entry;
9520
9706
  const template = parseSkillTemplate(opts.template ?? "blank");
9521
9707
  const manifest = PackageManifestSchema.parse({
@@ -9536,17 +9722,17 @@ async function initSkill(opts) {
9536
9722
  if (source) {
9537
9723
  await copySourceIntoSkillRoot(source, root, source);
9538
9724
  } else {
9539
- await (0, import_promises11.mkdir)(root, { recursive: true });
9725
+ await (0, import_promises12.mkdir)(root, { recursive: true });
9540
9726
  }
9541
- await writeStarterFile((0, import_node_path14.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
9727
+ await writeStarterFile((0, import_node_path17.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
9542
9728
  if (!opts.from) {
9543
9729
  await writeStarterFile(
9544
- (0, import_node_path14.join)(root, entry),
9730
+ (0, import_node_path17.join)(root, entry),
9545
9731
  SKILL_TEMPLATES[template](opts.name)
9546
9732
  );
9547
9733
  }
9548
9734
  await writeStarterFile(
9549
- (0, import_node_path14.join)(root, ".aipmignore"),
9735
+ (0, import_node_path17.join)(root, ".aipmignore"),
9550
9736
  [
9551
9737
  "# Files that should never be published with this skill",
9552
9738
  ".env*",
@@ -9564,14 +9750,14 @@ async function initSkill(opts) {
9564
9750
  ""
9565
9751
  ].join("\n")
9566
9752
  );
9567
- await (0, import_promises11.mkdir)((0, import_node_path14.join)(root, ".aipm"), { recursive: true });
9753
+ await (0, import_promises12.mkdir)((0, import_node_path17.join)(root, ".aipm"), { recursive: true });
9568
9754
  console.log(`Created ${opts.name} skill folder: ${root}`);
9569
9755
  printPublishGuide(
9570
9756
  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.`,
9571
9757
  cdTarget ? `Run cd ${cdTarget}, edit/review the files, then run aipm publish add .` : "Edit/review the files, then run aipm publish add ."
9572
9758
  );
9573
9759
  }
9574
- 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) => {
9760
+ 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) => {
9575
9761
  const scope = { global: opts.global };
9576
9762
  const configRoot = resolveConfigRoot(scope);
9577
9763
  const existing = await readProjectPackageJson(configRoot);
@@ -9579,7 +9765,7 @@ program2.command("init").description("Create aipm.package.json in the current pr
9579
9765
  console.log(`aipm.package.json already exists (${scopeLabel(scope)}).`);
9580
9766
  return;
9581
9767
  }
9582
- if (scope.global) await (0, import_promises11.mkdir)(configRoot, { recursive: true });
9768
+ if (scope.global) await (0, import_promises12.mkdir)(configRoot, { recursive: true });
9583
9769
  const installRoot = resolveInstallRoot(scope);
9584
9770
  const detected = await detectToolsInProject(installRoot);
9585
9771
  const parsedTarget = parseTargetFlag(opts.target);
@@ -9682,7 +9868,7 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
9682
9868
  console.log(`Auth file: ${data.authFile}`);
9683
9869
  console.log(`Publish guide: ${data.publishDoc}`);
9684
9870
  });
9685
- 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, or *").option("--token <token>", "Install token for private packages").option("--ci", "Non-interactive; fail if prompt needed").action(async (pkgArg, opts) => {
9871
+ 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) => {
9686
9872
  const scope = { global: opts.global };
9687
9873
  const configRoot = resolveConfigRoot(scope);
9688
9874
  const installRoot = resolveInstallRoot(scope);
@@ -9705,7 +9891,7 @@ program2.command("add <package-or-prompt>").description("Add a skill package or
9705
9891
  const { name, version: requestedVersion } = parsePackageArg(pkgArg);
9706
9892
  const token = await tokenForRead(registry, opts.token);
9707
9893
  const version = requestedVersion ?? project.packages[name] ?? await latestVersionForPackage(registry, name, token);
9708
- if (!version) throw new Error("Specify version: aipm add @scope/pkg@1.0.0");
9894
+ if (!version) throw new Error(`Specify version: ${recommendCmd("aipm add <@scope/pkg>@<version>")}`);
9709
9895
  project = {
9710
9896
  ...project,
9711
9897
  packages: { ...project.packages, [name]: version.replace(/^\^/, "") }
@@ -9754,7 +9940,7 @@ program2.command("search [query]").description("Search public registry packages"
9754
9940
  console.log(` ${meta}`);
9755
9941
  }
9756
9942
  });
9757
- 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) => {
9943
+ 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) => {
9758
9944
  const scope = { global: opts.global };
9759
9945
  const configRoot = resolveConfigRoot(scope);
9760
9946
  const installRoot = resolveInstallRoot(scope);
@@ -9797,7 +9983,7 @@ program2.command("show <package-or-prompt>").description("Show an installed prom
9797
9983
  if (reference && project.prompts[reference.alias] === reference.url) {
9798
9984
  const lock2 = await readLockfile(configRoot);
9799
9985
  const entry2 = lock2?.prompts[reference.alias];
9800
- if (!entry2) throw new Error(`Prompt is not installed: ${reference.url}. Run aipm install.`);
9986
+ if (!entry2) throw new Error(`Prompt is not installed: ${reference.url}. Run ${recommendCmd("aipm install")}.`);
9801
9987
  console.log(await readInstalledPrompt(configRoot, entry2));
9802
9988
  return;
9803
9989
  }
@@ -9811,7 +9997,7 @@ program2.command("show-prompt <package>").description("Show the manual setup pro
9811
9997
  await showInstalledPrompt(resolveConfigRoot({ global: opts.global }), pkgArg);
9812
9998
  });
9813
9999
  function promptImageContentType(path2) {
9814
- const extension = (0, import_node_path14.extname)(path2).toLowerCase();
10000
+ const extension = (0, import_node_path17.extname)(path2).toLowerCase();
9815
10001
  if (extension === ".png") return "image/png";
9816
10002
  if (extension === ".jpg" || extension === ".jpeg") return "image/jpeg";
9817
10003
  if (extension === ".webp") return "image/webp";
@@ -9821,9 +10007,9 @@ var promptCommand = program2.command("prompt").description("Publish prompt listi
9821
10007
  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) => {
9822
10008
  const registry = registryFromEnvOrDefault(opts.registry);
9823
10009
  const accessToken = await authTokenForRegistry(registry, { throwOnFailure: true });
9824
- if (!accessToken) throw new Error("Run aipm login before publishing prompts.");
9825
- const absoluteFile = (0, import_node_path14.resolve)(file);
9826
- const parsed = JSON.parse(await (0, import_promises11.readFile)(absoluteFile, "utf8"));
10010
+ if (!accessToken) throw new Error(`Run ${recommendCmd("aipm login")} before publishing prompts.`);
10011
+ const absoluteFile = (0, import_node_path17.resolve)(file);
10012
+ const parsed = JSON.parse(await (0, import_promises12.readFile)(absoluteFile, "utf8"));
9827
10013
  const rows = Array.isArray(parsed) ? parsed : "prompts" in parsed ? parsed.prompts : [parsed];
9828
10014
  if (rows.length === 0) throw new Error("Prompt publish file contains no prompts.");
9829
10015
  if (!opts.yes) {
@@ -9834,10 +10020,10 @@ promptCommand.command("publish <file>").description("Publish one prompt or a bat
9834
10020
  const { sampleImagePath, ...input2 } = row;
9835
10021
  let sampleImage;
9836
10022
  if (sampleImagePath) {
9837
- const imagePath = (0, import_node_path14.resolve)((0, import_node_path14.dirname)(absoluteFile), sampleImagePath);
10023
+ const imagePath = (0, import_node_path17.resolve)((0, import_node_path17.dirname)(absoluteFile), sampleImagePath);
9838
10024
  sampleImage = {
9839
- data: await (0, import_promises11.readFile)(imagePath),
9840
- filename: (0, import_node_path14.basename)(imagePath),
10025
+ data: await (0, import_promises12.readFile)(imagePath),
10026
+ filename: (0, import_node_path17.basename)(imagePath),
9841
10027
  contentType: promptImageContentType(imagePath)
9842
10028
  };
9843
10029
  }
@@ -9860,8 +10046,8 @@ var publish = program2.command("publish [dir]").description("Stage, validate, an
9860
10046
  publish.help();
9861
10047
  return;
9862
10048
  }
9863
- const abs = (0, import_node_path14.resolve)(dir);
9864
- const manifestRaw = await (0, import_promises11.readFile)((0, import_node_path14.join)(abs, "aipm.manifest.json"), "utf8");
10049
+ const abs = (0, import_node_path17.resolve)(dir);
10050
+ const manifestRaw = await (0, import_promises12.readFile)((0, import_node_path17.join)(abs, "aipm.manifest.json"), "utf8");
9865
10051
  const manifest = PackageManifestSchema.parse(JSON.parse(manifestRaw));
9866
10052
  const tarball = await packDirectory(abs);
9867
10053
  const registry = registryFromEnvOrDefault(opts.registry);
@@ -10026,6 +10212,7 @@ program2.command("list").description("List installed skills and prompts from aip
10026
10212
  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) => {
10027
10213
  const scope = { global: opts.global };
10028
10214
  const configRoot = resolveConfigRoot(scope);
10215
+ const installRoot = resolveInstallRoot(scope);
10029
10216
  const project = await readProjectPackageJson(configRoot);
10030
10217
  if (!project) throw new Error(initRequiredMessage(scope));
10031
10218
  const promptReference = resolveTrackedPrompt(project, pkgArg);
@@ -10035,19 +10222,32 @@ program2.command("remove <package-or-prompt>").alias("rm").description("Remove a
10035
10222
  return;
10036
10223
  }
10037
10224
  const { name } = parsePackageArg(pkgArg);
10225
+ const lock = await readLockfile(configRoot);
10226
+ const lockEntry = lock?.packages[name];
10227
+ if (lockEntry) {
10228
+ const otherEntries = Object.entries(lock.packages).filter(([packageName]) => packageName !== name).map(([, entry]) => entry);
10229
+ const removal = await removeInstalledPackageFiles({
10230
+ configRoot,
10231
+ installRoot,
10232
+ entry: lockEntry,
10233
+ otherEntries
10234
+ });
10235
+ console.log(`Deleted ${removal.removed} tracked installed ${removal.removed === 1 ? "file" : "files"}.`);
10236
+ if (removal.retainedShared > 0) {
10237
+ console.log(`Retained ${removal.retainedShared} ${removal.retainedShared === 1 ? "file" : "files"} shared with another installed package.`);
10238
+ }
10239
+ }
10038
10240
  const packages = { ...project.packages };
10039
10241
  delete packages[name];
10040
10242
  await writeProjectPackageJson(configRoot, { ...project, packages });
10041
- const lock = await readLockfile(configRoot);
10042
10243
  if (lock) {
10043
10244
  const lockPackages = { ...lock.packages };
10044
10245
  delete lockPackages[name];
10045
10246
  await writeLockfile(configRoot, { ...lock, packages: lockPackages });
10046
10247
  }
10047
10248
  console.log(`Removed ${name} from AIPM ${scopeLabel(scope)} files.`);
10048
- console.log("Adapter-written files are not deleted yet; review your project before committing.");
10049
10249
  });
10050
- 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) => {
10250
+ 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) => {
10051
10251
  const scope = { global: opts.global };
10052
10252
  const configRoot = resolveConfigRoot(scope);
10053
10253
  const installRoot = resolveInstallRoot(scope);