@ccpluginizer/ccpluginizer 0.2.2 → 0.4.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 CHANGED
@@ -2,39 +2,46 @@
2
2
 
3
3
  > CLI for pluginizing non-plugin Claude Code repos.
4
4
 
5
- Generate, validate, and submit [ccpluginizer marketplace](https://github.com/lifebugz/ccpluginizer) entries from any GitHub repo containing Claude Code-compatible content (skills, agents, commands, hooks, MCP servers).
5
+ Generate and validate [ccpluginizer marketplace](https://github.com/lifebugz/ccpluginizer) entries from any GitHub repo with Claude Code-compatible content (skills, agents, commands, hooks, MCP servers).
6
6
 
7
7
  ## Install
8
8
 
9
+ Works with either runtime. Pick whichever you have.
10
+
11
+ With Bun:
12
+
9
13
  ```bash
10
14
  bun add -g @ccpluginizer/ccpluginizer
15
+ # or one-shot:
16
+ bunx @ccpluginizer/ccpluginizer scan <owner/repo>
11
17
  ```
12
18
 
13
- Or run one-shot without installing:
19
+ With npm or Node:
14
20
 
15
21
  ```bash
16
- bunx @ccpluginizer/ccpluginizer scan <owner/repo>
22
+ npm install -g @ccpluginizer/ccpluginizer
23
+ # or one-shot:
24
+ npx @ccpluginizer/ccpluginizer scan <owner/repo>
17
25
  ```
18
26
 
27
+ At runtime the CLI prefers Bun when it's around (it starts faster), and falls back to Node otherwise. You don't need to configure anything.
28
+
19
29
  ## Usage
20
30
 
21
31
  ```bash
22
32
  ccpluginizer scan <owner/repo> # Generate a marketplace entry
23
- ccpluginizer submit <owner/repo> # Open a PR to add the repo to the catalog
24
33
  ccpluginizer validate <entry.json> # Validate an entry against the schema
25
34
  ```
26
35
 
36
+ To add a repo to the catalog, run `scan`, commit the JSON to `entries/<name>.json` in the catalog repo, and open a PR. See the catalog's [CONTRIBUTING.md](https://github.com/lifebugz/ccpluginizer/blob/main/CONTRIBUTING.md).
37
+
27
38
  `<owner/repo>` accepts either GitHub shorthand (`elysiajs/skills`) or a full URL (`https://github.com/elysiajs/skills`).
28
39
 
29
40
  ## How it works
30
41
 
31
- ccpluginizer detects skills, agents, commands, hooks, and MCP servers in the source repo, then synthesizes a marketplace entry that uses Claude Code's `strict: false` mode to point at the source. Source code is never copied or redistributed.
32
-
33
- Three detection layers:
42
+ ccpluginizer detects skills, agents, commands, hooks, and MCP servers in the source repo, then synthesizes a marketplace entry that uses Claude Code's `strict: false` mode to point at the source. The catalog never holds a copy of the source itself.
34
43
 
35
- 1. **Convention paths** `.claude/skills/`, `.claude/agents/`, `.claude/commands/`, etc.
36
- 2. **Manifest metadata** — `.claude-plugin/manifest.json` or `.ccpluginizer.json` marker file.
37
- 3. **Heuristic fallback** — looks for `SKILL.md` files with YAML frontmatter, `commands/*.md`, etc.
44
+ Detection runs in three passes. The first looks at convention paths like `.claude/skills/`, `.claude/agents/`, and `.claude/commands/`. The second reads `.claude-plugin/manifest.json` or a `.ccpluginizer.json` marker file if the repo has one. The third is a heuristic fallback for repos that follow neither convention. It scans for `SKILL.md` files with YAML frontmatter, `commands/*.md`, and similar patterns.
38
45
 
39
46
  ## Repository
40
47
 
package/bin/ccpluginizer CHANGED
@@ -8,4 +8,10 @@ while [ -L "$script" ]; do
8
8
  *) script="$(dirname "$script")/$link" ;;
9
9
  esac
10
10
  done
11
- exec bun "$(cd "$(dirname "$script")" && pwd)/../dist/index.js" "$@"
11
+ dist="$(cd "$(dirname "$script")" && pwd)/../dist/index.js"
12
+ # Prefer bun when available (bunx users); fall back to node (npx/npm users).
13
+ # The dist bundle is built with --target node so both runtimes work.
14
+ if command -v bun >/dev/null 2>&1; then
15
+ exec bun "$dist" "$@"
16
+ fi
17
+ exec node "$dist" "$@"
package/dist/index.js CHANGED
@@ -589,13 +589,324 @@ class R {
589
589
  }
590
590
  }
