@ai-plugin-marketplace/core 0.1.0 → 0.3.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 (61) 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 +187 -4
  6. package/dist/index.d.ts +4 -4
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -2
  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/init-template.d.ts +16 -5
  19. package/dist/pipeline/init-template.d.ts.map +1 -1
  20. package/dist/pipeline/init-template.js +65 -21
  21. package/dist/pipeline/init-template.js.map +1 -1
  22. package/dist/pipeline/init.d.ts +17 -14
  23. package/dist/pipeline/init.d.ts.map +1 -1
  24. package/dist/pipeline/init.js +23 -15
  25. package/dist/pipeline/init.js.map +1 -1
  26. package/dist/pipeline/load-config.d.ts +62 -2
  27. package/dist/pipeline/load-config.d.ts.map +1 -1
  28. package/dist/pipeline/load-config.js +147 -30
  29. package/dist/pipeline/load-config.js.map +1 -1
  30. package/dist/pipeline/operations.d.ts +15 -3
  31. package/dist/pipeline/operations.d.ts.map +1 -1
  32. package/dist/pipeline/operations.js +25 -4
  33. package/dist/pipeline/operations.js.map +1 -1
  34. package/dist/pipeline/scaffold-refresh.d.ts +80 -0
  35. package/dist/pipeline/scaffold-refresh.d.ts.map +1 -0
  36. package/dist/pipeline/scaffold-refresh.js +152 -0
  37. package/dist/pipeline/scaffold-refresh.js.map +1 -0
  38. package/dist/pipeline/scaffold.d.ts.map +1 -1
  39. package/dist/pipeline/scaffold.js +55 -26
  40. package/dist/pipeline/scaffold.js.map +1 -1
  41. package/dist/pipeline/types.d.ts +51 -3
  42. package/dist/pipeline/types.d.ts.map +1 -1
  43. package/dist/pipeline/types.js +1 -0
  44. package/dist/pipeline/types.js.map +1 -1
  45. package/dist/pipeline/validate.d.ts +12 -2
  46. package/dist/pipeline/validate.d.ts.map +1 -1
  47. package/dist/pipeline/validate.js +342 -38
  48. package/dist/pipeline/validate.js.map +1 -1
  49. package/dist/targets/codex/scaffold.d.ts +31 -0
  50. package/dist/targets/codex/scaffold.d.ts.map +1 -0
  51. package/dist/targets/codex/scaffold.js +47 -0
  52. package/dist/targets/codex/scaffold.js.map +1 -0
  53. package/dist/targets/codex/schemas.d.ts +70 -0
  54. package/dist/targets/codex/schemas.d.ts.map +1 -0
  55. package/dist/targets/codex/schemas.js +153 -0
  56. package/dist/targets/codex/schemas.js.map +1 -0
  57. package/dist/targets/codex/validate.d.ts +25 -0
  58. package/dist/targets/codex/validate.d.ts.map +1 -0
  59. package/dist/targets/codex/validate.js +117 -0
  60. package/dist/targets/codex/validate.js.map +1 -0
  61. package/package.json +1 -1
package/dist/config.d.ts CHANGED
@@ -18,6 +18,18 @@ export interface AipmConfigInput {
18
18
  version: string;
19
19
  /** Targets this plugin supports. See §6 of the spec. */
20
20
  targets: readonly TargetId[];
21
+ /**
22
+ * Optional one-line description of the plugin. When the repo opts into registry generation (an
23
+ * `aipm.workspace.ts` is present), this becomes the plugin entry's `description` (Claude/Cursor)
24
+ * in the generated `marketplace.json`. Optional so existing configs stay valid.
25
+ */
26
+ description?: string;
27
+ /**
28
+ * Optional discovery keywords for the plugin. When the repo opts into registry generation, these
29
+ * become the plugin entry's `tags` (Claude/Cursor) in the generated `marketplace.json`. Optional
30
+ * so existing configs stay valid.
31
+ */
32
+ keywords?: readonly string[];
21
33
  }
22
34
  /**
23
35
  * Module-private brand marker. Intentionally never exported (§8.1: "The brand symbol is
@@ -43,5 +55,105 @@ export type AipmConfig = AipmConfigInput & {
43
55
  * @public
44
56
  */
45
57
  export declare function defineConfig(config: AipmConfigInput): AipmConfig;
