@aipm-registry/cli 0.1.2 → 0.1.5
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 +32 -10
- package/dist/bin.cjs +135 -29
- package/dist/bin.cjs.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,6 +38,9 @@ Search the registry:
|
|
|
38
38
|
aipm search sentry
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
Search results include package version, supported targets, description,
|
|
42
|
+
publisher identity when available, license, and package size.
|
|
43
|
+
|
|
41
44
|
Update installed skills:
|
|
42
45
|
|
|
43
46
|
```bash
|
|
@@ -47,19 +50,23 @@ aipm update
|
|
|
47
50
|
This package is bundled. Installing `@aipm-registry/cli` gives you the `aipm`
|
|
48
51
|
command without needing to install any other AIPM npm packages manually.
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
Publish a public skill:
|
|
51
54
|
|
|
52
55
|
```bash
|
|
53
|
-
aipm publish init --name @team/review-helper
|
|
54
|
-
|
|
56
|
+
aipm publish init --name @team/review-helper --template code-review
|
|
57
|
+
cd review-helper
|
|
58
|
+
aipm publish explain # (optional)
|
|
55
59
|
aipm publish add .
|
|
56
|
-
aipm publish status
|
|
57
|
-
aipm publish preview
|
|
58
|
-
aipm publish validate
|
|
59
|
-
aipm publish token --package @team/review-helper
|
|
60
|
+
aipm publish status # (optional)
|
|
61
|
+
aipm publish preview # (optional)
|
|
62
|
+
aipm publish validate # (optional)
|
|
63
|
+
aipm publish token --package @team/review-helper # (optional)
|
|
60
64
|
AIPM_TOKEN=<5-minute-token> aipm publish push --yes
|
|
61
65
|
```
|
|
62
66
|
|
|
67
|
+
Create an account on `https://aipm-registry.com`, create an org, reserve the
|
|
68
|
+
package name, and generate the 5-minute token from the package dashboard.
|
|
69
|
+
|
|
63
70
|
Use `.aipmignore` to exclude local-only files from publishing. AIPM also
|
|
64
71
|
rejects common private key, env, Azure connection string, publish profile, and
|
|
65
72
|
large package mistakes before upload.
|
|
@@ -67,9 +74,24 @@ large package mistakes before upload.
|
|
|
67
74
|
Helpful publishing commands:
|
|
68
75
|
|
|
69
76
|
```bash
|
|
70
|
-
aipm publish
|
|
71
|
-
aipm publish
|
|
72
|
-
aipm
|
|
77
|
+
aipm publish init --name @team/issue-summary --template issue-summary
|
|
78
|
+
aipm publish init --name @team/release-notes --template release-notes
|
|
79
|
+
aipm publish open --docs # (optional)
|
|
80
|
+
aipm publish open --package @team/review-helper # (optional)
|
|
81
|
+
aipm doctor --publish # (optional)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Starter templates are `blank`, `code-review`, `issue-summary`, and
|
|
85
|
+
`release-notes`. They only change the starter `SKILL.md`; you can edit every
|
|
86
|
+
file before staging and publishing.
|
|
87
|
+
|
|
88
|
+
If your AI tool already generated a skill or rule file, import it into an AIPM package folder:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
aipm publish import ~/.codex/skills/review-helper --name @team/review-helper
|
|
92
|
+
cd review-helper
|
|
93
|
+
aipm publish add .
|
|
94
|
+
aipm publish preview # (optional)
|
|
73
95
|
```
|
|
74
96
|
|
|
75
97
|
The default registry API is `https://api.aipm-registry.com`. Use `--registry <url>`,
|
package/dist/bin.cjs
CHANGED
|
@@ -8360,7 +8360,7 @@ var DEFAULT_REGISTRY = "https://api.aipm-registry.com";
|
|
|
8360
8360
|
var SITE_URL = "https://aipm-registry.com";
|
|
8361
8361
|
var PUBLISH_DOC_URL = "https://aipm-registry.com/publish";
|
|
8362
8362
|
var DASHBOARD_URL = "https://aipm-registry.com/dashboard";
|
|
8363
|
-
program2.name("aipm").description("AI package manager").version("0.1.
|
|
8363
|
+
program2.name("aipm").description("AI package manager").enablePositionalOptions().version("0.1.4", "-v, --version", "output the current version").option("--verbose", "Print extra diagnostic output").option("--quiet", "Reduce non-essential output").addHelpText(
|
|
8364
8364
|
"after",
|
|
8365
8365
|
`
|
|
8366
8366
|
|
|
@@ -8371,6 +8371,7 @@ Examples:
|
|
|
8371
8371
|
$ aipm search sentry
|
|
8372
8372
|
$ aipm add @scope/name@1.0.0 --target cursor --ci
|
|
8373
8373
|
$ aipm publish init --name @org/skill
|
|
8374
|
+
$ cd skill
|
|
8374
8375
|
$ aipm publish add .
|
|
8375
8376
|
$ AIPM_TOKEN=<token> aipm publish push
|
|
8376
8377
|
`
|
|
@@ -8385,6 +8386,23 @@ function parsePackageArg(value) {
|
|
|
8385
8386
|
if (!isValidScopeName(name)) throw new Error("Invalid @scope/name");
|
|
8386
8387
|
return { name, version: match[2] };
|
|
8387
8388
|
}
|
|
8389
|
+
function skillFolderName(name) {
|
|
8390
|
+
const parsed = parsePackageArg(name);
|
|
8391
|
+
const folder = parsed.name.split("/").pop();
|
|
8392
|
+
if (!folder) throw new Error("Invalid @scope/name");
|
|
8393
|
+
return folder;
|
|
8394
|
+
}
|
|
8395
|
+
async function writeStarterFile(path2, content) {
|
|
8396
|
+
await (0, import_promises9.writeFile)(path2, content, { encoding: "utf8", flag: "wx" });
|
|
8397
|
+
}
|
|
8398
|
+
async function inferEntryFromSource(source, fallback) {
|
|
8399
|
+
const sourceInfo = await (0, import_promises9.stat)(source);
|
|
8400
|
+
if (sourceInfo.isFile()) return (0, import_node_path9.basename)(source);
|
|
8401
|
+
if (!sourceInfo.isDirectory()) return fallback;
|
|
8402
|
+
const entries = await (0, import_promises9.readdir)(source);
|
|
8403
|
+
if (entries.includes(fallback)) return fallback;
|
|
8404
|
+
return entries.find((entry) => entry.endsWith(".md")) ?? entries.find((entry) => entry.endsWith(".mdc")) ?? fallback;
|
|
8405
|
+
}
|
|
8388
8406
|
async function latestVersionForPackage(registry, name) {
|
|
8389
8407
|
const packages = await searchPackages(registry, name, 20);
|
|
8390
8408
|
const exact = packages.find((pkg) => pkg.name === name);
|
|
@@ -8396,6 +8414,19 @@ function printPublishGuide(done, next) {
|
|
|
8396
8414
|
console.log(`Next: ${next}`);
|
|
8397
8415
|
console.log(`Guide: ${PUBLISH_DOC_URL}`);
|
|
8398
8416
|
}
|
|
8417
|
+
function formatBytes(bytes) {
|
|
8418
|
+
if (bytes === void 0 || !Number.isFinite(bytes) || bytes < 0) return null;
|
|
8419
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
8420
|
+
const units = ["KB", "MB", "GB"];
|
|
8421
|
+
let value = bytes / 1024;
|
|
8422
|
+
let unit = units[0] ?? "KB";
|
|
8423
|
+
for (const nextUnit of units.slice(1)) {
|
|
8424
|
+
if (value < 1024) break;
|
|
8425
|
+
value /= 1024;
|
|
8426
|
+
unit = nextUnit;
|
|
8427
|
+
}
|
|
8428
|
+
return `${value.toFixed(value >= 10 ? 1 : 2)} ${unit}`;
|
|
8429
|
+
}
|
|
8399
8430
|
function packageDashboardUrl(name) {
|
|
8400
8431
|
if (!name) return DASHBOARD_URL;
|
|
8401
8432
|
return `${DASHBOARD_URL}/packages/${name.replace(/^@/, "")}`;
|
|
@@ -8412,14 +8443,15 @@ function printPublishFlow() {
|
|
|
8412
8443
|
console.log("AIPM publish flow");
|
|
8413
8444
|
console.log("1. Create an account and organization in the dashboard.");
|
|
8414
8445
|
console.log("2. Reserve a package name such as @team/review-helper.");
|
|
8415
|
-
console.log("3. Create
|
|
8416
|
-
console.log("4.
|
|
8417
|
-
console.log("5.
|
|
8418
|
-
console.log("6.
|
|
8419
|
-
console.log("7.
|
|
8420
|
-
console.log("8.
|
|
8421
|
-
console.log("9.
|
|
8422
|
-
console.log("10.
|
|
8446
|
+
console.log("3. Create a package folder: aipm publish init --name @team/review-helper");
|
|
8447
|
+
console.log("4. Move into it: cd review-helper");
|
|
8448
|
+
console.log("5. Edit SKILL.md and any files the skill needs.");
|
|
8449
|
+
console.log("6. Stage files: aipm publish add .");
|
|
8450
|
+
console.log("7. Review files: aipm publish status (optional)");
|
|
8451
|
+
console.log("8. Preview package: aipm publish preview (optional)");
|
|
8452
|
+
console.log("9. Validate package: aipm publish validate (optional)");
|
|
8453
|
+
console.log("10. Open the dashboard token page: aipm publish token --package @team/review-helper (optional)");
|
|
8454
|
+
console.log("11. Push: AIPM_TOKEN=<token> aipm publish push --yes");
|
|
8423
8455
|
console.log(`Guide: ${PUBLISH_DOC_URL}`);
|
|
8424
8456
|
}
|
|
8425
8457
|
async function printPublishPreview(root, json) {
|
|
@@ -8472,30 +8504,99 @@ function parseTargets(value) {
|
|
|
8472
8504
|
}
|
|
8473
8505
|
return [...new Set(targets)];
|
|
8474
8506
|
}
|
|
8507
|
+
var SKILL_TEMPLATES = {
|
|
8508
|
+
blank: (name) => `# ${name}
|
|
8509
|
+
|
|
8510
|
+
Describe what this skill does and how an AI assistant should use it.
|
|
8511
|
+
`,
|
|
8512
|
+
"code-review": (name) => `# ${name}
|
|
8513
|
+
|
|
8514
|
+
Use this skill to review code changes in this project.
|
|
8515
|
+
|
|
8516
|
+
## Goal
|
|
8517
|
+
- Identify correctness, security, reliability, and maintainability issues.
|
|
8518
|
+
- Point to specific files or code when possible.
|
|
8519
|
+
- Prioritize actionable findings over broad style feedback.
|
|
8520
|
+
|
|
8521
|
+
## Review checklist
|
|
8522
|
+
- Confirm the change matches the requested behavior.
|
|
8523
|
+
- Look for edge cases, missing validation, and risky assumptions.
|
|
8524
|
+
- Check whether tests cover the changed behavior.
|
|
8525
|
+
- Call out secrets, credentials, or private data if they appear in files.
|
|
8526
|
+
|
|
8527
|
+
## Output
|
|
8528
|
+
Return findings first, ordered by severity. If there are no findings, say that clearly and mention any remaining test gaps.
|
|
8529
|
+
`,
|
|
8530
|
+
"issue-summary": (name) => `# ${name}
|
|
8531
|
+
|
|
8532
|
+
Use this skill to summarize product, support, or error-tracking issues for triage.
|
|
8533
|
+
|
|
8534
|
+
## Goal
|
|
8535
|
+
- Turn raw issue notes into a concise engineering summary.
|
|
8536
|
+
- Separate known facts from guesses.
|
|
8537
|
+
- Identify owner, impact, urgency, and next debugging steps.
|
|
8538
|
+
|
|
8539
|
+
## Inputs to look for
|
|
8540
|
+
- Error messages, stack traces, user reports, screenshots, logs, and recent deploys.
|
|
8541
|
+
- Reproduction steps and affected environments.
|
|
8542
|
+
|
|
8543
|
+
## Output
|
|
8544
|
+
Include summary, impact, likely cause, evidence, open questions, and recommended next action.
|
|
8545
|
+
`,
|
|
8546
|
+
"release-notes": (name) => `# ${name}
|
|
8547
|
+
|
|
8548
|
+
Use this skill to draft release notes from project changes.
|
|
8549
|
+
|
|
8550
|
+
## Goal
|
|
8551
|
+
- Explain what changed in user-facing language.
|
|
8552
|
+
- Separate features, fixes, operational notes, and breaking changes.
|
|
8553
|
+
- Keep internal implementation details out unless users need them.
|
|
8554
|
+
|
|
8555
|
+
## Output
|
|
8556
|
+
Create a concise release note with sections for highlights, fixes, upgrade notes, and known issues.
|
|
8557
|
+
`
|
|
8558
|
+
};
|
|
8559
|
+
function parseSkillTemplate(value) {
|
|
8560
|
+
if (value in SKILL_TEMPLATES) return value;
|
|
8561
|
+
throw new Error(`Unknown template "${value}". Use one of: ${Object.keys(SKILL_TEMPLATES).join(", ")}`);
|
|
8562
|
+
}
|
|
8475
8563
|
async function initSkill(opts) {
|
|
8476
8564
|
if (!isValidScopeName(opts.name)) throw new Error("Invalid @scope/name");
|
|
8477
|
-
const root = (0, import_node_process3.cwd)();
|
|
8565
|
+
const root = opts.here ? (0, import_node_process3.cwd)() : (0, import_node_path9.resolve)((0, import_node_process3.cwd)(), opts.dir ?? skillFolderName(opts.name));
|
|
8566
|
+
const cdTarget = opts.here ? null : opts.dir ?? skillFolderName(opts.name);
|
|
8567
|
+
await (0, import_promises9.mkdir)(root, { recursive: true });
|
|
8568
|
+
const source = opts.from ? (0, import_node_path9.resolve)(opts.from) : null;
|
|
8569
|
+
const entry = source ? await inferEntryFromSource(source, opts.entry) : opts.entry;
|
|
8478
8570
|
const manifest = {
|
|
8479
8571
|
schemaVersion: "0.1",
|
|
8480
8572
|
name: opts.name,
|
|
8481
8573
|
version: opts.version,
|
|
8482
8574
|
type: "skill",
|
|
8483
8575
|
description: opts.description,
|
|
8484
|
-
entry
|
|
8576
|
+
entry,
|
|
8485
8577
|
targets: parseTargets(opts.targets),
|
|
8486
8578
|
license: "Apache-2.0"
|
|
8487
8579
|
};
|
|
8488
8580
|
PackageManifestSchema.parse(manifest);
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
(
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8581
|
+
if (source) {
|
|
8582
|
+
const sourceInfo = await (0, import_promises9.stat)(source);
|
|
8583
|
+
if (sourceInfo.isDirectory()) {
|
|
8584
|
+
await (0, import_promises9.cp)(source, root, { recursive: true, force: false, errorOnExist: true });
|
|
8585
|
+
} else if (sourceInfo.isFile()) {
|
|
8586
|
+
await (0, import_promises9.cp)(source, (0, import_node_path9.join)(root, (0, import_node_path9.basename)(source)), { force: false, errorOnExist: true });
|
|
8587
|
+
} else {
|
|
8588
|
+
throw new Error(`Unsupported source path: ${opts.from}`);
|
|
8589
|
+
}
|
|
8590
|
+
}
|
|
8591
|
+
await writeStarterFile((0, import_node_path9.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
8592
|
+
if (!opts.from) {
|
|
8593
|
+
const template = parseSkillTemplate(opts.template ?? "blank");
|
|
8594
|
+
await writeStarterFile(
|
|
8595
|
+
(0, import_node_path9.join)(root, entry),
|
|
8596
|
+
SKILL_TEMPLATES[template](opts.name)
|
|
8597
|
+
);
|
|
8598
|
+
}
|
|
8599
|
+
await writeStarterFile(
|
|
8499
8600
|
(0, import_node_path9.join)(root, ".aipmignore"),
|
|
8500
8601
|
[
|
|
8501
8602
|
"# Files that should never be published with this skill",
|
|
@@ -8512,14 +8613,13 @@ Describe what this skill does and how an AI assistant should use it.
|
|
|
8512
8613
|
"*.p12",
|
|
8513
8614
|
"*.publishsettings",
|
|
8514
8615
|
""
|
|
8515
|
-
].join("\n")
|
|
8516
|
-
"utf8"
|
|
8616
|
+
].join("\n")
|
|
8517
8617
|
);
|
|
8518
8618
|
await (0, import_promises9.mkdir)((0, import_node_path9.join)(root, ".aipm"), { recursive: true });
|
|
8519
|
-
console.log(`Created ${opts.name} skill
|
|
8619
|
+
console.log(`Created ${opts.name} skill folder: ${root}`);
|
|
8520
8620
|
printPublishGuide(
|
|
8521
|
-
`Created aipm.manifest.json, ${
|
|
8522
|
-
"Edit the
|
|
8621
|
+
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.`,
|
|
8622
|
+
cdTarget ? `Run cd ${cdTarget}, edit/review the files, then run aipm publish add .` : "Edit/review the files, then run aipm publish add ."
|
|
8523
8623
|
);
|
|
8524
8624
|
}
|
|
8525
8625
|
program2.command("init").description("Create aipm.package.json in the current project").option("--registry <url>", "Default registry URL").action(async (opts) => {
|
|
@@ -8557,7 +8657,7 @@ program2.command("config").description("Show resolved AIPM CLI and project confi
|
|
|
8557
8657
|
const lock = await readLockfile(root);
|
|
8558
8658
|
const registry = resolveRegistryUrl(project, opts.registry, DEFAULT_REGISTRY);
|
|
8559
8659
|
const data = {
|
|
8560
|
-
cliVersion: "0.1.
|
|
8660
|
+
cliVersion: "0.1.4",
|
|
8561
8661
|
nodeVersion: process.versions.node,
|
|
8562
8662
|
cwd: root,
|
|
8563
8663
|
registry,
|
|
@@ -8620,6 +8720,9 @@ program2.command("search [query]").description("Search public registry packages"
|
|
|
8620
8720
|
for (const pkg of packages) {
|
|
8621
8721
|
console.log(`${pkg.name}@${pkg.version} [${pkg.targets.join(", ")}]`);
|
|
8622
8722
|
if (pkg.description) console.log(` ${pkg.description}`);
|
|
8723
|
+
const publisher = pkg.publisher ? `${pkg.publisher.user.name ?? `@${pkg.publisher.user.githubLogin}`} in @${pkg.publisher.org.slug}` : "publisher unavailable";
|
|
8724
|
+
const meta = [publisher, pkg.license ? `license ${pkg.license}` : null, formatBytes(pkg.sizeBytes)].filter(Boolean).join(" | ");
|
|
8725
|
+
console.log(` ${meta}`);
|
|
8623
8726
|
}
|
|
8624
8727
|
});
|
|
8625
8728
|
program2.command("install").description("Install all packages from aipm.package.json").option("--registry <url>", "Registry base URL").option("--target <tool>", "cursor or claude").option("--ci", "Non-interactive").action(async (opts) => {
|
|
@@ -8640,7 +8743,7 @@ program2.command("install").description("Install all packages from aipm.package.
|
|
|
8640
8743
|
});
|
|
8641
8744
|
}
|
|
8642
8745
|
});
|
|
8643
|
-
program2.command("skill").description("Create and manage local skill packages").command("init").description("Create aipm.manifest.json and SKILL.md").requiredOption("--name <name>", "Package name, e.g. @org/skill").option("--version <version>", "Initial version", "1.0.0").option("--description <description>", "Skill description", "AIPM skill").option("--targets <targets>", "Comma-separated targets", "cursor").option("--entry <entry>", "Entry file", "SKILL.md").action(
|
|
8746
|
+
program2.command("skill").description("Create and manage local skill packages").command("init").description("Create aipm.manifest.json and SKILL.md").requiredOption("--name <name>", "Package name, e.g. @org/skill").option("--version <version>", "Initial version", "1.0.0").option("--description <description>", "Skill description", "AIPM skill").option("--targets <targets>", "Comma-separated targets", "cursor").option("--entry <entry>", "Entry file", "SKILL.md").option("--template <template>", "Starter SKILL.md template: blank, code-review, issue-summary, release-notes", "blank").option("--dir <dir>", "Create files in this folder").option("--here", "Create files in the current folder instead of a skill-named folder").option("--from <path>", "Copy an existing AI-tool skill file or folder into the package folder").action(
|
|
8644
8747
|
async (opts) => initSkill(opts)
|
|
8645
8748
|
);
|
|
8646
8749
|
var publish = program2.command("publish [dir]").description("Stage, validate, and publish a skill package").option("--registry <url>", "Registry base URL").option("--token <token>", "Publish token").action(async (dir, opts) => {
|
|
@@ -8662,7 +8765,10 @@ var publish = program2.command("publish [dir]").description("Stage, validate, an
|
|
|
8662
8765
|
"Share the install command or open the package page to confirm the listing."
|
|
8663
8766
|
);
|
|
8664
8767
|
});
|
|
8665
|
-
publish.command("init").description("Alias for aipm skill init").requiredOption("--name <name>", "Package name, e.g. @org/skill").option("--version <version>", "Initial version", "1.0.0").option("--description <description>", "Skill description", "AIPM skill").option("--targets <targets>", "Comma-separated targets", "cursor").option("--entry <entry>", "Entry file", "SKILL.md").action(initSkill);
|
|
8768
|
+
publish.command("init").description("Alias for aipm skill init").requiredOption("--name <name>", "Package name, e.g. @org/skill").option("--version <version>", "Initial version", "1.0.0").option("--description <description>", "Skill description", "AIPM skill").option("--targets <targets>", "Comma-separated targets", "cursor").option("--entry <entry>", "Entry file", "SKILL.md").option("--template <template>", "Starter SKILL.md template: blank, code-review, issue-summary, release-notes", "blank").option("--dir <dir>", "Create files in this folder").option("--here", "Create files in the current folder instead of a skill-named folder").option("--from <path>", "Copy an existing AI-tool skill file or folder into the package folder").action(initSkill);
|
|
8769
|
+
publish.command("import <source>").description("Create a package folder from an existing AI-tool skill file or folder").requiredOption("--name <name>", "Package name, e.g. @org/skill").option("--version <version>", "Initial version", "1.0.0").option("--description <description>", "Skill description", "AIPM skill").option("--targets <targets>", "Comma-separated targets", "cursor").option("--entry <entry>", "Entry file", "SKILL.md").option("--dir <dir>", "Create files in this folder").option("--here", "Create files in the current folder instead of a skill-named folder").action(
|
|
8770
|
+
async (source, opts) => initSkill({ ...opts, from: source })
|
|
8771
|
+
);
|
|
8666
8772
|
publish.command("add [files...]").description("Stage files for publishing").action(async (files) => {
|
|
8667
8773
|
const state = await addPublishFiles((0, import_node_process3.cwd)(), files);
|
|
8668
8774
|
console.log(`Staged ${state.files.length} file${state.files.length === 1 ? "" : "s"}.`);
|