@aipm-registry/cli 0.2.13 → 0.3.1

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