@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/README.md +11 -2
- package/dist/bin.cjs +406 -77
- package/dist/bin.cjs.map +4 -4
- package/package.json +3 -3
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
|
|
7767
|
-
var
|
|
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:
|
|
7993
|
-
const { join:
|
|
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(
|
|
7996
|
-
const tgzPath =
|
|
8007
|
+
const tempDir = await mkdtemp2(join12(tmpdir2(), "aipm-install-"));
|
|
8008
|
+
const tgzPath = join12(tempDir, "pkg.tgz");
|
|
7997
8009
|
try {
|
|
7998
|
-
await
|
|
8010
|
+
await writeFile7(tgzPath, tarball);
|
|
7999
8011
|
await execFileAsync("tar", ["-xzf", tgzPath, "-C", tempDir]);
|
|
8000
|
-
return (0, import_promises5.readFile)(
|
|
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,
|
|
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
|
-
|
|
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
|
|
8089
|
-
var
|
|
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,
|
|
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,
|
|
8103
|
-
(0,
|
|
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,
|
|
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,
|
|
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
|
|
8252
|
-
var
|
|
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
|
|
8257
|
-
var
|
|
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,
|
|
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,
|
|
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}${
|
|
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(
|
|
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,
|
|
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,
|
|
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
|
|
8544
|
+
var import_node_path11 = require("node:path");
|
|
8424
8545
|
function getCliVersion() {
|
|
8425
|
-
const pkgPath = (0,
|
|
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
|
|
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,
|
|
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,
|
|
8558
|
-
if (sourceInfo.isFile()) return (0,
|
|
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,
|
|
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,
|
|
8566
|
-
await (0,
|
|
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,
|
|
8695
|
+
const entries = await (0, import_promises10.readdir)(source);
|
|
8569
8696
|
for (const entry of entries) {
|
|
8570
|
-
await (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
9030
|
+
await (0, import_promises10.mkdir)(root, { recursive: true });
|
|
8751
9031
|
}
|
|
8752
|
-
await writeStarterFile((0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
8798
|
-
|
|
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("
|
|
8812
|
-
const
|
|
8813
|
-
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
8938
|
-
const manifestRaw = await (0,
|
|
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: ${
|
|
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: ${
|
|
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
|
});
|