@aipm-registry/cli 0.2.12 → 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,15 +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
- license: external_exports.string().optional()
4184
+ license: external_exports.string().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()
4180
4191
  });
4181
4192
  }
4182
4193
  });
@@ -7761,9 +7772,11 @@ function useColor() {
7761
7772
  var program = new Command();
7762
7773
 
7763
7774
  // src/bin.ts
7775
+ var import_node_crypto2 = require("node:crypto");
7764
7776
  var import_node_child_process4 = require("node:child_process");
7765
- var import_promises9 = require("node:fs/promises");
7766
- 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");
7767
7780
  var import_node_process5 = require("node:process");
7768
7781
  init_dist();
7769
7782
  init_dist4();
@@ -7988,15 +8001,15 @@ async function packStagedFiles(root) {
7988
8001
  }
7989
8002
  }
7990
8003
  async function unpackTarballToBuffer(tarball, entry) {
7991
- const { mkdtemp: mkdtemp2, rm: rm3, writeFile: writeFile6 } = await import("node:fs/promises");
7992
- 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");
7993
8006
  const { tmpdir: tmpdir2 } = await import("node:os");
7994
- const tempDir = await mkdtemp2(join11(tmpdir2(), "aipm-install-"));
7995
- const tgzPath = join11(tempDir, "pkg.tgz");
8007
+ const tempDir = await mkdtemp2(join12(tmpdir2(), "aipm-install-"));
8008
+ const tgzPath = join12(tempDir, "pkg.tgz");
7996
8009
  try {
7997
- await writeFile6(tgzPath, tarball);
8010
+ await writeFile7(tgzPath, tarball);
7998
8011
  await execFileAsync("tar", ["-xzf", tgzPath, "-C", tempDir]);
7999
- return (0, import_promises5.readFile)(join11(tempDir, entry), "utf8");
8012
+ return (0, import_promises5.readFile)(join12(tempDir, entry), "utf8");
8000
8013
  } finally {
8001
8014
  await rm3(tempDir, { recursive: true, force: true });
8002
8015
  }
@@ -8031,7 +8044,7 @@ function privateInstallHint(name, status, token) {
8031
8044
  if (status !== 404 || !name.startsWith("@") || token) {
8032
8045
  return `Package not found: ${name} (${status})`;
8033
8046
  }
8034
- 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.`;
8035
8048
  }
8036
8049
  async function assertRegistryReachable(registry) {
8037
8050
  const base = registry.replace(/\/$/, "");
@@ -8053,16 +8066,63 @@ async function publishPackage(registry, name, tarball, token) {
8053
8066
  }
8054
8067
  return res.json();
8055
8068
  }
8056
- async function searchPackages(registry, query, limit = 20) {
8069
+ async function searchPackages(registry, query, limit = 20, token) {
8057
8070
  const base = registry.replace(/\/$/, "");
8058
8071
  const params = new URLSearchParams();
8059
8072
  if (query) params.set("q", query);
8060
8073
  params.set("limit", String(limit));
8061
- const res = await registryFetch(`${base}/v1/packages?${params}`, base);
8074
+ const res = await registryFetch(`${base}/v1/packages?${params}`, base, {
8075
+ headers: registryAuthHeaders(token)
8076
+ });
8062
8077
  if (!res.ok) throw new Error(`Search failed: ${res.status}`);
8063
8078
  const data = await res.json();
8064
8079
  return data.packages ?? [];
8065
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
+ }
8066
8126
  async function fetchPackageMetadata(registry, name, version, token) {
8067
8127
  const base = registry.replace(/\/$/, "");
8068
8128
  const url = `${base}/v1/packages/${encodePackageName(name)}/versions/${version}`;
@@ -8079,41 +8139,102 @@ async function fetchPackageTarball(registry, name, version, token) {
8079
8139
  const ab = await res.arrayBuffer();
8080
8140
  return Buffer.from(ab);
8081
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
+ }
8082
8203
 
8083
8204
  // src/install-one.ts
8084
8205
  init_dist4();
8085
8206
 
8086
8207
  // src/project-files.ts
8087
- var import_promises7 = require("node:fs/promises");
8088
- var import_node_path7 = require("node:path");
8208
+ var import_promises8 = require("node:fs/promises");
8209
+ var import_node_path8 = require("node:path");
8089
8210
  init_dist();
8090
8211
  var PACKAGE_JSON = "aipm.package.json";
8091
8212
  var LOCKFILE = "aipm-lock.json";
8092
8213
  async function readProjectPackageJson(projectRoot) {
8093
8214
  try {
8094
- 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");
8095
8216
  return ProjectPackageJsonSchema.parse(JSON.parse(raw));
8096
8217
  } catch {
8097
8218
  return null;
8098
8219
  }
8099
8220
  }
8100
8221
  async function writeProjectPackageJson(projectRoot, data) {
8101
- await (0, import_promises7.writeFile)(
8102
- (0, import_node_path7.join)(projectRoot, PACKAGE_JSON),
8222
+ await (0, import_promises8.writeFile)(
8223
+ (0, import_node_path8.join)(projectRoot, PACKAGE_JSON),
8103
8224
  JSON.stringify(data, null, 2) + "\n",
8104
8225
  "utf8"
8105
8226
  );
8106
8227
  }
8107
8228
  async function readLockfile(projectRoot) {
8108
8229
  try {
8109
- 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");
8110
8231
  return LockfileSchema.parse(JSON.parse(raw));
8111
8232
  } catch {
8112
8233
  return null;
8113
8234
  }
8114
8235
  }
8115
8236
  async function writeLockfile(projectRoot, data) {
8116
- 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");
8117
8238
  }
8118
8239
  function upsertLockEntry(lock, name, entry) {
8119
8240
  return {
@@ -8247,23 +8368,23 @@ async function installOnePackage(options) {
8247
8368
 
8248
8369
  // src/doctor.ts
8249
8370
  var import_node_child_process3 = require("node:child_process");
8250
- var import_promises8 = require("node:fs/promises");
8251
- var import_node_path9 = require("node:path");
8371
+ var import_promises9 = require("node:fs/promises");
8372
+ var import_node_path10 = require("node:path");
8252
8373
  var import_node_util4 = require("node:util");
8253
8374
 
8254
8375
  // src/project-root.ts
8255
- var import_node_os2 = require("node:os");
8256
- var import_node_path8 = require("node:path");
8376
+ var import_node_os3 = require("node:os");
8377
+ var import_node_path9 = require("node:path");
8257
8378
  var import_node_process3 = require("node:process");
8258
8379
  function globalConfigDir(env2 = process.env) {
8259
8380
  const fromEnv = env2.AIPM_HOME?.trim();
8260
- 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");
8261
8382
  }
8262
8383
  function resolveConfigRoot(options = {}) {
8263
8384
  return options.global ? globalConfigDir() : (0, import_node_process3.cwd)();
8264
8385
  }
8265
8386
  function resolveInstallRoot(options = {}) {
8266
- 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)();
8267
8388
  }
8268
8389
  function scopeLabel(options) {
8269
8390
  return options.global ? "global" : "project";
@@ -8288,11 +8409,11 @@ async function commandOutput(command, args) {
8288
8409
  }
8289
8410
  function npmGlobalBin(prefix) {
8290
8411
  if (!prefix) return null;
8291
- return process.platform === "win32" ? prefix : `${prefix}${import_node_path9.sep}bin`;
8412
+ return process.platform === "win32" ? prefix : `${prefix}${import_node_path10.sep}bin`;
8292
8413
  }
8293
8414
  function pathIncludes(pathDir) {
8294
8415
  if (!pathDir) return false;
8295
- return (process.env.PATH ?? "").split(import_node_path9.delimiter).includes(pathDir);
8416
+ return (process.env.PATH ?? "").split(import_node_path10.delimiter).includes(pathDir);
8296
8417
  }
8297
8418
  function shellPathHint(binDir) {
8298
8419
  if (!binDir) return "Run npm prefix -g and add its bin folder to PATH.";
@@ -8345,11 +8466,11 @@ async function runDoctor(options) {
8345
8466
  if (!options.publish) {
8346
8467
  const configLabel = options.global ? "Global config" : "Project config";
8347
8468
  try {
8348
- 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"));
8349
8470
  checks.push({
8350
8471
  name: configLabel,
8351
8472
  ok: true,
8352
- 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)}).`
8353
8474
  });
