@ai-plugin-marketplace/core 0.1.0 → 0.2.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 (49) hide show
  1. package/dist/config.d.ts +112 -0
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +56 -0
  4. package/dist/config.js.map +1 -1
  5. package/dist/core.d.ts +136 -4
  6. package/dist/index.d.ts +2 -2
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/pipeline/build.d.ts +159 -1
  11. package/dist/pipeline/build.d.ts.map +1 -1
  12. package/dist/pipeline/build.js +413 -9
  13. package/dist/pipeline/build.js.map +1 -1
  14. package/dist/pipeline/discover.d.ts +20 -13
  15. package/dist/pipeline/discover.d.ts.map +1 -1
  16. package/dist/pipeline/discover.js +53 -32
  17. package/dist/pipeline/discover.js.map +1 -1
  18. package/dist/pipeline/load-config.d.ts +62 -2
  19. package/dist/pipeline/load-config.d.ts.map +1 -1
  20. package/dist/pipeline/load-config.js +147 -30
  21. package/dist/pipeline/load-config.js.map +1 -1
  22. package/dist/pipeline/operations.d.ts +4 -2
  23. package/dist/pipeline/operations.d.ts.map +1 -1
  24. package/dist/pipeline/operations.js +9 -4
  25. package/dist/pipeline/operations.js.map +1 -1
  26. package/dist/pipeline/scaffold.d.ts.map +1 -1
  27. package/dist/pipeline/scaffold.js +55 -26
  28. package/dist/pipeline/scaffold.js.map +1 -1
  29. package/dist/pipeline/types.d.ts +13 -3
  30. package/dist/pipeline/types.d.ts.map +1 -1
  31. package/dist/pipeline/types.js +1 -0
  32. package/dist/pipeline/types.js.map +1 -1
  33. package/dist/pipeline/validate.d.ts +12 -2
  34. package/dist/pipeline/validate.d.ts.map +1 -1
  35. package/dist/pipeline/validate.js +342 -38
  36. package/dist/pipeline/validate.js.map +1 -1
  37. package/dist/targets/codex/scaffold.d.ts +31 -0
  38. package/dist/targets/codex/scaffold.d.ts.map +1 -0
  39. package/dist/targets/codex/scaffold.js +47 -0
  40. package/dist/targets/codex/scaffold.js.map +1 -0
  41. package/dist/targets/codex/schemas.d.ts +70 -0
  42. package/dist/targets/codex/schemas.d.ts.map +1 -0
  43. package/dist/targets/codex/schemas.js +153 -0
  44. package/dist/targets/codex/schemas.js.map +1 -0
  45. package/dist/targets/codex/validate.d.ts +25 -0
  46. package/dist/targets/codex/validate.d.ts.map +1 -0
  47. package/dist/targets/codex/validate.js +117 -0
  48. package/dist/targets/codex/validate.js.map +1 -0
  49. package/package.json +1 -1
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Scaffold templates for the OpenAI Codex CLI target.
3
+ *
4
+ * `scaffoldCodexFiles` is a pure function returning the skeleton files this target contributes
5
+ * to a new plugin. Codex is an in-place marketplace target like Cursor: it has no mechanical
6
+ * transform in v0.1.0, but it still owns a manifest (`.codex-plugin/plugin.json`). Every manifest
7
+ * carries `schemaVersion: "0.1.0"` (§12.2). No generated-file sentinels — these are
8
+ * author-authored skeleton files (§4.3).
9
+ *
10
+ * Intentionally duplicated from the Cursor scaffold rather than shared: per §3.4 no file in this
11
+ * folder may import from a sibling target folder, and §13 Phase A keeps target schemas free to
12
+ * diverge later.
13
+ *
14
+ * @see https://developers.openai.com/codex/plugins/build
15
+ * @see docs/specs/architecture.md §4 (plugin source layout)
16
+ * @see docs/specs/architecture.md §6.4 (compatibility-assist)
17
+ * @see docs/specs/architecture.md §12.2 (schemaVersion on every manifest)
18
+ * @see docs/specs/architecture.md §12.5 (per-target scaffold.ts)
19
+ */
20
+ import { type ScaffoldedFile, type TargetScaffoldOptions } from '../scaffold-kit.js';
21
+ /**
22
+ * Produce the Codex skeleton files for a plugin.
23
+ *
24
+ * The minimum required artifact (`TARGET_MIN_REQUIRED.codex`) is `.codex-plugin/plugin.json`.
25
+ *
26
+ * @param pluginName - Plugin identity; written verbatim as the manifest `name`.
27
+ * @param opts - Optional description and add-target placeholder behaviour.
28
+ * @returns Files contributed by this target, with paths relative to the plugin directory.
29
+ */
30
+ export declare function scaffoldCodexFiles(pluginName: string, opts?: TargetScaffoldOptions): ScaffoldedFile[];
31
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/targets/codex/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,qBAA0B,GAC/B,cAAc,EAAE,CAiBlB"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Scaffold templates for the OpenAI Codex CLI target.
3
+ *
4
+ * `scaffoldCodexFiles` is a pure function returning the skeleton files this target contributes
5
+ * to a new plugin. Codex is an in-place marketplace target like Cursor: it has no mechanical
6
+ * transform in v0.1.0, but it still owns a manifest (`.codex-plugin/plugin.json`). Every manifest
7
+ * carries `schemaVersion: "0.1.0"` (§12.2). No generated-file sentinels — these are
8
+ * author-authored skeleton files (§4.3).
9
+ *
10
+ * Intentionally duplicated from the Cursor scaffold rather than shared: per §3.4 no file in this
11
+ * folder may import from a sibling target folder, and §13 Phase A keeps target schemas free to
12
+ * diverge later.
13
+ *
14
+ * @see https://developers.openai.com/codex/plugins/build
15
+ * @see docs/specs/architecture.md §4 (plugin source layout)
16
+ * @see docs/specs/architecture.md §6.4 (compatibility-assist)
17
+ * @see docs/specs/architecture.md §12.2 (schemaVersion on every manifest)
18
+ * @see docs/specs/architecture.md §12.5 (per-target scaffold.ts)
19
+ */
20
+ import { resolveDescription, SCHEMA_VERSION, } from '../scaffold-kit.js';
21
+ /**
22
+ * Produce the Codex skeleton files for a plugin.
23
+ *
24
+ * The minimum required artifact (`TARGET_MIN_REQUIRED.codex`) is `.codex-plugin/plugin.json`.
25
+ *
26
+ * @param pluginName - Plugin identity; written verbatim as the manifest `name`.
27
+ * @param opts - Optional description and add-target placeholder behaviour.
28
+ * @returns Files contributed by this target, with paths relative to the plugin directory.
29
+ */
30
+ export function scaffoldCodexFiles(pluginName, opts = {}) {
31
+ const description = resolveDescription(pluginName, opts);
32
+ const manifest = {
33
+ schemaVersion: SCHEMA_VERSION,
34
+ name: pluginName,
35
+ version: '0.0.1',
36
+ // `description` is optional and constrained to min length 1; omit it in placeholder mode
37
+ // (add-target) so the skeleton stays schema-valid while leaving the field for the author.
38
+ ...(description !== '' ? { description } : {}),
39
+ };
40
+ return [
41
+ {
42
+ path: '.codex-plugin/plugin.json',
43
+ content: `${JSON.stringify(manifest, null, 2)}\n`,
44
+ },
45
+ ];
46
+ }
47
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/targets/codex/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EACL,kBAAkB,EAClB,cAAc,GAGf,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,UAAkB,EAClB,OAA8B,EAAE;IAEhC,MAAM,WAAW,GAAG,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACzD,MAAM,QAAQ,GAA4B;QACxC,aAAa,EAAE,cAAc;QAC7B,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;QAChB,yFAAyF;QACzF,0FAA0F;QAC1F,GAAG,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/C,CAAC;IAEF,OAAO;QACL;YACE,IAAI,EAAE,2BAA2B;YACjC,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI;SAClD;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Zod schemas for the OpenAI Codex CLI target manifests.
3
+ *
4
+ * These schemas are internal to @ai-plugin-marketplace/core — they are not exported from the
5
+ * package root. Per §3.4 of the architecture spec, this module must not import from any sibling
6
+ * targets/<other>/ folder, so the shapes are intentionally duplicated from the Claude target
7
+ * (rather than imported) and may diverge independently in the future.
8
+ *
9
+ * Codex is an in-place marketplace target like Claude/Cursor: its plugin manifest lives at
10
+ * `.codex-plugin/plugin.json` and is consumed in place (no `dist/` bundle, no mechanical
11
+ * transform). The field list mirrors Claude's `.claude-plugin/plugin.json` with two
12
+ * Codex-specific additions documented at developers.openai.com/codex/plugins/build:
13
+ *
14
+ * - `interface` — an optional loose object describing the plugin's presentation in the Codex
15
+ * marketplace UI (displayName, category, capabilities, …). Loose because the field set is
16
+ * UI-driven and free to grow.
17
+ * - `apps` — an optional relative path string pointing at an apps directory.
18
+ *
19
+ * `skills`/`agents`/`commands`/`hooks` accept exactly what Claude accepts (relative path string,
20
+ * array of relative path strings, or — for hooks/commands — an inline object), plus Codex's
21
+ * tolerance for a plain string wherever Claude already accepts one.
22
+ *
23
+ * @see https://developers.openai.com/codex/plugins/build
24
+ */
25
+ import { z } from 'zod';
26
+ /**
27
+ * Schema for `.codex-plugin/plugin.json`.
28
+ *
29
+ * Mirrors Claude's plugin manifest (same `name` pattern, optional `version`/`description`/etc.)
30
+ * with Codex's optional `interface` (loose object) and `apps` (relative path string) fields.
31
+ * Strict (`additionalProperties: false`) at the top level so unknown keys are rejected.
32
+ * `schemaVersion` is accepted but not validated (§9.4 / §12.2).
33
+ */
34
+ export declare const codexPluginManifestSchema: z.ZodObject<{
35
+ schemaVersion: z.ZodOptional<z.ZodString>;
36
+ name: z.ZodString;
37
+ version: z.ZodOptional<z.ZodString>;
38
+ description: z.ZodOptional<z.ZodString>;
39
+ author: z.ZodOptional<z.ZodObject<{
40
+ name: z.ZodString;
41
+ email: z.ZodOptional<z.ZodString>;
42
+ url: z.ZodOptional<z.ZodString>;
43
+ }, z.core.$strict>>;
44
+ homepage: z.ZodOptional<z.ZodString>;
45
+ repository: z.ZodOptional<z.ZodString>;
46
+ license: z.ZodOptional<z.ZodString>;
47
+ keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
48
+ hooks: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
49
+ commands: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
50
+ agents: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
51
+ skills: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
52
+ mcpServers: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
53
+ apps: z.ZodOptional<z.ZodString>;
54
+ interface: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
55
+ }, z.core.$strict>;
56
+ /**
57
+ * Schema for `.mcp.json` (the MCP configuration Codex reads — identical to Claude's format).
58
+ *
59
+ * `mcpServers` maps server name → server config. Strict at the top level.
60
+ * `schemaVersion` accepted but not validated per §9.4 / §12.2.
61
+ */
62
+ export declare const codexMcpConfigSchema: z.ZodObject<{
63
+ schemaVersion: z.ZodOptional<z.ZodString>;
64
+ mcpServers: z.ZodRecord<z.ZodString, z.ZodObject<{
65
+ command: z.ZodString;
66
+ args: z.ZodOptional<z.ZodArray<z.ZodString>>;
67
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
68
+ }, z.core.$strict>>;
69
+ }, z.core.$strict>;
70
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/targets/codex/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsBxB;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;kBA4F3B,CAAC;AAkBZ;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;kBAOtB,CAAC"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Zod schemas for the OpenAI Codex CLI target manifests.
3
+ *
4
+ * These schemas are internal to @ai-plugin-marketplace/core — they are not exported from the
5
+ * package root. Per §3.4 of the architecture spec, this module must not import from any sibling
6
+ * targets/<other>/ folder, so the shapes are intentionally duplicated from the Claude target
7
+ * (rather than imported) and may diverge independently in the future.
8
+ *
9
+ * Codex is an in-place marketplace target like Claude/Cursor: its plugin manifest lives at
10
+ * `.codex-plugin/plugin.json` and is consumed in place (no `dist/` bundle, no mechanical
11
+ * transform). The field list mirrors Claude's `.claude-plugin/plugin.json` with two
12
+ * Codex-specific additions documented at developers.openai.com/codex/plugins/build:
13
+ *
14
+ * - `interface` — an optional loose object describing the plugin's presentation in the Codex
15
+ * marketplace UI (displayName, category, capabilities, …). Loose because the field set is
16
+ * UI-driven and free to grow.
17
+ * - `apps` — an optional relative path string pointing at an apps directory.
18
+ *
19
+ * `skills`/`agents`/`commands`/`hooks` accept exactly what Claude accepts (relative path string,
20
+ * array of relative path strings, or — for hooks/commands — an inline object), plus Codex's
21
+ * tolerance for a plain string wherever Claude already accepts one.
22
+ *
23
+ * @see https://developers.openai.com/codex/plugins/build
24
+ */
25
+ import { z } from 'zod';
26
+ // ---------------------------------------------------------------------------
27
+ // Shared sub-schemas
28
+ // ---------------------------------------------------------------------------
29
+ /**
30
+ * Author object in the plugin manifest. Strict per the canonical JSON Schema
31
+ * (`additionalProperties: false`).
32
+ */
33
+ const codexPluginAuthorSchema = z
34
+ .object({
35
+ name: z.string(),
36
+ email: z.string().optional(),
37
+ url: z.string().optional(),
38
+ })
39
+ .strict();
40
+ // ---------------------------------------------------------------------------
41
+ // codexPluginManifestSchema
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * Schema for `.codex-plugin/plugin.json`.
45
+ *
46
+ * Mirrors Claude's plugin manifest (same `name` pattern, optional `version`/`description`/etc.)
47
+ * with Codex's optional `interface` (loose object) and `apps` (relative path string) fields.
48
+ * Strict (`additionalProperties: false`) at the top level so unknown keys are rejected.
49
+ * `schemaVersion` is accepted but not validated (§9.4 / §12.2).
50
+ */
51
+ export const codexPluginManifestSchema = z
52
+ .object({
53
+ /** Reserved for future migrex adoption. Accepted but not validated in v0.1.0. */
54
+ schemaVersion: z.string().optional(),
55
+ /** Plugin name: lowercase, hyphens, no spaces; must start with a letter. Max 64 chars. */
56
+ name: z
57
+ .string()
58
+ .regex(/^[a-z][a-z0-9-]*$/, 'name must be lowercase alphanumeric with hyphens, starting with a letter')
59
+ .max(64),
60
+ /** Semantic version string (optional). */
61
+ version: z
62
+ .string()
63
+ .regex(/^\d+\.\d+\.\d+/, 'version must be a valid semver string')
64
+ .optional(),
65
+ /** What this plugin does. */
66
+ description: z.string().min(1).max(1024).optional(),
67
+ /** Plugin author information. */
68
+ author: codexPluginAuthorSchema.optional(),
69
+ /** Plugin homepage URL. */
70
+ homepage: z.string().optional(),
71
+ /** Source repository URL or shorthand. */
72
+ repository: z.string().optional(),
73
+ /** SPDX license identifier. */
74
+ license: z.string().optional(),
75
+ /** Discovery keywords. */
76
+ keywords: z.array(z.string()).optional(),
77
+ /**
78
+ * Hooks configuration — relative path to a `.json` file (must start with `./` and end
79
+ * with `.json`), or an inline hooks configuration object. Codex hook generation is out of
80
+ * scope for v0.1.0; the field is accepted but not exercised by the scaffolder.
81
+ */
82
+ hooks: z
83
+ .union([z.string().regex(/^\.\/.*\.json$/), z.record(z.string(), z.unknown())])
84
+ .optional(),
85
+ /**
86
+ * Commands — relative path starting with `./`, an array of such paths, or a record of
87
+ * command name → command object.
88
+ */
89
+ commands: z
90
+ .union([
91
+ z.string().regex(/^\.\//),
92
+ z.array(z.string().regex(/^\.\//)),
93
+ z.record(z.string(), z.unknown()),
94
+ ])
95
+ .optional(),
96
+ /**
97
+ * Agent definitions — relative `.md` path or array of such paths.
98
+ * Must start with `./` and end with `.md`.
99
+ */
100
+ agents: z
101
+ .union([z.string().regex(/^\.\/.+\.md$/), z.array(z.string().regex(/^\.\/.+\.md$/))])
102
+ .optional(),
103
+ /**
104
+ * Skill definitions — relative path to a skill directory or array of such paths.
105
+ * Must start with `./`. Codex tolerates a single string (e.g. "./skills/") as well as the
106
+ * array form Claude uses.
107
+ */
108
+ skills: z.union([z.string().regex(/^\.\//), z.array(z.string().regex(/^\.\//))]).optional(),
109
+ /**
110
+ * MCP server configuration — relative path string to a `.mcp.json` (Codex consumes the
111
+ * shared Claude/Cursor format) or an inline record of server configs.
112
+ */
113
+ mcpServers: z.union([z.string().regex(/^\.\//), z.record(z.string(), z.unknown())]).optional(),
114
+ /**
115
+ * Apps — relative path string to an apps directory (Codex-specific). Must start with `./`.
116
+ */
117
+ apps: z.string().regex(/^\.\//).optional(),
118
+ /**
119
+ * Marketplace presentation metadata (displayName, category, capabilities, websiteURL,
120
+ * defaultPrompt, brandColor, logo, screenshots, …). Loose: the field set is UI-driven and
121
+ * free to grow, so unknown keys are tolerated rather than rejected.
122
+ */
123
+ interface: z.object({}).loose().optional(),
124
+ })
125
+ .strict();
126
+ // ---------------------------------------------------------------------------
127
+ // codexMcpConfigSchema
128
+ // ---------------------------------------------------------------------------
129
+ /**
130
+ * Schema for a single MCP server entry. Strict: only `command`, `args`, and `env` are
131
+ * accepted — matching the shared `.mcp.json` format Codex reuses from Claude/Cursor.
132
+ */
133
+ const codexMcpServerSchema = z
134
+ .object({
135
+ command: z.string(),
136
+ args: z.array(z.string()).optional(),
137
+ env: z.record(z.string(), z.string()).optional(),
138
+ })
139
+ .strict();
140
+ /**
141
+ * Schema for `.mcp.json` (the MCP configuration Codex reads — identical to Claude's format).
142
+ *
143
+ * `mcpServers` maps server name → server config. Strict at the top level.
144
+ * `schemaVersion` accepted but not validated per §9.4 / §12.2.
145
+ */
146
+ export const codexMcpConfigSchema = z
147
+ .object({
148
+ /** Reserved for future migrex adoption. Accepted but not validated in v0.1.0. */
149
+ schemaVersion: z.string().optional(),
150
+ mcpServers: z.record(z.string(), codexMcpServerSchema),
151
+ })
152
+ .strict();
153
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../src/targets/codex/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Per-target validator for the OpenAI Codex CLI target.
3
+ *
4
+ * Responsibilities (v0.1.0):
5
+ * 1. Manifest file refs resolve — checks that paths in .codex-plugin/plugin.json exist on disk
6
+ * with the correct type (directory for skills, .md for agents, either for commands). Hooks
7
+ * and apps refs are intentionally excluded: Codex hook/app generation is out of scope for
8
+ * v0.1.0, so those paths are not guaranteed to exist in a Codex-only build context.
9
+ *
10
+ * Cross-target concerns (envelope adherence, name consistency, MCP key sync, marketplace
11
+ * registration, freshness) are NOT checked here.
12
+ *
13
+ * @see https://developers.openai.com/codex/plugins/build
14
+ * @see packages/core/docs/specs/architecture.md §10 (validation contract)
15
+ * @see packages/core/docs/specs/architecture.md §8.1 (Finding, FindingCode)
16
+ */
17
+ import type { Finding } from '../../pipeline/types.js';
18
+ /**
19
+ * Run all Codex-specific validators against a plugin directory.
20
+ *
21
+ * `pluginDir` is the absolute path to a `plugins/<name>/` directory.
22
+ * All findings use `plugin: path.basename(pluginDir)`.
23
+ */
24
+ export declare function validateCodexPlugin(pluginDir: string): Finding[];
25
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/targets/codex/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AA4IvD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,CAGhE"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Per-target validator for the OpenAI Codex CLI target.
3
+ *
4
+ * Responsibilities (v0.1.0):
5
+ * 1. Manifest file refs resolve — checks that paths in .codex-plugin/plugin.json exist on disk
6
+ * with the correct type (directory for skills, .md for agents, either for commands). Hooks
7
+ * and apps refs are intentionally excluded: Codex hook/app generation is out of scope for
8
+ * v0.1.0, so those paths are not guaranteed to exist in a Codex-only build context.
9
+ *
10
+ * Cross-target concerns (envelope adherence, name consistency, MCP key sync, marketplace
11
+ * registration, freshness) are NOT checked here.
12
+ *
13
+ * @see https://developers.openai.com/codex/plugins/build
14
+ * @see packages/core/docs/specs/architecture.md §10 (validation contract)
15
+ * @see packages/core/docs/specs/architecture.md §8.1 (Finding, FindingCode)
16
+ */
17
+ import * as fs from 'node:fs';
18
+ import * as path from 'node:path';
19
+ import { codexPluginManifestSchema } from './schemas.js';
20
+ // ---------------------------------------------------------------------------
21
+ // Helpers
22
+ // ---------------------------------------------------------------------------
23
+ function makeInvalid(plugin, message, hint) {
24
+ const finding = { severity: 'hard', code: 'schema-invalid', plugin, message };
25
+ if (hint !== undefined)
26
+ finding.hint = hint;
27
+ return finding;
28
+ }
29
+ /**
30
+ * Normalise a manifest field that may be a single string path, an array of string paths, or an
31
+ * inline object (which has no resolvable paths). Returns only the string path entries.
32
+ */
33
+ function normalisePathField(value) {
34
+ if (value === undefined)
35
+ return [];
36
+ if (typeof value === 'string')
37
+ return [value];
38
+ if (Array.isArray(value))
39
+ return value.filter((v) => typeof v === 'string');
40
+ // Inline object (record of commands, inline hooks object) — no paths to check.
41
+ return [];
42
+ }
43
+ // ---------------------------------------------------------------------------
44
+ // Manifest file-ref validation
45
+ // ---------------------------------------------------------------------------
46
+ function validateManifestFileRefs(pluginDir, pluginName) {
47
+ const manifestPath = path.join(pluginDir, '.codex-plugin', 'plugin.json');
48
+ if (!fs.existsSync(manifestPath))
49
+ return [];
50
+ let raw;
51
+ try {
52
+ raw = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
53
+ }
54
+ catch {
55
+ return [
56
+ makeInvalid(pluginName, `.codex-plugin/plugin.json is not valid JSON`, 'Ensure the file is well-formed JSON.'),
57
+ ];
58
+ }
59
+ const parsed = codexPluginManifestSchema.safeParse(raw);
60
+ if (!parsed.success) {
61
+ const issues = parsed.error.issues.map((i) => i.message).join('; ');
62
+ return [
63
+ makeInvalid(pluginName, `.codex-plugin/plugin.json failed schema validation: ${issues}`, 'Verify the manifest fields match the codex plugin manifest schema.'),
64
+ ];
65
+ }
66
+ const manifest = parsed.data;
67
+ const findings = [];
68
+ // Ref groups: skills → directory, agents → .md file, commands → either.
69
+ // hooks/apps are intentionally excluded — Codex hook/app generation is out of scope for
70
+ // v0.1.0, so those paths are not guaranteed present in a Codex-only build context.
71
+ const refGroups = [
72
+ { field: 'skills', paths: normalisePathField(manifest.skills), mustBeDir: true },
73
+ { field: 'agents', paths: normalisePathField(manifest.agents), mustBeDir: false },
74
+ { field: 'commands', paths: normalisePathField(manifest.commands) },
75
+ ];
76
+ for (const { field, paths: refPaths, mustBeDir } of refGroups) {
77
+ for (const refPath of refPaths) {
78
+ // All manifest paths must start with "./"
79
+ if (!refPath.startsWith('./')) {
80
+ findings.push(makeInvalid(pluginName, `.codex-plugin/plugin.json: ${field} path must start with "./": ${refPath}`, `Change the path to start with "./" (e.g. "./${refPath.replace(/^\/+/, '')}").`));
81
+ continue;
82
+ }
83
+ // Paths must not contain ".." segments (path traversal guard)
84
+ if (refPath.includes('..')) {
85
+ findings.push(makeInvalid(pluginName, `.codex-plugin/plugin.json: ${field} path must not contain "..": ${refPath}`, 'Use a path relative to the plugin root without ".." traversal.'));
86
+ continue;
87
+ }
88
+ const resolved = path.join(pluginDir, refPath.slice(2));
89
+ if (!fs.existsSync(resolved)) {
90
+ findings.push(makeInvalid(pluginName, `.codex-plugin/plugin.json: ${field} references non-existent path: ${refPath}`, `Create the missing ${field === 'skills' ? 'directory' : 'file'} at ${resolved}.`));
91
+ continue;
92
+ }
93
+ const stat = fs.statSync(resolved);
94
+ if (mustBeDir === true && !stat.isDirectory()) {
95
+ findings.push(makeInvalid(pluginName, `.codex-plugin/plugin.json: ${field} path must be a directory, but a file was found: ${refPath}`, `The ${field} field expects a directory path, not a file path.`));
96
+ }
97
+ else if (mustBeDir === false && !stat.isFile()) {
98
+ findings.push(makeInvalid(pluginName, `.codex-plugin/plugin.json: ${field} path must be a file, but a directory was found: ${refPath}`, `The ${field} field expects a file path, not a directory path.`));
99
+ }
100
+ }
101
+ }
102
+ return findings;
103
+ }
104
+ // ---------------------------------------------------------------------------
105
+ // Public API
106
+ // ---------------------------------------------------------------------------
107
+ /**
108
+ * Run all Codex-specific validators against a plugin directory.
109
+ *
110
+ * `pluginDir` is the absolute path to a `plugins/<name>/` directory.
111
+ * All findings use `plugin: path.basename(pluginDir)`.
112
+ */
113
+ export function validateCodexPlugin(pluginDir) {
114
+ const pluginName = path.basename(pluginDir);
115
+ return [...validateManifestFileRefs(pluginDir, pluginName)];
116
+ }
117
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/targets/codex/validate.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-plugin-marketplace/core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Core build pipeline, validation, and scaffolding for the AI plugin marketplace toolkit.",
5
5
  "type": "module",
6
6
  "author": "Mike North <michael.l.north@gmail.com>",