58
+ /**
59
+ * Raw input shape accepted by `defineRepoConfig`. Authored as `aipm.repo.ts` at the **repo
60
+ * root** of a project that hosts a marketplace inside a larger software repo. The file is
61
+ * optional: when absent, the toolkit behaves as if `defineRepoConfig({})` was used, reproducing
62
+ * the historical "repo root == marketplace root, fixed `plugins/`" topology.
63
+ *
64
+ * Both paths are repo-root-relative and must stay within the repo (no absolute paths, no `..`
65
+ * segments), because host platforms resolve a plugin's `source` relative to the repo root.
66
+ *
67
+ * @public
68
+ */
69
+ export interface AipmRepoConfigInput {
70
+ /**
71
+ * Directory (relative to the repo root) that holds plugin folders. Relocate this when the host
72
+ * software already owns a top-level `plugins/` directory. Default: `'plugins'`.
73
+ */
74
+ pluginsRoot?: string;
75
+ /**
76
+ * Directory (relative to the repo root) for generated `dist/` bundles. Relocate this when the
77
+ * host software already owns a top-level `dist/`. Default: `'dist'`.
78
+ */
79
+ distDir?: string;
80
+ }
81
+ /**
82
+ * Module-private brand marker for {@link AipmRepoConfig}. Never exported.
83
+ *
84
+ * @internal
85
+ */
86
+ declare const aipmRepoConfigBrand: unique symbol;
87
+ /**
88
+ * Validated repo configuration. Carries a module-private brand indicating `defineRepoConfig`
89
+ * validated it; unlike the input, both fields are always present (defaults applied).
90
+ *
91
+ * @public
92
+ */
93
+ export type AipmRepoConfig = {
94
+ readonly pluginsRoot: string;
95
+ readonly distDir: string;
96
+ } & {
97
+ readonly [aipmRepoConfigBrand]: 'AipmRepoConfig';
98
+ };
99
+ /**
100
+ * Validate and brand a repo configuration, applying defaults for any omitted field. Throws a
101
+ * `ZodError` on invalid input (unknown keys, absolute paths, `..` escapes).
102
+ *
103
+ * @public
104
+ */
105
+ export declare function defineRepoConfig(config?: AipmRepoConfigInput): AipmRepoConfig;
106
+ /**
107
+ * Raw input shape accepted by `defineWorkspace`. Authored as `aipm.workspace.ts` at the **repo
108
+ * root**. Its presence opts the repo into **marketplace-registry generation**: the toolkit
109
+ * generates the per-target `marketplace.json` registries from this workspace metadata plus the
110
+ * discovered plugins, commits them, and freshness-checks them. When the file is **absent**, the
111
+ * toolkit behaves exactly as before (registries are hand-authored and `validateMarketplaceRegistration`
112
+ * runs).
113
+ *
114
+ * @public
115
+ */
116
+ export interface AipmWorkspaceInput {
117
+ /** Marketplace-level metadata shared across all generated registries. */
118
+ marketplace: {
119
+ /** Marketplace name — the registry's top-level `name`. */
120
+ name: string;
121
+ /**
122
+ * Optional owner block written to the Claude/Cursor registries' top-level `owner`. The Codex
123
+ * registry has no owner concept, so this is ignored there.
124
+ */
125
+ owner?: {
126
+ name: string;
127
+ email?: string;
128
+ };
129
+ /**
130
+ * Optional marketplace description. For Claude/Cursor it becomes `metadata.description`; for
131
+ * Codex it is currently unused (the Codex registry has no marketplace-level description field).
132
+ */
133
+ description?: string;
134
+ };
135
+ }
136
+ /**
137
+ * Module-private brand marker for {@link AipmWorkspace}. Never exported.
138
+ *
139
+ * @internal
140
+ */
141
+ declare const aipmWorkspaceBrand: unique symbol;
142
+ /**
143
+ * Validated workspace configuration. Structurally identical to {@link AipmWorkspaceInput} but
144
+ * carries a module-private brand indicating `defineWorkspace` validated it at runtime.
145
+ *
146
+ * @public
147
+ */
148
+ export type AipmWorkspace = AipmWorkspaceInput & {
149
+ readonly [aipmWorkspaceBrand]: 'AipmWorkspace';
150
+ };
151
+ /**
152
+ * Validate and brand a workspace configuration. Throws a `ZodError` on invalid input (unknown
153
+ * keys, missing `marketplace.name`).
154
+ *
155
+ * @public
156
+ */
157
+ export declare function defineWorkspace(config: AipmWorkspaceInput): AipmWorkspace;
46
158
  export {};
47
159
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,OAAO,CAAC,MAAM,eAAe,EAAE,OAAO,MAAM,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG;IACzC,QAAQ,CAAC,CAAC,eAAe,CAAC,EAAE,YAAY,CAAC;CAC1C,CAAC;AAqBF;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,UAAU,CAKhE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC7B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,OAAO,CAAC,MAAM,eAAe,EAAE,OAAO,MAAM,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG;IACzC,QAAQ,CAAC,CAAC,eAAe,CAAC,EAAE,YAAY,CAAC;CAC1C,CAAC;AAuBF;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,UAAU,CAKhE;AAMD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,OAAO,CAAC,MAAM,mBAAmB,EAAE,OAAO,MAAM,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,GAAG;IAAE,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAuBzD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,mBAAwB,GAAG,cAAc,CAGjF;AAMD;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,WAAW,EAAE;QACX,0DAA0D;QAC1D,IAAI,EAAE,MAAM,CAAC;QACb;;;WAGG;QACH,KAAK,CAAC,EAAE;YACN,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;QACF;;;WAGG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;;;GAIG;AACH,OAAO,CAAC,MAAM,kBAAkB,EAAE,OAAO,MAAM,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,kBAAkB,GAAG;IAC/C,QAAQ,CAAC,CAAC,kBAAkB,CAAC,EAAE,eAAe,CAAC;CAChD,CAAC;AAoBF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,GAAG,aAAa,CAGzE"}
package/dist/config.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * `AipmConfig` as `AipmConfigInput` plus a structural marker proving `defineConfig` validated
7
7
  * the value.