591
591
 
592
+ // ../../node_modules/.bun/@crustjs+core@0.0.16+7524df1edfed9f02/node_modules/@crustjs/core/dist/index.js
593
+ init_chunk_vt64gs69();
594
+ function T2(j) {
595
+ return { meta: { name: j }, localFlags: {}, effectiveFlags: {}, args: undefined, subCommands: {}, plugins: [], preRun: undefined, run: undefined, postRun: undefined };
596
+ }
597
+ function z2(j, q2) {
598
+ let J = {};
599
+ for (let [Q, $] of Object.entries(j))
600
+ if ($.inherit === true)
601
+ J[Q] = $;
602
+ for (let [Q, $] of Object.entries(q2))
603
+ J[Q] = $;
604
+ return J;
605
+ }
606
+ function D2(j, q2) {
607
+ let J = [j.meta.name], Q = j, $ = q2;
608
+ while ($.length > 0) {
609
+ let K = Q.subCommands;
610
+ if (!K || Object.keys(K).length === 0)
611
+ break;
612
+ let Z = $[0];
613
+ if (!Z || Z.startsWith("-"))
614
+ break;
615
+ if (Z in K && K[Z]) {
616
+ Q = K[Z], J.push(Z), $ = $.slice(1);
617
+ continue;
618
+ }
619
+ if (Q.run)
620
+ break;
621
+ let H = Object.keys(K);
622
+ throw new W("COMMAND_NOT_FOUND", `Unknown command "${Z}".`, { input: Z, available: H, commandPath: [...J], parentCommand: Q });
623
+ }
624
+ return { command: Q, argv: $, commandPath: J };
625
+ }
626
+ function N2(j) {
627
+ for (let [q2, J] of Object.entries(j)) {
628
+ if (q2.startsWith("no-")) {
629
+ let Q = q2.slice(3);
630
+ throw new W("DEFINITION", `Flag "--${q2}" must not use "no-" prefix; define "${Q}" and negate with "--no-${Q}"`);
631
+ }
632
+ if (J.short?.startsWith("no-"))
633
+ throw new W("DEFINITION", `Short alias "-${J.short}" on "--${q2}" must not use "no-" prefix (reserved for negation)`);
634
+ if (J.aliases) {
635
+ for (let Q of J.aliases)
636
+ if (Q.startsWith("no-"))
637
+ throw new W("DEFINITION", `Alias "--${Q}" on "--${q2}" must not use "no-" prefix (reserved for negation)`);
638
+ }
639
+ }
640
+ }
641
+ var w2 = "CRUST_INTERNAL_VALIDATE_ONLY";
642
+ var P3 = 130;
643
+ var v2 = "__CRUST_VALIDATE_RESULT__";
644
+ function x2() {
645
+ let j = new Map;
646
+ return { get(q2) {
647
+ return j.get(q2);
648
+ }, has(q2) {
649
+ return j.has(q2);
650
+ }, set(q2, J) {
651
+ j.set(q2, J);
652
+ }, delete(q2) {
653
+ return j.delete(q2);
654
+ } };
655
+ }
656
+ function B2(j) {
657
+ if (!(j instanceof Error))
658
+ return false;
659
+ return j.name === "CancelledError";
660
+ }
661
+ function b3(j, q2) {
662
+ j.effectiveFlags = z2(q2, j.localFlags);
663
+ for (let J of Object.values(j.subCommands))
664
+ b3(J, j.effectiveFlags);
665
+ }
666
+ function y2(j) {
667
+ return { addFlag(q2, J, Q) {
668
+ if (J in q2.effectiveFlags)
669
+ j?.push(`Plugin flag "--${J}" on "${q2.meta.name}" overrides existing flag`);
670
+ q2.effectiveFlags[J] = Q;
671
+ }, addSubCommand(q2, J, Q) {
672
+ if (!J.trim())
673
+ throw new W("DEFINITION", "addSubCommand: name must be a non-empty string");
674
+ if (q2.subCommands[J]) {
675
+ j?.push(`Plugin subcommand "${J}" on "${q2.meta.name}" skipped (already exists)`);
676
+ return;
677
+ }
678
+ b3(Q, q2.effectiveFlags), q2.subCommands[J] = Q;
679
+ } };
680
+ }
681
+ async function A3(j, q2, J) {
682
+ for (let Q of j) {
683
+ if (!Q.setup)
684
+ continue;
685
+ await Q.setup(q2, J);
686
+ }
687
+ }
688
+ async function F2(j, q2, J) {
689
+ let Q = j.map((Z) => Z.middleware).filter((Z) => Boolean(Z)), $ = -1, K = async (Z) => {
690
+ if (Z <= $)
691
+ throw new W("DEFINITION", "Plugin middleware called next() multiple times");
692
+ if ($ = Z, Z === Q.length) {
693
+ await J();
694
+ return;
695
+ }
696
+ let H = Q[Z];
697
+ if (!H)
698
+ throw new W("DEFINITION", "Plugin middleware stack is invalid");
699
+ await H(q2, () => K(Z + 1));
700
+ };
701
+ await K(0);
702
+ }
703
+ function I3(j) {
704
+ let q2 = [...j.plugins];
705
+ for (let J of Object.values(j.subCommands))
706
+ q2.push(...I3(J));
707
+ return q2;
708
+ }
709
+ function k2(j) {
710
+ let q2 = {};
711
+ for (let [J, Q] of Object.entries(j))
712
+ q2[J] = { ...Q, aliases: Q.aliases ? [...Q.aliases] : undefined };
713
+ return q2;
714
+ }
715
+ function h3(j) {
716
+ let q2 = {};
717
+ for (let [J, Q] of Object.entries(j.subCommands))
718
+ q2[J] = h3(Q);
719
+ return { meta: { ...j.meta }, localFlags: k2(j.localFlags), effectiveFlags: k2(j.effectiveFlags), args: j.args ? j.args.map((J) => ({ ...J })) : undefined, subCommands: q2, plugins: [...j.plugins], preRun: j.preRun, run: j.run, postRun: j.postRun };
720
+ }
721
+ function _4(j) {
722
+ if (Object.freeze(j), Object.freeze(j.localFlags), Object.freeze(j.effectiveFlags), Object.freeze(j.meta), Object.freeze(j.plugins), j.args)
723
+ Object.freeze(j.args);
724
+ for (let q2 of Object.values(j.subCommands))
725
+ _4(q2);
726
+ Object.freeze(j.subCommands);
727
+ }
728
+
729
+ class R2 {
730
+ _node;
731
+ _inheritedFlags;
732
+ constructor(j) {
733
+ if (!j.trim())
734
+ throw new W("DEFINITION", "meta.name must be a non-empty string");
735
+ this._node = T2(j), this._inheritedFlags = {};
736
+ }
737
+ static _createChild(j, q2) {
738
+ let J = new R2(j);
739
+ return J._inheritedFlags = q2, J;
740
+ }
741
+ _clone(j) {
742
+ let q2 = Object.create(Object.getPrototypeOf(this)), J = { ...this._node, localFlags: { ...this._node.localFlags }, effectiveFlags: { ...this._node.effectiveFlags }, subCommands: { ...this._node.subCommands }, plugins: [...this._node.plugins], meta: { ...this._node.meta }, args: this._node.args ? [...this._node.args] : undefined, ...j };
743
+ return q2._node = J, q2._inheritedFlags = this._inheritedFlags, q2;
744
+ }
745
+ meta(j) {
746
+ return this._clone({ meta: { ...this._node.meta, ...j } });
747
+ }
748
+ flags(j) {
749
+ N2(j);
750
+ let q2 = {};
751
+ for (let [J, Q] of Object.entries(j))
752
+ q2[J] = { ...Q };
753
+ return this._clone({ localFlags: q2, effectiveFlags: z2(this._inheritedFlags, q2) });
754
+ }
755
+ args(j) {
756
+ let q2 = j.map((J) => ({ ...J }));
757
+ return this._clone({ args: q2 });
758
+ }
759
+ run(j) {
760
+ return this._clone({ run: j });
761
+ }
762
+ preRun(j) {
763
+ return this._clone({ preRun: j });
764
+ }
765
+ postRun(j) {
766
+ return this._clone({ postRun: j });
767
+ }
768
+ use(j) {
769
+ return this._clone({ plugins: [...this._node.plugins, j] });
770
+ }
771
+ sub(j) {
772
+ if (!j.trim())
773
+ throw new W("DEFINITION", "Subcommand name must be a non-empty string");
774
+ let q2 = z2(this._inheritedFlags, this._node.localFlags);
775
+ return R2._createChild(j, q2);
776
+ }
777
+ command(j, q2) {
778
+ if (typeof j === "string") {
779
+ let K = j;
780
+ if (!q2)
781
+ throw new W("DEFINITION", "command(name, cb) requires a callback");
782
+ if (!K.trim())
783
+ throw new W("DEFINITION", "Subcommand name must be a non-empty string");
784
+ if (this._node.subCommands[K])
785
+ throw new W("DEFINITION", `Subcommand "${K}" is already registered`);
786
+ let Z = z2(this._inheritedFlags, this._node.localFlags), H = R2._createChild(K, Z), X2 = q2(H), W2 = { ...X2._node, effectiveFlags: z2(X2._inheritedFlags, X2._node.localFlags) };
787
+ return this._clone({ subCommands: { ...this._node.subCommands, [K]: W2 } });
788
+ }
789
+ let J = j, Q = J._node.meta.name;
790
+ if (!Q.trim())
791
+ throw new W("DEFINITION", "Subcommand name must be a non-empty string");
792
+ if (this._node.subCommands[Q])
793
+ throw new W("DEFINITION", `Subcommand "${Q}" is already registered`);
794
+ let $ = { ...J._node, effectiveFlags: z2(J._inheritedFlags, J._node.localFlags) };
795
+ return this._clone({ subCommands: { ...this._node.subCommands, [Q]: $ } });
796
+ }
797
+ async prepareCommandTree(j) {
798
+ let q2 = j?.argv ?? [], J = h3(this._node), Q = I3(J), $ = [], K = x2(), Z = { argv: [...q2], rootCommand: J, state: K }, H = y2($);
799
+ try {
800
+ await A3(Q, Z, H);
801
+ } catch (W2) {
802
+ if (B2(W2))
803
+ throw W2;
804
+ if (W2 instanceof W)
805
+ throw W2;
806
+ if (W2 instanceof Error)
807
+ throw W2;
808
+ throw new W("DEFINITION", String(W2));
809
+ }
810
+ _4(J);
811
+ let { validateCommandTree: X2 } = await Promise.resolve().then(() => (init_chunk_5apf3vnv(), exports_chunk_5apf3vnv));
812
+ return X2(J), { root: J, warnings: $ };
813
+ }
814
+ async execute(j) {
815
+ let q2 = j?.argv ?? process.argv.slice(2), J = this._node, Q = I3(J), $ = [], K = x2(), Z = { argv: [...q2], rootCommand: J, state: K }, H = y2($);
816
+ try {
817
+ await A3(Q, Z, H);
818
+ } catch (W2) {
819
+ if (B2(W2)) {
820
+ process.exitCode = P3;
821
+ return;
822
+ }
823
+ if (W2 instanceof W) {
824
+ console.error(`Error: ${W2.message}`), process.exitCode = 1;
825
+ return;
826
+ }
827
+ let U2 = W2 instanceof Error ? W2.message : String(W2);
828
+ console.error(`Error: ${U2}`), process.exitCode = 1;
829
+ return;
830
+ }
831
+ if (_4(J), process.env[w2] === "1") {
832
+ let W2 = (async () => {
833
+ try {
834
+ let { validateCommandTree: U2 } = await Promise.resolve().then(() => (init_chunk_5apf3vnv(), exports_chunk_5apf3vnv));
835
+ U2(J);
836
+ for (let Y of $)
837
+ console.warn(`Warning: ${Y}`);
838
+ return { ok: true };
839
+ } catch (U2) {
840
+ let Y = U2 instanceof Error ? U2.message : String(U2);
841
+ return console.error(Y), process.exitCode = 1, { ok: false, error: U2 };
842
+ }
843
+ })();
844
+ return globalThis[v2] = W2, await W2, process.exit(process.exitCode ?? 0);
845
+ }
846
+ for (let W2 of $)
847
+ console.warn(`Warning: ${W2}`);
848
+ let X2 = { argv: [...q2], rootCommand: J, state: K, route: null, input: null };
849
+ try {
850
+ let W2, U2;
851
+ try {
852
+ let Y = D2(J, [...q2]);
853
+ X2.route = Y, W2 = Y.command, U2 = b(W2, Y.argv), X2.input = U2;
854
+ } catch (Y) {
855
+ await F2(Q, X2, async () => {
856
+ throw Y;
857
+ });
858
+ return;
859
+ }
860
+ await F2(Q, X2, async () => {
861
+ if (E(W2, U2), !W2.run)
862
+ return;
863
+ let Y = { args: U2.args, flags: U2.flags, rawArgs: U2.rawArgs, command: W2 }, V;
864
+ try {
865
+ if (W2.preRun)
866
+ await W2.preRun(Y);
867
+ await W2.run(Y);
868
+ } catch (M3) {
869
+ V = M3;
870
+ }
871
+ if (W2.postRun)
872
+ try {
873
+ await W2.postRun(Y);
874
+ } catch (M3) {
875
+ if (!V)
876
+ V = M3;
877
+ else
878
+ console.error(`Error in postRun: ${M3 instanceof Error ? M3.message : String(M3)}`);
879
+ }
880
+ if (V)
881
+ throw V;
882
+ });
883
+ } catch (W2) {
884
+ if (B2(W2)) {
885
+ process.exitCode = P3;
886
+ return;
887
+ }
888
+ if (W2 instanceof W) {
889
+ console.error(`Error: ${W2.message}`), process.exitCode = 1;
890
+ return;
891
+ }
892
+ if (W2 instanceof Error) {
893
+ let U2 = new W("EXECUTION", W2.message).withCause(W2);
894
+ console.error(`Error: ${U2.message}`), process.exitCode = 1;
895
+ return;
896
+ }
897
+ console.error(`Error: ${String(W2)}`), process.exitCode = 1;
898
+ }
899
+ }
900
+ }
901
+
592
902
  // src/commands/scan.ts
