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