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