@aipm-registry/cli 0.2.13 → 0.3.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
@@ -4160,7 +4160,7 @@ function expandTargets(targets) {
4160
4160
  return [...ALL_TOOLS];
4161
4161
  return targets.filter((t) => t !== "*");
4162
4162
  }
4163
- var AiToolSchema, ALL_TOOLS, PackageManifestSchema;
4163
+ var AiToolSchema, ALL_TOOLS, PackageExampleSchema, PackageManifestSchema;
4164
4164
  var init_manifest = __esm({
4165
4165
  "../../packages/schemas/dist/manifest.js"() {
4166
4166
  "use strict";
@@ -4168,16 +4168,26 @@ var init_manifest = __esm({
4168
4168
  init_scope_name();
4169
4169
  AiToolSchema = external_exports.enum(["cursor", "claude", "*"]);
4170
4170
  ALL_TOOLS = ["cursor", "claude"];
4171
+ PackageExampleSchema = external_exports.object({
4172
+ title: external_exports.string().trim().min(1).max(80),
4173
+ description: external_exports.string().trim().min(1).max(240).optional(),
4174
+ prompt: external_exports.string().trim().min(1).max(1e3)
4175
+ });
4171
4176
  PackageManifestSchema = external_exports.object({
4172
4177
  schemaVersion: external_exports.literal("0.1"),
4173
4178
  name: external_exports.string().regex(SCOPE_NAME_REGEX, "name must be @scope/name"),
4174
4179
  version: external_exports.string().min(1),
4175
4180
  type: external_exports.literal("skill"),
4176
- description: external_exports.string().min(1),
4181
+ description: external_exports.string().trim().min(1).max(240),
4177
4182
  entry: external_exports.string().min(1),
4178
4183
  targets: external_exports.array(AiToolSchema).min(1),
4179
4184
  license: external_exports.string().optional(),
4180
- usage: external_exports.string().min(1).optional()
4185
+ usage: external_exports.string().trim().min(1).max(2e3).optional(),
4186
+ tags: external_exports.array(external_exports.string().trim().min(1).max(40)).max(12).optional(),
4187
+ categories: external_exports.array(external_exports.string().trim().min(1).max(40)).max(4).optional(),
4188
+ sourceUrl: external_exports.string().trim().url().max(500).optional(),
4189
+ examples: external_exports.array(PackageExampleSchema).max(5).optional(),
4190
+ releaseNotes: external_exports.string().trim().min(1).max(2e3).optional()
4181
4191
  });
4182
4192
  }
4183
4193
  });
@@ -7762,9 +7772,11 @@ function useColor() {
7762
7772
  var program = new Command();
7763
7773
 
7764
7774
  // src/bin.ts
7775
+ var import_node_crypto2 = require("node:crypto");
7765
7776
  var import_node_child_process4 = require("node:child_process");
7766
- var import_promises9 = require("node:fs/promises");
7767
- var import_node_path11 = require("node:path");
7777
+ var import_node_http = require("node:http");
7778
+ var import_promises10 = require("node:fs/promises");
7779
+ var import_node_path12 = require("node:path");
7768
7780
  var import_node_process5 = require("node:process");
7769
7781
  init_dist();
7770
7782
  init_dist4();
@@ -7989,15 +8001,15 @@ async function packStagedFiles(root) {
7989
8001
  }
7990
8002
  }
7991
8003
  async function unpackTarballToBuffer(tarball, entry) {
7992
- const { mkdtemp: mkdtemp2, rm: rm3, writeFile: writeFile6 } = await import("node:fs/promises");
7993
- const { join: join11 } = await import("node:path");
8004
+ const { mkdtemp: mkdtemp2, rm: rm3, writeFile: writeFile7 } = await import("node:fs/promises");
8005
+ const { join: join12 } = await import("node:path");
7994
8006
  const { tmpdir: tmpdir2 } = await import("node:os");
7995
- const tempDir = await mkdtemp2(join11(tmpdir2(), "aipm-install-"));
7996
- const tgzPath = join11(tempDir, "pkg.tgz");
8007
+ const tempDir = await mkdtemp2(join12(tmpdir2(), "aipm-install-"));
8008
+ const tgzPath = join12(tempDir, "pkg.tgz");
7997
8009
  try {
7998
- await writeFile6(tgzPath, tarball);
8010
+ await writeFile7(tgzPath, tarball);
7999
8011
  await execFileAsync("tar", ["-xzf", tgzPath, "-C", tempDir]);
8000
- return (0, import_promises5.readFile)(join11(tempDir, entry), "utf8");
8012
+ return (0, import_promises5.readFile)(join12(tempDir, entry), "utf8");
8001
8013
  } finally {
8002
8014
  await rm3(tempDir, { recursive: true, force: true });
8003
8015
  }
@@ -8032,7 +8044,7 @@ function privateInstallHint(name, status, token) {
8032
8044
  if (status !== 404 || !name.startsWith("@") || token) {
8033
8045
  return `Package not found: ${name} (${status})`;
8034
8046
  }
8035
- return `Package not found: ${name} (${status}). If @org/pkg is private, set AIPM_TOKEN with an install token from the dashboard.`;
8047
+ return `Package not found: ${name} (${status}). If @org/pkg is private, run aipm login, or set AIPM_TOKEN for CI.`;
8036
8048
  }
8037
8049
  async function assertRegistryReachable(registry) {
8038
8050
  const base = registry.replace(/\/$/, "");
@@ -8054,16 +8066,63 @@ async function publishPackage(registry, name, tarball, token) {
8054
8066
  }
8055
8067
  return res.json();
8056
8068
  }
8057
- async function searchPackages(registry, query, limit = 20) {
8069
+ async function searchPackages(registry, query, limit = 20, token) {
8058
8070
  const base = registry.replace(/\/$/, "");
8059
8071
  const params = new URLSearchParams();
8060
8072
  if (query) params.set("q", query);
8061
8073
  params.set("limit", String(limit));
8062
- const res = await registryFetch(`${base}/v1/packages?${params}`, base);
8074
+ const res = await registryFetch(`${base}/v1/packages?${params}`, base, {
8075
+ headers: registryAuthHeaders(token)
8076
+ });
8063
8077
  if (!res.ok) throw new Error(`Search failed: ${res.status}`);
8064
8078
  const data = await res.json();
8065
8079
  return data.packages ?? [];
8066
8080
  }
8081
+ async function exchangeCliAuthCode(registry, input2) {
8082
+ const base = registry.replace(/\/$/, "");
8083
+ const res = await registryFetch(`${base}/v1/cli-auth/token`, base, {
8084
+ method: "POST",
8085
+ headers: { "content-type": "application/json" },
8086
+ body: JSON.stringify(input2)
8087
+ });
8088
+ if (!res.ok) {
8089
+ const err = await res.json().catch(() => ({}));
8090
+ throw new Error(err.error ?? `CLI login failed: ${res.status}`);
8091
+ }
8092
+ return res.json();
8093
+ }
8094
+ async function refreshCliAuth(registry, refreshToken) {
8095
+ const base = registry.replace(/\/$/, "");
8096
+ const res = await registryFetch(`${base}/v1/cli-auth/refresh`, base, {
8097
+ method: "POST",
8098
+ headers: { "content-type": "application/json" },
8099
+ body: JSON.stringify({ refreshToken })
8100
+ });
8101
+ if (!res.ok) {
8102
+ const err = await res.json().catch(() => ({}));
8103
+ throw new Error(err.error ?? `CLI session refresh failed: ${res.status}`);
8104
+ }
8105
+ return res.json();
8106
+ }
8107
+ async function fetchCliAuthMe(registry, accessToken) {
8108
+ const base = registry.replace(/\/$/, "");
8109
+ const res = await registryFetch(`${base}/v1/cli-auth/me`, base, {
8110
+ headers: registryAuthHeaders(accessToken)
8111
+ });
8112
+ if (!res.ok) {
8113
+ const err = await res.json().catch(() => ({}));
8114
+ throw new Error(err.error ?? `CLI auth check failed: ${res.status}`);
8115
+ }
8116
+ return res.json();
8117
+ }
8118
+ async function logoutCliAuth(registry, refreshToken) {
8119
+ const base = registry.replace(/\/$/, "");
8120
+ await registryFetch(`${base}/v1/cli-auth/logout`, base, {
8121
+ method: "POST",
8122
+ headers: { "content-type": "application/json" },
8123
+ body: JSON.stringify({ refreshToken })
8124
+ });
8125
+ }
8067
8126
  async function fetchPackageMetadata(registry, name, version, token) {
8068
8127
  const base = registry.replace(/\/$/, "");
8069
8128
  const url = `${base}/v1/packages/${encodePackageName(name)}/versions/${version}`;
@@ -8080,41 +8139,102 @@ async function fetchPackageTarball(registry, name, version, token) {
8080
8139
  const ab = await res.arrayBuffer();
8081
8140
  return Buffer.from(ab);
8082
8141
  }
8142
+ async function recordPackageInstall(registry, name, token) {
8143
+ const base = registry.replace(/\/$/, "");
8144
+ const url = `${base}/v1/packages/${encodePackageName(name)}/installs`;
8145
+ const res = await registryFetch(url, base, {
8146
+ method: "POST",
8147
+ headers: registryAuthHeaders(token)
8148
+ });
8149
+ if (!res.ok) {
8150
+ const err = await res.json().catch(() => ({}));
8151
+ throw new Error(err.error ?? `Install recording failed: ${res.status}`);
8152
+ }
8153
+ return res.json();
8154
+ }
8155
+
8156
+ // src/auth-store.ts
8157
+ var import_promises7 = require("node:fs/promises");
8158
+ var import_node_os2 = require("node:os");
8159
+ var import_node_path7 = require("node:path");
8160
+ var AUTH_FILE = (0, import_node_path7.join)((0, import_node_os2.homedir)(), ".aipm", "auth.json");
8161
+ function normalizeRegistry(registry) {
8162
+ return registry.replace(/\/$/, "");
8163
+ }
8164
+ async function readAuthStore() {
8165
+ try {
8166
+ const raw = await (0, import_promises7.readFile)(AUTH_FILE, "utf8");
8167
+ const parsed = JSON.parse(raw);
8168
+ return { registries: parsed.registries ?? {} };
8169
+ } catch {
8170
+ return { registries: {} };
8171
+ }
8172
+ }
8173
+ async function writeAuthStore(store) {
8174
+ await (0, import_promises7.mkdir)((0, import_node_path7.dirname)(AUTH_FILE), { recursive: true });
8175
+ await (0, import_promises7.writeFile)(AUTH_FILE, JSON.stringify(store, null, 2) + "\n", "utf8");
8176
+ await (0, import_promises7.chmod)(AUTH_FILE, 384).catch(() => void 0);
8177
+ }
8178
+ async function getStoredRegistryAuth(registry) {
8179
+ const store = await readAuthStore();
8180
+ return store.registries[normalizeRegistry(registry)] ?? null;
8181
+ }
8182
+ async function setStoredRegistryAuth(registry, auth) {
8183
+ const store = await readAuthStore();
8184
+ store.registries[normalizeRegistry(registry)] = auth;
8185
+ await writeAuthStore(store);
8186
+ }
8187
+ async function clearStoredRegistryAuth(registry) {
8188
+ const store = await readAuthStore();
8189
+ const key = normalizeRegistry(registry);
8190
+ const existing = store.registries[key] ?? null;
8191
+ delete store.registries[key];
8192
+ await writeAuthStore(store);
8193
+ return existing;
8194
+ }
8195
+ function authFilePath() {
8196
+ return AUTH_FILE;
8197
+ }
8198
+ function isAccessTokenFresh(auth, skewMs = 6e4) {
8199
+ if (!auth?.accessToken || !auth.accessTokenExpiresAt) return false;
8200
+ const expiresAt = Date.parse(auth.accessTokenExpiresAt);
8201
+ return Number.isFinite(expiresAt) && expiresAt - skewMs > Date.now();
8202
+ }
8083
8203
 
8084
8204
  // src/install-one.ts
8085
8205
  init_dist4();
8086
8206
 
8087
8207
  // src/project-files.ts
8088
- var import_promises7 = require("node:fs/promises");
8089
- var import_node_path7 = require("node:path");
8208
+ var import_promises8 = require("node:fs/promises");
8209
+ var import_node_path8 = require("node:path");
8090
8210
  init_dist();
8091
8211
  var PACKAGE_JSON = "aipm.package.json";
8092
8212
  var LOCKFILE = "aipm-lock.json";
8093
8213
  async function readProjectPackageJson(projectRoot) {
8094
8214
  try {
8095
- const raw = await (0, import_promises7.readFile)((0, import_node_path7.join)(projectRoot, PACKAGE_JSON), "utf8");
8215
+ const raw = await (0, import_promises8.readFile)((0, import_node_path8.join)(projectRoot, PACKAGE_JSON), "utf8");
8096
8216
  return ProjectPackageJsonSchema.parse(JSON.parse(raw));
8097
8217
  } catch {
8098
8218
  return null;
8099
8219
  }
8100
8220
  }
8101
8221
  async function writeProjectPackageJson(projectRoot, data) {
8102
- await (0, import_promises7.writeFile)(
8103
- (0, import_node_path7.join)(projectRoot, PACKAGE_JSON),
8222
+ await (0, import_promises8.writeFile)(
8223
+ (0, import_node_path8.join)(projectRoot, PACKAGE_JSON),
8104
8224
  JSON.stringify(data, null, 2) + "\n",
8105
8225
  "utf8"
8106
8226
  );
8107
8227
  }
8108
8228
  async function readLockfile(projectRoot) {
8109
8229
  try {
8110
- const raw = await (0, import_promises7.readFile)((0, import_node_path7.join)(projectRoot, LOCKFILE), "utf8");
8230
+ const raw = await (0, import_promises8.readFile)((0, import_node_path8.join)(projectRoot, LOCKFILE), "utf8");
8111
8231
  return LockfileSchema.parse(JSON.parse(raw));
8112
8232
  } catch {
8113
8233
  return null;
8114
8234
  }
8115
8235
  }
8116
8236
  async function writeLockfile(projectRoot, data) {
8117
- await (0, import_promises7.writeFile)((0, import_node_path7.join)(projectRoot, LOCKFILE), JSON.stringify(data, null, 2) + "\n", "utf8");
8237
+ await (0, import_promises8.writeFile)((0, import_node_path8.join)(projectRoot, LOCKFILE), JSON.stringify(data, null, 2) + "\n", "utf8");
8118
8238
  }
8119
8239
  function upsertLockEntry(lock, name, entry) {
8120
8240
  return {
@@ -8248,23 +8368,23 @@ async function installOnePackage(options) {
8248
8368
 
8249
8369
  // src/doctor.ts
8250
8370
  var import_node_child_process3 = require("node:child_process");
8251
- var import_promises8 = require("node:fs/promises");
8252
- var import_node_path9 = require("node:path");
8371
+ var import_promises9 = require("node:fs/promises");
8372
+ var import_node_path10 = require("node:path");
8253
8373
  var import_node_util4 = require("node:util");
8254
8374
 
8255
8375
  // src/project-root.ts
8256
- var import_node_os2 = require("node:os");
8257
- var import_node_path8 = require("node:path");
8376
+ var import_node_os3 = require("node:os");
8377
+ var import_node_path9 = require("node:path");
8258
8378
  var import_node_process3 = require("node:process");
8259
8379
  function globalConfigDir(env2 = process.env) {
8260
8380
  const fromEnv = env2.AIPM_HOME?.trim();
8261
- return fromEnv ? fromEnv.replace(/\/$/, "") : (0, import_node_path8.join)((0, import_node_os2.homedir)(), ".aipm");
8381
+ return fromEnv ? fromEnv.replace(/\/$/, "") : (0, import_node_path9.join)((0, import_node_os3.homedir)(), ".aipm");
8262
8382
  }
8263
8383
  function resolveConfigRoot(options = {}) {
8264
8384
  return options.global ? globalConfigDir() : (0, import_node_process3.cwd)();
8265
8385
  }
8266
8386
  function resolveInstallRoot(options = {}) {
8267
- return options.global ? (0, import_node_os2.homedir)() : (0, import_node_process3.cwd)();
8387
+ return options.global ? (0, import_node_os3.homedir)() : (0, import_node_process3.cwd)();
8268
8388
  }
8269
8389
  function scopeLabel(options) {
8270
8390
  return options.global ? "global" : "project";
@@ -8289,11 +8409,11 @@ async function commandOutput(command, args) {
8289
8409
  }
8290
8410
  function npmGlobalBin(prefix) {
8291
8411
  if (!prefix) return null;
8292
- return process.platform === "win32" ? prefix : `${prefix}${import_node_path9.sep}bin`;
8412
+ return process.platform === "win32" ? prefix : `${prefix}${import_node_path10.sep}bin`;
8293
8413
  }
8294
8414
  function pathIncludes(pathDir) {
8295
8415
  if (!pathDir) return false;
8296
- return (process.env.PATH ?? "").split(import_node_path9.delimiter).includes(pathDir);
8416
+ return (process.env.PATH ?? "").split(import_node_path10.delimiter).includes(pathDir);
8297
8417
  }
8298
8418
  function shellPathHint(binDir) {
8299
8419
  if (!binDir) return "Run npm prefix -g and add its bin folder to PATH.";
@@ -8346,11 +8466,11 @@ async function runDoctor(options) {
8346
8466
  if (!options.publish) {
8347
8467
  const configLabel = options.global ? "Global config" : "Project config";
8348
8468
  try {
8349
- await (0, import_promises8.access)((0, import_node_path9.join)(configRoot, "aipm.package.json"));
8469
+ await (0, import_promises9.access)((0, import_node_path10.join)(configRoot, "aipm.package.json"));
8350
8470
  checks.push({
8351
8471
  name: configLabel,
8352
8472
  ok: true,
8353
- detail: `${(0, import_node_path9.join)(configRoot, "aipm.package.json")} exists (${scopeLabel(scope)}).`
8473
+ detail: `${(0, import_node_path10.join)(configRoot, "aipm.package.json")} exists (${scopeLabel(scope)}).`
8354
8474
  });
8355
8475
  } catch {
8356
8476
  checks.push({
@@ -8420,9 +8540,9 @@ async function runDoctor(options) {
8420
8540
 
8421
8541
  // src/version.ts
8422
8542
  var import_node_fs2 = require("node:fs");
8423
- var import_node_path10 = require("node:path");
8543
+ var import_node_path11 = require("node:path");
8424
8544
  function getCliVersion() {
8425
- const pkgPath = (0, import_node_path10.join)(__dirname, "..", "package.json");
8545
+ const pkgPath = (0, import_node_path11.join)(__dirname, "..", "package.json");
8426
8546
  const pkg = JSON.parse((0, import_node_fs2.readFileSync)(pkgPath, "utf8"));
8427
8547
  return pkg.version;
8428
8548
  }
@@ -8523,7 +8643,9 @@ program2.name("aipm").description("AI package manager").enablePositionalOptions(
8523
8643
  Examples:
8524
8644
  $ npm install -g @aipm-registry/cli
8525
8645
  $ aipm doctor
8526
- $ aipm init
8646
+ $ aipm login
8647
+ $ aipm whoami
8648
+ $ aipm init --target cursor
8527
8649
  $ aipm init -g
8528
8650
  $ aipm search sentry
8529
8651
  $ aipm add @scope/name@1.0.0 --target cursor --ci
@@ -8537,6 +8659,10 @@ Examples:
8537
8659
  function registryFromEnvOrDefault(flag) {
8538
8660
  return resolveRegistryUrl(null, flag, DEFAULT_REGISTRY);
8539
8661
  }
8662
+ function packagePageUrl(packageName, version) {
8663
+ const [scope, name] = packageName.replace(/^@/, "").split("/");
8664
+ return `${SITE_URL}/packages/${encodeURIComponent(scope ?? "")}/${encodeURIComponent(name ?? "")}/${encodeURIComponent(version)}`;
8665
+ }
8540
8666
  function parsePackageArg(value) {
8541
8667
  const match = value.match(/^(@[^@]+)(?:@(.+))?$/);
8542
8668
  if (!match) throw new Error("Package must be @scope/name or @scope/name@version");
@@ -8551,23 +8677,23 @@ function skillFolderName(name) {
8551
8677
  return folder;
8552
8678
  }
8553
8679
  async function writeStarterFile(path2, content) {
8554
- await (0, import_promises9.writeFile)(path2, content, { encoding: "utf8", flag: "wx" });
8680
+ await (0, import_promises10.writeFile)(path2, content, { encoding: "utf8", flag: "wx" });
8555
8681
  }
8556
8682
  async function inferEntryFromSource(source, fallback) {
8557
- const sourceInfo = await (0, import_promises9.stat)(source);
8558
- if (sourceInfo.isFile()) return (0, import_node_path11.basename)(source);
8683
+ const sourceInfo = await (0, import_promises10.stat)(source);
8684
+ if (sourceInfo.isFile()) return (0, import_node_path12.basename)(source);
8559
8685
  if (!sourceInfo.isDirectory()) return fallback;
8560
- const entries = await (0, import_promises9.readdir)(source);
8686
+ const entries = await (0, import_promises10.readdir)(source);
8561
8687
  if (entries.includes(fallback)) return fallback;
8562
8688
  return entries.find((entry) => entry.endsWith(".md")) ?? entries.find((entry) => entry.endsWith(".mdc")) ?? fallback;
8563
8689
  }
8564
8690
  async function copySourceIntoSkillRoot(source, root, sourceLabel) {
8565
- const sourceInfo = await (0, import_promises9.stat)(source);
8566
- await (0, import_promises9.mkdir)(root, { recursive: true });
8691
+ const sourceInfo = await (0, import_promises10.stat)(source);
8692
+ await (0, import_promises10.mkdir)(root, { recursive: true });
8567
8693
  if (sourceInfo.isDirectory()) {
8568
- const entries = await (0, import_promises9.readdir)(source);
8694
+ const entries = await (0, import_promises10.readdir)(source);
8569
8695
  for (const entry of entries) {
8570
- await (0, import_promises9.cp)((0, import_node_path11.join)(source, entry), (0, import_node_path11.join)(root, entry), {
8696
+ await (0, import_promises10.cp)((0, import_node_path12.join)(source, entry), (0, import_node_path12.join)(root, entry), {
8571
8697
  recursive: true,
8572
8698
  force: false,
8573
8699
  errorOnExist: true
@@ -8576,13 +8702,13 @@ async function copySourceIntoSkillRoot(source, root, sourceLabel) {
8576
8702
  return;
8577
8703
  }
8578
8704
  if (sourceInfo.isFile()) {
8579
- await (0, import_promises9.cp)(source, (0, import_node_path11.join)(root, (0, import_node_path11.basename)(source)), { force: false, errorOnExist: true });
8705
+ await (0, import_promises10.cp)(source, (0, import_node_path12.join)(root, (0, import_node_path12.basename)(source)), { force: false, errorOnExist: true });
8580
8706
  return;
8581
8707
  }
8582
8708
  throw new Error(`Unsupported source path: ${sourceLabel}`);
8583
8709
  }
8584
- async function latestVersionForPackage(registry, name) {
8585
- const packages = await searchPackages(registry, name, 20);
8710
+ async function latestVersionForPackage(registry, name, token) {
8711
+ const packages = await searchPackages(registry, name, 20, token);
8586
8712
  const exact = packages.find((pkg) => pkg.name === name);
8587
8713
  if (!exact) throw new Error(`Package not found in registry: ${name}`);
8588
8714
  return exact.version;
@@ -8617,6 +8743,111 @@ async function openUrl(url) {
8617
8743
  });
8618
8744
  console.log(`Open: ${url}`);
8619
8745
  }
8746
+ function randomBase64Url(bytes = 32) {
8747
+ return (0, import_node_crypto2.randomBytes)(bytes).toString("base64url");
8748
+ }
8749
+ function sha256Base64Url(value) {
8750
+ return (0, import_node_crypto2.createHash)("sha256").update(value).digest("base64url");
8751
+ }
8752
+ function deviceName() {
8753
+ return `AIPM CLI on ${process.platform}`;
8754
+ }
8755
+ async function authTokenForRegistry(registry, options = {}) {
8756
+ const stored = await getStoredRegistryAuth(registry);
8757
+ if (!stored?.refreshToken) return void 0;
8758
+ if (isAccessTokenFresh(stored)) return stored.accessToken;
8759
+ try {
8760
+ const refreshed = await refreshCliAuth(registry, stored.refreshToken);
8761
+ await setStoredRegistryAuth(registry, {
8762
+ ...stored,
8763
+ accessToken: refreshed.accessToken,
8764
+ accessTokenExpiresAt: refreshed.accessTokenExpiresAt
8765
+ });
8766
+ return refreshed.accessToken;
8767
+ } catch {
8768
+ await clearStoredRegistryAuth(registry);
8769
+ const message = `CLI login for ${registry} expired or was revoked. Run aipm login to access private packages.`;
8770
+ if (options.throwOnFailure) throw new Error(message);
8771
+ if (!options.quiet) console.warn(`Warning: ${message}`);
8772
+ return void 0;
8773
+ }
8774
+ }
8775
+ async function tokenForRead(registry, explicitToken, options = {}) {
8776
+ return explicitToken ?? import_node_process5.env.AIPM_TOKEN ?? await authTokenForRegistry(registry, options);
8777
+ }
8778
+ async function runLoopbackLogin(options) {
8779
+ const state = randomBase64Url(24);
8780
+ const verifier = randomBase64Url(48);
8781
+ const challenge = sha256Base64Url(verifier);
8782
+ const result = await new Promise((resolveLogin, rejectLogin) => {
8783
+ const server = (0, import_node_http.createServer)((request, response) => {
8784
+ const host = request.headers.host ?? "127.0.0.1";
8785
+ const url = new URL(request.url ?? "/", `http://${host}`);
8786
+ if (url.pathname !== "/callback") {
8787
+ response.writeHead(404, { "content-type": "text/plain" });
8788
+ response.end("Not found");
8789
+ return;
8790
+ }
8791
+ if (url.searchParams.get("state") !== state) {
8792
+ response.writeHead(400, { "content-type": "text/html" });
8793
+ response.end("<h1>AIPM login failed</h1><p>Invalid state. Return to the terminal and try again.</p>");
8794
+ rejectLogin(new Error("Invalid CLI login state"));
8795
+ server.close();
8796
+ return;
8797
+ }
8798
+ const code = url.searchParams.get("code");
8799
+ if (!code) {
8800
+ response.writeHead(400, { "content-type": "text/html" });
8801
+ response.end("<h1>AIPM login failed</h1><p>Missing code. Return to the terminal and try again.</p>");
8802
+ rejectLogin(new Error("Missing CLI authorization code"));
8803
+ server.close();
8804
+ return;
8805
+ }
8806
+ response.writeHead(200, { "content-type": "text/html" });
8807
+ response.end("<h1>AIPM CLI is signed in</h1><p>You can close this window and return to the terminal.</p>");
8808
+ const address = server.address();
8809
+ if (!address || typeof address === "string") {
8810
+ rejectLogin(new Error("Could not read CLI callback address"));
8811
+ } else {
8812
+ resolveLogin({ code, redirectUri: `http://127.0.0.1:${address.port}/callback` });
8813
+ }
8814
+ server.close();
8815
+ });
8816
+ server.once("error", rejectLogin);
8817
+ server.listen(0, "127.0.0.1", () => {
8818
+ const address = server.address();
8819
+ const redirectUri = `http://127.0.0.1:${address.port}/callback`;
8820
+ const loginUrl = new URL("/cli/login", options.siteUrl);
8821
+ loginUrl.searchParams.set("redirect_uri", redirectUri);
8822
+ loginUrl.searchParams.set("state", state);
8823
+ loginUrl.searchParams.set("code_challenge", challenge);
8824
+ loginUrl.searchParams.set("device", deviceName());
8825
+ console.log("Authorize the AIPM CLI in your browser.");
8826
+ if (options.open) void openUrl(loginUrl.toString());
8827
+ else console.log(`Open: ${loginUrl.toString()}`);
8828
+ });
8829
+ server.setTimeout(5 * 60 * 1e3, () => {
8830
+ rejectLogin(new Error("CLI login timed out"));
8831
+ server.close();
8832
+ });
8833
+ });
8834
+ const tokens = await exchangeCliAuthCode(options.registry, {
8835
+ code: result.code,
8836
+ codeVerifier: verifier,
8837
+ redirectUri: result.redirectUri,
8838
+ deviceName: deviceName()
8839
+ });
8840
+ await setStoredRegistryAuth(options.registry, {
8841
+ accessToken: tokens.accessToken,
8842
+ accessTokenExpiresAt: tokens.accessTokenExpiresAt,
8843
+ refreshToken: tokens.refreshToken,
8844
+ refreshTokenExpiresAt: tokens.refreshTokenExpiresAt,
8845
+ user: tokens.user
8846
+ });
8847
+ const label = tokens.user?.username ?? tokens.user?.githubLogin ?? tokens.user?.email ?? "AIPM user";
8848
+ console.log(`Logged in as ${label}.`);
8849
+ console.log(`Credentials saved to ${authFilePath()}`);
8850
+ }
8620
8851
  function printPublishFlow() {
8621
8852
  console.log("AIPM publish flow");
8622
8853
  console.log("1. Create an account and organization in the dashboard.");
@@ -8728,12 +8959,55 @@ function parseSkillTemplate(value) {
8728
8959
  if (value in SKILL_TEMPLATES) return value;
8729
8960
  throw new Error(`Unknown template "${value}". Use one of: ${Object.keys(SKILL_TEMPLATES).join(", ")}`);
8730
8961
  }
8962
+ var TEMPLATE_METADATA = {
8963
+ blank: {
8964
+ tags: ["ai-skill"],
8965
+ categories: ["AI workflow"],
8966
+ exampleTitle: "Use this skill in a project",
8967
+ examplePrompt: "Use this skill with the current project context and explain the next useful action."
8968
+ },
8969
+ "code-review": {
8970
+ tags: ["code-review", "pull-requests", "quality"],
8971
+ categories: ["Engineering", "Quality"],
8972
+ exampleTitle: "Review a pull request",
8973
+ examplePrompt: "Review my current diff for correctness, regressions, missing tests, and security risk."
8974
+ },
8975
+ "issue-summary": {
8976
+ tags: ["issue-summary", "triage", "support"],
8977
+ categories: ["Support", "Engineering"],
8978
+ exampleTitle: "Summarize a production issue",
8979
+ examplePrompt: "Summarize this issue with impact, likely cause, evidence, and next debugging steps."
8980
+ },
8981
+ "release-notes": {
8982
+ tags: ["release-notes", "changelog", "documentation"],
8983
+ categories: ["Product", "Documentation"],
8984
+ exampleTitle: "Draft release notes",
8985
+ examplePrompt: "Draft release notes from these changes with highlights, fixes, upgrade notes, and known issues."
8986
+ }
8987
+ };
8988
+ function buildStarterQualityMetadata(options) {
8989
+ const metadata = TEMPLATE_METADATA[options.template];
8990
+ const shortName = skillFolderName(options.name);
8991
+ return {
8992
+ usage: `Install ${options.name}, then ask your AI assistant to use the ${shortName} skill when the project needs: ${options.description}`,
8993
+ tags: metadata.tags,
8994
+ categories: metadata.categories,
8995
+ examples: [
8996
+ {
8997
+ title: metadata.exampleTitle,
8998
+ prompt: metadata.examplePrompt
8999
+ }
9000
+ ],
9001
+ releaseNotes: "Initial release."
9002
+ };
9003
+ }
8731
9004
  async function initSkill(opts) {
8732
9005
  if (!isValidScopeName(opts.name)) throw new Error("Invalid @scope/name");
8733
- const root = opts.here ? (0, import_node_process5.cwd)() : (0, import_node_path11.resolve)((0, import_node_process5.cwd)(), opts.dir ?? skillFolderName(opts.name));
9006
+ const root = opts.here ? (0, import_node_process5.cwd)() : (0, import_node_path12.resolve)((0, import_node_process5.cwd)(), opts.dir ?? skillFolderName(opts.name));
8734
9007
  const cdTarget = opts.here ? null : opts.dir ?? skillFolderName(opts.name);
8735
- const source = opts.from ? (0, import_node_path11.resolve)(opts.from) : null;
9008
+ const source = opts.from ? (0, import_node_path12.resolve)(opts.from) : null;
8736
9009
  const entry = source ? await inferEntryFromSource(source, opts.entry) : opts.entry;
9010
+ const template = parseSkillTemplate(opts.template ?? "blank");
8737
9011
  const manifest = PackageManifestSchema.parse({
8738
9012
  schemaVersion: "0.1",
8739
9013
  name: opts.name,
@@ -8742,23 +9016,27 @@ async function initSkill(opts) {
8742
9016
  description: opts.description,
8743
9017
  entry,
8744
9018
  targets: parseTargetsFlag(opts.targets),
8745
- license: "Apache-2.0"
9019
+ license: "Apache-2.0",
9020
+ ...buildStarterQualityMetadata({
9021
+ name: opts.name,
9022
+ description: opts.description,
9023
+ template
9024
+ })
8746
9025
  });
8747
9026
  if (source) {
8748
9027
  await copySourceIntoSkillRoot(source, root, source);
8749
9028
  } else {
8750
- await (0, import_promises9.mkdir)(root, { recursive: true });
9029
+ await (0, import_promises10.mkdir)(root, { recursive: true });
8751
9030
  }
8752
- await writeStarterFile((0, import_node_path11.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
9031
+ await writeStarterFile((0, import_node_path12.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
8753
9032
  if (!opts.from) {
8754
- const template = parseSkillTemplate(opts.template ?? "blank");
8755
9033
  await writeStarterFile(
8756
- (0, import_node_path11.join)(root, entry),
9034
+ (0, import_node_path12.join)(root, entry),
8757
9035
  SKILL_TEMPLATES[template](opts.name)
8758
9036
  );
8759
9037
  }
8760
9038
  await writeStarterFile(
8761
- (0, import_node_path11.join)(root, ".aipmignore"),
9039
+ (0, import_node_path12.join)(root, ".aipmignore"),
8762
9040
  [
8763
9041
  "# Files that should never be published with this skill",
8764
9042
  ".env*",
@@ -8776,14 +9054,14 @@ async function initSkill(opts) {
8776
9054
  ""
8777
9055
  ].join("\n")
8778
9056
  );
8779
- await (0, import_promises9.mkdir)((0, import_node_path11.join)(root, ".aipm"), { recursive: true });
9057
+ await (0, import_promises10.mkdir)((0, import_node_path12.join)(root, ".aipm"), { recursive: true });
8780
9058
  console.log(`Created ${opts.name} skill folder: ${root}`);
8781
9059
  printPublishGuide(
8782
9060
  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.`,
8783
9061
  cdTarget ? `Run cd ${cdTarget}, edit/review the files, then run aipm publish add .` : "Edit/review the files, then run aipm publish add ."
8784
9062
  );
8785
9063
  }
8786
- 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) => {
9064
+ 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) => {
8787
9065
  const scope = { global: opts.global };
8788
9066
  const configRoot = resolveConfigRoot(scope);
8789
9067
  const existing = await readProjectPackageJson(configRoot);
@@ -8791,11 +9069,12 @@ program2.command("init").description("Create aipm.package.json in the current pr
8791
9069
  console.log(`aipm.package.json already exists (${scopeLabel(scope)}).`);
8792
9070
  return;
8793
9071
  }
8794
- if (scope.global) await (0, import_promises9.mkdir)(configRoot, { recursive: true });
9072
+ if (scope.global) await (0, import_promises10.mkdir)(configRoot, { recursive: true });
8795
9073
  const installRoot = resolveInstallRoot(scope);
8796
9074
  const detected = await detectToolsInProject(installRoot);
8797
- let preferredTools = detected;
8798
- if (detected.length === 0) {
9075
+ const parsedTarget = parseTargetFlag(opts.target);
9076
+ let preferredTools = parsedTarget ? [parsedTarget] : detected;
9077
+ if (!opts.target && detected.length === 0) {
8799
9078
  const choice = await promptForTool();
8800
9079
  preferredTools = [choice];
8801
9080
  }
@@ -8808,12 +9087,44 @@ program2.command("init").description("Create aipm.package.json in the current pr
8808
9087
  });
8809
9088
  console.log(`Created aipm.package.json (${scopeLabel(scope)}, registry: ${registry})`);
8810
9089
  });
8811
- program2.command("login").description("Open the AIPM dashboard sign-in page").option("--no-open", "Print the URL without opening a browser").action(async (opts) => {
8812
- const url = `${SITE_URL}/login`;
8813
- console.log("AIPM uses the website dashboard for account sign-in and short-lived publish tokens.");
8814
- console.log("After signing in, create or open an organization, reserve a package, and generate a token.");
8815
- if (opts.open) await openUrl(url);
8816
- else console.log(`Open: ${url}`);
9090
+ program2.command("login").description("Sign in and store a local CLI session for private installs").option("--registry <url>", "Registry API base URL").option("--site <url>", "Website base URL", SITE_URL).option("--no-open", "Print the URL without opening a browser").action(async (opts) => {
9091
+ const registry = registryFromEnvOrDefault(opts.registry);
9092
+ await runLoopbackLogin({
9093
+ registry,
9094
+ siteUrl: opts.site.replace(/\/$/, ""),
9095
+ open: opts.open
9096
+ });
9097
+ });
9098
+ program2.command("whoami").description("Show the current AIPM CLI login").option("--registry <url>", "Registry API base URL").option("--json", "Print machine-readable JSON").action(async (opts) => {
9099
+ const registry = registryFromEnvOrDefault(opts.registry);
9100
+ const token = await authTokenForRegistry(registry, { quiet: opts.json, throwOnFailure: true });
9101
+ if (!token) {
9102
+ if (opts.json) console.log(JSON.stringify({ loggedIn: false }, null, 2));
9103
+ else console.log("Not logged in. Run aipm login.");
9104
+ return;
9105
+ }
9106
+ const me = await fetchCliAuthMe(registry, token);
9107
+ if (opts.json) {
9108
+ console.log(JSON.stringify({ loggedIn: true, registry, ...me }, null, 2));
9109
+ return;
9110
+ }
9111
+ const label = me.user?.username ?? me.user?.githubLogin ?? me.user?.email ?? me.user?.userId ?? "AIPM user";
9112
+ console.log(`Logged in as ${label}`);
9113
+ console.log(`Registry: ${registry}`);
9114
+ if (me.orgs.length > 0) {
9115
+ console.log("Organizations:");
9116
+ for (const org of me.orgs) console.log(` @${org.slug} (${org.role})`);
9117
+ } else {
9118
+ console.log("Organizations: none");
9119
+ }
9120
+ });
9121
+ program2.command("logout").description("Revoke and remove the local AIPM CLI session").option("--registry <url>", "Registry API base URL").action(async (opts) => {
9122
+ const registry = registryFromEnvOrDefault(opts.registry);
9123
+ const existing = await clearStoredRegistryAuth(registry);
9124
+ if (existing?.refreshToken) {
9125
+ await logoutCliAuth(registry, existing.refreshToken).catch(() => void 0);
9126
+ }
9127
+ console.log(`Logged out of ${registry}.`);
8817
9128
  });
8818
9129
  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) => {
8819
9130
  const scope = { global: opts.global };
@@ -8822,6 +9133,7 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
8822
9133
  const project = await readProjectPackageJson(configRoot);
8823
9134
  const lock = await readLockfile(configRoot);
8824
9135
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
9136
+ const storedAuth = await getStoredRegistryAuth(registry);
8825
9137
  const data = {
8826
9138
  cliVersion: CLI_VERSION,
8827
9139
  nodeVersion: process.versions.node,
@@ -8835,6 +9147,8 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
8835
9147
  projectPackages: project ? Object.keys(project.packages) : [],
8836
9148
  hasLockfile: Boolean(lock),
8837
9149
  installedPackages: lock ? Object.keys(lock.packages) : [],
9150
+ loggedIn: Boolean(storedAuth?.refreshToken),
9151
+ authFile: authFilePath(),
8838
9152
  publishDoc: PUBLISH_DOC_URL
8839
9153
  };
8840
9154
  if (opts.json) {
@@ -8853,6 +9167,8 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
8853
9167
  console.log(`Configured packages: ${data.projectPackages.length}`);
8854
9168
  console.log(`Lockfile: ${data.hasLockfile ? "found" : "not found"}`);
8855
9169
  console.log(`Installed packages: ${data.installedPackages.length}`);
9170
+ console.log(`CLI login: ${data.loggedIn ? "found" : "not found"}`);
9171
+ console.log(`Auth file: ${data.authFile}`);
8856
9172
  console.log(`Publish guide: ${data.publishDoc}`);
8857
9173
  });
8858
9174
  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("--token <token>", "Install token for private packages").option("--ci", "Non-interactive; fail if prompt needed").action(async (pkgArg, opts) => {
@@ -8863,7 +9179,8 @@ program2.command("add <package>").description("Add and install a package @scope/
8863
9179
  let project = await readProjectPackageJson(configRoot);
8864
9180
  if (!project) throw new Error(initRequiredMessage(scope));
8865
9181
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
8866
- const version = requestedVersion ?? project.packages[name] ?? await latestVersionForPackage(registry, name);
9182
+ const token = await tokenForRead(registry, opts.token);
9183
+ const version = requestedVersion ?? project.packages[name] ?? await latestVersionForPackage(registry, name, token);
8867
9184
  if (!version) throw new Error("Specify version: aipm add @scope/pkg@1.0.0");
8868
9185
  project = {
8869
9186
  ...project,
@@ -8879,15 +9196,24 @@ program2.command("add <package>").description("Add and install a package @scope/
8879
9196
  project,
8880
9197
  explicitTarget: parseTargetFlag(opts.target),
8881
9198
  ci: opts.ci,
8882
- token: opts.token ?? process.env.AIPM_TOKEN
9199
+ token
8883
9200
  });
9201
+ try {
9202
+ await recordPackageInstall(registry, name, token);
9203
+ } catch (error) {
9204
+ if (!opts.ci && !program2.opts().quiet) {
9205
+ const message = error instanceof Error ? error.message : String(error);
9206
+ console.warn(`Warning: could not record install count: ${message}`);
9207
+ }
9208
+ }
8884
9209
  if (!opts.ci && !program2.opts().quiet) {
8885
9210
  await notifyCliUpdateIfNeeded(CLI_VERSION);
8886
9211
  }
8887
9212
  });
8888
- 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) => {
9213
+ program2.command("search [query]").description("Search public registry packages").option("--registry <url>", "Registry base URL").option("--limit <number>", "Maximum results", "20").option("--token <token>", "Install token for private package search").option("--json", "Print machine-readable JSON").action(async (query = "", opts) => {
8889
9214
  const registry = registryFromEnvOrDefault(opts.registry);
8890
- const packages = await searchPackages(registry, query, Number(opts.limit));
9215
+ const token = await tokenForRead(registry, opts.token, { quiet: opts.json });
9216
+ const packages = await searchPackages(registry, query, Number(opts.limit), token);
8891
9217
  if (opts.json) {
8892
9218
  console.log(JSON.stringify({ packages }, null, 2));
8893
9219
  return;
@@ -8912,6 +9238,7 @@ program2.command("install").description("Install all packages from aipm.package.
8912
9238
  if (!project) throw new Error(initRequiredMessage(scope));
8913
9239
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
8914
9240
  const target = parseTargetFlag(opts.target);
9241
+ const token = await tokenForRead(registry, opts.token);
8915
9242
  for (const [name, version] of Object.entries(project.packages)) {
8916
9243
  await installOnePackage({
8917
9244
  configRoot,
@@ -8922,7 +9249,7 @@ program2.command("install").description("Install all packages from aipm.package.
8922
9249
  project,
8923
9250
  explicitTarget: target,
8924
9251
  ci: opts.ci,
8925
- token: opts.token ?? process.env.AIPM_TOKEN
9252
+ token
8926
9253
  });
8927
9254
  }
8928
9255
  });
@@ -8934,14 +9261,14 @@ var publish = program2.command("publish [dir]").description("Stage, validate, an
8934
9261
  publish.help();
8935
9262
  return;
8936
9263
  }
8937
- const abs = (0, import_node_path11.resolve)(dir);
8938
- const manifestRaw = await (0, import_promises9.readFile)((0, import_node_path11.join)(abs, "aipm.manifest.json"), "utf8");
9264
+ const abs = (0, import_node_path12.resolve)(dir);
9265
+ const manifestRaw = await (0, import_promises10.readFile)((0, import_node_path12.join)(abs, "aipm.manifest.json"), "utf8");
8939
9266
  const manifest = PackageManifestSchema.parse(JSON.parse(manifestRaw));
8940
9267
  const tarball = await packDirectory(abs);
8941
9268
  const registry = registryFromEnvOrDefault(opts.registry);
8942
9269
  const result = await publishPackage(registry, manifest.name, tarball, opts.token ?? import_node_process5.env.AIPM_TOKEN);
8943
9270
  console.log(`Published ${manifest.name}@${result.version}`);
8944
- console.log(`View: ${registry.replace(/\/$/, "")}/packages/${manifest.name.replace(/^@/, "").replace("/", "/")}/${result.version}`);
9271
+ console.log(`View: ${packagePageUrl(manifest.name, result.version)}`);
8945
9272
  console.log(`Install: aipm add ${manifest.name}@${result.version} --target ${manifest.targets[0]} --ci`);
8946
9273
  printPublishGuide(
8947
9274
  `Published ${manifest.name}@${result.version} from ${abs}.`,
@@ -9061,9 +9388,8 @@ publish.command("push").description("Publish staged files").option("--registry <
9061
9388
  console.log(`Uploading ${staged.length} file${staged.length === 1 ? "" : "s"} to ${registry}.`);
9062
9389
  for (const entry of staged) console.log(` ${entry.path}`);
9063
9390
  const result = await publishPackage(registry, manifest.name, tarball, opts.token ?? import_node_process5.env.AIPM_TOKEN);
9064
- const base = registry.replace(/\/$/, "");
9065
9391
  console.log(`Published ${manifest.name}@${result.version}`);
9066
- console.log(`View: ${base}/packages/${manifest.name.replace(/^@/, "")}/${result.version}`);
9392
+ console.log(`View: ${packagePageUrl(manifest.name, result.version)}`);
9067
9393
  console.log(`Install: aipm add ${manifest.name}@${result.version} --target ${manifest.targets[0]} --ci`);
9068
9394
  printPublishGuide(
9069
9395
  `Published ${manifest.name}@${result.version} to ${registry}.`,
@@ -9099,20 +9425,21 @@ program2.command("remove <package>").alias("rm").description("Remove a package f
9099
9425
  console.log(`Removed ${name} from AIPM ${scopeLabel(scope)} files.`);
9100
9426
  console.log("Adapter-written files are not deleted yet; review your project before committing.");
9101
9427
  });
9102
- 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) => {
9428
+ 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) => {
9103
9429
  const scope = { global: opts.global };
9104
9430
  const configRoot = resolveConfigRoot(scope);
9105
9431
  const installRoot = resolveInstallRoot(scope);
9106
9432
  let project = await readProjectPackageJson(configRoot);
9107
9433
  if (!project) throw new Error(initRequiredMessage(scope));
9108
9434
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
9435
+ const token = await tokenForRead(registry, opts.token);
9109
9436
  const names = pkgArg ? [parsePackageArg(pkgArg).name] : Object.keys(project.packages);
9110
9437
  if (names.length === 0) {
9111
9438
  console.log("No packages configured.");
9112
9439
  return;
9113
9440
  }
9114
9441
  for (const name of names) {
9115
- const version = await latestVersionForPackage(registry, name);
9442
+ const version = await latestVersionForPackage(registry, name, token);
9116
9443
  project = {
9117
9444
  ...project,
9118
9445
  packages: { ...project.packages, [name]: version }
@@ -9126,7 +9453,8 @@ program2.command("update [package]").description("Update one installed package,
9126
9453
  version,
9127
9454
  project,
9128
9455
  explicitTarget: parseTargetFlag(opts.target),
9129
- ci: opts.ci
9456
+ ci: opts.ci,
9457
+ token
9130
9458
  });
9131
9459
  }
9132
9460
  });