8
8
  */
9
+ import * as path from 'node:path';
9
10
  import { z } from 'zod';
10
11
  import { TARGET_IDS } from './pipeline/types.js';
11
12
  /**
@@ -22,6 +23,8 @@ const aipmConfigSchema = z
22
23
  .array(z.enum(TARGET_IDS))
23
24
  .min(1, 'targets must contain at least one target')
24
25
  .refine((arr) => new Set(arr).size === arr.length, 'targets must not contain duplicates'),
26
+ description: z.string().optional(),
27
+ keywords: z.array(z.string()).optional(),
25
28
  })
26
29
  .strict();
27
30
  /**
@@ -35,4 +38,57 @@ export function defineConfig(config) {
35
38
  // type-only marker proving validation ran. Cast through `unknown` per TS guidance.
36
39
  return parsed;
37
40
  }
41
+ /**
42
+ * A repo-relative path that is safe to join onto the repo root: non-empty, not absolute, and
43
+ * containing no `..` segment that could escape the repo. Host platforms resolve plugin `source`
44
+ * paths relative to the repo root, so an escaping root would be unrepresentable.
45
+ */
46
+ const repoRelativePath = z
47
+ .string()
48
+ .min(1, 'path must not be empty')
49
+ .refine((p) => !path.isAbsolute(p), 'path must be relative to the repo root, not absolute')
50
+ .refine((p) => !p.split(/[\\/]/).includes('..'), "path must not contain a '..' segment (it must stay within the repo root)");
51
+ const aipmRepoConfigSchema = z
52
+ .object({
53
+ pluginsRoot: repoRelativePath.default('plugins'),
54
+ distDir: repoRelativePath.default('dist'),
55
+ })
56
+ .strict();
57
+ /**
58
+ * Validate and brand a repo configuration, applying defaults for any omitted field. Throws a
59
+ * `ZodError` on invalid input (unknown keys, absolute paths, `..` escapes).
60
+ *
61
+ * @public
62
+ */
63
+ export function defineRepoConfig(config = {}) {
64
+ const parsed = aipmRepoConfigSchema.parse(config);
65
+ return parsed;
66
+ }
67
+ const aipmWorkspaceSchema = z
68
+ .object({
69
+ marketplace: z
70
+ .object({
71
+ name: z.string().min(1, 'marketplace.name must not be empty'),
72
+ owner: z
73
+ .object({
74
+ name: z.string().min(1, 'marketplace.owner.name must not be empty'),
75
+ email: z.string().optional(),
76
+ })
77
+ .strict()
78
+ .optional(),
79
+ description: z.string().optional(),
80
+ })
81
+ .strict(),
82
+ })
83
+ .strict();
84
+ /**
85
+ * Validate and brand a workspace configuration. Throws a `ZodError` on invalid input (unknown
86
+ * keys, missing `marketplace.name`).
87
+ *
88
+ * @public
89
+ */
90
+ export function defineWorkspace(config) {
91
+ const parsed = aipmWorkspaceSchema.parse(config);
92
+ return parsed;
93
+ }
38
94
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAmCjD;;;;;GAKG;AACH,MAAM,aAAa,GACjB,qFAAqF,CAAC;AAExF,MAAM,gBAAgB,GAAG,CAAC;KACvB,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,uCAAuC,CAAC;IACjF,OAAO,EAAE,CAAC;SACP,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SACzB,GAAG,CAAC,CAAC,EAAE,0CAA0C,CAAC;SAClD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,MAAM,EAAE,qCAAqC,CAAC;CAC5F,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAuB;IAClD,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9C,oFAAoF;IACpF,mFAAmF;IACnF,OAAO,MAA+B,CAAC;AACzC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/core.d.ts CHANGED
@@ -47,6 +47,110 @@ export declare interface AipmConfigInput {
47
47
  version: string;
48
48
  /** Targets this plugin supports. See §6 of the spec. */
49
49
  targets: readonly TargetId[];
50
+ /**
51
+ * Optional one-line description of the plugin. When the repo opts into registry generation (an
52
+ * `aipm.workspace.ts` is present), this becomes the plugin entry's `description` (Claude/Cursor)
53
+ * in the generated `marketplace.json`. Optional so existing configs stay valid.
54
+ */
55
+ description?: string;
56
+ /**
57
+ * Optional discovery keywords for the plugin. When the repo opts into registry generation, these
58
+ * become the plugin entry's `tags` (Claude/Cursor) in the generated `marketplace.json`. Optional
59
+ * so existing configs stay valid.
60
+ */
61
+ keywords?: readonly string[];
62
+ }
63
+
64
+ /**
65
+ * Validated repo configuration. Carries a module-private brand indicating `defineRepoConfig`
66
+ * validated it; unlike the input, both fields are always present (defaults applied).
67
+ *
68
+ * @public
69
+ */
70
+ export declare type AipmRepoConfig = {
71
+ readonly pluginsRoot: string;
72
+ readonly distDir: string;
73
+ } & {
74
+ readonly [aipmRepoConfigBrand]: 'AipmRepoConfig';
75
+ };
76
+
77
+ /**
78
+ * Module-private brand marker for {@link AipmRepoConfig}. Never exported.
79
+ *
80
+ * @internal
81
+ */
82
+ declare const aipmRepoConfigBrand: unique symbol;
83
+
84
+ /**
85
+ * Raw input shape accepted by `defineRepoConfig`. Authored as `aipm.repo.ts` at the **repo
86
+ * root** of a project that hosts a marketplace inside a larger software repo. The file is
87
+ * optional: when absent, the toolkit behaves as if `defineRepoConfig({})` was used, reproducing
88
+ * the historical "repo root == marketplace root, fixed `plugins/`" topology.
89
+ *
90
+ * Both paths are repo-root-relative and must stay within the repo (no absolute paths, no `..`
91
+ * segments), because host platforms resolve a plugin's `source` relative to the repo root.
92
+ *
93
+ * @public
94
+ */
95
+ export declare interface AipmRepoConfigInput {
96
+ /**
97
+ * Directory (relative to the repo root) that holds plugin folders. Relocate this when the host
98
+ * software already owns a top-level `plugins/` directory. Default: `'plugins'`.
99
+ */
100
+ pluginsRoot?: string;
101
+ /**
102
+ * Directory (relative to the repo root) for generated `dist/` bundles. Relocate this when the
103
+ * host software already owns a top-level `dist/`. Default: `'dist'`.
104
+ */
105
+ distDir?: string;
106
+ }
107
+
108
+ /**
109
+ * Validated workspace configuration. Structurally identical to {@link AipmWorkspaceInput} but
110
+ * carries a module-private brand indicating `defineWorkspace` validated it at runtime.
111
+ *
112
+ * @public
113
+ */
114
+ export declare type AipmWorkspace = AipmWorkspaceInput & {
115
+ readonly [aipmWorkspaceBrand]: 'AipmWorkspace';
116
+ };
117
+
118
+ /**
119
+ * Module-private brand marker for {@link AipmWorkspace}. Never exported.
120
+ *
121
+ * @internal
122
+ */
123
+ declare const aipmWorkspaceBrand: unique symbol;
124
+
125
+ /**
126
+ * Raw input shape accepted by `defineWorkspace`. Authored as `aipm.workspace.ts` at the **repo
127
+ * root**. Its presence opts the repo into **marketplace-registry generation**: the toolkit
128
+ * generates the per-target `marketplace.json` registries from this workspace metadata plus the
129
+ * discovered plugins, commits them, and freshness-checks them. When the file is **absent**, the
130
+ * toolkit behaves exactly as before (registries are hand-authored and `validateMarketplaceRegistration`
131
+ * runs).
132
+ *
133
+ * @public
134
+ */
135
+ export declare interface AipmWorkspaceInput {
136
+ /** Marketplace-level metadata shared across all generated registries. */
137
+ marketplace: {
138
+ /** Marketplace name — the registry's top-level `name`. */
139
+ name: string;
140
+ /**
141
+ * Optional owner block written to the Claude/Cursor registries' top-level `owner`. The Codex
142
+ * registry has no owner concept, so this is ignored there.
143
+ */
144
+ owner?: {
145
+ name: string;
146
+ email?: string;
147
+ };
148
+ /**
149
+ * Optional marketplace description. For Claude/Cursor it becomes `metadata.description`; for
150
+ * Codex it is currently unused (the Codex registry has no marketplace-level description field).
151
+ */
152
+ description?: string;
153
+ };
50
154
  }
