@aipm-registry/cli 0.2.2 → 0.2.13
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 +80 -44
- package/dist/bin.cjs +58 -24
- package/dist/bin.cjs.map +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
|
+
# Search the registry at [aipm-registry.com](https://aipm-registry.com) for a skill
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
# AIPM CLI
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
**An Open source command-line tool for AI skills management and discovery [AIPM](https://aipm-registry.com)**
|
|
7
|
+
|
|
8
|
+
## What is this?
|
|
9
|
+
|
|
10
|
+
AI coding tools like Cursor and Claude can follow **skills**: small instruction files that teach the assistant how to do a job (code review, release notes, issue summaries, and more).
|
|
11
|
+
|
|
12
|
+
AIPM makes skills easy to **find, install, and share** — like npm, but for AI skills.
|
|
13
|
+
|
|
14
|
+
This package gives you the `aipm` command. With it you can:
|
|
15
|
+
|
|
16
|
+
- **Browse and install** skills from the public registry at **[aipm-registry.com](https://aipm-registry.com)**
|
|
17
|
+
- **Add skills to your project** so your whole team uses the same instructions
|
|
18
|
+
- **Publish your own skills** so others can install them
|
|
19
|
+
|
|
20
|
+
No other AIPM packages are required — everything is bundled in one install.
|
|
21
|
+
|
|
22
|
+
**Supported tools today:** Cursor and Claude (more targets at [aipm-registry.com/targets](https://aipm-registry.com/targets)).
|
|
5
23
|
|
|
6
24
|
## Install
|
|
7
25
|
|
|
@@ -9,91 +27,109 @@ Claude.
|
|
|
9
27
|
npm install -g @aipm-registry/cli
|
|
10
28
|
aipm --version
|
|
11
29
|
aipm doctor
|
|
12
|
-
aipm config
|
|
13
30
|
```
|
|
14
31
|
|
|
15
|
-
|
|
32
|
+
`aipm doctor` checks that your setup is ready. Run it if something does not work.
|
|
16
33
|
|
|
17
|
-
|
|
34
|
+
## Install skills in your project
|
|
35
|
+
|
|
36
|
+
Start in any project folder:
|
|
18
37
|
|
|
19
38
|
```bash
|
|
20
39
|
aipm init
|
|
21
40
|
```
|
|
22
41
|
|
|
23
|
-
|
|
42
|
+
*Search the registry at [aipm-registry.com](https://aipm-registry.com) for a skill:*
|
|
24
43
|
|
|
25
44
|
```bash
|
|
26
|
-
aipm
|
|
45
|
+
aipm search sentry
|
|
27
46
|
```
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
Results show version, supported tools, description, publisher, license, and size.
|
|
49
|
+
|
|
50
|
+
Install a skill:
|
|
30
51
|
|
|
31
52
|
```bash
|
|
32
|
-
aipm
|
|
53
|
+
aipm add @scope/name@1.0.0 --target cursor
|
|
33
54
|
```
|
|
34
55
|
|
|
35
|
-
|
|
56
|
+
See what is installed:
|
|
36
57
|
|
|
37
58
|
```bash
|
|
38
|
-
aipm
|
|
59
|
+
aipm list
|
|
39
60
|
```
|
|
40
61
|
|
|
41
|
-
Search results include package version, supported targets, description,
|
|
42
|
-
publisher identity when available, license, and package size.
|
|
43
|
-
|
|
44
62
|
Update installed skills:
|
|
45
63
|
|
|
46
64
|
```bash
|
|
47
65
|
aipm update
|
|
48
66
|
```
|
|
49
67
|
|
|
50
|
-
|
|
51
|
-
|
|
68
|
+
Browse more packages on the website: **[aipm-registry.com](https://aipm-registry.com)**
|
|
69
|
+
|
|
70
|
+
## Publish your skill (public / private / organization-only)
|
|
52
71
|
|
|
53
|
-
|
|
72
|
+
Share a skill with your team or the public registry.
|
|
73
|
+
|
|
74
|
+
1. Create a free account at **[aipm-registry.com](https://aipm-registry.com)**
|
|
75
|
+
2. Create an org and reserve your package name (for example `@team/review-helper`)
|
|
76
|
+
3. Scaffold a new skill package:
|
|
54
77
|
|
|
55
78
|
```bash
|
|
56
79
|
aipm publish init --name @team/review-helper --template code-review
|
|
57
80
|
cd review-helper
|
|
58
|
-
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
1. Add your files and push:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
59
86
|
aipm publish add .
|
|
60
|
-
aipm publish
|
|
61
|
-
aipm publish
|
|
62
|
-
aipm publish validate # (optional)
|
|
63
|
-
aipm publish token --package @team/review-helper # (optional)
|
|
87
|
+
aipm publish preview # optional — see what will be uploaded
|
|
88
|
+
aipm publish validate # optional — check for problems
|
|
64
89
|
AIPM_TOKEN=<5-minute-token> aipm publish push --yes
|
|
65
90
|
```
|
|
66
91
|
|
|
67
|
-
|
|
68
|
-
|
|
92
|
+
Get the short-lived publish token from your package page on **[aipm-registry.com/dashboard](https://aipm-registry.com/dashboard)**.
|
|
93
|
+
|
|
94
|
+
**Starter templates:** `blank`, `code-review`, `issue-summary`, `release-notes`. They only set the initial `SKILL.md` — edit any file before publishing.
|
|
95
|
+
|
|
96
|
+
**Already have a skill file?** Import it into an AIPM package:
|
|
69
97
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
98
|
+
```bash
|
|
99
|
+
aipm publish import ~/.codex/skills/review-helper --name @team/review-helper
|
|
100
|
+
cd review-helper
|
|
101
|
+
aipm publish add .
|
|
102
|
+
```
|
|
73
103
|
|
|
74
|
-
Helpful
|
|
104
|
+
**Helpful extras:**
|
|
75
105
|
|
|
76
106
|
```bash
|
|
77
|
-
aipm publish
|
|
78
|
-
aipm publish
|
|
79
|
-
aipm publish
|
|
80
|
-
aipm publish open --
|
|
81
|
-
aipm
|
|
107
|
+
aipm publish explain # what publishing does
|
|
108
|
+
aipm publish status # staged files
|
|
109
|
+
aipm publish token --package @team/review-helper
|
|
110
|
+
aipm publish open --docs # open publishing docs
|
|
111
|
+
aipm publish open --package @team/review-helper
|
|
112
|
+
aipm doctor --publish # check publish setup
|
|
82
113
|
```
|
|
83
114
|
|
|
84
|
-
|
|
85
|
-
`release-notes`. They only change the starter `SKILL.md`; you can edit every
|
|
86
|
-
file before staging and publishing.
|
|
115
|
+
Use `.aipmignore` to skip local-only files. Before upload, AIPM blocks common mistakes such as private keys, `.env` files, and oversized packages.
|
|
87
116
|
|
|
88
|
-
|
|
117
|
+
Full publishing guide: **[aipm-registry.com/publish](https://aipm-registry.com/publish)**
|
|
118
|
+
|
|
119
|
+
## Configuration
|
|
89
120
|
|
|
90
121
|
```bash
|
|
91
|
-
aipm
|
|
92
|
-
cd review-helper
|
|
93
|
-
aipm publish add .
|
|
94
|
-
aipm publish preview # (optional)
|
|
122
|
+
aipm config
|
|
95
123
|
```
|
|
96
124
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
125
|
+
Default registry API: `https://api.aipm-registry.com`
|
|
126
|
+
|
|
127
|
+
For a local or private registry, use `--registry <url>`, or set `AIPM_REGISTRY_URL` / `AIPM_REGISTRY`.
|
|
128
|
+
|
|
129
|
+
## Links
|
|
130
|
+
|
|
131
|
+
- **Registry & browse skills:** [aipm-registry.com](https://aipm-registry.com)
|
|
132
|
+
- **Publishing guide:** [aipm-registry.com/publish](https://aipm-registry.com/publish)
|
|
133
|
+
- **Docs & examples:** [aipm-registry.com/examples](https://aipm-registry.com/examples)
|
|
134
|
+
- **Source code:** [github.com/aipm-registry/aipm](https://github.com/aipm-registry/aipm)
|
|
135
|
+
|
package/dist/bin.cjs
CHANGED
|
@@ -4176,7 +4176,8 @@ var init_manifest = __esm({
|
|
|
4176
4176
|
description: external_exports.string().min(1),
|
|
4177
4177
|
entry: external_exports.string().min(1),
|
|
4178
4178
|
targets: external_exports.array(AiToolSchema).min(1),
|
|
4179
|
-
license: external_exports.string().optional()
|
|
4179
|
+
license: external_exports.string().optional(),
|
|
4180
|
+
usage: external_exports.string().min(1).optional()
|
|
4180
4181
|
});
|
|
4181
4182
|
}
|
|
4182
4183
|
});
|
|
@@ -8015,6 +8016,10 @@ function registryFetchError(registry, cause) {
|
|
|
8015
8016
|
}
|
|
8016
8017
|
return new Error(`Registry request failed (${registry}): ${msg}`);
|
|
8017
8018
|
}
|
|
8019
|
+
function registryAuthHeaders(token) {
|
|
8020
|
+
if (!token) return void 0;
|
|
8021
|
+
return { Authorization: `Bearer ${token}` };
|
|
8022
|
+
}
|
|
8018
8023
|
async function registryFetch(url, registry, init) {
|
|
8019
8024
|
const timeoutSignal = typeof AbortSignal !== "undefined" && "timeout" in AbortSignal ? AbortSignal.timeout(1e4) : void 0;
|
|
8020
8025
|
try {
|
|
@@ -8023,6 +8028,12 @@ async function registryFetch(url, registry, init) {
|
|
|
8023
8028
|
throw registryFetchError(registry, e);
|
|
8024
8029
|
}
|
|
8025
8030
|
}
|
|
8031
|
+
function privateInstallHint(name, status, token) {
|
|
8032
|
+
if (status !== 404 || !name.startsWith("@") || token) {
|
|
8033
|
+
return `Package not found: ${name} (${status})`;
|
|
8034
|
+
}
|
|
8035
|
+
return `Package not found: ${name} (${status}). If @org/pkg is private, set AIPM_TOKEN with an install token from the dashboard.`;
|
|
8036
|
+
}
|
|
8026
8037
|
async function assertRegistryReachable(registry) {
|
|
8027
8038
|
const base = registry.replace(/\/$/, "");
|
|
8028
8039
|
const res = await registryFetch(`${base}/health`, base);
|
|
@@ -8053,19 +8064,19 @@ async function searchPackages(registry, query, limit = 20) {
|
|
|
8053
8064
|
const data = await res.json();
|
|
8054
8065
|
return data.packages ?? [];
|
|
8055
8066
|
}
|
|
8056
|
-
async function fetchPackageMetadata(registry, name, version) {
|
|
8067
|
+
async function fetchPackageMetadata(registry, name, version, token) {
|
|
8057
8068
|
const base = registry.replace(/\/$/, "");
|
|
8058
8069
|
const url = `${base}/v1/packages/${encodePackageName(name)}/versions/${version}`;
|
|
8059
|
-
const res = await registryFetch(url, base);
|
|
8060
|
-
if (!res.ok) throw new Error(
|
|
8070
|
+
const res = await registryFetch(url, base, { headers: registryAuthHeaders(token) });
|
|
8071
|
+
if (!res.ok) throw new Error(privateInstallHint(`${name}@${version}`, res.status, token));
|
|
8061
8072
|
const data = await res.json();
|
|
8062
|
-
return { manifest: data.manifest, integrity: data.integrity };
|
|
8073
|
+
return { manifest: data.manifest, integrity: data.integrity, deprecated: data.deprecated ?? null };
|
|
8063
8074
|
}
|
|
8064
|
-
async function fetchPackageTarball(registry, name, version) {
|
|
8075
|
+
async function fetchPackageTarball(registry, name, version, token) {
|
|
8065
8076
|
const base = registry.replace(/\/$/, "");
|
|
8066
8077
|
const url = `${base}/v1/packages/${encodePackageName(name)}/versions/${version}/tarball`;
|
|
8067
|
-
const res = await registryFetch(url, base);
|
|
8068
|
-
if (!res.ok) throw new Error(
|
|
8078
|
+
const res = await registryFetch(url, base, { headers: registryAuthHeaders(token) });
|
|
8079
|
+
if (!res.ok) throw new Error(privateInstallHint(`${name}@${version}`, res.status, token));
|
|
8069
8080
|
const ab = await res.arrayBuffer();
|
|
8070
8081
|
return Buffer.from(ab);
|
|
8071
8082
|
}
|
|
@@ -8163,11 +8174,17 @@ async function installOnePackage(options) {
|
|
|
8163
8174
|
const configRoot = options.configRoot;
|
|
8164
8175
|
const installRoot = options.installRoot ?? configRoot;
|
|
8165
8176
|
await assertRegistryReachable(options.registry);
|
|
8166
|
-
const { manifest, integrity: remoteIntegrity } = await fetchPackageMetadata(
|
|
8177
|
+
const { manifest, integrity: remoteIntegrity, deprecated } = await fetchPackageMetadata(
|
|
8167
8178
|
options.registry,
|
|
8168
8179
|
options.name,
|
|
8169
|
-
options.version
|
|
8180
|
+
options.version,
|
|
8181
|
+
options.token
|
|
8170
8182
|
);
|
|
8183
|
+
if (deprecated) {
|
|
8184
|
+
console.warn(
|
|
8185
|
+
`Warning: ${options.name} is deprecated${deprecated.message ? `: ${deprecated.message}` : ""}.`
|
|
8186
|
+
);
|
|
8187
|
+
}
|
|
8171
8188
|
let explicitTarget = options.explicitTarget;
|
|
8172
8189
|
let preferredTools = options.project.preferredTools;
|
|
8173
8190
|
const { resolveInstallTools: resolveInstallTools2 } = await Promise.resolve().then(() => (init_dist4(), dist_exports));
|
|
@@ -8196,7 +8213,8 @@ async function installOnePackage(options) {
|
|
|
8196
8213
|
const tarball = await fetchPackageTarball(
|
|
8197
8214
|
options.registry,
|
|
8198
8215
|
options.name,
|
|
8199
|
-
options.version
|
|
8216
|
+
options.version,
|
|
8217
|
+
options.token
|
|
8200
8218
|
);
|
|
8201
8219
|
const skillMarkdown = await unpackTarballToBuffer(tarball, manifest.entry);
|
|
8202
8220
|
const result = await installSkillPackage({
|
|
@@ -8543,6 +8561,26 @@ async function inferEntryFromSource(source, fallback) {
|
|
|
8543
8561
|
if (entries.includes(fallback)) return fallback;
|
|
8544
8562
|
return entries.find((entry) => entry.endsWith(".md")) ?? entries.find((entry) => entry.endsWith(".mdc")) ?? fallback;
|
|
8545
8563
|
}
|
|
8564
|
+
async function copySourceIntoSkillRoot(source, root, sourceLabel) {
|
|
8565
|
+
const sourceInfo = await (0, import_promises9.stat)(source);
|
|
8566
|
+
await (0, import_promises9.mkdir)(root, { recursive: true });
|
|
8567
|
+
if (sourceInfo.isDirectory()) {
|
|
8568
|
+
const entries = await (0, import_promises9.readdir)(source);
|
|
8569
|
+
for (const entry of entries) {
|
|
8570
|
+
await (0, import_promises9.cp)((0, import_node_path11.join)(source, entry), (0, import_node_path11.join)(root, entry), {
|
|
8571
|
+
recursive: true,
|
|
8572
|
+
force: false,
|
|
8573
|
+
errorOnExist: true
|
|
8574
|
+
});
|
|
8575
|
+
}
|
|
8576
|
+
return;
|
|
8577
|
+
}
|
|
8578
|
+
if (sourceInfo.isFile()) {
|
|
8579
|
+
await (0, import_promises9.cp)(source, (0, import_node_path11.join)(root, (0, import_node_path11.basename)(source)), { force: false, errorOnExist: true });
|
|
8580
|
+
return;
|
|
8581
|
+
}
|
|
8582
|
+
throw new Error(`Unsupported source path: ${sourceLabel}`);
|
|
8583
|
+
}
|
|
8546
8584
|
async function latestVersionForPackage(registry, name) {
|
|
8547
8585
|
const packages = await searchPackages(registry, name, 20);
|
|
8548
8586
|
const exact = packages.find((pkg) => pkg.name === name);
|
|
@@ -8694,7 +8732,6 @@ async function initSkill(opts) {
|
|
|
8694
8732
|
if (!isValidScopeName(opts.name)) throw new Error("Invalid @scope/name");
|
|
8695
8733
|
const root = opts.here ? (0, import_node_process5.cwd)() : (0, import_node_path11.resolve)((0, import_node_process5.cwd)(), opts.dir ?? skillFolderName(opts.name));
|
|
8696
8734
|
const cdTarget = opts.here ? null : opts.dir ?? skillFolderName(opts.name);
|
|
8697
|
-
await (0, import_promises9.mkdir)(root, { recursive: true });
|
|
8698
8735
|
const source = opts.from ? (0, import_node_path11.resolve)(opts.from) : null;
|
|
8699
8736
|
const entry = source ? await inferEntryFromSource(source, opts.entry) : opts.entry;
|
|
8700
8737
|
const manifest = PackageManifestSchema.parse({
|
|
@@ -8708,14 +8745,9 @@ async function initSkill(opts) {
|
|
|
8708
8745
|
license: "Apache-2.0"
|
|
8709
8746
|
});
|
|
8710
8747
|
if (source) {
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
} else if (sourceInfo.isFile()) {
|
|
8715
|
-
await (0, import_promises9.cp)(source, (0, import_node_path11.join)(root, (0, import_node_path11.basename)(source)), { force: false, errorOnExist: true });
|
|
8716
|
-
} else {
|
|
8717
|
-
throw new Error(`Unsupported source path: ${opts.from}`);
|
|
8718
|
-
}
|
|
8748
|
+
await copySourceIntoSkillRoot(source, root, source);
|
|
8749
|
+
} else {
|
|
8750
|
+
await (0, import_promises9.mkdir)(root, { recursive: true });
|
|
8719
8751
|
}
|
|
8720
8752
|
await writeStarterFile((0, import_node_path11.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
8721
8753
|
if (!opts.from) {
|
|
@@ -8823,7 +8855,7 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
|
|
|
8823
8855
|
console.log(`Installed packages: ${data.installedPackages.length}`);
|
|
8824
8856
|
console.log(`Publish guide: ${data.publishDoc}`);
|
|
8825
8857
|
});
|
|
8826
|
-
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("--ci", "Non-interactive; fail if prompt needed").action(async (pkgArg, opts) => {
|
|
8858
|
+
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) => {
|
|
8827
8859
|
const { name, version: requestedVersion } = parsePackageArg(pkgArg);
|
|
8828
8860
|
const scope = { global: opts.global };
|
|
8829
8861
|
const configRoot = resolveConfigRoot(scope);
|
|
@@ -8846,7 +8878,8 @@ program2.command("add <package>").description("Add and install a package @scope/
|
|
|
8846
8878
|
version: version.replace(/^\^/, ""),
|
|
8847
8879
|
project,
|
|
8848
8880
|
explicitTarget: parseTargetFlag(opts.target),
|
|
8849
|
-
ci: opts.ci
|
|
8881
|
+
ci: opts.ci,
|
|
8882
|
+
token: opts.token ?? process.env.AIPM_TOKEN
|
|
8850
8883
|
});
|
|
8851
8884
|
if (!opts.ci && !program2.opts().quiet) {
|
|
8852
8885
|
await notifyCliUpdateIfNeeded(CLI_VERSION);
|
|
@@ -8871,7 +8904,7 @@ program2.command("search [query]").description("Search public registry packages"
|
|
|
8871
8904
|
console.log(` ${meta}`);
|
|
8872
8905
|
}
|
|
8873
8906
|
});
|
|
8874
|
-
program2.command("install").description("Install all packages from aipm.package.json").option(GLOBAL_OPTION, GLOBAL_OPTION_DESC).option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor, claude, or *").option("--ci", "Non-interactive").action(async (opts) => {
|
|
8907
|
+
program2.command("install").description("Install all packages from aipm.package.json").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 (opts) => {
|
|
8875
8908
|
const scope = { global: opts.global };
|
|
8876
8909
|
const configRoot = resolveConfigRoot(scope);
|
|
8877
8910
|
const installRoot = resolveInstallRoot(scope);
|
|
@@ -8888,7 +8921,8 @@ program2.command("install").description("Install all packages from aipm.package.
|
|
|
8888
8921
|
version: version.replace(/^\^/, ""),
|
|
8889
8922
|
project,
|
|
8890
8923
|
explicitTarget: target,
|
|
8891
|
-
ci: opts.ci
|
|
8924
|
+
ci: opts.ci,
|
|
8925
|
+
token: opts.token ?? process.env.AIPM_TOKEN
|
|
8892
8926
|
});
|
|
8893
8927
|
}
|
|
8894
8928
|
});
|