@aipm-registry/cli 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.cjs CHANGED
@@ -4155,13 +4155,19 @@ var init_zod = __esm({
4155
4155
  });
4156
4156
 
4157
4157
  // ../../packages/schemas/dist/manifest.js
4158
- var AiToolSchema, PackageManifestSchema;
4158
+ function expandTargets(targets) {
4159
+ if (targets.includes("*"))
4160
+ return [...ALL_TOOLS];
4161
+ return targets.filter((t) => t !== "*");
4162
+ }
4163
+ var AiToolSchema, ALL_TOOLS, PackageManifestSchema;
4159
4164
  var init_manifest = __esm({
4160
4165
  "../../packages/schemas/dist/manifest.js"() {
4161
4166
  "use strict";
4162
4167
  init_zod();
4163
4168
  init_scope_name();
4164
- AiToolSchema = external_exports.enum(["cursor", "claude"]);
4169
+ AiToolSchema = external_exports.enum(["cursor", "claude", "*"]);
4170
+ ALL_TOOLS = ["cursor", "claude"];
4165
4171
  PackageManifestSchema = external_exports.object({
4166
4172
  schemaVersion: external_exports.literal("0.1"),
4167
4173
  name: external_exports.string().regex(SCOPE_NAME_REGEX, "name must be @scope/name"),
@@ -4245,26 +4251,36 @@ async function detectToolsInProject(projectRoot) {
4245
4251
  detected.push("claude");
4246
4252
  return detected;
4247
4253
  }
4254
+ function manifestAllowsTool(manifest, tool) {
4255
+ if (manifest.targets.includes("*"))
4256
+ return true;
4257
+ return manifest.targets.includes(tool);
4258
+ }
4248
4259
  async function resolveInstallTools(options) {
4249
4260
  const { manifest } = options;
4250
- const allowed = new Set(manifest.targets);
4261
+ const expandedAllowed = expandTargets(manifest.targets);
4251
4262
  if (options.explicitTarget) {
4252
- if (!allowed.has(options.explicitTarget)) {
4263
+ if (options.explicitTarget === "*") {
4264
+ return [...ALL_TOOLS];
4265
+ }
4266
+ if (!manifestAllowsTool(manifest, options.explicitTarget)) {
4253
4267
  throw new Error(`Package ${manifest.name} does not target "${options.explicitTarget}". Targets: ${manifest.targets.join(", ")}`);
4254
4268
  }
4255
4269
  return [options.explicitTarget];
4256
4270
  }
4257
4271
  const detected = await detectToolsInProject(options.projectRoot);
4258
4272
  if (detected.length > 0) {
4259
- const intersection = detected.filter((t) => allowed.has(t));
4273
+ const intersection = detected.filter((t) => manifestAllowsTool(manifest, t));
4260
4274
  if (intersection.length === 0) {
4261
4275
  throw new Error(`Package ${manifest.name} targets [${manifest.targets.join(", ")}] but project only has [${detected.join(", ")}].`);
4262
4276
  }
4263
4277
  return intersection;
4264
4278
  }
4265
- const preferred = (options.preferredTools ?? []).filter((t) => allowed.has(t));
4279
+ const preferred = expandTargets(options.preferredTools ?? []).filter((t) => manifestAllowsTool(manifest, t));
4266
4280
  if (preferred.length > 0)
4267
4281
  return preferred;
4282
+ if (manifest.targets.includes("*"))
4283
+ return expandedAllowed;
4268
4284
  return [];
4269
4285
  }
4270
4286
  var import_promises, import_node_path2;
@@ -4273,6 +4289,7 @@ var init_detect_tools = __esm({
4273
4289
  "use strict";
4274
4290
  import_promises = require("node:fs/promises");
4275
4291
  import_node_path2 = require("node:path");
4292
+ init_dist();
4276
4293
  }
4277
4294
  });
4278
4295
 
@@ -4331,7 +4348,7 @@ async function installSkillPackage(options) {
4331
4348
  explicitTarget: options.explicitTarget
4332
4349
  });
4333
4350
  if (tools.length === 0) {
4334
- throw new Error("No AI tool detected (.cursor/ or .claude/). Use --target cursor|claude or set preferredTools in aipm.package.json.");
4351
+ throw new Error("No AI tool detected (.cursor/ or .claude/). Use --target cursor|claude|* or set preferredTools in aipm.package.json.");
4335
4352
  }
4336
4353
  const installed = {};
4337
4354
  for (const tool of tools) {
@@ -4375,74 +4392,6 @@ var init_dist4 = __esm({
4375
4392
  }
4376
4393
  });
4377
4394
 
4378
- // src/project-files.ts
4379
- var project_files_exports = {};
4380
- __export(project_files_exports, {
4381
- parseTargetFlag: () => parseTargetFlag,
4382
- readLockfile: () => readLockfile,
4383
- readProjectPackageJson: () => readProjectPackageJson,
4384
- resolveRegistryUrl: () => resolveRegistryUrl,
4385
- upsertLockEntry: () => upsertLockEntry,
4386
- writeLockfile: () => writeLockfile,
4387
- writeProjectPackageJson: () => writeProjectPackageJson
4388
- });
4389
- async function readProjectPackageJson(projectRoot) {
4390
- try {
4391
- const raw = await (0, import_promises7.readFile)((0, import_node_path7.join)(projectRoot, PACKAGE_JSON), "utf8");
4392
- return ProjectPackageJsonSchema.parse(JSON.parse(raw));
4393
- } catch {
4394
- return null;
4395
- }
4396
- }
4397
- async function writeProjectPackageJson(projectRoot, data) {
4398
- await (0, import_promises7.writeFile)(
4399
- (0, import_node_path7.join)(projectRoot, PACKAGE_JSON),
4400
- JSON.stringify(data, null, 2) + "\n",
4401
- "utf8"
4402
- );
4403
- }
4404
- async function readLockfile(projectRoot) {
4405
- try {
4406
- const raw = await (0, import_promises7.readFile)((0, import_node_path7.join)(projectRoot, LOCKFILE), "utf8");
4407
- return LockfileSchema.parse(JSON.parse(raw));
4408
- } catch {
4409
- return null;
4410
- }
4411
- }
4412
- async function writeLockfile(projectRoot, data) {
4413
- await (0, import_promises7.writeFile)((0, import_node_path7.join)(projectRoot, LOCKFILE), JSON.stringify(data, null, 2) + "\n", "utf8");
4414
- }
4415
- function upsertLockEntry(lock, name, entry) {
4416
- return {
4417
- ...lock,
4418
- packages: { ...lock.packages, [name]: entry }
4419
- };
4420
- }
4421
- function resolveRegistryUrl(project, flag, fallback) {
4422
- const fromEnv = process.env.AIPM_REGISTRY_URL ?? process.env.AIPM_REGISTRY;
4423
- if (flag) return flag.replace(/\/$/, "");
4424
- if (project?.registry) return project.registry.replace(/\/$/, "");
4425
- if (fromEnv) return fromEnv.replace(/\/$/, "");
4426
- if (fallback) return fallback.replace(/\/$/, "");
4427
- throw new Error("Registry URL required: set registry in aipm.package.json or AIPM_REGISTRY_URL");
4428
- }
4429
- function parseTargetFlag(target) {
4430
- if (!target) return void 0;
4431
- if (target === "cursor" || target === "claude") return target;
4432
- throw new Error('--target must be "cursor" or "claude"');
4433
- }
4434
- var import_promises7, import_node_path7, PACKAGE_JSON, LOCKFILE;
4435
- var init_project_files = __esm({
4436
- "src/project-files.ts"() {
4437
- "use strict";
4438
- import_promises7 = require("node:fs/promises");
4439
- import_node_path7 = require("node:path");
4440
- init_dist();
4441
- PACKAGE_JSON = "aipm.package.json";
4442
- LOCKFILE = "aipm-lock.json";
4443
- }
4444
- });
4445
-
4446
4395
  // ../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
4447
4396
  var CommanderError = class extends Error {
4448
4397
  /**
@@ -7814,8 +7763,8 @@ var program = new Command();
7814
7763
  // src/bin.ts
7815
7764
  var import_node_child_process4 = require("node:child_process");
7816
7765
  var import_promises9 = require("node:fs/promises");
7817
- var import_node_path10 = require("node:path");
7818
- var import_node_process3 = require("node:process");
7766
+ var import_node_path11 = require("node:path");
7767
+ var import_node_process5 = require("node:process");
7819
7768
  init_dist();
7820
7769
  init_dist4();
7821
7770
 
@@ -8040,14 +7989,14 @@ async function packStagedFiles(root) {
8040
7989
  }
8041
7990
  async function unpackTarballToBuffer(tarball, entry) {
8042
7991
  const { mkdtemp: mkdtemp2, rm: rm3, writeFile: writeFile6 } = await import("node:fs/promises");
8043
- const { join: join9 } = await import("node:path");
7992
+ const { join: join11 } = await import("node:path");
8044
7993
  const { tmpdir: tmpdir2 } = await import("node:os");
8045
- const tempDir = await mkdtemp2(join9(tmpdir2(), "aipm-install-"));
8046
- const tgzPath = join9(tempDir, "pkg.tgz");
7994
+ const tempDir = await mkdtemp2(join11(tmpdir2(), "aipm-install-"));
7995
+ const tgzPath = join11(tempDir, "pkg.tgz");
8047
7996
  try {
8048
7997
  await writeFile6(tgzPath, tarball);
8049
7998
  await execFileAsync("tar", ["-xzf", tgzPath, "-C", tempDir]);
8050
- return (0, import_promises5.readFile)(join9(tempDir, entry), "utf8");
7999
+ return (0, import_promises5.readFile)(join11(tempDir, entry), "utf8");
8051
8000
  } finally {
8052
8001
  await rm3(tempDir, { recursive: true, force: true });
8053
8002
  }
@@ -8123,7 +8072,70 @@ async function fetchPackageTarball(registry, name, version) {
8123
8072
 
8124
8073
  // src/install-one.ts
8125
8074
  init_dist4();
8126
- init_project_files();
8075
+
8076
+ // src/project-files.ts
8077
+ var import_promises7 = require("node:fs/promises");
8078
+ var import_node_path7 = require("node:path");
8079
+ init_dist();
8080
+ var PACKAGE_JSON = "aipm.package.json";
8081
+ var LOCKFILE = "aipm-lock.json";
8082
+ async function readProjectPackageJson(projectRoot) {
8083
+ try {
8084
+ const raw = await (0, import_promises7.readFile)((0, import_node_path7.join)(projectRoot, PACKAGE_JSON), "utf8");
8085
+ return ProjectPackageJsonSchema.parse(JSON.parse(raw));
8086
+ } catch {
8087
+ return null;
8088
+ }
8089
+ }
8090
+ async function writeProjectPackageJson(projectRoot, data) {
8091
+ await (0, import_promises7.writeFile)(
8092
+ (0, import_node_path7.join)(projectRoot, PACKAGE_JSON),
8093
+ JSON.stringify(data, null, 2) + "\n",
8094
+ "utf8"
8095
+ );
8096
+ }
8097
+ async function readLockfile(projectRoot) {
8098
+ try {
8099
+ const raw = await (0, import_promises7.readFile)((0, import_node_path7.join)(projectRoot, LOCKFILE), "utf8");
8100
+ return LockfileSchema.parse(JSON.parse(raw));
8101
+ } catch {
8102
+ return null;
8103
+ }
8104
+ }
8105
+ async function writeLockfile(projectRoot, data) {
8106
+ await (0, import_promises7.writeFile)((0, import_node_path7.join)(projectRoot, LOCKFILE), JSON.stringify(data, null, 2) + "\n", "utf8");
8107
+ }
8108
+ function upsertLockEntry(lock, name, entry) {
8109
+ return {
8110
+ ...lock,
8111
+ packages: { ...lock.packages, [name]: entry }
8112
+ };
8113
+ }
8114
+ function resolveRegistryUrl(project, flag, fallback) {
8115
+ const fromEnv = process.env.AIPM_REGISTRY_URL ?? process.env.AIPM_REGISTRY;
8116
+ if (flag) return flag.replace(/\/$/, "");
8117
+ if (project?.registry) return project.registry.replace(/\/$/, "");
8118
+ if (fromEnv) return fromEnv.replace(/\/$/, "");
8119
+ if (fallback) return fallback.replace(/\/$/, "");
8120
+ throw new Error("Registry URL required: set registry in aipm.package.json or AIPM_REGISTRY_URL");
8121
+ }
8122
+ function parseTargetFlag(target) {
8123
+ if (!target) return void 0;
8124
+ if (target === "cursor" || target === "claude" || target === "*") return target;
8125
+ throw new Error('--target must be "cursor", "claude", or "*"');
8126
+ }
8127
+ function parseTargetsFlag(value) {
8128
+ const targets = value.split(",").map((target) => target.trim()).filter(Boolean);
8129
+ if (targets.length === 0) throw new Error("At least one target is required.");
8130
+ for (const target of targets) {
8131
+ if (target !== "cursor" && target !== "claude" && target !== "*") {
8132
+ throw new Error('--targets must contain only "cursor", "claude", and/or "*"');
8133
+ }
8134
+ }
8135
+ const unique = [...new Set(targets)];
8136
+ if (unique.includes("*")) return ["*"];
8137
+ return unique;
8138
+ }
8127
8139
 
8128
8140
  // src/prompt.ts
8129
8141
  var readline = __toESM(require("node:readline/promises"), 1);
@@ -8148,6 +8160,8 @@ async function promptForTool() {
8148
8160
 
8149
8161
  // src/install-one.ts
8150
8162
  async function installOnePackage(options) {
8163
+ const configRoot = options.configRoot;
8164
+ const installRoot = options.installRoot ?? configRoot;
8151
8165
  await assertRegistryReachable(options.registry);
8152
8166
  const { manifest, integrity: remoteIntegrity } = await fetchPackageMetadata(
8153
8167
  options.registry,
@@ -8158,7 +8172,7 @@ async function installOnePackage(options) {
8158
8172
  let preferredTools = options.project.preferredTools;
8159
8173
  const { resolveInstallTools: resolveInstallTools2 } = await Promise.resolve().then(() => (init_dist4(), dist_exports));
8160
8174
  let tools = await resolveInstallTools2({
8161
- projectRoot: options.projectRoot,
8175
+ projectRoot: installRoot,
8162
8176
  manifest,
8163
8177
  preferredTools,
8164
8178
  explicitTarget
@@ -8166,14 +8180,14 @@ async function installOnePackage(options) {
8166
8180
  if (tools.length === 0) {
8167
8181
  if (options.ci) {
8168
8182
  throw new Error(
8169
- "No tool detected. Use --target cursor|claude in CI mode."
8183
+ "No tool detected. Use --target cursor|claude|* in CI mode."
8170
8184
  );
8171
8185
  }
8172
8186
  const choice = await promptForTool();
8173
8187
  explicitTarget = choice;
8174
8188
  preferredTools = [choice];
8175
8189
  tools = await resolveInstallTools2({
8176
- projectRoot: options.projectRoot,
8190
+ projectRoot: installRoot,
8177
8191
  manifest,
8178
8192
  preferredTools,
8179
8193
  explicitTarget
@@ -8186,13 +8200,13 @@ async function installOnePackage(options) {
8186
8200
  );
8187
8201
  const skillMarkdown = await unpackTarballToBuffer(tarball, manifest.entry);
8188
8202
  const result = await installSkillPackage({
8189
- projectRoot: options.projectRoot,
8203
+ projectRoot: installRoot,
8190
8204
  manifest,
8191
8205
  skillMarkdown,
8192
8206
  preferredTools,
8193
8207
  explicitTarget
8194
8208
  });
8195
- const lock = await readLockfile(options.projectRoot) ?? {
8209
+ const lock = await readLockfile(configRoot) ?? {
8196
8210
  schemaVersion: "0.1",
8197
8211
  packages: {}
8198
8212
  };
@@ -8202,7 +8216,7 @@ async function installOnePackage(options) {
8202
8216
  if (paths) installed[tool] = paths;
8203
8217
  }
8204
8218
  await writeLockfile(
8205
- options.projectRoot,
8219
+ configRoot,
8206
8220
  upsertLockEntry(lock, options.name, {
8207
8221
  version: options.version,
8208
8222
  integrity: remoteIntegrity,
@@ -8217,9 +8231,31 @@ async function installOnePackage(options) {
8217
8231
  // src/doctor.ts
8218
8232
  var import_node_child_process3 = require("node:child_process");
8219
8233
  var import_promises8 = require("node:fs/promises");
8220
- var import_node_path8 = require("node:path");
8234
+ var import_node_path9 = require("node:path");
8221
8235
  var import_node_util4 = require("node:util");
8222
- init_project_files();
8236
+
8237
+ // src/project-root.ts
8238
+ var import_node_os2 = require("node:os");
8239
+ var import_node_path8 = require("node:path");
8240
+ var import_node_process3 = require("node:process");
8241
+ function globalConfigDir(env2 = process.env) {
8242
+ const fromEnv = env2.AIPM_HOME?.trim();
8243
+ return fromEnv ? fromEnv.replace(/\/$/, "") : (0, import_node_path8.join)((0, import_node_os2.homedir)(), ".aipm");
8244
+ }
8245
+ function resolveConfigRoot(options = {}) {
8246
+ return options.global ? globalConfigDir() : (0, import_node_process3.cwd)();
8247
+ }
8248
+ function resolveInstallRoot(options = {}) {
8249
+ return options.global ? (0, import_node_os2.homedir)() : (0, import_node_process3.cwd)();
8250
+ }
8251
+ function scopeLabel(options) {
8252
+ return options.global ? "global" : "project";
8253
+ }
8254
+ function initRequiredMessage(options) {
8255
+ return options.global ? "Run aipm init -g first" : "Run aipm init first";
8256
+ }
8257
+
8258
+ // src/doctor.ts
8223
8259
  var execFileAsync2 = (0, import_node_util4.promisify)(import_node_child_process3.execFile);
8224
8260
  var MIN_NODE_MAJOR = 20;
8225
8261
  async function commandOutput(command, args) {
@@ -8235,11 +8271,11 @@ async function commandOutput(command, args) {
8235
8271
  }
8236
8272
  function npmGlobalBin(prefix) {
8237
8273
  if (!prefix) return null;
8238
- return process.platform === "win32" ? prefix : `${prefix}${import_node_path8.sep}bin`;
8274
+ return process.platform === "win32" ? prefix : `${prefix}${import_node_path9.sep}bin`;
8239
8275
  }
8240
8276
  function pathIncludes(pathDir) {
8241
8277
  if (!pathDir) return false;
8242
- return (process.env.PATH ?? "").split(import_node_path8.delimiter).includes(pathDir);
8278
+ return (process.env.PATH ?? "").split(import_node_path9.delimiter).includes(pathDir);
8243
8279
  }
8244
8280
  function shellPathHint(binDir) {
8245
8281
  if (!binDir) return "Run npm prefix -g and add its bin folder to PATH.";
@@ -8253,8 +8289,10 @@ async function commandExists(command) {
8253
8289
  return await commandOutput(probe, args) !== null;
8254
8290
  }
8255
8291
  async function runDoctor(options) {
8292
+ const scope = { global: options.global };
8293
+ const configRoot = resolveConfigRoot(scope);
8256
8294
  const root = process.cwd();
8257
- const project = await readProjectPackageJson(root);
8295
+ const project = await readProjectPackageJson(configRoot);
8258
8296
  const registry = resolveRegistryUrl(project, options.registry, "https://api.aipm-registry.com");
8259
8297
  const nodeMajor = Number(process.versions.node.split(".")[0]);
8260
8298
  const npmPrefix = await commandOutput("npm", ["prefix", "-g"]);
@@ -8288,11 +8326,20 @@ async function runDoctor(options) {
8288
8326
  });
8289
8327
  }
8290
8328
  if (!options.publish) {
8329
+ const configLabel = options.global ? "Global config" : "Project config";
8291
8330
  try {
8292
- await (0, import_promises8.access)("aipm.package.json");
8293
- checks.push({ name: "Project config", ok: true, detail: "aipm.package.json exists." });
8331
+ await (0, import_promises8.access)((0, import_node_path9.join)(configRoot, "aipm.package.json"));
8332
+ checks.push({
8333
+ name: configLabel,
8334
+ ok: true,
8335
+ detail: `${(0, import_node_path9.join)(configRoot, "aipm.package.json")} exists (${scopeLabel(scope)}).`
8336
+ });
8294
8337
  } catch {
8295
- checks.push({ name: "Project config", ok: false, detail: "Run aipm init in this project." });
8338
+ checks.push({
8339
+ name: configLabel,
8340
+ ok: false,
8341
+ detail: initRequiredMessage(scope)
8342
+ });
8296
8343
  }
8297
8344
  }
8298
8345
  try {
@@ -8353,18 +8400,95 @@ async function runDoctor(options) {
8353
8400
  }
8354
8401
  }
8355
8402
 
8356
- // src/bin.ts
8357
- init_project_files();
8358
-
8359
8403
  // src/version.ts
8360
8404
  var import_node_fs2 = require("node:fs");
8361
- var import_node_path9 = require("node:path");
8405
+ var import_node_path10 = require("node:path");
8362
8406
  function getCliVersion() {
8363
- const pkgPath = (0, import_node_path9.join)(__dirname, "..", "package.json");
8407
+ const pkgPath = (0, import_node_path10.join)(__dirname, "..", "package.json");
8364
8408
  const pkg = JSON.parse((0, import_node_fs2.readFileSync)(pkgPath, "utf8"));
8365
8409
  return pkg.version;
8366
8410
  }
8367
8411
 
8412
+ // src/cli-update-check.ts
8413
+ var import_node_process4 = require("node:process");
8414
+ var CLI_PACKAGE_NAME = "@aipm-registry/cli";
8415
+ var CLI_UPDATE_COMMAND = `npm install -g ${CLI_PACKAGE_NAME}`;
8416
+ var NPM_REGISTRY = "https://registry.npmjs.org";
8417
+ var FETCH_TIMEOUT_MS = 3e3;
8418
+ function parseSemVer(version) {
8419
+ const match = version.trim().match(/^(\d+)\.(\d+)\.(\d+)/);
8420
+ if (!match) return null;
8421
+ return {
8422
+ major: Number(match[1]),
8423
+ minor: Number(match[2]),
8424
+ patch: Number(match[3])
8425
+ };
8426
+ }
8427
+ function isSemVerNewer(current, latest) {
8428
+ if (latest.major !== current.major) return latest.major > current.major;
8429
+ if (latest.minor !== current.minor) return latest.minor > current.minor;
8430
+ return latest.patch > current.patch;
8431
+ }
8432
+ function classifyCliUpdate(current, latest) {
8433
+ const cur = parseSemVer(current);
8434
+ const lat = parseSemVer(latest);
8435
+ if (!cur || !lat || !isSemVerNewer(cur, lat)) return "none";
8436
+ if (lat.major > cur.major) return "major";
8437
+ return "patch-minor";
8438
+ }
8439
+ async function fetchLatestCliVersion(fetchImpl = fetch) {
8440
+ try {
8441
+ const response = await fetchImpl(
8442
+ `${NPM_REGISTRY}/${encodeURIComponent(CLI_PACKAGE_NAME)}/latest`,
8443
+ {
8444
+ headers: { Accept: "application/json" },
8445
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
8446
+ }
8447
+ );
8448
+ if (!response.ok) return null;
8449
+ const data = await response.json();
8450
+ return data.version ?? null;
8451
+ } catch {
8452
+ return null;
8453
+ }
8454
+ }
8455
+ function formatCliUpdateNotice(options) {
8456
+ const { currentVersion, latestVersion, level } = options;
8457
+ const cmd = CLI_UPDATE_COMMAND;
8458
+ if (level === "major") {
8459
+ return `AIPM CLI ${latestVersion} is available (you have ${currentVersion}). Update now: ${cmd}`;
8460
+ }
8461
+ return `A new AIPM CLI version is available (${currentVersion} \u2192 ${latestVersion}). Run: ${cmd}`;
8462
+ }
8463
+ function printCliUpdateNotice(options) {
8464
+ const useColor2 = options.useColor ?? import_node_process4.stderr.isTTY;
8465
+ const writeInfo = options.writeInfo ?? ((message2) => console.log(message2));
8466
+ const writeWarn = options.writeWarn ?? ((message2) => console.error(message2));
8467
+ const message = formatCliUpdateNotice(options);
8468
+ if (options.level === "major") {
8469
+ const red = useColor2 ? "\x1B[31m" : "";
8470
+ const reset = useColor2 ? "\x1B[0m" : "";
8471
+ writeWarn(`${red}${message}${reset}`);
8472
+ return;
8473
+ }
8474
+ writeInfo(message);
8475
+ }
8476
+ async function notifyCliUpdateIfNeeded(currentVersion, options) {
8477
+ const latestVersion = await (options?.fetchLatest ?? fetchLatestCliVersion)();
8478
+ if (!latestVersion) return "none";
8479
+ const level = classifyCliUpdate(currentVersion, latestVersion);
8480
+ if (level === "none") return "none";
8481
+ printCliUpdateNotice({
8482
+ currentVersion,
8483
+ latestVersion,
8484
+ level,
8485
+ useColor: options?.useColor,
8486
+ writeInfo: options?.writeInfo,
8487
+ writeWarn: options?.writeWarn
8488
+ });
8489
+ return level;
8490
+ }
8491
+
8368
8492
  // src/bin.ts
8369
8493
  var CLI_VERSION = getCliVersion();
8370
8494
  var program2 = new Command();
@@ -8372,6 +8496,8 @@ var DEFAULT_REGISTRY = "https://api.aipm-registry.com";
8372
8496
  var SITE_URL = "https://aipm-registry.com";
8373
8497
  var PUBLISH_DOC_URL = "https://aipm-registry.com/publish";
8374
8498
  var DASHBOARD_URL = "https://aipm-registry.com/dashboard";
8499
+ var GLOBAL_OPTION = "-g, --global";
8500
+ var GLOBAL_OPTION_DESC = "Use global config (~/.aipm) and install skills under your home directory";
8375
8501
  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(
8376
8502
  "after",
8377
8503
  `
@@ -8380,8 +8506,10 @@ Examples:
8380
8506
  $ npm install -g @aipm-registry/cli
8381
8507
  $ aipm doctor
8382
8508
  $ aipm init
8509
+ $ aipm init -g
8383
8510
  $ aipm search sentry
8384
8511
  $ aipm add @scope/name@1.0.0 --target cursor --ci
8512
+ $ aipm add @scope/name -g
8385
8513
  $ aipm publish init --name @org/skill
8386
8514
  $ cd skill
8387
8515
  $ aipm publish add .
@@ -8409,7 +8537,7 @@ async function writeStarterFile(path2, content) {
8409
8537
  }
8410
8538
  async function inferEntryFromSource(source, fallback) {
8411
8539
  const sourceInfo = await (0, import_promises9.stat)(source);
8412
- if (sourceInfo.isFile()) return (0, import_node_path10.basename)(source);
8540
+ if (sourceInfo.isFile()) return (0, import_node_path11.basename)(source);
8413
8541
  if (!sourceInfo.isDirectory()) return fallback;
8414
8542
  const entries = await (0, import_promises9.readdir)(source);
8415
8543
  if (entries.includes(fallback)) return fallback;
@@ -8506,16 +8634,6 @@ async function printPublishPreview(root, json) {
8506
8634
  preview.warnings.length > 0 ? "Fix the warnings, then run aipm publish preview again." : "Run aipm publish validate."
8507
8635
  );
8508
8636
  }
8509
- function parseTargets(value) {
8510
- const targets = value.split(",").map((target) => target.trim()).filter(Boolean);
8511
- if (targets.length === 0) throw new Error("At least one target is required.");
8512
- for (const target of targets) {
8513
- if (target !== "cursor" && target !== "claude") {
8514
- throw new Error('--targets must contain only "cursor" and/or "claude"');
8515
- }
8516
- }
8517
- return [...new Set(targets)];
8518
- }
8519
8637
  var SKILL_TEMPLATES = {
8520
8638
  blank: (name) => `# ${name}
8521
8639
 
@@ -8574,10 +8692,10 @@ function parseSkillTemplate(value) {
8574
8692
  }
8575
8693
  async function initSkill(opts) {
8576
8694
  if (!isValidScopeName(opts.name)) throw new Error("Invalid @scope/name");
8577
- const root = opts.here ? (0, import_node_process3.cwd)() : (0, import_node_path10.resolve)((0, import_node_process3.cwd)(), opts.dir ?? skillFolderName(opts.name));
8695
+ const root = opts.here ? (0, import_node_process5.cwd)() : (0, import_node_path11.resolve)((0, import_node_process5.cwd)(), opts.dir ?? skillFolderName(opts.name));
8578
8696
  const cdTarget = opts.here ? null : opts.dir ?? skillFolderName(opts.name);
8579
8697
  await (0, import_promises9.mkdir)(root, { recursive: true });
8580
- const source = opts.from ? (0, import_node_path10.resolve)(opts.from) : null;
8698
+ const source = opts.from ? (0, import_node_path11.resolve)(opts.from) : null;
8581
8699
  const entry = source ? await inferEntryFromSource(source, opts.entry) : opts.entry;
8582
8700
  const manifest = {
8583
8701
  schemaVersion: "0.1",
@@ -8586,7 +8704,7 @@ async function initSkill(opts) {
8586
8704
  type: "skill",
8587
8705
  description: opts.description,
8588
8706
  entry,
8589
- targets: parseTargets(opts.targets),
8707
+ targets: parseTargetsFlag(opts.targets),
8590
8708
  license: "Apache-2.0"
8591
8709
  };
8592
8710
  PackageManifestSchema.parse(manifest);
@@ -8595,21 +8713,21 @@ async function initSkill(opts) {
8595
8713
  if (sourceInfo.isDirectory()) {
8596
8714
  await (0, import_promises9.cp)(source, root, { recursive: true, force: false, errorOnExist: true });
8597
8715
  } else if (sourceInfo.isFile()) {
8598
- await (0, import_promises9.cp)(source, (0, import_node_path10.join)(root, (0, import_node_path10.basename)(source)), { force: false, errorOnExist: true });
8716
+ await (0, import_promises9.cp)(source, (0, import_node_path11.join)(root, (0, import_node_path11.basename)(source)), { force: false, errorOnExist: true });
8599
8717
  } else {
8600
8718
  throw new Error(`Unsupported source path: ${opts.from}`);
8601
8719
  }
8602
8720
  }
8603
- await writeStarterFile((0, import_node_path10.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
8721
+ await writeStarterFile((0, import_node_path11.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
8604
8722
  if (!opts.from) {
8605
8723
  const template = parseSkillTemplate(opts.template ?? "blank");
8606
8724
  await writeStarterFile(
8607
- (0, import_node_path10.join)(root, entry),
8725
+ (0, import_node_path11.join)(root, entry),
8608
8726
  SKILL_TEMPLATES[template](opts.name)
8609
8727
  );
8610
8728
  }
8611
8729
  await writeStarterFile(
8612
- (0, import_node_path10.join)(root, ".aipmignore"),
8730
+ (0, import_node_path11.join)(root, ".aipmignore"),
8613
8731
  [
8614
8732
  "# Files that should never be published with this skill",
8615
8733
  ".env*",
@@ -8627,34 +8745,37 @@ async function initSkill(opts) {
8627
8745
  ""
8628
8746
  ].join("\n")
8629
8747
  );
8630
- await (0, import_promises9.mkdir)((0, import_node_path10.join)(root, ".aipm"), { recursive: true });
8748
+ await (0, import_promises9.mkdir)((0, import_node_path11.join)(root, ".aipm"), { recursive: true });
8631
8749
  console.log(`Created ${opts.name} skill folder: ${root}`);
8632
8750
  printPublishGuide(
8633
8751
  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.`,
8634
8752
  cdTarget ? `Run cd ${cdTarget}, edit/review the files, then run aipm publish add .` : "Edit/review the files, then run aipm publish add ."
8635
8753
  );
8636
8754
  }
8637
- program2.command("init").description("Create aipm.package.json in the current project").option("--registry <url>", "Default registry URL").action(async (opts) => {
8638
- const root = (0, import_node_process3.cwd)();
8639
- const existing = await readProjectPackageJson(root);
8755
+ 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").action(async (opts) => {
8756
+ const scope = { global: opts.global };
8757
+ const configRoot = resolveConfigRoot(scope);
8758
+ const existing = await readProjectPackageJson(configRoot);
8640
8759
  if (existing) {
8641
- console.log("aipm.package.json already exists.");
8760
+ console.log(`aipm.package.json already exists (${scopeLabel(scope)}).`);
8642
8761
  return;
8643
8762
  }
8644
- const detected = await detectToolsInProject(root);
8763
+ if (scope.global) await (0, import_promises9.mkdir)(configRoot, { recursive: true });
8764
+ const installRoot = resolveInstallRoot(scope);
8765
+ const detected = await detectToolsInProject(installRoot);
8645
8766
  let preferredTools = detected;
8646
8767
  if (detected.length === 0) {
8647
8768
  const choice = await promptForTool();
8648
8769
  preferredTools = [choice];
8649
8770
  }
8650
8771
  const registry = registryFromEnvOrDefault(opts.registry);
8651
- await writeProjectPackageJson(root, {
8772
+ await writeProjectPackageJson(configRoot, {
8652
8773
  schemaVersion: "0.1",
8653
8774
  registry,
8654
8775
  preferredTools: preferredTools.length ? preferredTools : void 0,
8655
8776
  packages: {}
8656
8777
  });
8657
- console.log(`Created aipm.package.json (registry: ${registry})`);
8778
+ console.log(`Created aipm.package.json (${scopeLabel(scope)}, registry: ${registry})`);
8658
8779
  });
8659
8780
  program2.command("login").description("Open the AIPM dashboard sign-in page").option("--no-open", "Print the URL without opening a browser").action(async (opts) => {
8660
8781
  const url = `${SITE_URL}/login`;
@@ -8663,17 +8784,22 @@ program2.command("login").description("Open the AIPM dashboard sign-in page").op
8663
8784
  if (opts.open) await openUrl(url);
8664
8785
  else console.log(`Open: ${url}`);
8665
8786
  });
8666
- program2.command("config").description("Show resolved AIPM CLI and project configuration").option("--registry <url>", "Registry base URL").option("--json", "Print machine-readable JSON").action(async (opts) => {
8667
- const root = (0, import_node_process3.cwd)();
8668
- const project = await readProjectPackageJson(root);
8669
- const lock = await readLockfile(root);
8787
+ program2.command("config").description("Show resolved AIPM CLI and project configuration").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Registry base URL").option("--json", "Print machine-readable JSON").action(async (opts) => {
8788
+ const scope = { global: opts.global };
8789
+ const configRoot = resolveConfigRoot(scope);
8790
+ const installRoot = resolveInstallRoot(scope);
8791
+ const project = await readProjectPackageJson(configRoot);
8792
+ const lock = await readLockfile(configRoot);
8670
8793
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
8671
8794
  const data = {
8672
8795
  cliVersion: CLI_VERSION,
8673
8796
  nodeVersion: process.versions.node,
8674
- cwd: root,
8797
+ scope: scopeLabel(scope),
8798
+ configRoot,
8799
+ installRoot,
8800
+ cwd: (0, import_node_process5.cwd)(),
8675
8801
  registry,
8676
- envRegistry: import_node_process3.env.AIPM_REGISTRY_URL ?? import_node_process3.env.AIPM_REGISTRY ?? null,
8802
+ envRegistry: import_node_process5.env.AIPM_REGISTRY_URL ?? import_node_process5.env.AIPM_REGISTRY ?? null,
8677
8803
  hasProjectConfig: Boolean(project),
8678
8804
  projectPackages: project ? Object.keys(project.packages) : [],
8679
8805
  hasLockfile: Boolean(lock),
@@ -8686,7 +8812,10 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
8686
8812
  }
8687
8813
  console.log(`CLI: ${data.cliVersion}`);
8688
8814
  console.log(`Node: ${data.nodeVersion}`);
8689
- console.log(`Project: ${data.cwd}`);
8815
+ console.log(`Scope: ${data.scope}`);
8816
+ console.log(`Config: ${data.configRoot}`);
8817
+ console.log(`Install root: ${data.installRoot}`);
8818
+ console.log(`Working directory: ${data.cwd}`);
8690
8819
  console.log(`Registry: ${data.registry}`);
8691
8820
  console.log(`Env registry: ${data.envRegistry ?? "not set"}`);
8692
8821
  console.log(`Project config: ${data.hasProjectConfig ? "found" : "not found"}`);
@@ -8695,11 +8824,13 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
8695
8824
  console.log(`Installed packages: ${data.installedPackages.length}`);
8696
8825
  console.log(`Publish guide: ${data.publishDoc}`);
8697
8826
  });
8698
- program2.command("add <package>").description("Add and install a package @scope/name[@version]").option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor or claude").option("--ci", "Non-interactive; fail if prompt needed").action(async (pkgArg, opts) => {
8827
+ program2.command("add <package>").description("Add and install a package @scope/name[@version]").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor, claude, or *").option("--ci", "Non-interactive; fail if prompt needed").action(async (pkgArg, opts) => {
8699
8828
  const { name, version: requestedVersion } = parsePackageArg(pkgArg);
8700
- const root = (0, import_node_process3.cwd)();
8701
- let project = await readProjectPackageJson(root);
8702
- if (!project) throw new Error("Run aipm init first");
8829
+ const scope = { global: opts.global };
8830
+ const configRoot = resolveConfigRoot(scope);
8831
+ const installRoot = resolveInstallRoot(scope);
8832
+ let project = await readProjectPackageJson(configRoot);
8833
+ if (!project) throw new Error(initRequiredMessage(scope));
8703
8834
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
8704
8835
  const version = requestedVersion ?? project.packages[name] ?? await latestVersionForPackage(registry, name);
8705
8836
  if (!version) throw new Error("Specify version: aipm add @scope/pkg@1.0.0");
@@ -8707,9 +8838,10 @@ program2.command("add <package>").description("Add and install a package @scope/
8707
8838
  ...project,
8708
8839
  packages: { ...project.packages, [name]: version.replace(/^\^/, "") }
8709
8840
  };
8710
- await writeProjectPackageJson(root, project);
8841
+ await writeProjectPackageJson(configRoot, project);
8711
8842
  await installOnePackage({
8712
- projectRoot: root,
8843
+ configRoot,
8844
+ installRoot,
8713
8845
  registry,
8714
8846
  name,
8715
8847
  version: version.replace(/^\^/, ""),
@@ -8717,6 +8849,9 @@ program2.command("add <package>").description("Add and install a package @scope/
8717
8849
  explicitTarget: parseTargetFlag(opts.target),
8718
8850
  ci: opts.ci
8719
8851
  });
8852
+ if (!opts.ci && !program2.opts().quiet) {
8853
+ await notifyCliUpdateIfNeeded(CLI_VERSION);
8854
+ }
8720
8855
  });
8721
8856
  program2.command("search [query]").description("Search public registry packages").option("--registry <url>", "Registry base URL").option("--limit <number>", "Maximum results", "20").option("--json", "Print machine-readable JSON").action(async (query = "", opts) => {
8722
8857
  const registry = registryFromEnvOrDefault(opts.registry);
@@ -8737,15 +8872,18 @@ program2.command("search [query]").description("Search public registry packages"
8737
8872
  console.log(` ${meta}`);
8738
8873
  }
8739
8874
  });
8740
- program2.command("install").description("Install all packages from aipm.package.json").option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor or claude").option("--ci", "Non-interactive").action(async (opts) => {
8741
- const root = (0, import_node_process3.cwd)();
8742
- const project = await readProjectPackageJson(root);
8743
- if (!project) throw new Error("Run aipm init first");
8875
+ 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("--ci", "Non-interactive").action(async (opts) => {
8876
+ const scope = { global: opts.global };
8877
+ const configRoot = resolveConfigRoot(scope);
8878
+ const installRoot = resolveInstallRoot(scope);
8879
+ const project = await readProjectPackageJson(configRoot);
8880
+ if (!project) throw new Error(initRequiredMessage(scope));
8744
8881
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
8745
8882
  const target = parseTargetFlag(opts.target);
8746
8883
  for (const [name, version] of Object.entries(project.packages)) {
8747
8884
  await installOnePackage({
8748
- projectRoot: root,
8885
+ configRoot,
8886
+ installRoot,
8749
8887
  registry,
8750
8888
  name,
8751
8889
  version: version.replace(/^\^/, ""),
@@ -8763,12 +8901,12 @@ var publish = program2.command("publish [dir]").description("Stage, validate, an
8763
8901
  publish.help();
8764
8902
  return;
8765
8903
  }
8766
- const abs = (0, import_node_path10.resolve)(dir);
8767
- const manifestRaw = await (0, import_promises9.readFile)((0, import_node_path10.join)(abs, "aipm.manifest.json"), "utf8");
8904
+ const abs = (0, import_node_path11.resolve)(dir);
8905
+ const manifestRaw = await (0, import_promises9.readFile)((0, import_node_path11.join)(abs, "aipm.manifest.json"), "utf8");
8768
8906
  const manifest = PackageManifestSchema.parse(JSON.parse(manifestRaw));
8769
8907
  const tarball = await packDirectory(abs);
8770
8908
  const registry = registryFromEnvOrDefault(opts.registry);
8771
- const result = await publishPackage(registry, manifest.name, tarball, opts.token ?? import_node_process3.env.AIPM_TOKEN);
8909
+ const result = await publishPackage(registry, manifest.name, tarball, opts.token ?? import_node_process5.env.AIPM_TOKEN);
8772
8910
  console.log(`Published ${manifest.name}@${result.version}`);
8773
8911
  console.log(`View: ${registry.replace(/\/$/, "")}/packages/${manifest.name.replace(/^@/, "").replace("/", "/")}/${result.version}`);
8774
8912
  console.log(`Install: aipm add ${manifest.name}@${result.version} --target ${manifest.targets[0]} --ci`);
@@ -8782,7 +8920,7 @@ publish.command("import <source>").description("Create a package folder from an
8782
8920
  async (source, opts) => initSkill({ ...opts, from: source })
8783
8921
  );
8784
8922
  publish.command("add [files...]").description("Stage files for publishing").action(async (files) => {
8785
- const state = await addPublishFiles((0, import_node_process3.cwd)(), files);
8923
+ const state = await addPublishFiles((0, import_node_process5.cwd)(), files);
8786
8924
  console.log(`Staged ${state.files.length} file${state.files.length === 1 ? "" : "s"}.`);
8787
8925
  printPublishGuide(
8788
8926
  `Added ${files.length > 0 ? files.join(", ") : "."} to the publish stage, respecting .aipmignore and secret-file exclusions.`,
@@ -8813,7 +8951,7 @@ publish.command("token").description("Open the dashboard page used to generate a
8813
8951
  );
8814
8952
  });
8815
8953
  publish.command("remove <files...>").alias("rm").description("Remove files from the publish stage").action(async (files) => {
8816
- const state = await removePublishFiles((0, import_node_process3.cwd)(), files);
8954
+ const state = await removePublishFiles((0, import_node_process5.cwd)(), files);
8817
8955
  console.log(`Staged ${state.files.length} file${state.files.length === 1 ? "" : "s"}.`);
8818
8956
  printPublishGuide(
8819
8957
  `Removed ${files.join(", ")} from the publish stage.`,
@@ -8821,7 +8959,7 @@ publish.command("remove <files...>").alias("rm").description("Remove files from
8821
8959
  );
8822
8960
  });
8823
8961
  publish.command("reset").description("Clear staged publish files").action(async () => {
8824
- await resetPublishState((0, import_node_process3.cwd)());
8962
+ await resetPublishState((0, import_node_process5.cwd)());
8825
8963
  console.log("Cleared publish stage.");
8826
8964
  printPublishGuide(
8827
8965
  "Cleared all staged publish files.",
@@ -8829,7 +8967,7 @@ publish.command("reset").description("Clear staged publish files").action(async
8829
8967
  );
8830
8968
  });
8831
8969
  publish.command("status").description("Show staged publish files").option("--json", "Print machine-readable JSON").action(async (opts) => {
8832
- const rows = await statusPublishState((0, import_node_process3.cwd)());
8970
+ const rows = await statusPublishState((0, import_node_process5.cwd)());
8833
8971
  if (opts.json) {
8834
8972
  console.log(JSON.stringify({ files: rows }, null, 2));
8835
8973
  return;
@@ -8852,7 +8990,7 @@ publish.command("status").description("Show staged publish files").option("--jso
8852
8990
  );
8853
8991
  });
8854
8992
  publish.command("diff").description("Show staged files that changed since add").action(async () => {
8855
- const rows = await statusPublishState((0, import_node_process3.cwd)());
8993
+ const rows = await statusPublishState((0, import_node_process5.cwd)());
8856
8994
  const changed = rows.filter((row) => row.changed);
8857
8995
  if (changed.length === 0) {
8858
8996
  console.log("No staged files changed.");
@@ -8869,16 +9007,16 @@ publish.command("diff").description("Show staged files that changed since add").
8869
9007
  );
8870
9008
  });
8871
9009
  publish.command("validate").description("Validate staged files before publish").action(async () => {
8872
- const result = await validatePublishState((0, import_node_process3.cwd)());
9010
+ const result = await validatePublishState((0, import_node_process5.cwd)());
8873
9011
  console.log(`Valid ${result.manifest.name}@${result.manifest.version} (${result.size} bytes staged).`);
8874
9012
  printPublishGuide(
8875
9013
  `Validated ${result.manifest.name}@${result.manifest.version}; manifest, entry file, staged hashes, ignored paths, package size, and obvious secrets passed.`,
8876
9014
  "Generate a 5-minute token from the dashboard, then run AIPM_TOKEN=<token> aipm publish push."
8877
9015
  );
8878
9016
  });
8879
- publish.command("preview").description("Preview exactly what will be uploaded").option("--json", "Print machine-readable JSON").action((opts) => printPublishPreview((0, import_node_process3.cwd)(), opts.json));
9017
+ publish.command("preview").description("Preview exactly what will be uploaded").option("--json", "Print machine-readable JSON").action((opts) => printPublishPreview((0, import_node_process5.cwd)(), opts.json));
8880
9018
  publish.command("push").description("Publish staged files").option("--registry <url>", "Registry base URL").option("--token <token>", "Publish token").option("--yes", "Confirm upload without an extra reminder").action(async (opts) => {
8881
- const root = (0, import_node_process3.cwd)();
9019
+ const root = (0, import_node_process5.cwd)();
8882
9020
  const { manifest } = await validatePublishState(root);
8883
9021
  const registry = registryFromEnvOrDefault(opts.registry);
8884
9022
  const tarball = await packStagedFiles(root);
@@ -8889,7 +9027,7 @@ publish.command("push").description("Publish staged files").option("--registry <
8889
9027
  }
8890
9028
  console.log(`Uploading ${staged.length} file${staged.length === 1 ? "" : "s"} to ${registry}.`);
8891
9029
  for (const entry of staged) console.log(` ${entry.path}`);
8892
- const result = await publishPackage(registry, manifest.name, tarball, opts.token ?? import_node_process3.env.AIPM_TOKEN);
9030
+ const result = await publishPackage(registry, manifest.name, tarball, opts.token ?? import_node_process5.env.AIPM_TOKEN);
8893
9031
  const base = registry.replace(/\/$/, "");
8894
9032
  console.log(`Published ${manifest.name}@${result.version}`);
8895
9033
  console.log(`View: ${base}/packages/${manifest.name.replace(/^@/, "")}/${result.version}`);
@@ -8899,9 +9037,9 @@ publish.command("push").description("Publish staged files").option("--registry <
8899
9037
  "Open the registry page, test the install command in a clean project, and share the package link."
8900
9038
  );
8901
9039
  });
8902
- program2.command("list").description("List packages from aipm-lock.json").action(async () => {
8903
- const { readLockfile: readLockfile2 } = await Promise.resolve().then(() => (init_project_files(), project_files_exports));
8904
- const lock = await readLockfile2((0, import_node_process3.cwd)());
9040
+ program2.command("list").description("List packages from aipm-lock.json").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).action(async (opts) => {
9041
+ const configRoot = resolveConfigRoot({ global: opts.global });
9042
+ const lock = await readLockfile(configRoot);
8905
9043
  if (!lock || Object.keys(lock.packages).length === 0) {
8906
9044
  console.log("No packages installed.");
8907
9045
  return;
@@ -8910,27 +9048,30 @@ program2.command("list").description("List packages from aipm-lock.json").action
8910
9048
  console.log(`${name}@${entry.version} [${entry.resolvedTools.join(", ")}]`);
8911
9049
  }
8912
9050
  });
8913
- program2.command("remove <package>").alias("rm").description("Remove a package from aipm.package.json and aipm-lock.json").action(async (pkgArg) => {
9051
+ program2.command("remove <package>").alias("rm").description("Remove a package from aipm.package.json and aipm-lock.json").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).action(async (pkgArg, opts) => {
8914
9052
  const { name } = parsePackageArg(pkgArg);
8915
- const root = (0, import_node_process3.cwd)();
8916
- const project = await readProjectPackageJson(root);
8917
- if (!project) throw new Error("Run aipm init first");
9053
+ const scope = { global: opts.global };
9054
+ const configRoot = resolveConfigRoot(scope);
9055
+ const project = await readProjectPackageJson(configRoot);
9056
+ if (!project) throw new Error(initRequiredMessage(scope));
8918
9057
  const packages = { ...project.packages };
8919
9058
  delete packages[name];
8920
- await writeProjectPackageJson(root, { ...project, packages });
8921
- const lock = await readLockfile(root);
9059
+ await writeProjectPackageJson(configRoot, { ...project, packages });
9060
+ const lock = await readLockfile(configRoot);
8922
9061
  if (lock) {
8923
9062
  const lockPackages = { ...lock.packages };
8924
9063
  delete lockPackages[name];
8925
- await writeLockfile(root, { ...lock, packages: lockPackages });
9064
+ await writeLockfile(configRoot, { ...lock, packages: lockPackages });
8926
9065
  }
8927
- console.log(`Removed ${name} from AIPM project files.`);
9066
+ console.log(`Removed ${name} from AIPM ${scopeLabel(scope)} files.`);
8928
9067
  console.log("Adapter-written files are not deleted yet; review your project before committing.");
8929
9068
  });
8930
- program2.command("update [package]").description("Update one installed package, or all installed packages, to the latest registry version").option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor or claude").option("--ci", "Non-interactive").action(async (pkgArg, opts) => {
8931
- const root = (0, import_node_process3.cwd)();
8932
- let project = await readProjectPackageJson(root);
8933
- if (!project) throw new Error("Run aipm init first");
9069
+ 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("--ci", "Non-interactive").action(async (pkgArg, opts) => {
9070
+ const scope = { global: opts.global };
9071
+ const configRoot = resolveConfigRoot(scope);
9072
+ const installRoot = resolveInstallRoot(scope);
9073
+ let project = await readProjectPackageJson(configRoot);
9074
+ if (!project) throw new Error(initRequiredMessage(scope));
8934
9075
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
8935
9076
  const names = pkgArg ? [parsePackageArg(pkgArg).name] : Object.keys(project.packages);
8936
9077
  if (names.length === 0) {
@@ -8943,9 +9084,10 @@ program2.command("update [package]").description("Update one installed package,
8943
9084
  ...project,
8944
9085
  packages: { ...project.packages, [name]: version }
8945
9086
  };
8946
- await writeProjectPackageJson(root, project);
9087
+ await writeProjectPackageJson(configRoot, project);
8947
9088
  await installOnePackage({
8948
- projectRoot: root,
9089
+ configRoot,
9090
+ installRoot,
8949
9091
  registry,
8950
9092
  name,
8951
9093
  version,
@@ -8955,7 +9097,7 @@ program2.command("update [package]").description("Update one installed package,
8955
9097
  });
8956
9098
  }
8957
9099
  });
8958
- program2.command("doctor").description("Check PATH, Node, registry, project config, and publish readiness").option("--registry <url>", "Registry base URL").option("--json", "Print machine-readable JSON").option("--publish", "Only show publish-readiness checks").action((opts) => runDoctor(opts));
9100
+ 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));
8959
9101
  program2.parseAsync(process.argv).catch((err) => {
8960
9102
  console.error(err.message);
8961
9103
  const message = err.message.toLowerCase();