51
155
 
52
156
  /**
@@ -98,6 +202,22 @@ export declare function checkSupport(pluginDir: string): Promise<SupportReport>;
98
202
  */
99
203
  export declare function defineConfig(config: AipmConfigInput): AipmConfig;
100
204
 
205
+ /**
206
+ * Validate and brand a repo configuration, applying defaults for any omitted field. Throws a
207
+ * `ZodError` on invalid input (unknown keys, absolute paths, `..` escapes).
208
+ *
209
+ * @public
210
+ */
211
+ export declare function defineRepoConfig(config?: AipmRepoConfigInput): AipmRepoConfig;
212
+
213
+ /**
214
+ * Validate and brand a workspace configuration. Throws a `ZodError` on invalid input (unknown
215
+ * keys, missing `marketplace.name`).
216
+ *
217
+ * @public
218
+ */
219
+ export declare function defineWorkspace(config: AipmWorkspaceInput): AipmWorkspace;
220
+
101
221
  /**
102
222
  * A single validation finding.
103
223
  *
@@ -118,9 +238,19 @@ export declare interface Finding {
118
238
  * Enumerated finding codes. Additive — new codes arrive in toolkit MINOR releases; removing
119
239
  * or renaming a code is MAJOR. Consumers SHOULD handle unknown codes gracefully.
120
240
  *
241
+ * `single-artifact-host` — a "single-artifact host" (`gemini` or `kiro`), which installs ONE
242
+ * extension/power per repo from the repo ROOT and has no marketplace concept, is declared by MORE
243
+ * THAN ONE plugin in the repo. The root artifact for that host is NOT emitted while the ambiguity
244
+ * stands (the toolkit can't choose which plugin owns the single root slot).
245
+ *
246
+ * `root-artifact-collision` — a generated repo-root path the toolkit would write is already
247
+ * occupied by a file the toolkit does NOT track as previously-generated (i.e. it belongs to the
248
+ * host software / the author). Generation refuses to overwrite it rather than clobber repo-root
249
+ * state.
250
+ *
121
251
  * @public
122
252
  */
