codex-marketplace 0.1.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.
Files changed (54) hide show
  1. package/README.md +25 -0
  2. package/dist/banner.d.ts +4 -0
  3. package/dist/banner.d.ts.map +1 -0
  4. package/dist/banner.js +20 -0
  5. package/dist/banner.js.map +1 -0
  6. package/dist/config.d.ts +2 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +83 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/filesystem.d.ts +2 -0
  11. package/dist/filesystem.d.ts.map +1 -0
  12. package/dist/filesystem.js +45 -0
  13. package/dist/filesystem.js.map +1 -0
  14. package/dist/git.d.ts +3 -0
  15. package/dist/git.d.ts.map +1 -0
  16. package/dist/git.js +48 -0
  17. package/dist/git.js.map +1 -0
  18. package/dist/github.d.ts +3 -0
  19. package/dist/github.d.ts.map +1 -0
  20. package/dist/github.js +29 -0
  21. package/dist/github.js.map +1 -0
  22. package/dist/index.d.ts +3 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +124 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/install.d.ts +16 -0
  27. package/dist/install.d.ts.map +1 -0
  28. package/dist/install.js +77 -0
  29. package/dist/install.js.map +1 -0
  30. package/dist/manifest.d.ts +4 -0
  31. package/dist/manifest.d.ts.map +1 -0
  32. package/dist/manifest.js +146 -0
  33. package/dist/manifest.js.map +1 -0
  34. package/dist/marketplace.d.ts +6 -0
  35. package/dist/marketplace.d.ts.map +1 -0
  36. package/dist/marketplace.js +100 -0
  37. package/dist/marketplace.js.map +1 -0
  38. package/dist/repository.d.ts +3 -0
  39. package/dist/repository.d.ts.map +1 -0
  40. package/dist/repository.js +44 -0
  41. package/dist/repository.js.map +1 -0
  42. package/dist/schema.d.ts +360 -0
  43. package/dist/schema.d.ts.map +1 -0
  44. package/dist/schema.js +59 -0
  45. package/dist/schema.js.map +1 -0
  46. package/dist/types.d.ts +117 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -0
  50. package/dist/utils.d.ts +7 -0
  51. package/dist/utils.d.ts.map +1 -0
  52. package/dist/utils.js +32 -0
  53. package/dist/utils.js.map +1 -0
  54. package/package.json +38 -0
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # codex-marketplace
2
+
3
+ Install Codex plugins from GitHub with a single `npx` command.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npx codex-marketplace add openai/plugins --plugin figma
9
+ ```
10
+
11
+ If you omit `--project` and `--global`, the CLI prompts for scope interactively.
12
+
13
+ ## Commands
14
+
15
+ ```bash
16
+ codex-marketplace add <owner/repo>
17
+ codex-marketplace install <owner/repo>
18
+ ```
19
+
20
+ ## Flags
21
+
22
+ - `--plugin <name>`: install one plugin from a multi-plugin repository
23
+ - `--project`, `-p`: write the marketplace into the current directory
24
+ - `--global`, `-g`: write the marketplace into your home directory
25
+ - `--yes`, `-y`: skip the final confirmation prompt
@@ -0,0 +1,4 @@
1
+ export declare function renderBanner({ color }?: {
2
+ color?: boolean;
3
+ }): string;
4
+ //# sourceMappingURL=banner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"banner.d.ts","sourceRoot":"","sources":["../src/banner.ts"],"names":[],"mappings":"AAeA,wBAAgB,YAAY,CAAC,EAAE,KAAY,EAAE,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAM/E"}
package/dist/banner.js ADDED
@@ -0,0 +1,20 @@
1
+ const BANNER_LINES = [
2
+ " ██████ ██████ ██████ ███████ ██ ██",
3
+ " ██ ██ ██ ██ ██ ██ ██ ██ ",
4
+ " ██ ██ ██ ██ ██ █████ ███ ",
5
+ " ██ ██ ██ ██ ██ ██ ██ ██ ",
6
+ " ██████ ██████ ██████ ███████ ██ ██",
7
+ " ██████ ██ ██ ██ ██████ ██ ███ ██ ███████",
8
+ " ██ ██ ██ ██ ██ ██ ██ ████ ██ ██",
9
+ " ██████ ██ ██ ██ ██ ███ ██ ██ ██ ██ ███████",
10
+ " ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██",
11
+ " ██ ███████ █████ ██████ ██ ██ ████ ███████",
12
+ ];
13
+ const COLORS = ["31", "91", "93", "33"];
14
+ export function renderBanner({ color = true } = {}) {
15
+ if (!color) {
16
+ return BANNER_LINES.join("\n");
17
+ }
18
+ return BANNER_LINES.map((line, index) => `\u001b[${COLORS[index % COLORS.length]}m${line}\u001b[0m`).join("\n");
19
+ }
20
+ //# sourceMappingURL=banner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"banner.js","sourceRoot":"","sources":["../src/banner.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAAG;IACnB,2CAA2C;IAC3C,2CAA2C;IAC3C,2CAA2C;IAC3C,2CAA2C;IAC3C,2CAA2C;IAC3C,mEAAmE;IACnE,8DAA8D;IAC9D,mEAAmE;IACnE,mEAAmE;IACnE,mEAAmE;CACpE,CAAC;AAEF,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAExC,MAAM,UAAU,YAAY,CAAC,EAAE,KAAK,GAAG,IAAI,KAA0B,EAAE;IACrE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function writeCodexPluginConfig(codexHome: string, marketplaceName: string, pluginNames: string[]): Promise<string>;
2
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAwFA,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,MAAM,CAAC,CAgBjB"}
package/dist/config.js ADDED
@@ -0,0 +1,83 @@
1
+ import path from "node:path";
2
+ import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
3
+ import { ensureTrailingNewline } from "./utils.js";
4
+ async function fileExists(targetPath) {
5
+ try {
6
+ await stat(targetPath);
7
+ return true;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ function parseToml(text) {
14
+ const lines = text.replace(/\r\n/g, "\n").split("\n");
15
+ const preamble = [];
16
+ const sections = [];
17
+ let current = null;
18
+ for (const line of lines) {
19
+ const match = line.match(/^\s*\[([^\]]+)\]\s*$/);
20
+ if (match) {
21
+ current = { header: match[1], lines: [] };
22
+ sections.push(current);
23
+ continue;
24
+ }
25
+ if (current) {
26
+ current.lines.push(line);
27
+ }
28
+ else {
29
+ preamble.push(line);
30
+ }
31
+ }
32
+ return { preamble, sections };
33
+ }
34
+ function serializeToml(parsed) {
35
+ const blocks = [];
36
+ const preamble = parsed.preamble.join("\n").trimEnd();
37
+ if (preamble) {
38
+ blocks.push(preamble);
39
+ }
40
+ for (const section of parsed.sections) {
41
+ const body = section.lines.join("\n").replace(/\n+$/g, "");
42
+ blocks.push(`[${section.header}]${body ? `\n${body}` : ""}`);
43
+ }
44
+ return ensureTrailingNewline(blocks.join("\n\n"));
45
+ }
46
+ function upsertKey(section, key, renderedValue) {
47
+ const keyPattern = new RegExp(`^\\s*${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*=`);
48
+ const nextLine = `${key} = ${renderedValue}`;
49
+ const index = section.lines.findIndex((line) => keyPattern.test(line));
50
+ if (index >= 0) {
51
+ section.lines.splice(index, 1, nextLine);
52
+ }
53
+ else {
54
+ while (section.lines.length > 0 && section.lines[section.lines.length - 1] === "") {
55
+ section.lines.pop();
56
+ }
57
+ section.lines.push(nextLine);
58
+ }
59
+ }
60
+ function ensureSection(parsed, header) {
61
+ const existing = parsed.sections.find((section) => section.header === header);
62
+ if (existing) {
63
+ return existing;
64
+ }
65
+ const created = { header, lines: [] };
66
+ parsed.sections.push(created);
67
+ return created;
68
+ }
69
+ export async function writeCodexPluginConfig(codexHome, marketplaceName, pluginNames) {
70
+ const configPath = path.join(codexHome, "config.toml");
71
+ const existing = (await fileExists(configPath)) ? await readFile(configPath, "utf8") : "";
72
+ const parsed = parseToml(existing);
73
+ const features = ensureSection(parsed, "features");
74
+ upsertKey(features, "plugins", "true");
75
+ for (const pluginName of pluginNames) {
76
+ const pluginSection = ensureSection(parsed, `plugins."${pluginName}@${marketplaceName}"`);
77
+ upsertKey(pluginSection, "enabled", "true");
78
+ }
79
+ await mkdir(path.dirname(configPath), { recursive: true });
80
+ await writeFile(configPath, serializeToml(parsed), "utf8");
81
+ return configPath;
82
+ }
83
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function replaceDirectoryAtomically(source: string, target: string): Promise<void>;
2
+ //# sourceMappingURL=filesystem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":"AAaA,wBAAsB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC9F"}
@@ -0,0 +1,45 @@
1
+ import path from "node:path";
2
+ import { cp, mkdir, rename, rm, stat } from "node:fs/promises";
3
+ import { randomUUID } from "node:crypto";
4
+ async function pathExists(targetPath) {
5
+ try {
6
+ await stat(targetPath);
7
+ return true;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ export async function replaceDirectoryAtomically(source, target) {
14
+ const parent = path.dirname(target);
15
+ const base = path.basename(target);
16
+ const tempTarget = path.join(parent, `${base}.tmp-${randomUUID()}`);
17
+ const backupTarget = path.join(parent, `${base}.bak-${randomUUID()}`);
18
+ await mkdir(parent, { recursive: true });
19
+ await cp(source, tempTarget, {
20
+ recursive: true,
21
+ errorOnExist: false,
22
+ force: true,
23
+ filter(entry) {
24
+ return path.basename(entry) !== ".git";
25
+ },
26
+ });
27
+ const hadExistingTarget = await pathExists(target);
28
+ try {
29
+ if (hadExistingTarget) {
30
+ await rename(target, backupTarget);
31
+ }
32
+ await rename(tempTarget, target);
33
+ if (hadExistingTarget) {
34
+ await rm(backupTarget, { recursive: true, force: true });
35
+ }
36
+ }
37
+ catch (error) {
38
+ await rm(tempTarget, { recursive: true, force: true }).catch(() => undefined);
39
+ if (hadExistingTarget && !(await pathExists(target)) && (await pathExists(backupTarget))) {
40
+ await rename(backupTarget, target).catch(() => undefined);
41
+ }
42
+ throw error;
43
+ }
44
+ }
45
+ //# sourceMappingURL=filesystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,KAAK,UAAU,UAAU,CAAC,UAAkB;IAC1C,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,MAAc,EAAE,MAAc;IAC7E,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,QAAQ,UAAU,EAAE,EAAE,CAAC,CAAC;IACpE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,QAAQ,UAAU,EAAE,EAAE,CAAC,CAAC;IAEtE,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE;QAC3B,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,KAAK;QACnB,KAAK,EAAE,IAAI;QACX,MAAM,CAAC,KAAK;YACV,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC;QACzC,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC;QACH,IAAI,iBAAiB,EAAE,CAAC;YACtB,MAAM,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACrC,CAAC;QAED,MAAM,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAEjC,IAAI,iBAAiB,EAAE,CAAC;YACtB,MAAM,EAAE,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC9E,IAAI,iBAAiB,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;YACzF,MAAM,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { CheckedOutRepository, GitHubRepoMetadata } from "./types.js";
2
+ export declare function cloneRepository(metadata: GitHubRepoMetadata): Promise<CheckedOutRepository>;
3
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA4BtE,wBAAsB,eAAe,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAqBjG"}
package/dist/git.js ADDED
@@ -0,0 +1,48 @@
1
+ import path from "node:path";
2
+ import { execFile } from "node:child_process";
3
+ import { mkdtemp } from "node:fs/promises";
4
+ import { tmpdir } from "node:os";
5
+ import { promisify } from "node:util";
6
+ const execFileAsync = promisify(execFile);
7
+ function withGitHubToken(cloneUrl, token) {
8
+ if (!token || !cloneUrl.startsWith("https://github.com/")) {
9
+ return cloneUrl;
10
+ }
11
+ const url = new URL(cloneUrl);
12
+ url.username = "x-access-token";
13
+ url.password = token;
14
+ return url.toString();
15
+ }
16
+ async function runGit(args, cwd) {
17
+ try {
18
+ const { stdout } = await execFileAsync("git", args, {
19
+ cwd,
20
+ env: process.env,
21
+ });
22
+ return stdout.trim();
23
+ }
24
+ catch (error) {
25
+ const reason = error instanceof Error ? error.message : String(error);
26
+ throw new Error(`Git command failed: git ${args.join(" ")}\n${reason}`);
27
+ }
28
+ }
29
+ export async function cloneRepository(metadata) {
30
+ const checkoutPath = await mkdtemp(path.join(tmpdir(), "codex-marketplace-"));
31
+ const cloneUrl = withGitHubToken(metadata.cloneUrl, process.env.GITHUB_TOKEN);
32
+ await runGit([
33
+ "clone",
34
+ "--depth",
35
+ "1",
36
+ "--branch",
37
+ metadata.defaultBranch,
38
+ cloneUrl,
39
+ checkoutPath,
40
+ ]);
41
+ const commitSha = await runGit(["-C", checkoutPath, "rev-parse", "HEAD"]);
42
+ return {
43
+ checkoutPath,
44
+ commitSha,
45
+ metadata,
46
+ };
47
+ }
48
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,SAAS,eAAe,CAAC,QAAgB,EAAE,KAAc;IACvD,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC1D,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9B,GAAG,CAAC,QAAQ,GAAG,gBAAgB,CAAC;IAChC,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC;IACrB,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAc,EAAE,GAAY;IAChD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE;YAClD,GAAG;YACH,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAA4B;IAChE,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAE9E,MAAM,MAAM,CAAC;QACX,OAAO;QACP,SAAS;QACT,GAAG;QACH,UAAU;QACV,QAAQ,CAAC,aAAa;QACtB,QAAQ;QACR,YAAY;KACb,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAE1E,OAAO;QACL,YAAY;QACZ,SAAS;QACT,QAAQ;KACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { GitHubRepoMetadata, GitHubRepoSpec } from "./types.js";
2
+ export declare function fetchGitHubRepositoryMetadata(spec: GitHubRepoSpec, fetchImpl?: typeof fetch, token?: string): Promise<GitHubRepoMetadata>;
3
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAShE,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,cAAc,EACpB,SAAS,GAAE,OAAO,KAAa,EAC/B,KAAK,SAAiC,GACrC,OAAO,CAAC,kBAAkB,CAAC,CAoC7B"}
package/dist/github.js ADDED
@@ -0,0 +1,29 @@
1
+ export async function fetchGitHubRepositoryMetadata(spec, fetchImpl = fetch, token = process.env.GITHUB_TOKEN ?? "") {
2
+ const response = await fetchImpl(`https://api.github.com/repos/${spec.fullName}`, {
3
+ headers: {
4
+ Accept: "application/vnd.github+json",
5
+ "User-Agent": "codex-marketplace",
6
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
7
+ },
8
+ });
9
+ if (!response.ok) {
10
+ if (response.status === 404) {
11
+ throw new Error(`GitHub repository not found: ${spec.fullName}`);
12
+ }
13
+ if (response.status === 403) {
14
+ throw new Error(`GitHub API rejected the request for ${spec.fullName} (${response.status}). Check rate limits or GITHUB_TOKEN.`);
15
+ }
16
+ throw new Error(`GitHub API request failed for ${spec.fullName} with status ${response.status}.`);
17
+ }
18
+ const payload = (await response.json());
19
+ if (!payload.clone_url || !payload.default_branch) {
20
+ throw new Error(`GitHub repository metadata for ${spec.fullName} is missing clone information.`);
21
+ }
22
+ return {
23
+ ...spec,
24
+ cloneUrl: payload.clone_url,
25
+ defaultBranch: payload.default_branch,
26
+ description: payload.description ?? undefined,
27
+ };
28
+ }
29
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,IAAoB,EACpB,YAA0B,KAAK,EAC/B,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE;IAEtC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gCAAgC,IAAI,CAAC,QAAQ,EAAE,EAAE;QAChF,OAAO,EAAE;YACP,MAAM,EAAE,6BAA6B;YACrC,YAAY,EAAE,mBAAmB;YACjC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvD;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CACb,uCAAuC,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,MAAM,uCAAuC,CAChH,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,KAAK,CACb,iCAAiC,IAAI,CAAC,QAAQ,gBAAgB,QAAQ,CAAC,MAAM,GAAG,CACjF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA0B,CAAC;IACjE,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,QAAQ,gCAAgC,CAAC,CAAC;IACnG,CAAC;IAED,OAAO;QACL,GAAG,IAAI;QACP,QAAQ,EAAE,OAAO,CAAC,SAAS;QAC3B,aAAa,EAAE,OAAO,CAAC,cAAc;QACrC,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,SAAS;KAC9C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ import { confirm, intro, isCancel, log, outro, select, spinner } from "@clack/prompts";
3
+ import { Command } from "commander";
4
+ import { performInstall, prepareInstall, resolveRuntimeContext, selectPreparedPlugins } from "./install.js";
5
+ import { renderBanner } from "./banner.js";
6
+ import { pluralize } from "./utils.js";
7
+ function resolveScope(options) {
8
+ if (options.project && options.global) {
9
+ throw new Error("Choose either --project or --global, not both.");
10
+ }
11
+ if (options.project)
12
+ return "project";
13
+ if (options.global)
14
+ return "global";
15
+ return null;
16
+ }
17
+ async function promptForScope() {
18
+ const result = await select({
19
+ message: "Where should Codex install these plugins?",
20
+ options: [
21
+ {
22
+ value: "project",
23
+ label: "Project scope",
24
+ hint: "Use the current directory's marketplace layout",
25
+ },
26
+ {
27
+ value: "global",
28
+ label: "Global scope",
29
+ hint: "Use your home-directory Codex marketplace layout",
30
+ },
31
+ ],
32
+ });
33
+ if (isCancel(result)) {
34
+ throw new Error("Install cancelled.");
35
+ }
36
+ return result;
37
+ }
38
+ async function runAddCommand(repository, options) {
39
+ const runtime = resolveRuntimeContext();
40
+ const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
41
+ let scope = resolveScope(options);
42
+ if (!scope) {
43
+ if (!interactive) {
44
+ throw new Error("Non-interactive installs must set either --project or --global.");
45
+ }
46
+ console.log(renderBanner());
47
+ intro("Codex Plugins");
48
+ scope = await promptForScope();
49
+ }
50
+ else if (interactive) {
51
+ console.log(renderBanner());
52
+ intro("Codex Plugins");
53
+ }
54
+ const prepSpinner = spinner();
55
+ prepSpinner.start(`Inspecting ${repository}`);
56
+ let prepared;
57
+ let selected;
58
+ try {
59
+ prepared = await prepareInstall(repository, {}, options.plugin);
60
+ selected = selectPreparedPlugins(prepared, options.plugin);
61
+ prepSpinner.stop(`Found ${selected.discoveredPlugins.length} ${pluralize(selected.discoveredPlugins.length, "plugin")} in ${prepared.checkout.metadata.fullName}`);
62
+ }
63
+ catch (error) {
64
+ prepSpinner.stop("Inspection failed");
65
+ throw error;
66
+ }
67
+ try {
68
+ if (!options.yes && interactive) {
69
+ const confirmed = await confirm({
70
+ message: `Install ${selected.discoveredPlugins.length} ${pluralize(selected.discoveredPlugins.length, "plugin")} from ${prepared.checkout.metadata.fullName} into ${scope} scope?`,
71
+ });
72
+ if (isCancel(confirmed) || !confirmed) {
73
+ throw new Error("Install cancelled.");
74
+ }
75
+ }
76
+ const installSpinner = spinner();
77
+ installSpinner.start("Installing plugins into marketplace and Codex cache");
78
+ let result;
79
+ try {
80
+ result = await performInstall(selected, scope, runtime);
81
+ installSpinner.stop(`Installed ${result.installedPlugins.length} ${pluralize(result.installedPlugins.length, "plugin")}`);
82
+ }
83
+ catch (error) {
84
+ installSpinner.stop("Install failed");
85
+ throw error;
86
+ }
87
+ log.info(`Marketplace: ${result.marketplacePath}`);
88
+ log.info(`Codex config: ${result.configPath}`);
89
+ log.info(`Revision: ${result.commitSha}`);
90
+ for (const plugin of result.installedPlugins) {
91
+ log.message(`${plugin.name} -> ${plugin.relativeSourcePath}`);
92
+ }
93
+ outro(`Installed ${result.installedPlugins.length} ${pluralize(result.installedPlugins.length, "plugin")} from ${result.repo.fullName}.`);
94
+ }
95
+ finally {
96
+ await prepared.cleanup();
97
+ }
98
+ }
99
+ const program = new Command();
100
+ program
101
+ .name("codex-marketplace")
102
+ .description("Install Codex plugins from GitHub into project or global scope.")
103
+ .showHelpAfterError()
104
+ .addHelpText("beforeAll", `${renderBanner({ color: false })}\n\n`);
105
+ program
106
+ .command("add <repository>")
107
+ .alias("install")
108
+ .description("Fetch a GitHub repository and install its Codex plugin(s).")
109
+ .option("-p, --project", "Install into the current directory's project marketplace")
110
+ .option("-g, --global", "Install into the home-directory marketplace")
111
+ .option("--plugin <name>", "Install only a specific plugin from a multi-plugin repository")
112
+ .option("-y, --yes", "Skip the final confirmation prompt")
113
+ .action(async (repository, options) => {
114
+ try {
115
+ await runAddCommand(repository, options);
116
+ }
117
+ catch (error) {
118
+ const message = error instanceof Error ? error.message : String(error);
119
+ log.error(message);
120
+ process.exitCode = 1;
121
+ }
122
+ });
123
+ await program.parseAsync(process.argv);
124
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC5G,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,SAAS,YAAY,CAAC,OAAgD;IACpE,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,OAAO,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IACtC,IAAI,OAAO,CAAC,MAAM;QAAE,OAAO,QAAQ,CAAC;IACpC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,cAAc;IAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;QAC1B,OAAO,EAAE,2CAA2C;QACpD,OAAO,EAAE;YACP;gBACE,KAAK,EAAE,SAAS;gBAChB,KAAK,EAAE,eAAe;gBACtB,IAAI,EAAE,gDAAgD;aACvD;YACD;gBACE,KAAK,EAAE,QAAQ;gBACf,KAAK,EAAE,cAAc;gBACrB,IAAI,EAAE,kDAAkD;aACzD;SACF;KACF,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,UAAkB,EAClB,OAKC;IAED,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;IACxC,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzE,IAAI,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAElC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;QACrF,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;QAC5B,KAAK,CAAC,eAAe,CAAC,CAAC;QACvB,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;IACjC,CAAC;SAAM,IAAI,WAAW,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;QAC5B,KAAK,CAAC,eAAe,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,EAAE,CAAC;IAC9B,WAAW,CAAC,KAAK,CAAC,cAAc,UAAU,EAAE,CAAC,CAAC;IAC9C,IAAI,QAAQ,CAAC;IACb,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,cAAc,CAAC,UAAU,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAChE,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3D,WAAW,CAAC,IAAI,CACd,SAAS,QAAQ,CAAC,iBAAiB,CAAC,MAAM,IAAI,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,CACjJ,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACtC,MAAM,KAAK,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,WAAW,EAAE,CAAC;YAChC,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC;gBAC9B,OAAO,EAAE,WAAW,QAAQ,CAAC,iBAAiB,CAAC,MAAM,IAAI,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,SAAS,KAAK,SAAS;aACnL,CAAC,CAAC;YACH,IAAI,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACtC,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,MAAM,cAAc,GAAG,OAAO,EAAE,CAAC;QACjC,cAAc,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QAC5E,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YACxD,cAAc,CAAC,IAAI,CACjB,aAAa,MAAM,CAAC,gBAAgB,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CACrG,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,cAAc,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACtC,MAAM,KAAK,CAAC;QACd,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;QACnD,GAAG,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QAC/C,GAAG,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QAC1C,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;YAC7C,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,KAAK,CAAC,aAAa,MAAM,CAAC,gBAAgB,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;IAC5I,CAAC;YAAS,CAAC;QACT,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,OAAO;KACJ,IAAI,CAAC,mBAAmB,CAAC;KACzB,WAAW,CAAC,iEAAiE,CAAC;KAC9E,kBAAkB,EAAE;KACpB,WAAW,CAAC,WAAW,EAAE,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC;AAErE,OAAO;KACJ,OAAO,CAAC,kBAAkB,CAAC;KAC3B,KAAK,CAAC,SAAS,CAAC;KAChB,WAAW,CAAC,4DAA4D,CAAC;KACzE,MAAM,CAAC,eAAe,EAAE,0DAA0D,CAAC;KACnF,MAAM,CAAC,cAAc,EAAE,6CAA6C,CAAC;KACrE,MAAM,CAAC,iBAAiB,EAAE,+DAA+D,CAAC;KAC1F,MAAM,CAAC,WAAW,EAAE,oCAAoC,CAAC;KACzD,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,OAAgF,EAAE,EAAE;IACrH,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { DiscoveredPluginSource, GitHubRepoMetadata, GitHubRepoSpec, InstallResult, InstallScope, PreparedInstall, RuntimeContext } from "./types.js";
2
+ interface PrepareDependencies {
3
+ fetchRepositoryMetadata?: (spec: GitHubRepoSpec) => Promise<GitHubRepoMetadata>;
4
+ cloneRepository?: (repo: GitHubRepoMetadata) => Promise<{
5
+ checkoutPath: string;
6
+ commitSha: string;
7
+ metadata: GitHubRepoMetadata;
8
+ }>;
9
+ discoverPluginSources?: (checkoutRoot: string, pluginName?: string) => Promise<DiscoveredPluginSource[]>;
10
+ }
11
+ export declare function resolveRuntimeContext(cwd?: string, homeDir?: string, codexHome?: string): RuntimeContext;
12
+ export declare function prepareInstall(repositoryInput: string, dependencies?: PrepareDependencies, pluginName?: string): Promise<PreparedInstall>;
13
+ export declare function performInstall(prepared: PreparedInstall, scope: InstallScope, runtime: RuntimeContext): Promise<InstallResult>;
14
+ export declare function selectPreparedPlugins(prepared: PreparedInstall, pluginName?: string): PreparedInstall;
15
+ export {};
16
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,YAAY,EACZ,eAAe,EACf,cAAc,EACf,MAAM,YAAY,CAAC;AASpB,UAAU,mBAAmB;IAC3B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChF,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,kBAAkB,CAAA;KAAE,CAAC,CAAC;IACnI,qBAAqB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAC;CAC1G;AAED,wBAAgB,qBAAqB,CACnC,GAAG,SAAgB,EACnB,OAAO,SAAyB,EAChC,SAAS,SAAwE,GAChF,cAAc,CAUhB;AAED,wBAAsB,cAAc,CAClC,eAAe,EAAE,MAAM,EACvB,YAAY,GAAE,mBAAwB,EACtC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CAgB1B;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAqDxB;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,eAAe,EACzB,UAAU,CAAC,EAAE,MAAM,GAClB,eAAe,CAkBjB"}
@@ -0,0 +1,77 @@
1
+ import path from "node:path";
2
+ import { rm } from "node:fs/promises";
3
+ import { parseRepositoryInput } from "./repository.js";
4
+ import { fetchGitHubRepositoryMetadata } from "./github.js";
5
+ import { cloneRepository } from "./git.js";
6
+ import { discoverPluginSources } from "./manifest.js";
7
+ import { replaceDirectoryAtomically } from "./filesystem.js";
8
+ import { loadMarketplace, resolveScopeLayout, upsertMarketplacePlugin, writeMarketplace } from "./marketplace.js";
9
+ import { writeCodexPluginConfig } from "./config.js";
10
+ export function resolveRuntimeContext(cwd = process.cwd(), homeDir = process.env.HOME ?? "", codexHome = process.env.CODEX_HOME ?? path.join(process.env.HOME ?? "", ".codex")) {
11
+ if (!homeDir) {
12
+ throw new Error("HOME is required to determine global install paths.");
13
+ }
14
+ return {
15
+ cwd: path.resolve(cwd),
16
+ homeDir: path.resolve(homeDir),
17
+ codexHome: path.resolve(codexHome),
18
+ };
19
+ }
20
+ export async function prepareInstall(repositoryInput, dependencies = {}, pluginName) {
21
+ const spec = parseRepositoryInput(repositoryInput);
22
+ const repoMetadata = await (dependencies.fetchRepositoryMetadata ?? fetchGitHubRepositoryMetadata)(spec);
23
+ const checkout = await (dependencies.cloneRepository ?? cloneRepository)(repoMetadata);
24
+ const discoveredPlugins = await (dependencies.discoverPluginSources ?? discoverPluginSources)(checkout.checkoutPath, pluginName);
25
+ return {
26
+ checkout,
27
+ discoveredPlugins,
28
+ cleanup: async () => {
29
+ await rm(checkout.checkoutPath, { recursive: true, force: true }).catch(() => undefined);
30
+ },
31
+ };
32
+ }
33
+ export async function performInstall(prepared, scope, runtime) {
34
+ const layout = resolveScopeLayout(scope, runtime.cwd, runtime.homeDir);
35
+ const mutableMarketplace = await loadMarketplace(layout);
36
+ let marketplace = mutableMarketplace.config;
37
+ const installedPlugins = [];
38
+ for (const discovered of prepared.discoveredPlugins) {
39
+ const sourcePath = path.join(layout.pluginSourceRoot, discovered.manifest.name);
40
+ await replaceDirectoryAtomically(discovered.sourcePath, sourcePath);
41
+ marketplace = upsertMarketplacePlugin(marketplace, discovered.manifest.name, sourcePath, layout.marketplaceRoot, discovered.category, discovered.policy);
42
+ installedPlugins.push({
43
+ name: discovered.manifest.name,
44
+ sourcePath,
45
+ relativeSourcePath: marketplace.plugins.find((entry) => entry.name === discovered.manifest.name)?.source.path ?? "",
46
+ cachePath: path.join(runtime.codexHome, "plugins", "cache", marketplace.name, discovered.manifest.name, "local"),
47
+ });
48
+ }
49
+ await writeMarketplace(layout, marketplace);
50
+ for (const installed of installedPlugins) {
51
+ await replaceDirectoryAtomically(installed.sourcePath, installed.cachePath);
52
+ }
53
+ const configPath = await writeCodexPluginConfig(runtime.codexHome, marketplace.name, installedPlugins.map((plugin) => plugin.name));
54
+ return {
55
+ scope,
56
+ repo: prepared.checkout.metadata,
57
+ commitSha: prepared.checkout.commitSha,
58
+ marketplacePath: layout.marketplacePath,
59
+ marketplaceName: marketplace.name,
60
+ configPath,
61
+ installedPlugins,
62
+ };
63
+ }
64
+ export function selectPreparedPlugins(prepared, pluginName) {
65
+ if (!pluginName) {
66
+ return prepared;
67
+ }
68
+ const selected = prepared.discoveredPlugins.filter((plugin) => plugin.manifest.name === pluginName);
69
+ if (selected.length === 0) {
70
+ throw new Error(`Repository ${prepared.checkout.metadata.fullName} does not expose a plugin named ${pluginName}.`);
71
+ }
72
+ return {
73
+ ...prepared,
74
+ discoveredPlugins: selected,
75
+ };
76
+ }
77
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { DiscoveredPluginSource, PluginManifest } from "./types.js";
2
+ export declare function loadPluginManifest(pluginRoot: string): Promise<PluginManifest>;
3
+ export declare function discoverPluginSources(checkoutRoot: string, pluginName?: string): Promise<DiscoveredPluginSource[]>;
4
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAwC,cAAc,EAAE,MAAM,YAAY,CAAC;AA0B1G,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAkBpF;AAyED,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAmDnC"}