@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 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
- Publishing is currently approval-only:
53
+ Publish a public skill:
51
54
 
52
55
  ```bash
53
- aipm publish init --name @team/review-helper
54
- aipm publish explain
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 open --docs
71
- aipm publish open --package @team/review-helper
72
- aipm doctor --publish
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.2", "-v, --version", "output the current version").option("--verbose", "Print extra diagnostic output").option("--quiet", "Reduce non-essential output").addHelpText(
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 local skill files: aipm publish init --name @team/review-helper");
8416
- console.log("4. Edit SKILL.md and any files the skill needs.");
8417
- console.log("5. Stage files: aipm publish add .");
8418
- console.log("6. Review files: aipm publish status");
8419
- console.log("7. Preview package: aipm publish preview");
8420
- console.log("8. Validate package: aipm publish validate");
8421
- console.log("9. Generate a 5-minute token from the dashboard.");
8422
- console.log("10. Push: AIPM_TOKEN=<token> aipm publish push --yes");
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: opts.entry,
8576
+ entry,
8485
8577
  targets: parseTargets(opts.targets),
8486
8578
  license: "Apache-2.0"
8487
8579
  };
8488
8580
  PackageManifestSchema.parse(manifest);
8489
- await (0, import_promises9.writeFile)((0, import_node_path9.join)(root, "aipm.manifest.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
8490
- await (0, import_promises9.writeFile)(
8491
- (0, import_node_path9.join)(root, opts.entry),
8492
- `# ${opts.name}
8493
-
8494
- Describe what this skill does and how an AI assistant should use it.
8495
- `,
8496
- "utf8"
8497
- );
8498
- await (0, import_promises9.writeFile)(
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 files.`);
8619
+ console.log(`Created ${opts.name} skill folder: ${root}`);
8520
8620
  printPublishGuide(
8521
- `Created aipm.manifest.json, ${opts.entry}, .aipmignore, and the local publish state folder.`,
8522
- "Edit the skill files, then run aipm publish add ."
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.2",
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"}.`);