123
- export declare type FindingCode = 'envelope-invalid' | 'envelope-adherence' | 'schema-invalid' | 'name-consistency' | 'mcp-key-sync' | 'marketplace-registration' | 'freshness';
253
+ export declare type FindingCode = 'envelope-invalid' | 'repo-config-invalid' | 'envelope-adherence' | 'schema-invalid' | 'name-consistency' | 'mcp-key-sync' | 'marketplace-registration' | 'freshness' | 'single-artifact-host' | 'root-artifact-collision';
124
254
 
125
255
  /**
126
256
  * A file produced or verified by the build.
@@ -157,6 +287,13 @@ export declare interface InitOptions {
157
287
  * directory.
158
288
  */
159
289
  name?: string;
290
+ /**
291
+ * Version of `@ai-plugin-marketplace/cli` to pin the generated `package.json`'s `cli`
292
+ * dev dependency to (as `^<cliVersion>`). The cli entrypoint supplies its own version here; cli
293
+ * and core ship independently and may differ (e.g. `cli 0.1.1` ships with `core 0.2.0`). When
294
+ * omitted, falls back to core's own version (the historical lockstep assumption).
295
+ */
296
+ cliVersion?: string;
160
297
  }
161
298
 
162
299
  /**
@@ -203,8 +340,54 @@ export declare interface MigrateResult {
203
340
  }
204
341
 
205
342
  /**
206
- * Scaffold a new plugin under `<cwd>/plugins/<name>`. The plugins directory is derived from the
207
- * current working directory, matching how `aipm scaffold` is invoked from a template repo root.
343
+ * Options for {@link refreshScaffold}.
344
+ *
345
+ * @public
346
+ */
347
+ export declare interface RefreshOptions {
348
+ /**
349
+ * Overwrite toolkit-owned scaffold files even when their on-disk content has diverged from what
350
+ * the toolkit last wrote (i.e. the user edited them). Without this, diverged files are reported
351
+ * as conflicts and left untouched.
352
+ */
353
+ force?: boolean;
354
+ }
355
+
356
+ /**
357
+ * Per-file outcome of a {@link refreshScaffold} run. Returned (one per managed scaffold file) so
358
+ * the CLI can report what changed without re-deriving it.
359
+ *
360
+ * @public
361
+ */
362
+ export declare interface RefreshOutcome {
363
+ /** Repo-relative POSIX path of the managed scaffold file. */
364
+ path: string;
365
+ /**
366
+ * - `updated` — content changed and was rewritten (file was pristine or `--force`).
367
+ * - `unchanged` — already matched the current render; nothing written.
368
+ * - `recreated` — file was missing and was written from the render.
369
+ * - `conflict` — on-disk content diverged from the recorded hash; left untouched (no `--force`).
370
+ * - `overwritten` — diverged but rewritten because `--force` was set.
371
+ */
372
+ status: 'updated' | 'unchanged' | 'recreated' | 'conflict' | 'overwritten';
373
+ }
374
+
375
+ /**
376
+ * Refresh the toolkit-owned scaffold files (CI workflow, `.gitignore`) of an existing marketplace
377
+ * repo at `targetDir` to match the installed tooling — the upgrade path after
378
+ * `pnpm up @ai-plugin-marketplace/*`. Guarded by the `.aipm/scaffold.json` content-hash sidecar:
379
+ * user-modified files are reported as conflicts and left untouched unless `opts.force` is set.
380
+ * Returns one outcome per managed file; never rejects on conflict.
381
+ *
382
+ * @public
383
+ */
384
+ export declare function refreshScaffold(targetDir: string, opts?: RefreshOptions): Promise<RefreshOutcome[]>;
385
+
386
+ /**
387
+ * Scaffold a new plugin under the cwd's configured plugins root (`<cwd>/plugins/<name>` by
388
+ * default, or the relocated `pluginsRoot` from an `aipm.repo.ts`). The plugins directory is
389
+ * derived from the current working directory, matching how `aipm scaffold` is invoked from a repo
390
+ * root.
208
391
  *
209
392
  * @public
210
393
  */