8354
8475
  } catch {
8355
8476
  checks.push({
@@ -8419,9 +8540,9 @@ async function runDoctor(options) {
8419
8540
 
8420
8541
  // src/version.ts
8421
8542
  var import_node_fs2 = require("node:fs");
8422
- var import_node_path10 = require("node:path");
8543
+ var import_node_path11 = require("node:path");
8423
8544
  function getCliVersion() {
8424
- const pkgPath = (0, import_node_path10.join)(__dirname, "..", "package.json");
8545
+ const pkgPath = (0, import_node_path11.join)(__dirname, "..", "package.json");
8425
8546
  const pkg = JSON.parse((0, import_node_fs2.readFileSync)(pkgPath, "utf8"));
8426
8547
  return pkg.version;
8427
8548
  }
@@ -8522,7 +8643,9 @@ program2.name("aipm").description("AI package manager").enablePositionalOptions(
8522
8643
  Examples:
8523
8644
  $ npm install -g @aipm-registry/cli
8524
8645
  $ aipm doctor
8525
- $ aipm init
8646
+ $ aipm login
8647
+ $ aipm whoami
8648
+ $ aipm init --target cursor
8526
8649
  $ aipm init -g
8527
8650
  $ aipm search sentry
8528
8651
  $ aipm add @scope/name@1.0.0 --target cursor --ci
@@ -8536,6 +8659,10 @@ Examples:
8536
8659
  function registryFromEnvOrDefault(flag) {
8537
8660
  return resolveRegistryUrl(null, flag, DEFAULT_REGISTRY);
8538
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
+ }
8539
8666
  function parsePackageArg(value) {
8540
8667
  const match = value.match(/^(@[^@]+)(?:@(.+))?$/);
8541
8668
  if (!match) throw new Error("Package must be @scope/name or @scope/name@version");
@@ -8550,23 +8677,23 @@ function skillFolderName(name) {
8550
8677
  return folder;
8551
8678
  }
8552
8679
  async function writeStarterFile(path2, content) {
8553
- await (0, import_promises9.writeFile)(path2, content, { encoding: "utf8", flag: "wx" });
8680
+ await (0, import_promises10.writeFile)(path2, content, { encoding: "utf8", flag: "wx" });
8554
8681
  }
8555
8682
  async function inferEntryFromSource(source, fallback) {
8556
- const sourceInfo = await (0, import_promises9.stat)(source);
8557
- 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);
8558
8685
  if (!sourceInfo.isDirectory()) return fallback;
8559
- const entries = await (0, import_promises9.readdir)(source);
8686
+ const entries = await (0, import_promises10.readdir)(source);
8560
8687
  if (entries.includes(fallback)) return fallback;
8561
8688
  return entries.find((entry) => entry.endsWith(".md")) ?? entries.find((entry) => entry.endsWith(".mdc")) ?? fallback;
8562
8689
  }
8563
8690
  async function copySourceIntoSkillRoot(source, root, sourceLabel) {
8564
- const sourceInfo = await (0, import_promises9.stat)(source);
8565
- 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 });
8566
8693
  if (sourceInfo.isDirectory()) {
8567
- const entries = await (0, import_promises9.readdir)(source);
8694
+ const entries = await (0, import_promises10.readdir)(source);
8568
8695
  for (const entry of entries) {
8569
- 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), {
8570
8697
  recursive: true,
8571
8698
  force: false,
8572
8699
  errorOnExist: true
@@ -8575,13 +8702,13 @@ async function copySourceIntoSkillRoot(source, root, sourceLabel) {
8575
8702
  return;
8576
8703
  }
8577
8704
  if (sourceInfo.isFile()) {
8578
- 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 });
8579
8706
  return;
8580
8707
  }
8581
8708
  throw new Error(`Unsupported source path: ${sourceLabel}`);
8582
8709
  }
8583
- async function latestVersionForPackage(registry, name) {
8584
- const packages = await searchPackages(registry, name, 20);
8710
+ async function latestVersionForPackage(registry, name, token) {
8711
+ const packages = await searchPackages(registry, name, 20, token);
8585
8712
  const exact = packages.find((pkg) => pkg.name === name);
8586
8713
  if (!exact) throw new Error(`Package not found in registry: ${name}`);
8587
8714
  return exact.version;
@@ -8616,6 +8743,111 @@ async function openUrl(url) {
8616
8743
  });
8617
8744
  console.log(`Open: ${url}`);
8618
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
+ }
8619
8851
  function printPublishFlow() {
8620
8852
  console.log("AIPM publish flow");
8621
8853
  console.log("1. Create an account and organization in the dashboard.");
@@ -8727,12 +8959,55 @@ function parseSkillTemplate(value) {
8727
8959
  if (value in SKILL_TEMPLATES) return value;
8728
8960
  throw new Error(`Unknown template "${value}". Use one of: ${Object.keys(SKILL_TEMPLATES).join(", ")}`);
8729
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
+ }
8730
9004
  async function initSkill(opts) {
8731
9005
  if (!isValidScopeName(opts.name)) throw new Error("Invalid @scope/name");
8732
- 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));
8733
9007
  const cdTarget = opts.here ? null : opts.dir ?? skillFolderName(opts.name);
8734
- 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;
8735
9009
  const entry = source ? await inferEntryFromSource(source, opts.entry) : opts.entry;
9010
+ const template = parseSkillTemplate(opts.template ?? "blank");
8736
9011
  const manifest = PackageManifestSchema.parse({
8737
9012
  schemaVersion: "0.1",
8738
9013
  name: opts.name,
@@ -8741,23 +9016,27 @@ async function initSkill(opts) {
8741
9016
  description: opts.description,
8742
9017
  entry,
8743
9018
  targets: parseTargetsFlag(opts.targets),
8744
- license: "Apache-2.0"
9019
+ license: "Apache-2.0",
9020
+ ...buildStarterQualityMetadata({
9021
+ name: opts.name,
9022
+ description: opts.description,
9023
+ template
9024
+ })
8745
9025
  });
8746
9026
  if (source) {
8747
9027
  await copySourceIntoSkillRoot(source, root, source);
8748
9028
  } else {
8749
- await (0, import_promises9.mkdir)(root, { recursive: true });
9029
+ await (0, import_promises10.mkdir)(root, { recursive: true });
8750
9030
  }
8751
- 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");
8752
9032
  if (!opts.from) {
8753
- const template = parseSkillTemplate(opts.template ?? "blank");
8754
9033
  await writeStarterFile(
8755
- (0, import_node_path11.join)(root, entry),
9034
+ (0, import_node_path12.join)(root, entry),
8756
9035
  SKILL_TEMPLATES[template](opts.name)
8757
9036
  );
8758
9037
  }
8759
9038
  await writeStarterFile(
8760
- (0, import_node_path11.join)(root, ".aipmignore"),
9039
+ (0, import_node_path12.join)(root, ".aipmignore"),
8761
9040
  [
8762
9041
  "# Files that should never be published with this skill",
8763
9042
  ".env*",
@@ -8775,14 +9054,14 @@ async function initSkill(opts) {
8775
9054
  ""
8776
9055
  ].join("\n")
8777
9056
  );
8778
- 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 });
8779
9058
  console.log(`Created ${opts.name} skill folder: ${root}`);
8780
9059
  printPublishGuide(
8781
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.`,
8782
9061
  cdTarget ? `Run cd ${cdTarget}, edit/review the files, then run aipm publish add .` : "Edit/review the files, then run aipm publish add ."
8783
9062
  );
8784
9063
  }
8785
- 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) => {
8786
9065
  const scope = { global: opts.global };
8787
9066
  const configRoot = resolveConfigRoot(scope);
8788
9067
  const existing = await readProjectPackageJson(configRoot);
@@ -8790,11 +9069,12 @@ program2.command("init").description("Create aipm.package.json in the current pr
8790
9069
  console.log(`aipm.package.json already exists (${scopeLabel(scope)}).`);
8791
9070
  return;
8792
9071
  }
8793
- if (scope.global) await (0, import_promises9.mkdir)(configRoot, { recursive: true });
9072
+ if (scope.global) await (0, import_promises10.mkdir)(configRoot, { recursive: true });
8794
9073
  const installRoot = resolveInstallRoot(scope);
8795
9074
  const detected = await detectToolsInProject(installRoot);
8796
- let preferredTools = detected;
8797
- if (detected.length === 0) {
9075
+ const parsedTarget = parseTargetFlag(opts.target);
9076
+ let preferredTools = parsedTarget ? [parsedTarget] : detected;
9077
+ if (!opts.target && detected.length === 0) {
8798
9078
  const choice = await promptForTool();
8799
9079
  preferredTools = [choice];
8800
9080
  }
@@ -8807,12 +9087,44 @@ program2.command("init").description("Create aipm.package.json in the current pr
8807
9087
  });
8808
9088
  console.log(`Created aipm.package.json (${scopeLabel(scope)}, registry: ${registry})`);
8809
9089
  });
8810
- program2.command("login").description("Open the AIPM dashboard sign-in page").option("--no-open", "Print the URL without opening a browser").action(async (opts) => {
8811
- const url = `${SITE_URL}/login`;
8812
- console.log("AIPM uses the website dashboard for account sign-in and short-lived publish tokens.");
8813
- console.log("After signing in, create or open an organization, reserve a package, and generate a token.");
8814
- if (opts.open) await openUrl(url);
8815
- 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}.`);
8816
9128
  });
8817
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) => {
8818
9130
  const scope = { global: opts.global };
@@ -8821,6 +9133,7 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
8821
9133
  const project = await readProjectPackageJson(configRoot);
8822
9134
  const lock = await readLockfile(configRoot);
8823
9135
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
9136
+ const storedAuth = await getStoredRegistryAuth(registry);
8824
9137
  const data = {
8825
9138
  cliVersion: CLI_VERSION,
8826
9139
  nodeVersion: process.versions.node,
@@ -8834,6 +9147,8 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
8834
9147
  projectPackages: project ? Object.keys(project.packages) : [],
8835
9148
  hasLockfile: Boolean(lock),
8836
9149
  installedPackages: lock ? Object.keys(lock.packages) : [],
9150
+ loggedIn: Boolean(storedAuth?.refreshToken),
9151
+ authFile: authFilePath(),
8837
9152
  publishDoc: PUBLISH_DOC_URL
8838
9153
  };
8839
9154
  if (opts.json) {
@@ -8852,6 +9167,8 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
8852
9167
  console.log(`Configured packages: ${data.projectPackages.length}`);
8853
9168
  console.log(`Lockfile: ${data.hasLockfile ? "found" : "not found"}`);
8854
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}`);
8855
9172
  console.log(`Publish guide: ${data.publishDoc}`);
8856
9173
  });
8857
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) => {
@@ -8862,7 +9179,8 @@ program2.command("add <package>").description("Add and install a package @scope/
8862
9179
  let project = await readProjectPackageJson(configRoot);
8863
9180
  if (!project) throw new Error(initRequiredMessage(scope));
8864
9181
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
8865
- 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);
8866
9184
  if (!version) throw new Error("Specify version: aipm add @scope/pkg@1.0.0");
8867
9185
  project = {
8868
9186
  ...project,
@@ -8878,15 +9196,24 @@ program2.command("add <package>").description("Add and install a package @scope/
8878
9196
  project,
8879
9197
  explicitTarget: parseTargetFlag(opts.target),
8880
9198
  ci: opts.ci,
8881
- token: opts.token ?? process.env.AIPM_TOKEN
9199
+ token
8882
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
+ }
8883
9209
  if (!opts.ci && !program2.opts().quiet) {
8884
9210
  await notifyCliUpdateIfNeeded(CLI_VERSION);
8885
9211
  }
8886
9212
  });
8887
- 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) => {
8888
9214
  const registry = registryFromEnvOrDefault(opts.registry);
8889
- 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);
8890
9217
  if (opts.json) {
8891
9218
  console.log(JSON.stringify({ packages }, null, 2));
8892
9219
  return;
@@ -8911,6 +9238,7 @@ program2.command("install").description("Install all packages from aipm.package.
8911
9238
  if (!project) throw new Error(initRequiredMessage(scope));
8912
9239
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
8913
9240
  const target = parseTargetFlag(opts.target);
9241
+ const token = await tokenForRead(registry, opts.token);
8914
9242
  for (const [name, version] of Object.entries(project.packages)) {
8915
9243
  await installOnePackage({
8916
9244
  configRoot,
@@ -8921,7 +9249,7 @@ program2.command("install").description("Install all packages from aipm.package.
8921
9249
  project,
8922
9250
  explicitTarget: target,
8923
9251
  ci: opts.ci,
8924
- token: opts.token ?? process.env.AIPM_TOKEN
9252
+ token
8925
9253
  });
8926
9254
  }
8927
9255
  });
@@ -8933,14 +9261,14 @@ var publish = program2.command("publish [dir]").description("Stage, validate, an
8933
9261
  publish.help();
8934
9262
  return;
8935
9263
  }
8936
- const abs = (0, import_node_path11.resolve)(dir);
8937
- 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");
8938
9266
  const manifest = PackageManifestSchema.parse(JSON.parse(manifestRaw));
8939
9267
  const tarball = await packDirectory(abs);
8940
9268
  const registry = registryFromEnvOrDefault(opts.registry);
8941
9269
  const result = await publishPackage(registry, manifest.name, tarball, opts.token ?? import_node_process5.env.AIPM_TOKEN);
8942
9270
  console.log(`Published ${manifest.name}@${result.version}`);
8943
- console.log(`View: ${registry.replace(/\/$/, "")}/packages/${manifest.name.replace(/^@/, "").replace("/", "/")}/${result.version}`);
9271
+ console.log(`View: ${packagePageUrl(manifest.name, result.version)}`);
8944
9272
  console.log(`Install: aipm add ${manifest.name}@${result.version} --target ${manifest.targets[0]} --ci`);
8945
9273
  printPublishGuide(
8946
9274
  `Published ${manifest.name}@${result.version} from ${abs}.`,
@@ -9060,9 +9388,8 @@ publish.command("push").description("Publish staged files").option("--registry <
9060
9388
  console.log(`Uploading ${staged.length} file${staged.length === 1 ? "" : "s"} to ${registry}.`);
9061
9389
  for (const entry of staged) console.log(` ${entry.path}`);
9062
9390
  const result = await publishPackage(registry, manifest.name, tarball, opts.token ?? import_node_process5.env.AIPM_TOKEN);
9063
- const base = registry.replace(/\/$/, "");
9064
9391
  console.log(`Published ${manifest.name}@${result.version}`);
9065
- console.log(`View: ${base}/packages/${manifest.name.replace(/^@/, "")}/${result.version}`);
9392
+ console.log(`View: ${packagePageUrl(manifest.name, result.version)}`);
9066
9393
  console.log(`Install: aipm add ${manifest.name}@${result.version} --target ${manifest.targets[0]} --ci`);
9067
9394
  printPublishGuide(
9068
9395
  `Published ${manifest.name}@${result.version} to ${registry}.`,
@@ -9098,20 +9425,21 @@ program2.command("remove <package>").alias("rm").description("Remove a package f
9098
9425
  console.log(`Removed ${name} from AIPM ${scopeLabel(scope)} files.`);
9099
9426
  console.log("Adapter-written files are not deleted yet; review your project before committing.");
9100
9427
  });
9101
- 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) => {
9102
9429
  const scope = { global: opts.global };
9103
9430
  const configRoot = resolveConfigRoot(scope);
9104
9431
  const installRoot = resolveInstallRoot(scope);
9105
9432
  let project = await readProjectPackageJson(configRoot);
9106
9433
  if (!project) throw new Error(initRequiredMessage(scope));
9107
9434
  const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
9435
+ const token = await tokenForRead(registry, opts.token);
9108
9436
  const names = pkgArg ? [parsePackageArg(pkgArg).name] : Object.keys(project.packages);
9109
9437
  if (names.length === 0) {
9110
9438
  console.log("No packages configured.");
9111
9439
  return;
9112
9440
  }
9113
9441
  for (const name of names) {
9114
- const version = await latestVersionForPackage(registry, name);
9442
+ const version = await latestVersionForPackage(registry, name, token);
9115
9443
  project = {
9116
9444
  ...project,
9117
9445
  packages: { ...project.packages, [name]: version }
@@ -9125,7 +9453,8 @@ program2.command("update [package]").description("Update one installed package,
9125
9453
  version,
9126
9454
  project,
9127
9455
  explicitTarget: parseTargetFlag(opts.target),
9128
- ci: opts.ci
9456
+ ci: opts.ci,
9457
+ token
9129
9458
  });
9130
9459
  }
9131
9460
  });