593
- import { writeFileSync } from "fs";
903
+ import { writeFileSync } from "node:fs";
594
904
 
595
905
  // src/sources/github.ts
596
- import { mkdtempSync } from "fs";
597
- import { tmpdir } from "os";
598
- import { join } from "path";
906
+ import { spawnSync } from "node:child_process";
907
+ import { mkdtempSync } from "node:fs";
908
+ import { tmpdir } from "node:os";
909
+ import { join } from "node:path";
599
910
 
600
911
  // src/errors.ts
601
912
  class CcpluginizerError extends Error {
@@ -639,19 +950,17 @@ class SourceCloneError extends CcpluginizerError {
639
950
  }
640
951
 
641
952
  // src/sources/github.ts
642
- async function resolveGithub(repo) {
953
+ function resolveGithub(repo) {
643
954
  const dest = mkdtempSync(join(tmpdir(), `ccp-${repo.replace("/", "-")}-`));
644
955
  const url = `https://github.com/${repo}.git`;
645
- const proc = Bun.spawn(["git", "clone", "--depth=1", url, dest], {
646
- stdout: "pipe",
647
- stderr: "pipe"
956
+ const result = spawnSync("git", ["clone", "--depth=1", url, dest], {
957
+ stdio: ["ignore", "pipe", "pipe"],
958
+ encoding: "utf8"
648
959
  });
649
- const exitCode = await proc.exited;
650
- if (exitCode !== 0) {
651
- const stderr = await new Response(proc.stderr).text();
652
- throw new SourceCloneError(repo, stderr);
960
+ if (result.status !== 0) {
961
+ throw new SourceCloneError(repo, result.stderr);
653
962
  }
654
- return dest;
963
+ return Promise.resolve(dest);
655
964
  }
656
965
 
657
966
  // src/sources/index.ts
@@ -690,8 +999,8 @@ async function resolveSource(input) {
690
999
  }
691
1000
 
692
1001
  // src/detector/marketplaceGuard.ts
693
- import { existsSync } from "fs";
694
- import { join as join2 } from "path";
1002
+ import { existsSync } from "node:fs";
1003
+ import { join as join2 } from "node:path";
695
1004
  function checkMarketplaceGuard(repoRoot) {
696
1005
  const marketplaceFile = join2(repoRoot, ".claude-plugin", "marketplace.json");
697
1006
  if (existsSync(marketplaceFile)) {
@@ -700,8 +1009,8 @@ function checkMarketplaceGuard(repoRoot) {
700
1009
  }
701
1010
 
702
1011
  // src/detector/markerFile.ts
703
- import { existsSync as existsSync2, readFileSync } from "fs";
704
- import { join as join3 } from "path";
1012
+ import { existsSync as existsSync2, readFileSync } from "node:fs";
1013
+ import { join as join3 } from "node:path";
705
1014
 
706
1015
  // ../../node_modules/.bun/valibot@1.3.1+7524df1edfed9f02/node_modules/valibot/dist/index.mjs
707
1016
  var store$4;
@@ -1413,8 +1722,8 @@ function detectMarkerFile(repoRoot) {
1413
1722
  }
1414
1723
 
1415
1724
  // src/detector/conventions.ts
1416
- import { existsSync as existsSync3, readdirSync, statSync } from "fs";
1417
- import { join as join4 } from "path";
1725
+ import { existsSync as existsSync3, readdirSync, statSync } from "node:fs";
1726
+ import { join as join4 } from "node:path";
1418
1727
  var FOLDER_KINDS = [
1419
1728
  { folder: "skills", kind: "skills" },
1420
1729
  { folder: "agents", kind: "agents" },
@@ -1481,8 +1790,8 @@ function mergeByKind(findings) {
1481
1790
  }
1482
1791
 
1483
1792
  // src/detector/nonStandardManifest.ts
1484
- import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
1485
- import { join as join5 } from "path";
1793
+ import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
1794
+ import { join as join5 } from "node:path";
1486
1795
 
1487
1796
  // src/schemas/nonStandardManifest.ts
1488
1797
  var NonStandardManifestSchema = object({
@@ -1535,8 +1844,8 @@ function detectNonStandardManifest(repoRoot) {
1535
1844
  }
1536
1845
 
1537
1846
  // src/detector/contentSniff.ts
1538
- import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
1539
- import { join as join6, dirname, relative } from "path";
1847
+ import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
1848
+ import { join as join6, dirname, relative } from "node:path";
1540
1849
 
1541
1850
  // src/schemas/frontmatter.ts
1542
1851
  var SkillFrontmatterSchema = object({
@@ -1654,8 +1963,8 @@ function coerceYamlValue(raw) {
1654
1963
  }
1655
1964
 
1656
1965
  // src/detector/normalize.ts
1657
- import { existsSync as existsSync5 } from "fs";
1658
- import { join as join7 } from "path";
1966
+ import { existsSync as existsSync5 } from "node:fs";
1967
+ import { join as join7 } from "node:path";
1659
1968
  function normalizePath(input) {
1660
1969
  if (input.split("/").includes("..")) {
1661
1970
  throw new PathNormalizationError(input, "path traversal (..) not allowed");
@@ -1820,7 +2129,7 @@ function defaultEntryName(sourceRepo) {
1820
2129
  }
1821
2130
 
1822
2131
  // src/commands/scan.ts
1823
- var scanCommand = new R("scan").meta({ description: "Scan a non-plugin repo and emit a marketplace entry" }).args([{ name: "repo", type: "string", required: true, description: "owner/repo, URL, or local path" }]).flags({
2132
+ var scanCommand = new R2("scan").meta({ description: "Scan a non-plugin repo and emit a marketplace entry" }).args([{ name: "repo", type: "string", required: true, description: "owner/repo, URL, or local path" }]).flags({
1824
2133
  output: { type: "string", short: "o", description: "Write entry JSON to file" }
1825
2134
  }).run(async ({ args, flags }) => {
1826
2135
  const repoPath = await resolveSource(args.repo);
@@ -1836,7 +2145,7 @@ var scanCommand = new R("scan").meta({ description: "Scan a non-plugin repo and
1836
2145
  });
1837
2146
 
1838
2147
  // src/commands/validate.ts
1839
- import { readFileSync as readFileSync4 } from "fs";
2148
+ import { readFileSync as readFileSync4 } from "node:fs";
1840
2149
 
1841
2150
  // src/schemas/marketplaceEntry.ts
1842
2151
  var PathString = pipe(string(), startsWith("./"));
@@ -1882,7 +2191,7 @@ var MarketplaceEntrySchema = object({
1882
2191
  });
1883
2192
 
1884
2193
  // src/commands/validate.ts
1885
- var validateCommand = new R("validate").meta({ description: "Validate a marketplace entry JSON file against the schema" }).args([{ name: "entryFile", type: "string", required: true, description: "Path to entry JSON file" }]).run(({ args }) => {
2194
+ var validateCommand = new R2("validate").meta({ description: "Validate a marketplace entry JSON file against the schema" }).args([{ name: "entryFile", type: "string", required: true, description: "Path to entry JSON file" }]).run(({ args }) => {
1886
2195
  const raw = readFileSync4(args.entryFile, "utf8");
1887
2196
  const parsed = JSON.parse(raw);
1888
2197
  const result = safeParse(MarketplaceEntrySchema, parsed);
@@ -1896,30 +2205,6 @@ var validateCommand = new R("validate").meta({ description: "Validate a marketpl
1896
2205
  console.log("OK");
1897
2206
  });
1898
2207
 
1899
- // src/commands/submit.ts
1900
- import { writeFileSync as writeFileSync2, mkdtempSync as mkdtempSync2 } from "fs";
1901
- import { tmpdir as tmpdir2 } from "os";
1902
- import { join as join8 } from "path";
1903
- var submitCommand = new R("submit").meta({ description: "Generate an entry and open a PR against ccpluginizer/marketplace" }).args([{ name: "repo", type: "string", required: true, description: "owner/repo to pluginize" }]).flags({
1904
- dryRun: { type: "boolean", short: "n", description: "Print the PR plan without opening it" }
1905
- }).run(async ({ args, flags }) => {
1906
- const repoPath = await resolveSource(args.repo);
1907
- const sourceRepo = inferSourceRepo(args.repo);
1908
- const entry = synthesizeEntry({ repoRoot: repoPath, sourceRepo });
1909
- const tmpFile = join8(mkdtempSync2(join8(tmpdir2(), "ccp-submit-")), `${entry.name}.json`);
1910
- writeFileSync2(tmpFile, JSON.stringify(entry, null, 2) + `
1911
- `, "utf8");
1912
- if (flags.dryRun === true) {
1913
- console.log(`Would submit:
1914
- entry: ${tmpFile}
1915
- to: ccpluginizer/marketplace`);
1916
- console.log(JSON.stringify(entry, null, 2));
1917
- return;
1918
- }
1919
- console.log(`Generated entry at ${tmpFile}`);
1920
- console.log("Run with --dryRun to preview, or follow the manual PR workflow in CONTRIBUTING.md.");
1921
- });
1922
-
1923
2208
  // src/index.ts
1924
- var app = new R("ccpluginizer").meta({ description: "Pluginize non-plugin Claude Code repos" }).command(scanCommand).command(validateCommand).command(submitCommand);
2209
+ var app = new R("ccpluginizer").meta({ description: "Pluginize non-plugin Claude Code repos" }).command(scanCommand).command(validateCommand);
1925
2210
  await app.execute();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ccpluginizer/ccpluginizer",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "description": "CLI for pluginizing non-plugin Claude Code repos",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -34,11 +34,12 @@
34
34
  "typecheck": "tsc --noEmit",
35
35
  "lint": "eslint . --max-warnings 0",
36
36
  "test": "bun test",
37
- "build": "bun build src/index.ts --outdir dist --target bun --format esm",
37
+ "build": "bun build src/index.ts --outdir dist --target node --format esm",
38
38
  "dev": "bun run src/index.ts",
39
39
  "prepublishOnly": "bun run build"
40
40
  },
41
41
  "engines": {
42
+ "node": ">=20",
42
43
  "bun": ">=1.0.0"
43
44
  },
44
45
  "publishConfig": {