@@ -257,7 +440,7 @@ export declare interface SupportReport {
257
440
  *
258
441
  * @public
259
442
  */
260
- export declare type TargetId = 'claude' | 'cursor' | 'gemini' | 'kiro' | 'vercel';
443
+ export declare type TargetId = 'claude' | 'codex' | 'cursor' | 'gemini' | 'kiro' | 'vercel';
261
444
 
262
445
  /**
263
446
  * Validate a single plugin or every plugin under a repo root, in the order defined by §10.1.
package/dist/index.d.ts CHANGED
@@ -8,8 +8,8 @@
8
8
  *
9
9
  * @packageDocumentation
10
10
  */
11
- export { defineConfig } from './config.js';
12
- export type { AipmConfig, AipmConfigInput } from './config.js';
13
- export { build, validate, scaffold, init, migrate, checkSupport, addTarget, listTargets, } from './pipeline/operations.js';
14
- export type { TargetId, BuildOptions, BuildResult, GeneratedFile, ValidateOptions, ValidationResult, Finding, FindingCode, ScaffoldOptions, InitOptions, MigrateOptions, MigrateResult, SupportReport, } from './pipeline/types.js';
11
+ export { defineConfig, defineRepoConfig, defineWorkspace } from './config.js';
12
+ export type { AipmConfig, AipmConfigInput, AipmRepoConfig, AipmRepoConfigInput, AipmWorkspace, AipmWorkspaceInput, } from './config.js';
13
+ export { build, validate, scaffold, init, refreshScaffold, migrate, checkSupport, addTarget, listTargets, } from './pipeline/operations.js';
14
+ export type { TargetId, BuildOptions, BuildResult, GeneratedFile, ValidateOptions, ValidationResult, Finding, FindingCode, ScaffoldOptions, InitOptions, RefreshOptions, RefreshOutcome, MigrateOptions, MigrateResult, SupportReport, } from './pipeline/types.js';
15
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE/D,OAAO,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,OAAO,EACP,WAAW,EACX,eAAe,EACf,WAAW,EACX,cAAc,EACd,aAAa,EACb,aAAa,GACd,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9E,YAAY,EACV,UAAU,EACV,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,IAAI,EACJ,eAAe,EACf,OAAO,EACP,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,OAAO,EACP,WAAW,EACX,eAAe,EACf,WAAW,EACX,cAAc,EACd,cAAc,EACd,cAAc,EACd,aAAa,EACb,aAAa,GACd,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -8,6 +8,6 @@
8
8
  *
9
9
  * @packageDocumentation
10
10
  */
11
- export { defineConfig } from './config.js';
12
- export { build, validate, scaffold, init, migrate, checkSupport, addTarget, listTargets, } from './pipeline/operations.js';
11
+ export { defineConfig, defineRepoConfig, defineWorkspace } from './config.js';
12
+ export { build, validate, scaffold, init, refreshScaffold, migrate, checkSupport, addTarget, listTargets, } from './pipeline/operations.js';
13
13
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAU9E,OAAO,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,IAAI,EACJ,eAAe,EACf,OAAO,EACP,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,MAAM,0BAA0B,CAAC"}
@@ -14,8 +14,10 @@
14
14
  *
15
15
  * @see docs/specs/architecture.md §5.2 (build phase), §5.4 (phase invariants), §7.2, §10.5
16
16
  */
17
+ import type { AipmWorkspace } from '../config.js';
18
+ import type { ConfigCache } from './load-config.js';
17
19
  import type { SentinelMode } from './sentinel.js';
18
- import type { BuildOptions, BuildResult, TargetId } from './types.js';
20
+ import type { BuildOptions, BuildResult, Finding, TargetId } from './types.js';
19
21
  /**
20
22
  * A toolkit-generated file that lives **inside the plugin directory** and carries a sentinel.
21
23
  * Both the build (which writes `expectedContent`) and the freshness check (which compares the
@@ -64,6 +66,161 @@ export interface DistBundle {
64
66
  * build (calls `regenerate(destDir)`) and freshness (calls `regenerate(tempDir)` then compares).
65
67
  */
66
68
  export declare function computeDistBundles(pluginDir: string, distDir: string, envelope: readonly TargetId[]): DistBundle[];
69
+ /**
70
+ * One discovered plugin's contribution to registry generation. The repo-level
71
+ * {@link computeRegistryArtifacts} step assembles these (loading each plugin's `aipm.config.ts`
72
+ * for `description`/`keywords` and its envelope) so the registry generator never re-reads disk.
73
+ */
74
+ export interface RegistryPluginInfo {
75
+ /** Plugin directory basename (the registry entry `name`). */
76
+ name: string;
77
+ /**
78
+ * The plugin directory relative to the repo root, `./`-prefixed and POSIX-separated (e.g.
79
+ * `./plugins/<name>`). This is the registry entry's `source` (string for Claude/Cursor, the
80
+ * `source.path` for Codex). Honors a relocated `pluginsRoot`.
81
+ */
82
+ source: string;
83
+ /** The plugin's declared support envelope (`config.targets`). */
84
+ envelope: readonly TargetId[];
85
+ /** Optional one-line description from `aipm.config.ts`; maps to the entry `description`/`tags` host. */
86
+ description?: string;
87
+ /** Optional keywords from `aipm.config.ts`; maps to the entry `tags` (Claude/Cursor). */
88
+ keywords?: readonly string[];
89
+ }
90
+ /**
91
+ * A generated marketplace registry file. Like `dist/` bundles, registries are **sentinel-less**:
92
+ * the host schemas are strict and there is no companion sidecar, so freshness is a whole-file
93
+ * regenerate-and-byte-compare against `expectedContent`. Both `runBuild` (which writes the bytes)
94
+ * and the freshness check (which compares disk to the bytes) derive these from one place.
95
+ */
96
+ export interface RegistryArtifact {
97
+ /** The registry-backed target this file serves. */
98
+ target: TargetId;
99
+ /** Absolute path of the registry file (always at the repo root). */
100
+ absPath: string;
101
+ /** Exact bytes the build writes (2-space JSON + trailing newline). */
102
+ expectedContent: string;
103
+ }
104
+ /**
105
+ * Absolute paths of every registry the toolkit MANAGES under a repo root (one per registry-backed
106
+ * target), regardless of whether the current envelope produces it. Used to detect **orphaned**
107
+ * registries — a committed `marketplace.json` for a target no longer declared by any plugin —
108
+ * which `runBuild` removes and the validator flags as stale. Shared so build and validate agree
109
+ * on exactly which files generation owns (and never touch anything else).
110
+ */
111
+ export declare function managedRegistryPaths(repoRoot: string): string[];
112
+ /**
113
+ * Compute the generated marketplace registries for a repo, **without writing**. The single source
114
+ * of truth shared by `runBuild` (which writes `expectedContent`) and the freshness check (which
115
+ * compares the on-disk bytes against it).
116
+ *
117
+ * A registry file is produced for each registry-backed target (`claude` → `.claude-plugin/`,
118
+ * `cursor` → `.cursor-plugin/`, `codex` → `.agents/plugins/`) that appears in **at least one**
119
+ * plugin's envelope. Each registry lists exactly the plugins whose envelope includes that target,
120
+ * in the order given (callers pass plugins sorted by discovery). Registries are sentinel-less.
121
+ *
122
+ * @param repoRoot - Absolute repo root (where the registries live).
123
+ * @param plugins - Discovered plugins with name/source/envelope/description/keywords.
124
+ * @param workspace - The validated `aipm.workspace.ts` metadata.
125
+ */
126
+ export declare function computeRegistryArtifacts(repoRoot: string, plugins: readonly RegistryPluginInfo[], workspace: AipmWorkspace): RegistryArtifact[];
127
+ /**
128
+ * Assemble the {@link RegistryPluginInfo} for every discovered plugin under `repoRoot`, loading
129
+ * each plugin's `aipm.config.ts` for its envelope, description, and keywords. Shared by `runBuild`
130
+ * and the freshness check so both feed `computeRegistryArtifacts` identical input.
131
+ *
132
+ * @param repoRoot - Absolute repo root (the base for the `./`-prefixed `source`).
133
+ * @param pluginDirs - Absolute plugin directories (already discovery-sorted).
134
+ */
135
+ export declare function collectRegistryPlugins(repoRoot: string, pluginDirs: readonly string[], cache?: ConfigCache): Promise<RegistryPluginInfo[]>;
136
+ /**
137
+ * The hosts that have NO multi-plugin marketplace concept: each installs exactly ONE
138
+ * extension/power per repo, read from the **repo root**. `gemini extensions install <git>` reads a
139
+ * root `gemini-extension.json`; Kiro "Add from GitHub" reads a root `POWER.md`. Because the repo
140
+ * root has a single slot per host, at most one plugin may declare each — see the N=1 gate below.
141
+ */
142
+ declare const SINGLE_ARTIFACT_HOSTS: readonly ["gemini", "kiro"];
143
+ /** A single-artifact host (`gemini` | `kiro`). */
144
+ type SingleArtifactHost = (typeof SINGLE_ARTIFACT_HOSTS)[number];
145
+ /** Absolute path of the generated-root sidecar manifest under `repoRoot`. */
146
+ export declare function rootManifestPath(repoRoot: string): string;
147
+ /**
148
+ * A single repo-root file the toolkit generates for a single-artifact host. `relPath` is the path
149
+ * relative to the repo root (POSIX-separated, the tracked-set form); `content` is the exact bytes.
150
+ */
151
+ interface RootArtifactFile {
152
+ /** Repo-root-relative POSIX path (e.g. `gemini-extension.json`, `commands/foo.toml`). */
153
+ relPath: string;
154
+ /** The host whose bundle produced this file. */
155
+ host: SingleArtifactHost;
156
+ /** Exact bytes to write at the repo root. */
157
+ content: Buffer;
158
+ }
159
+ /**
160
+ * Result of {@link computeRootArtifacts}: the repo-root files to emit (across all single-artifact
161
+ * hosts that passed the N=1 gate), the set of repo-root-relative paths generation owns, and any
162
+ * `single-artifact-host` findings for hosts that more than one plugin declared (whose root artifact
163
+ * is suppressed).
164
+ */
165
+ export interface RootArtifacts {
166
+ /** Files to write at the repo root (empty if no host is emittable). */
167
+ files: RootArtifactFile[];
168
+ /** Repo-root-relative POSIX paths the toolkit generated this run (the tracked set). Sorted. */
169
+ trackedPaths: string[];
170
+ /** Hard `single-artifact-host` findings — one per host declared by more than one plugin. */
171
+ findings: Finding[];
172
+ }
173
+ /**
174
+ * Compute the repo-root native artifacts for the single-artifact hosts (`gemini`, `kiro`),
175
+ * **without writing**. The single source of truth shared by `runBuild` (which writes the files,
176
+ * applies the collision guard, and orphan-removes) and the freshness check (which compares disk to
177
+ * these bytes). Bundling happens into a throwaway temp dir — the repo root is never passed to a
178
+ * bundler, so the bundlers' `rmSync(destDir)` can never touch repo-root state.
179
+ *
180
+ * **N=1 gate (`single-artifact-host`).** For each host, count the plugins whose envelope declares
181
+ * it. Exactly one declarer → emit that plugin's bundled files at the repo root. More than one →
182
+ * emit a hard `single-artifact-host` finding and emit NOTHING for that host (the toolkit can't pick
183
+ * which plugin owns the single root slot). Zero → nothing to emit (and no finding). The two hosts
184
+ * are independent: a repo where plugin A declares `gemini` and plugin B declares `kiro` emits both
185
+ * (a root `gemini-extension.json` and a root `POWER.md` — distinct files).
186
+ *
187
+ * @param repoRoot - Absolute repo root (where the artifacts live). Accepted for signature
188
+ * parallelism with {@link computeRegistryArtifacts}; the bundlers read only the plugin dir.
189
+ * @param plugins - Discovered plugins with name/source/envelope (the registry plugin infos already
190
+ * collected for {@link computeRegistryArtifacts}). Each `source` resolves the plugin dir.
191
+ * @param _workspace - The validated workspace metadata. Unused by the bundlers today; accepted for
192
+ * parallelism with the registry compute signature and to future-proof host metadata injection.
193
+ */
194
+ export declare function computeRootArtifacts(repoRoot: string, plugins: readonly RegistryPluginInfo[], _workspace: AipmWorkspace): RootArtifacts;
195
+ /**
196
+ * Detect repo-root collisions for the freshly computed {@link RootArtifacts}, given the PRIOR
197
+ * tracked set. A file collides when it exists on disk AND its repo-root-relative path is NOT in the
198
+ * prior tracked set — i.e. it is not something the toolkit previously created, so it belongs to the
199
+ * host/author and must not be clobbered (safety guard 3). A clean repo (no pre-existing root files)
200
+ * never collides. Collision is evaluated PER HOST: if any of a host's files collide, that host is
201
+ * suppressed entirely (no partial writes) and a single finding names the first offending path.
202
+ *
203
+ * Returns the collision findings plus the set of hosts that collided (so the caller can skip
204
+ * writing/tracking their files). Pure — no I/O beyond `existsSync`.
205
+ */
206
+ export declare function detectRootCollisions(repoRoot: string, artifacts: RootArtifacts, priorTracked: readonly string[]): {
207
+ findings: Finding[];
208
+ collidedHosts: Set<SingleArtifactHost>;
209
+ };
210
+ /**
211
+ * Serialize the generated-root sidecar manifest. Shape: `{ version: 1, paths: string[] }` where
212
+ * `paths` is the sorted set of repo-root-relative POSIX paths the toolkit generated (the sidecar
213
+ * itself is NOT listed — it is tracked separately and always lives at {@link rootManifestPath}).
214
+ * 2-space JSON + trailing newline, byte-stable so the freshness compare is exact.
215
+ */
216
+ export declare function serializeRootManifest(trackedPaths: readonly string[]): string;
217
+ /**
218
+ * Read the prior generated-root sidecar manifest, returning the tracked-path set it recorded.
219
+ * Returns an empty array when the sidecar is absent or unparseable — a missing/corrupt sidecar is
220
+ * treated as "nothing tracked yet" (a clean first build), and the collision guard then protects any
221
+ * pre-existing root files. POSIX-separated paths are returned as-is.
222
+ */
223
+ export declare function readRootManifestPaths(repoRoot: string): string[];
67
224
  /** Collect every file path under `dir`, relative to `dir`. Returns `[]` if `dir` is absent. */
68
225
  export declare function collectFilesRelative(dir: string): string[];
69
226
  /**
@@ -87,4 +244,5 @@ export declare function runBuild(targetPath: string, opts?: BuildOptions): Promi
87
244
  * on-disk bundle without disturbing it.
88
245
  */
89
246
  export declare function regenerateBundleToTemp(bundle: DistBundle): string;
247
+ export {};
90
248
  //# sourceMappingURL=build.d.ts.map