@ai-plugin-marketplace/core 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 (136) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/config.d.ts +47 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/config.js +38 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/core.d.ts +291 -0
  8. package/dist/index.d.ts +15 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +13 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/pipeline/build.d.ts +90 -0
  13. package/dist/pipeline/build.d.ts.map +1 -0
  14. package/dist/pipeline/build.js +224 -0
  15. package/dist/pipeline/build.js.map +1 -0
  16. package/dist/pipeline/discover.d.ts +37 -0
  17. package/dist/pipeline/discover.d.ts.map +1 -0
  18. package/dist/pipeline/discover.js +71 -0
  19. package/dist/pipeline/discover.js.map +1 -0
  20. package/dist/pipeline/init-template.d.ts +33 -0
  21. package/dist/pipeline/init-template.d.ts.map +1 -0
  22. package/dist/pipeline/init-template.js +142 -0
  23. package/dist/pipeline/init-template.js.map +1 -0
  24. package/dist/pipeline/init.d.ts +39 -0
  25. package/dist/pipeline/init.d.ts.map +1 -0
  26. package/dist/pipeline/init.js +84 -0
  27. package/dist/pipeline/init.js.map +1 -0
  28. package/dist/pipeline/load-config.d.ts +47 -0
  29. package/dist/pipeline/load-config.d.ts.map +1 -0
  30. package/dist/pipeline/load-config.js +106 -0
  31. package/dist/pipeline/load-config.js.map +1 -0
  32. package/dist/pipeline/operations.d.ts +70 -0
  33. package/dist/pipeline/operations.d.ts.map +1 -0
  34. package/dist/pipeline/operations.js +100 -0
  35. package/dist/pipeline/operations.js.map +1 -0
  36. package/dist/pipeline/scaffold.d.ts +105 -0
  37. package/dist/pipeline/scaffold.d.ts.map +1 -0
  38. package/dist/pipeline/scaffold.js +422 -0
  39. package/dist/pipeline/scaffold.js.map +1 -0
  40. package/dist/pipeline/sentinel.d.ts +127 -0
  41. package/dist/pipeline/sentinel.d.ts.map +1 -0
  42. package/dist/pipeline/sentinel.js +263 -0
  43. package/dist/pipeline/sentinel.js.map +1 -0
  44. package/dist/pipeline/types.d.ts +178 -0
  45. package/dist/pipeline/types.d.ts.map +1 -0
  46. package/dist/pipeline/types.js +26 -0
  47. package/dist/pipeline/types.js.map +1 -0
  48. package/dist/pipeline/validate.d.ts +90 -0
  49. package/dist/pipeline/validate.d.ts.map +1 -0
  50. package/dist/pipeline/validate.js +617 -0
  51. package/dist/pipeline/validate.js.map +1 -0
  52. package/dist/targets/claude/scaffold.d.ts +32 -0
  53. package/dist/targets/claude/scaffold.d.ts.map +1 -0
  54. package/dist/targets/claude/scaffold.js +48 -0
  55. package/dist/targets/claude/scaffold.js.map +1 -0
  56. package/dist/targets/claude/schemas.d.ts +119 -0
  57. package/dist/targets/claude/schemas.d.ts.map +1 -0
  58. package/dist/targets/claude/schemas.js +204 -0
  59. package/dist/targets/claude/schemas.js.map +1 -0
  60. package/dist/targets/claude/transform.d.ts +40 -0
  61. package/dist/targets/claude/transform.d.ts.map +1 -0
  62. package/dist/targets/claude/transform.js +48 -0
  63. package/dist/targets/claude/transform.js.map +1 -0
  64. package/dist/targets/claude/validate.d.ts +25 -0
  65. package/dist/targets/claude/validate.d.ts.map +1 -0
  66. package/dist/targets/claude/validate.js +263 -0
  67. package/dist/targets/claude/validate.js.map +1 -0
  68. package/dist/targets/cursor/scaffold.d.ts +29 -0
  69. package/dist/targets/cursor/scaffold.d.ts.map +1 -0
  70. package/dist/targets/cursor/scaffold.js +45 -0
  71. package/dist/targets/cursor/scaffold.js.map +1 -0
  72. package/dist/targets/cursor/schemas.d.ts +49 -0
  73. package/dist/targets/cursor/schemas.d.ts.map +1 -0
  74. package/dist/targets/cursor/schemas.js +125 -0
  75. package/dist/targets/cursor/schemas.js.map +1 -0
  76. package/dist/targets/cursor/validate.d.ts +28 -0
  77. package/dist/targets/cursor/validate.d.ts.map +1 -0
  78. package/dist/targets/cursor/validate.js +181 -0
  79. package/dist/targets/cursor/validate.js.map +1 -0
  80. package/dist/targets/gemini/bundle.d.ts +25 -0
  81. package/dist/targets/gemini/bundle.d.ts.map +1 -0
  82. package/dist/targets/gemini/bundle.js +149 -0
  83. package/dist/targets/gemini/bundle.js.map +1 -0
  84. package/dist/targets/gemini/scaffold.d.ts +28 -0
  85. package/dist/targets/gemini/scaffold.d.ts.map +1 -0
  86. package/dist/targets/gemini/scaffold.js +57 -0
  87. package/dist/targets/gemini/scaffold.js.map +1 -0
  88. package/dist/targets/gemini/schemas.d.ts +53 -0
  89. package/dist/targets/gemini/schemas.d.ts.map +1 -0
  90. package/dist/targets/gemini/schemas.js +72 -0
  91. package/dist/targets/gemini/schemas.js.map +1 -0
  92. package/dist/targets/gemini/transform.d.ts +106 -0
  93. package/dist/targets/gemini/transform.d.ts.map +1 -0
  94. package/dist/targets/gemini/transform.js +137 -0
  95. package/dist/targets/gemini/transform.js.map +1 -0
  96. package/dist/targets/gemini/validate.d.ts +26 -0
  97. package/dist/targets/gemini/validate.d.ts.map +1 -0
  98. package/dist/targets/gemini/validate.js +146 -0
  99. package/dist/targets/gemini/validate.js.map +1 -0
  100. package/dist/targets/kiro/bundle.d.ts +32 -0
  101. package/dist/targets/kiro/bundle.d.ts.map +1 -0
  102. package/dist/targets/kiro/bundle.js +106 -0
  103. package/dist/targets/kiro/bundle.js.map +1 -0
  104. package/dist/targets/kiro/scaffold.d.ts +28 -0
  105. package/dist/targets/kiro/scaffold.d.ts.map +1 -0
  106. package/dist/targets/kiro/scaffold.js +55 -0
  107. package/dist/targets/kiro/scaffold.js.map +1 -0
  108. package/dist/targets/kiro/schemas.d.ts +100 -0
  109. package/dist/targets/kiro/schemas.d.ts.map +1 -0
  110. package/dist/targets/kiro/schemas.js +147 -0
  111. package/dist/targets/kiro/schemas.js.map +1 -0
  112. package/dist/targets/kiro/transform.d.ts +53 -0
  113. package/dist/targets/kiro/transform.d.ts.map +1 -0
  114. package/dist/targets/kiro/transform.js +113 -0
  115. package/dist/targets/kiro/transform.js.map +1 -0
  116. package/dist/targets/kiro/validate.d.ts +36 -0
  117. package/dist/targets/kiro/validate.d.ts.map +1 -0
  118. package/dist/targets/kiro/validate.js +232 -0
  119. package/dist/targets/kiro/validate.js.map +1 -0
  120. package/dist/targets/scaffold-kit.d.ts +56 -0
  121. package/dist/targets/scaffold-kit.d.ts.map +1 -0
  122. package/dist/targets/scaffold-kit.js +33 -0
  123. package/dist/targets/scaffold-kit.js.map +1 -0
  124. package/dist/targets/vercel/scaffold.d.ts +34 -0
  125. package/dist/targets/vercel/scaffold.d.ts.map +1 -0
  126. package/dist/targets/vercel/scaffold.js +58 -0
  127. package/dist/targets/vercel/scaffold.js.map +1 -0
  128. package/dist/targets/vercel/schemas.d.ts +42 -0
  129. package/dist/targets/vercel/schemas.d.ts.map +1 -0
  130. package/dist/targets/vercel/schemas.js +69 -0
  131. package/dist/targets/vercel/schemas.js.map +1 -0
  132. package/dist/targets/vercel/validate.d.ts +28 -0
  133. package/dist/targets/vercel/validate.d.ts.map +1 -0
  134. package/dist/targets/vercel/validate.js +180 -0
  135. package/dist/targets/vercel/validate.js.map +1 -0
  136. package/package.json +50 -0
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Generated-file sentinels.
3
+ *
4
+ * Per §4.3 of the architecture spec, every toolkit-generated file carries a sentinel so
5
+ * hand-edits are detectable by the freshness check (§10.5). There are three carriers:
6
+ *
7
+ * 1. **Inline text** — a comment block prepended to plain-text generated files.
8
+ * 2. **JSON `_generated` field** — a top-level object on JSON outputs that tolerate extra keys.
9
+ * 3. **Sidecar `<artifact>.generated`** — a companion file holding the inline-text body, used
10
+ * for strict-schema hosts that reject unknown top-level fields (Gemini's
11
+ * `gemini-extension.json`, Kiro's `.kiro/agents/*.json`).
12
+ *
13
+ * This module is **pure**: string/object in, string out. It performs no filesystem I/O — the
14
+ * build (§5.2) and freshness (§10.5) layers own all reads and writes. It is internal to
15
+ * `@ai-plugin-marketplace/core` and intentionally NOT re-exported from the package root.
16
+ *
17
+ * Round-trip invariants hold for every carrier:
18
+ * - `stripSentinel(applyXSentinel(x, src), mode) === x`
19
+ * - `readSentinelSource(applyXSentinel(x, src), mode) === src`
20
+ *
21
+ * @see docs/specs/architecture.md §4.3 (author-authored vs toolkit-generated — governing section)
22
+ * @see docs/specs/architecture.md §10.5 (freshness check — consumer of the detect/strip helpers)
23
+ * @see docs/specs/architecture.md §5.2 (build phase — consumer of the apply helpers)
24
+ */
25
+ /**
26
+ * Canonical generator identity string embedded in every sentinel. Centralized here so the
27
+ * inline comment block, the JSON `_generated.by` field, and any detector all agree on one
28
+ * literal — there is no second copy to drift.
29
+ */
30
+ export const GENERATOR_ID = '@ai-plugin-marketplace/cli';
31
+ // ---------------------------------------------------------------------------
32
+ // Inline-text carrier
33
+ // ---------------------------------------------------------------------------
34
+ /** First line of the inline/sidecar comment body. */
35
+ const INLINE_LINE_1 = `# Generated by ${GENERATOR_ID}. Do not edit directly.`;
36
+ /** Second line of the inline/sidecar comment body. */
37
+ const INLINE_LINE_2 = '# Edit the source file listed in the sentinel and run `aipm build`.';
38
+ /** Prefix of the third (source) line; the relative source path is appended verbatim. */
39
+ const INLINE_SOURCE_PREFIX = '# source: ';
40
+ /**
41
+ * Build the canonical inline-text sentinel body for a source path. This three-line block is
42
+ * shared by the inline carrier (prepended to content) and the sidecar carrier (used as the
43
+ * whole sidecar file). Always terminated by a trailing newline so the following content — or
44
+ * the file end, for a sidecar — starts on a fresh line.
45
+ *
46
+ * @param source - Author-authored source path, relative to the plugin directory.
47
+ * @returns The three-line comment block, newline-terminated.
48
+ */
49
+ function inlineSentinelBlock(source) {
50
+ return `${INLINE_LINE_1}\n${INLINE_LINE_2}\n${INLINE_SOURCE_PREFIX}${source}\n`;
51
+ }
52
+ /**
53
+ * Prepend the inline-text sentinel (§4.3) to a plain-text generated file's content.
54
+ *
55
+ * @param content - The generated file body, sans sentinel.
56
+ * @param source - Author-authored source path, relative to the plugin directory.
57
+ * @returns Content with the three-line sentinel block prepended.
58
+ */
59
+ export function applyInlineSentinel(content, source) {
60
+ return inlineSentinelBlock(source) + content;
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // Sidecar carrier
64
+ // ---------------------------------------------------------------------------
65
+ /** Suffix appended to an artifact path to form its sidecar sentinel path. */
66
+ const SIDECAR_SUFFIX = '.generated';
67
+ /**
68
+ * The body of a `<artifact>.generated` sidecar file (§4.3). Identical to the inline-text
69
+ * sentinel block — the sidecar carries no artifact content, only the sentinel.
70
+ *
71
+ * @param source - Author-authored source path, relative to the plugin directory.
72
+ * @returns The three-line sentinel block, newline-terminated.
73
+ */
74
+ export function sidecarContent(source) {
75
+ return inlineSentinelBlock(source);
76
+ }
77
+ /**
78
+ * Derive the sidecar sentinel path for an artifact: `<artifactPath>.generated` (§4.3). The
79
+ * sidecar sits next to the artifact; the artifact itself is left untouched.
80
+ *
81
+ * @param artifactPath - Path to the strict-schema artifact (e.g. `gemini-extension.json`).
82
+ * @returns The sidecar path.
83
+ */
84
+ export function sidecarPath(artifactPath) {
85
+ return `${artifactPath}${SIDECAR_SUFFIX}`;
86
+ }
87
+ // ---------------------------------------------------------------------------
88
+ // JSON `_generated`-field carrier
89
+ // ---------------------------------------------------------------------------
90
+ /**
91
+ * Serialize an object as canonical JSON with a top-level `_generated` sentinel (§4.3). The
92
+ * `_generated` key is emitted FIRST, every other own-enumerable key follows in its original
93
+ * order, and the output uses 2-space indentation with a trailing newline — matching the JSON
94
+ * conventions in `claude/transform.ts`'s `serializeClaudeHooksJson`.
95
+ *
96
+ * Any pre-existing `_generated` key on the input is overwritten by the fresh sentinel rather
97
+ * than duplicated, so re-applying is idempotent at the field level.
98
+ *
99
+ * @param obj - The value to serialize. Treated as a string-keyed object; non-object inputs
100
+ * (arrays, primitives) cannot carry a top-level field and are rejected.
101
+ * @param source - Author-authored source path, relative to the plugin directory.
102
+ * @returns Canonical JSON string with `_generated` first and a trailing `\n`.
103
+ * @throws {TypeError} If `obj` is not a plain JSON object (null, array, or primitive).
104
+ */
105
+ export function applyJsonSentinel(obj, source) {
106
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
107
+ throw new TypeError('applyJsonSentinel: expected a plain object to carry a top-level _generated field');
108
+ }
109
+ const sentinel = { by: GENERATOR_ID, source };
110
+ // `_generated` first, then every other own key in its original insertion order. Spreading a
111
+ // pre-existing `_generated` would re-introduce it after ours, so drop it from the rest.
112
+ const rest = {};
113
+ for (const [key, value] of Object.entries(obj)) {
114
+ if (key === '_generated')
115
+ continue;
116
+ rest[key] = value;
117
+ }
118
+ const withSentinel = { _generated: sentinel, ...rest };
119
+ return JSON.stringify(withSentinel, null, 2) + '\n';
120
+ }
121
+ /**
122
+ * Convenience overload for validated Claude hooks data, matching the call shape of
123
+ * `serializeClaudeHooksJson`. Equivalent to {@link applyJsonSentinel} with the hooks object.
124
+ *
125
+ * @param data - Validated {@link ClaudeHooksFile}.
126
+ * @param source - Author-authored source path, relative to the plugin directory.
127
+ * @returns Canonical JSON string with `_generated` first and a trailing `\n`.
128
+ */
129
+ export function applyJsonSentinelToHooks(data, source) {
130
+ return applyJsonSentinel(data, source);
131
+ }
132
+ // ---------------------------------------------------------------------------
133
+ // Detection / source extraction / stripping (consumed by freshness — §10.5)
134
+ // ---------------------------------------------------------------------------
135
+ /**
136
+ * Parse JSON content into a string-keyed object, returning `undefined` for malformed JSON or
137
+ * any non-object top-level value (array, primitive, null). Used by the JSON-carrier detectors
138
+ * so a hand-corrupted generated file degrades gracefully rather than throwing.
139
+ */
140
+ function parseJsonObject(content) {
141
+ let parsed;
142
+ try {
143
+ parsed = JSON.parse(content);
144
+ }
145
+ catch {
146
+ return undefined;
147
+ }
148
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
149
+ return undefined;
150
+ }
151
+ return parsed;
152
+ }
153
+ /**
154
+ * Read the `source` from a JSON `_generated` field, validating that the field is a well-formed
155
+ * {@link JsonSentinelField}. Returns `undefined` if absent or malformed.
156
+ */
157
+ function readJsonSentinelSource(content) {
158
+ const obj = parseJsonObject(content);
159
+ if (!obj)
160
+ return undefined;
161
+ const generated = obj['_generated'];
162
+ if (typeof generated !== 'object' || generated === null || Array.isArray(generated)) {
163
+ return undefined;
164
+ }
165
+ const source = generated['source'];
166
+ return typeof source === 'string' ? source : undefined;
167
+ }
168
+ /**
169
+ * Read the `source` from an inline/sidecar comment block. Returns `undefined` if the content
170
+ * does not begin with the canonical two-line preamble followed by a `# source:` line.
171
+ */
172
+ function readInlineSentinelSource(content) {
173
+ const lines = content.split('\n');
174
+ if (lines[0] !== INLINE_LINE_1 || lines[1] !== INLINE_LINE_2)
175
+ return undefined;
176
+ const sourceLine = lines[2];
177
+ if (!sourceLine?.startsWith(INLINE_SOURCE_PREFIX))
178
+ return undefined;
179
+ return sourceLine.slice(INLINE_SOURCE_PREFIX.length);
180
+ }
181
+ /**
182
+ * Detect whether `content` carries a sentinel for the given carrier (§4.3). For `'sidecar'`,
183
+ * `content` is the sidecar file body (same shape as inline); the artifact itself is never
184
+ * inspected by this function.
185
+ *
186
+ * @param content - File content to inspect (artifact body, or sidecar body for `'sidecar'`).
187
+ * @param mode - Which carrier to check for.
188
+ * @returns `true` iff a well-formed sentinel of that carrier is present.
189
+ */
190
+ export function hasSentinel(content, mode) {
191
+ return readSentinelSource(content, mode) !== undefined;
192
+ }
193
+ /**
194
+ * Extract the author-authored source path recorded in a sentinel, or `undefined` if no
195
+ * well-formed sentinel of the given carrier is present (§10.5 uses this to identify the source
196
+ * and to distinguish generated files from hand-authored ones).
197
+ *
198
+ * @param content - File content to inspect (artifact body, or sidecar body for `'sidecar'`).
199
+ * @param mode - Which carrier to read.
200
+ * @returns The recorded source path, or `undefined`.
201
+ */
202
+ export function readSentinelSource(content, mode) {
203
+ switch (mode) {
204
+ case 'inline':
205
+ case 'sidecar':
206
+ return readInlineSentinelSource(content);
207
+ case 'json-field':
208
+ return readJsonSentinelSource(content);
209
+ }
210
+ }
211
+ /**
212
+ * Remove a sentinel from `content`, returning the body sans sentinel. The inverse of the
213
+ * matching `applyXSentinel`, so freshness (§10.5) can compare an on-disk generated file to
214
+ * freshly-built content modulo the sentinel.
215
+ *
216
+ * - `'inline'` — drops the three-line comment block if present; otherwise returns `content`
217
+ * unchanged.
218
+ * - `'sidecar'` — the sidecar carries only the sentinel, so the stripped body is the empty
219
+ * string; if `content` is not a recognized sidecar it is returned unchanged.
220
+ * - `'json-field'` — re-serializes the object without `_generated`, preserving the remaining
221
+ * keys' order, 2-space indent, and trailing newline. Malformed JSON is returned unchanged.
222
+ *
223
+ * @param content - File content to strip.
224
+ * @param mode - Which carrier to strip.
225
+ * @returns The content with its sentinel removed.
226
+ */
227
+ export function stripSentinel(content, mode) {
228
+ switch (mode) {
229
+ case 'inline':
230
+ return stripInlineSentinel(content);
231
+ case 'sidecar':
232
+ // A sidecar is wholly sentinel; stripping yields an empty body. Leave unrecognized
233
+ // content untouched so a non-sidecar file is not silently emptied.
234
+ return hasSentinel(content, 'sidecar') ? '' : content;
235
+ case 'json-field':
236
+ return stripJsonSentinel(content);
237
+ }
238
+ }
239
+ /** Drop the leading three-line inline sentinel block, if present. */
240
+ function stripInlineSentinel(content) {
241
+ if (readInlineSentinelSource(content) === undefined)
242
+ return content;
243
+ // The block is exactly three newline-terminated lines; remove up to and including the third
244
+ // newline. Locate it without assuming the source path is newline-free beyond line 3.
245
+ const firstNl = content.indexOf('\n');
246
+ const secondNl = content.indexOf('\n', firstNl + 1);
247
+ const thirdNl = content.indexOf('\n', secondNl + 1);
248
+ return content.slice(thirdNl + 1);
249
+ }
250
+ /** Re-serialize JSON content without its `_generated` field; passthrough on malformed JSON. */
251
+ function stripJsonSentinel(content) {
252
+ const obj = parseJsonObject(content);
253
+ if (!obj)
254
+ return content;
255
+ const rest = {};
256
+ for (const [key, value] of Object.entries(obj)) {
257
+ if (key === '_generated')
258
+ continue;
259
+ rest[key] = value;
260
+ }
261
+ return JSON.stringify(rest, null, 2) + '\n';
262
+ }
263
+ //# sourceMappingURL=sentinel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentinel.js","sourceRoot":"","sources":["../../src/pipeline/sentinel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Public types for the core API. These are the contract surface per §8.1 of the spec.
3
+ */
4
+ /**
5
+ * A host-platform identity. The closed union of target IDs this toolkit version knows about.
6
+ *
7
+ * Declared as an explicit literal union (matching the public contract in spec §8.1) rather than
8
+ * derived from `TARGET_IDS`. This keeps the public type self-contained: a
9
+ * `typeof TARGET_IDS` derivation would make the published `TargetId` depend on the non-exported
10
+ * `TARGET_IDS` const, which API Extractor reports as `ae-forgotten-export`. The runtime array
11
+ * below is validated against this union with `satisfies`, so the two cannot drift.
12
+ *
13
+ * @public
14
+ */
15
+ export type TargetId = 'claude' | 'cursor' | 'gemini' | 'kiro' | 'vercel';
16
+ /**
17
+ * Canonical list of target IDs known to this toolkit version. Runtime-exposed so
18
+ * `listTargets()` and config validation share one source of truth.
19
+ *
20
+ * `as const satisfies readonly TargetId[]` preserves the literal tuple type (required by
21
+ * `z.enum`) while guaranteeing every entry is a valid {@link TargetId}. The
22
+ * `_targetIdsAreExhaustive` assertion below closes the other direction (every {@link TargetId}
23
+ * appears here), so the union and the array cannot drift in either direction.
24
+ *
25
+ * Not part of the public API — `index.ts` re-exports only the `TargetId` type, not this runtime
26
+ * array. Marked `@internal` so the release-tag lint rule is satisfied without widening the
27
+ * public surface.
28
+ *
29
+ * @internal
30
+ */
31
+ export declare const TARGET_IDS: readonly ["claude", "cursor", "gemini", "kiro", "vercel"];
32
+ /**
33
+ * Options for {@link build}.
34
+ *
35
+ * @public
36
+ */
37
+ export interface BuildOptions {
38
+ /** Abort after the first hard validation finding. Default: false. */
39
+ failFast?: boolean;
40
+ }
41
+ /**
42
+ * Result of building a single plugin. One entry per plugin built.
43
+ *
44
+ * @public
45
+ */
46
+ export interface BuildResult {
47
+ /** Plugin directory name, e.g. 'skill-evaluator'. */
48
+ plugin: string;
49
+ /** Absolute path to the plugin directory. */
50
+ pluginDir: string;
51
+ /** Every file the build produced or verified as up-to-date. */
52
+ artifacts: GeneratedFile[];
53
+ /** Wall-clock time in milliseconds. */
54
+ durationMs: number;
55
+ }
56
+ /**
57
+ * A file produced or verified by the build.
58
+ *
59
+ * @public
60
+ */
61
+ export interface GeneratedFile {
62
+ /** Absolute path. */
63
+ path: string;
64
+ /** The author-authored file this was generated from, if applicable. */
65
+ source?: string;
66
+ /** Which target's build step produced this file. */
67
+ target: TargetId;
68
+ }
69
+ /**
70
+ * Options for {@link validate}.
71
+ *
72
+ * @public
73
+ */
74
+ export interface ValidateOptions {
75
+ /** When true, skip the freshness check (§10.5). Default: false. */
76
+ skipFreshness?: boolean;
77
+ }
78
+ /**
79
+ * Result of validating one or more plugins.
80
+ *
81
+ * @public
82
+ */
83
+ export interface ValidationResult {
84
+ findings: Finding[];
85
+ /** True iff no hard findings were emitted. Soft findings do not flip this. */
86
+ passed: boolean;
87
+ }
88
+ /**
89
+ * Enumerated finding codes. Additive — new codes arrive in toolkit MINOR releases; removing
90
+ * or renaming a code is MAJOR. Consumers SHOULD handle unknown codes gracefully.
91
+ *
92
+ * @public
93
+ */
94
+ export type FindingCode = 'envelope-invalid' | 'envelope-adherence' | 'schema-invalid' | 'name-consistency' | 'mcp-key-sync' | 'marketplace-registration' | 'freshness';
95
+ /**
96
+ * A single validation finding.
97
+ *
98
+ * @public
99
+ */
100
+ export interface Finding {
101
+ severity: 'hard' | 'soft';
102
+ code: FindingCode;
103
+ /** Plugin name, if the finding is scoped to a specific plugin. */
104
+ plugin?: string;
105
+ /** Human-readable message. */
106
+ message: string;
107
+ /** Optional remediation hint. */
108
+ hint?: string;
109
+ }
110
+ /**
111
+ * Options for {@link scaffold}.
112
+ *
113
+ * @public
114
+ */
115
+ export interface ScaffoldOptions {
116
+ /** Targets to scaffold for. Defaults to all known targets. */
117
+ targets?: readonly TargetId[];
118
+ /** Description field for the generated plugin. */
119
+ description?: string;
120
+ }
121
+ /**
122
+ * Options for {@link init}.
123
+ *
124
+ * @public
125
+ */
126
+ export interface InitOptions {
127
+ /**
128
+ * Repo name written into the generated `package.json`. Defaults to the basename of the target
129
+ * directory.
130
+ */
131
+ name?: string;
132
+ }
133
+ /**
134
+ * Options for {@link migrate}.
135
+ *
136
+ * @public
137
+ */
138
+ export interface MigrateOptions {
139
+ /** When true, print planned changes without writing. Default: false. */
140
+ dryRun?: boolean;
141
+ }
142
+ /**
143
+ * Result of running {@link migrate}.
144
+ *
145
+ * @public
146
+ */
147
+ export interface MigrateResult {
148
+ /**
149
+ * Discriminant so consumers distinguish "ran and did nothing" from "ran and applied zero
150
+ * of N" from "ran and failed." Retrofitting this later would be breaking.
151
+ */
152
+ status: 'no-migrations-needed' | 'applied' | 'failed';
153
+ /** 0 in v0.1.0. */
154
+ migrationsApplied: number;
155
+ /** Absolute paths of files modified. */
156
+ filesChanged: string[];
157
+ }
158
+ /**
159
+ * Diagnostic report from {@link checkSupport} describing a plugin's support envelope.
160
+ *
161
+ * @public
162
+ */
163
+ export interface SupportReport {
164
+ plugin: string;
165
+ /** Targets the plugin declares support for. */
166
+ declared: TargetId[];
167
+ /** Declared targets that are missing required artifacts. */
168
+ missingArtifacts: {
169
+ target: TargetId;
170
+ missing: string[];
171
+ }[];
172
+ /** Targets not declared but plausibly addable, with the files the author would need. */
173
+ suggestions: {
174
+ target: TargetId;
175
+ wouldNeed: string[];
176
+ }[];
177
+ }
178
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pipeline/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE1E;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,UAAU,2DAMiB,CAAC;AAmBzC;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,MAAM,EAAE,QAAQ,CAAC;CAClB;AAKD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GACnB,kBAAkB,GAClB,oBAAoB,GACpB,gBAAgB,GAChB,kBAAkB,GAClB,cAAc,GACd,0BAA0B,GAC1B,WAAW,CAAC;AAEhB;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC9B,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAKD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,MAAM,EAAE,sBAAsB,GAAG,SAAS,GAAG,QAAQ,CAAC;IACtD,mBAAmB;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wCAAwC;IACxC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAKD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,4DAA4D;IAC5D,gBAAgB,EAAE;QAAE,MAAM,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IAC5D,wFAAwF;IACxF,WAAW,EAAE;QAAE,MAAM,EAAE,QAAQ,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;CAC1D"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Public types for the core API. These are the contract surface per §8.1 of the spec.
3
+ */
4
+ /**
5
+ * Canonical list of target IDs known to this toolkit version. Runtime-exposed so
6
+ * `listTargets()` and config validation share one source of truth.
7
+ *
8
+ * `as const satisfies readonly TargetId[]` preserves the literal tuple type (required by
9
+ * `z.enum`) while guaranteeing every entry is a valid {@link TargetId}. The
10
+ * `_targetIdsAreExhaustive` assertion below closes the other direction (every {@link TargetId}
11
+ * appears here), so the union and the array cannot drift in either direction.
12
+ *
13
+ * Not part of the public API — `index.ts` re-exports only the `TargetId` type, not this runtime
14
+ * array. Marked `@internal` so the release-tag lint rule is satisfied without widening the
15
+ * public surface.
16
+ *
17
+ * @internal
18
+ */
19
+ export const TARGET_IDS = [
20
+ 'claude',
21
+ 'cursor',
22
+ 'gemini',
23
+ 'kiro',
24
+ 'vercel',
25
+ ];
26
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/pipeline/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,QAAQ;CAC8B,CAAC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Cross-target validator for the pipeline layer.
3
+ *
4
+ * Implements §10.1 steps 1, 3, 4, and most of 5 (freshness deferred to Stage 5).
5
+ * Step 2 (per-target schema validation) lives in each target's own validate.ts and is
6
+ * not invoked here — this module is concerned only with cross-target consistency.
7
+ *
8
+ * @see docs/specs/architecture.md §6, §8.1, §10.1, §10.2
9
+ */
10
+ import type { Finding, TargetId, ValidateOptions, ValidationResult } from './types.js';
11
+ /**
12
+ * Minimum required artifacts for each target. Missing any of these when the target is
13
+ * in the envelope is an adherence violation.
14
+ * Vercel requires at least one skills/<name>/SKILL.md — handled specially below.
15
+ */
16
+ export declare const TARGET_MIN_REQUIRED: Record<TargetId, string[]>;
17
+ /**
18
+ * Validate an already-loaded `aipm.config.ts` value against AipmConfig's Zod schema.
19
+ * Loading from disk is the pipeline orchestrator's job (Stage 5). Here we only validate shape.
20
+ * Emits `envelope-invalid` findings on malformed input.
21
+ *
22
+ * `pluginName` is used to populate Finding.plugin.
23
+ */
24
+ export declare function validateEnvelopeShape(rawConfig: unknown, pluginName: string): Finding[];
25
+ /**
26
+ * For each target in the envelope: verify the plugin provides the minimum required artifacts.
27
+ * For each target NOT in the envelope: verify no target-specific artifacts exist for it.
28
+ *
29
+ * Emits `envelope-adherence` findings.
30
+ */
31
+ export declare function validateEnvelopeAdherence(pluginDir: string, envelope: readonly TargetId[]): Finding[];
32
+ /**
33
+ * Check that the plugin directory name matches the `name` field in every declared target's
34
+ * manifest. Reads each manifest and parses its `name` field (doesn't re-run the full schema —
35
+ * just extracts name).
36
+ *
37
+ * Emits `name-consistency` findings, one per mismatched manifest.
38
+ */
39
+ export declare function validateNameConsistency(pluginDir: string, envelope: readonly TargetId[]): Finding[];
40
+ /**
41
+ * When both Claude/Cursor (.mcp.json) and Kiro (mcp.json) are in the envelope, the set of
42
+ * mcpServers keys must match between them. Skip the check if fewer than two MCP-consuming
43
+ * targets are in the envelope.
44
+ *
45
+ * Emits `mcp-key-sync` findings.
46
+ */
47
+ export declare function validateMcpKeySync(pluginDir: string, envelope: readonly TargetId[]): Finding[];
48
+ /**
49
+ * Verify the plugin is listed in the appropriate template-level marketplace.json files.
50
+ *
51
+ * - If `claude` is in the envelope, the plugin MUST appear in `<repoRoot>/.claude-plugin/marketplace.json`'s
52
+ * plugins array with name matching directory basename and source pointing at `./plugins/<name>`.
53
+ * - If `cursor` is in the envelope, same check against `<repoRoot>/.cursor-plugin/marketplace.json`.
54
+ * - If a target is NOT in the envelope, the plugin MUST NOT be listed in that marketplace.
55
+ *
56
+ * Emits `marketplace-registration` findings.
57
+ */
58
+ export declare function validateMarketplaceRegistration(pluginDir: string, repoRoot: string, envelope: readonly TargetId[]): Finding[];
59
+ /**
60
+ * Convenience: run all cross-target validators for a single plugin and combine findings.
61
+ * Stage 5's pipeline operations.ts uses this.
62
+ *
63
+ * Note: validateEnvelopeShape is excluded here because the caller must already have a
64
+ * parsed envelope (TargetId[]) — meaning shape validation already passed. Shape validation
65
+ * must be done separately before calling this function.
66
+ */
67
+ export declare function validateCrossTarget(pluginDir: string, repoRoot: string, envelope: readonly TargetId[]): Finding[];
68
+ /**
69
+ * Validate one plugin or every plugin under a repo root (§5.3). Runs the validators in the order
70
+ * mandated by §10.1 / §10.3:
71
+ *
72
+ * 1. Envelope load + shape validation. A load/shape failure emits `envelope-invalid` and
73
+ * **skips all further checks for that plugin** (no point validating an undeclared target).
74
+ * 2. Per-target schema validation (each declared target's `validate.ts`). Schema errors
75
+ * **block cross-target checks** for that plugin (§10.3).
76
+ * 3. Envelope adherence.
77
+ * 4. Cross-target consistency (only when the envelope has more than one target and no blocking
78
+ * schema errors): name consistency, MCP key sync, marketplace registration.
79
+ * 5. Freshness (unless `opts.skipFreshness`). Severity is `hard` in CI, `soft` locally (§10.2).
80
+ *
81
+ * `passed` is `true` iff no **hard** findings were emitted (§10.2).
82
+ *
83
+ * @param targetPath - Absolute path to a single plugin directory or a repo root.
84
+ * @param opts - Validate options. `ci` controls freshness severity (default: local/soft).
85
+ * @returns The combined validation result.
86
+ */
87
+ export declare function runValidate(targetPath: string, opts?: ValidateOptions & {
88
+ ci?: boolean;
89
+ }): Promise<ValidationResult>;
90
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/pipeline/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqBH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAgCvF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,CAM1D,CAAC;AA4DF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,CAsBvF;AAMD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAC5B,OAAO,EAAE,CA4FX;AAMD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAC5B,OAAO,EAAE,CAkFX;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAAG,OAAO,EAAE,CAgD9F;AAMD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAC5B,OAAO,EAAE,CAqGX;AAMD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAC5B,OAAO,EAAE,CAOX;AA+KD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,eAAe,GAAG;IAAE,EAAE,CAAC,EAAE,OAAO,CAAA;CAAE,GACxC,OAAO,CAAC,gBAAgB,CAAC,CAwD3B"}