@mistralys/persona-builder 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.
- package/LICENSE +21 -0
- package/README.md +72 -0
- package/dist/cli.cjs +514 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +506 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +437 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +829 -0
- package/dist/index.d.ts +829 -0
- package/dist/index.js +404 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* partials.ts
|
|
3
|
+
*
|
|
4
|
+
* Pure template-engine function for resolving partial inclusions.
|
|
5
|
+
* Supports {{> name}} syntax with up to depth-2 recursion to handle
|
|
6
|
+
* partials-within-partials. No file-system I/O.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Resolve partial inclusions in a template string.
|
|
10
|
+
*
|
|
11
|
+
* Replaces `{{> name}}` markers with the content from `partialsMap`.
|
|
12
|
+
* Recursion is capped at depth 2 so that:
|
|
13
|
+
* - depth 0 → 1: outer partials are expanded
|
|
14
|
+
* - depth 1 → 2: one level of nested partials are expanded
|
|
15
|
+
* - depth 2: recursion stops, marker is left as-is
|
|
16
|
+
*
|
|
17
|
+
* Each resolved partial is `trimEnd()`-ed to prevent trailing blank lines
|
|
18
|
+
* from causing double-blank-line artefacts during concatenation.
|
|
19
|
+
*
|
|
20
|
+
* If a partial name is not found in `partialsMap`, the original marker is
|
|
21
|
+
* preserved and a warning is emitted via `console.warn`.
|
|
22
|
+
*
|
|
23
|
+
* @param text - Template string potentially containing {{> name}} markers
|
|
24
|
+
* @param partialsMap - Map of partial name → partial content
|
|
25
|
+
* @param depth - Current recursion depth (callers should omit; defaults to 0)
|
|
26
|
+
* @returns The template string with partial markers replaced
|
|
27
|
+
*/
|
|
28
|
+
declare function resolvePartials(text: string, partialsMap: Record<string, string>, depth?: number): string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* conditionals.ts
|
|
32
|
+
*
|
|
33
|
+
* Pure template-engine function for resolving conditional blocks.
|
|
34
|
+
* Handles {{#if flag}}…{{/if}} and {{#if flag}}…{{else}}…{{/if}} syntax.
|
|
35
|
+
* No file-system I/O.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* Resolve conditional blocks in a template string.
|
|
39
|
+
*
|
|
40
|
+
* Syntax:
|
|
41
|
+
* `{{#if flag}}content{{/if}}`
|
|
42
|
+
* `{{#if flag}}truthy-content{{else}}falsy-content{{/if}}`
|
|
43
|
+
*
|
|
44
|
+
* Behaviour:
|
|
45
|
+
* - When `context[flag]` is truthy: the delimiters are stripped and the
|
|
46
|
+
* content before `{{else}}` (or the entire inner block if no `{{else}}`)
|
|
47
|
+
* is kept, surrounded by single `\n` delimiters.
|
|
48
|
+
* - When `context[flag]` is falsy and a `{{else}}` branch exists: the
|
|
49
|
+
* content after `{{else}}` is kept, surrounded by single `\n` delimiters.
|
|
50
|
+
* - When `context[flag]` is falsy and no `{{else}}` branch exists: the
|
|
51
|
+
* entire block (including surrounding newlines) is removed, leaving a
|
|
52
|
+
* single `\n`.
|
|
53
|
+
* - Unknown flags (absent from context) are treated as falsy.
|
|
54
|
+
*
|
|
55
|
+
* Leading and trailing newlines within the kept content are trimmed so the
|
|
56
|
+
* output does not accumulate extra blank lines.
|
|
57
|
+
*
|
|
58
|
+
* @param text - Template string potentially containing {{#if}} blocks
|
|
59
|
+
* @param context - Key-value map used to evaluate flag truthiness
|
|
60
|
+
* @returns The template string with conditional blocks resolved
|
|
61
|
+
*/
|
|
62
|
+
declare function resolveConditionals(text: string, context: Record<string, unknown>): string;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* variables.ts
|
|
66
|
+
*
|
|
67
|
+
* Pure template-engine function for resolving variable substitutions.
|
|
68
|
+
* Handles {{varName}} syntax. No file-system I/O.
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* Resolve variable substitutions in a template string.
|
|
72
|
+
*
|
|
73
|
+
* Replaces `{{varName}}` markers with `String(context[varName])`.
|
|
74
|
+
* If a variable is not found in `context` (or its value is `undefined`),
|
|
75
|
+
* the original marker is preserved and a warning is emitted via
|
|
76
|
+
* `console.warn`, identifying the file by `filename` for easier debugging.
|
|
77
|
+
*
|
|
78
|
+
* Note: this step must run AFTER `resolvePartials` and `resolveConditionals`
|
|
79
|
+
* so that only plain variable markers remain.
|
|
80
|
+
*
|
|
81
|
+
* @param text - Template string potentially containing {{varName}} markers
|
|
82
|
+
* @param context - Key-value map of variable name → value
|
|
83
|
+
* @param filename - Identifier used in warning messages (e.g. persona file path)
|
|
84
|
+
* @returns The template string with variable markers substituted
|
|
85
|
+
*/
|
|
86
|
+
declare function resolveVariables(text: string, context: Record<string, unknown>, filename: string): string;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* postProcessor.ts
|
|
90
|
+
*
|
|
91
|
+
* Pure post-processing functions for cleaning up rendered persona output.
|
|
92
|
+
* All functions are side-effect-free and operate only on strings.
|
|
93
|
+
* No file-system I/O.
|
|
94
|
+
*/
|
|
95
|
+
/**
|
|
96
|
+
* Collapse 3 or more consecutive blank lines into 2 blank lines.
|
|
97
|
+
*
|
|
98
|
+
* Specifically converts 4 or more consecutive `\n` characters into `\n\n\n`
|
|
99
|
+
* (which equals 2 blank lines between paragraphs).
|
|
100
|
+
*
|
|
101
|
+
* @param text - Rendered output string
|
|
102
|
+
* @returns String with excessive blank lines collapsed
|
|
103
|
+
*/
|
|
104
|
+
declare function collapseBlankLines(text: string): string;
|
|
105
|
+
/**
|
|
106
|
+
* Ensure every Markdown heading has a blank line immediately before it.
|
|
107
|
+
*
|
|
108
|
+
* Also ensures horizontal rules (`---`) have a blank line before and after
|
|
109
|
+
* them. This corrects spacing gaps caused by partial concatenation where
|
|
110
|
+
* `trimEnd()` strips trailing newlines and conditionals add only a single
|
|
111
|
+
* `\n` delimiter.
|
|
112
|
+
*
|
|
113
|
+
* @param text - Rendered output string
|
|
114
|
+
* @returns String with blank lines inserted before headings and rules
|
|
115
|
+
*/
|
|
116
|
+
declare function ensureBlankLineBeforeHeadings(text: string): string;
|
|
117
|
+
/**
|
|
118
|
+
* Normalize line endings to LF (`\n`) for OS-agnostic output.
|
|
119
|
+
*
|
|
120
|
+
* Converts CRLF (`\r\n`) first, then strips any remaining stray CR (`\r`).
|
|
121
|
+
*
|
|
122
|
+
* @param text - String potentially containing CRLF or CR line endings
|
|
123
|
+
* @returns String with all line endings normalized to LF
|
|
124
|
+
*/
|
|
125
|
+
declare function normalizeNewlines(text: string): string;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* serializer.ts
|
|
129
|
+
*
|
|
130
|
+
* Pure serializer functions for converting tool lists to YAML-compatible
|
|
131
|
+
* string representations. No file-system I/O.
|
|
132
|
+
*/
|
|
133
|
+
/**
|
|
134
|
+
* Serialize a tools array in YAML single-quote flow format WITH outer brackets.
|
|
135
|
+
*
|
|
136
|
+
* Output format: `['tool1', 'tool2', 'tool3']`
|
|
137
|
+
* Used by the ledger suite to preserve byte-identical frontmatter output.
|
|
138
|
+
*
|
|
139
|
+
* @param tools - Array of tool name strings
|
|
140
|
+
* @returns YAML flow-sequence string including outer brackets
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* serializeTools(['Bash', 'Read']) // => "['Bash', 'Read']"
|
|
144
|
+
* serializeTools([]) // => "[]"
|
|
145
|
+
*/
|
|
146
|
+
declare function serializeTools(tools: string[]): string;
|
|
147
|
+
/**
|
|
148
|
+
* Serialize a tools array in YAML single-quote flow format WITHOUT outer brackets.
|
|
149
|
+
*
|
|
150
|
+
* Output format: `'tool1', 'tool2', 'tool3'`
|
|
151
|
+
* Used inside standalone frontmatter templates which supply the surrounding `[ ]`.
|
|
152
|
+
*
|
|
153
|
+
* @param tools - Array of tool name strings
|
|
154
|
+
* @returns Comma-separated quoted tool names (no outer brackets)
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* serializeToolsList(['Bash', 'Read']) // => "'Bash', 'Read'"
|
|
158
|
+
* serializeToolsList([]) // => ""
|
|
159
|
+
*/
|
|
160
|
+
declare function serializeToolsList(tools: string[]): string;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* src/loaders/partials-loader.ts
|
|
164
|
+
*
|
|
165
|
+
* File-system loader for Handlebars-style partial snippets.
|
|
166
|
+
*
|
|
167
|
+
* Reads every `.md` file in `dir`, keys each entry by the filename stem
|
|
168
|
+
* (i.e. the portion before the final `.md` extension), and returns the
|
|
169
|
+
* map. Callers that need a two-layer (shared → suite-local override)
|
|
170
|
+
* setup should call `loadPartials` twice and merge the results themselves,
|
|
171
|
+
* with the suite-local result spreading last.
|
|
172
|
+
*
|
|
173
|
+
* All file reads are performed asynchronously. Path construction uses
|
|
174
|
+
* `path.join` and `path.posix`-compatible operations so no path-separator
|
|
175
|
+
* assumptions are baked in.
|
|
176
|
+
*/
|
|
177
|
+
/**
|
|
178
|
+
* Load all `.md` files in `dir` and return them as a `Record<string, string>`
|
|
179
|
+
* keyed by filename stem.
|
|
180
|
+
*
|
|
181
|
+
* Files whose names do not end in `.md` are silently ignored.
|
|
182
|
+
* The directory must exist; a missing directory throws an `ENOENT` error from
|
|
183
|
+
* the underlying `readdir` call (let callers decide how to handle absence).
|
|
184
|
+
*
|
|
185
|
+
* @param dir Absolute (or relative) path to the directory to scan.
|
|
186
|
+
* @returns A map from filename stem → file content string.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* const partials = await loadPartials('/project/partials');
|
|
190
|
+
* // { greeting: 'Hello, {{name}}!', footer: '---\nEnd of file' }
|
|
191
|
+
*/
|
|
192
|
+
declare function loadPartials(dir: string): Promise<Record<string, string>>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* src/plugins/types.ts
|
|
196
|
+
*
|
|
197
|
+
* Core plugin system types for @smor/persona-build.
|
|
198
|
+
*
|
|
199
|
+
* Defines:
|
|
200
|
+
* - TargetType — union of supported output targets
|
|
201
|
+
* - PersonaMetadata — typed representation of a persona YAML file
|
|
202
|
+
* - SuiteConfig — configuration for a single persona suite
|
|
203
|
+
* - ValidationResult — outcome of a plugin's onValidate hook
|
|
204
|
+
* - PersonaBuildPlugin — interface every plugin must implement
|
|
205
|
+
*/
|
|
206
|
+
/**
|
|
207
|
+
* The two output formats supported by the build pipeline.
|
|
208
|
+
* 'vscode' → VS Code `.code-workspace` instruction files
|
|
209
|
+
* 'claude-code' → Claude Code instruction files
|
|
210
|
+
*/
|
|
211
|
+
type TargetType = 'vscode' | 'claude-code';
|
|
212
|
+
/**
|
|
213
|
+
* Typed representation of a persona YAML metadata file.
|
|
214
|
+
*
|
|
215
|
+
* Fields map directly to the keys expected in `*.yaml` persona files.
|
|
216
|
+
* All fields beyond `name` are optional — consumers should treat them
|
|
217
|
+
* as potentially absent and fall back to suite-level or shared defaults.
|
|
218
|
+
*/
|
|
219
|
+
interface PersonaMetadata {
|
|
220
|
+
/** Unique persona identifier (matches filename stem) */
|
|
221
|
+
name: string;
|
|
222
|
+
/** Human-readable display name */
|
|
223
|
+
displayName?: string;
|
|
224
|
+
/** Short description surfaced in frontmatter */
|
|
225
|
+
description?: string;
|
|
226
|
+
/** Semantic version string (e.g. "1.2.0") */
|
|
227
|
+
version?: string;
|
|
228
|
+
/** Ordered list of tool identifiers */
|
|
229
|
+
tools?: string[];
|
|
230
|
+
/** Free-form context variables available during template rendering */
|
|
231
|
+
[key: string]: unknown;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Configuration for a single persona suite (directory of related personas).
|
|
235
|
+
*/
|
|
236
|
+
interface SuiteConfig {
|
|
237
|
+
/** Absolute or relative path to the suite source directory */
|
|
238
|
+
srcDir: string;
|
|
239
|
+
/** Output path for VS Code formatted persona files */
|
|
240
|
+
outVscode: string;
|
|
241
|
+
/** Output path for Claude Code formatted persona files */
|
|
242
|
+
outClaudeCode: string;
|
|
243
|
+
/**
|
|
244
|
+
* Optional persona mode string (e.g. 'ledger').
|
|
245
|
+
* When present, plugins can use this to branch behaviour.
|
|
246
|
+
*/
|
|
247
|
+
personaMode?: string;
|
|
248
|
+
/** Sub-directory within srcDir that contains partials. Default: 'partials' */
|
|
249
|
+
partialsSubdir?: string;
|
|
250
|
+
/** Sub-directory within srcDir that contains YAML metadata. Default: 'meta' */
|
|
251
|
+
metaSubdir?: string;
|
|
252
|
+
/** Sub-directory within srcDir that contains content Markdown files. Default: 'content' */
|
|
253
|
+
contentSubdir?: string;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* A single validation outcome returned by a plugin's `onValidate` hook.
|
|
257
|
+
*/
|
|
258
|
+
interface ValidationResult {
|
|
259
|
+
/** Severity level of the issue */
|
|
260
|
+
severity: 'error' | 'warning' | 'info';
|
|
261
|
+
/** Human-readable description of the issue */
|
|
262
|
+
message: string;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Interface that every persona build plugin must implement.
|
|
266
|
+
*
|
|
267
|
+
* All hooks are optional — a plugin only needs to implement the hooks it
|
|
268
|
+
* uses. The only required field is `name`, which is used for logging and
|
|
269
|
+
* identification.
|
|
270
|
+
*
|
|
271
|
+
* Hook invocation order (per persona):
|
|
272
|
+
* 1. onSuiteInit — once per suite, before any persona is built
|
|
273
|
+
* 2. onBuildContext — per persona, before template rendering
|
|
274
|
+
* 3. onPostRender — per persona, after body rendering
|
|
275
|
+
* 4. onValidate — per persona, during the validation phase
|
|
276
|
+
*/
|
|
277
|
+
interface PersonaBuildPlugin {
|
|
278
|
+
/**
|
|
279
|
+
* Unique name for this plugin (used in log messages and error reporting).
|
|
280
|
+
*/
|
|
281
|
+
name: string;
|
|
282
|
+
/**
|
|
283
|
+
* Called once per suite before any persona is built.
|
|
284
|
+
*
|
|
285
|
+
* Use this hook to perform suite-level setup — e.g. loading external data,
|
|
286
|
+
* validating the suite config, or mutating `sharedMeta` for downstream hooks.
|
|
287
|
+
*
|
|
288
|
+
* @param suite The suite configuration object
|
|
289
|
+
* @param sharedMeta Shared metadata merged from `_shared.yaml` (mutate in place if needed)
|
|
290
|
+
*/
|
|
291
|
+
onSuiteInit?(suite: SuiteConfig, sharedMeta: Record<string, unknown>): void;
|
|
292
|
+
/**
|
|
293
|
+
* Called for each persona before template rendering.
|
|
294
|
+
*
|
|
295
|
+
* Receives the current rendering context and must return a (possibly mutated)
|
|
296
|
+
* context object. Plugins are chained: each plugin receives the output of the
|
|
297
|
+
* previous one.
|
|
298
|
+
*
|
|
299
|
+
* @param context Current rendering context (accumulates across plugins)
|
|
300
|
+
* @param persona Typed metadata for the persona being built
|
|
301
|
+
* @param suite The suite configuration object
|
|
302
|
+
* @returns Updated rendering context (must include all original keys)
|
|
303
|
+
*/
|
|
304
|
+
onBuildContext?(context: Record<string, unknown>, persona: PersonaMetadata, suite: SuiteConfig): Record<string, unknown>;
|
|
305
|
+
/**
|
|
306
|
+
* Called for each persona after body rendering.
|
|
307
|
+
*
|
|
308
|
+
* Receives the rendered output string and can return a mutated version.
|
|
309
|
+
* Plugins are chained: each plugin receives the output of the previous one.
|
|
310
|
+
*
|
|
311
|
+
* @param output The rendered persona output string (accumulates across plugins)
|
|
312
|
+
* @param persona Typed metadata for the persona being built
|
|
313
|
+
* @param target The current build target
|
|
314
|
+
* @returns Updated output string
|
|
315
|
+
*/
|
|
316
|
+
onPostRender?(output: string, persona: PersonaMetadata, target: TargetType): string;
|
|
317
|
+
/**
|
|
318
|
+
* Called during the validation phase for each persona.
|
|
319
|
+
*
|
|
320
|
+
* Return an array of ValidationResult objects (or an empty array).
|
|
321
|
+
* Results from all plugins are collected into a flat array by the runner.
|
|
322
|
+
*
|
|
323
|
+
* @param persona Typed metadata for the persona being built
|
|
324
|
+
* @param suite The suite configuration object
|
|
325
|
+
* @returns Array of validation results (may be empty)
|
|
326
|
+
*/
|
|
327
|
+
onValidate?(persona: PersonaMetadata, suite: SuiteConfig): ValidationResult[];
|
|
328
|
+
/**
|
|
329
|
+
* Optional map of custom frontmatter templates keyed by target type.
|
|
330
|
+
*
|
|
331
|
+
* When present, the builder will use these templates in place of (or to
|
|
332
|
+
* augment) the library defaults for the matching target.
|
|
333
|
+
*/
|
|
334
|
+
frontmatterTemplates?: Partial<Record<TargetType, string>>;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* src/loaders/metadata-loader.ts
|
|
339
|
+
*
|
|
340
|
+
* File-system loader for persona YAML metadata files.
|
|
341
|
+
*
|
|
342
|
+
* Provides two exports:
|
|
343
|
+
*
|
|
344
|
+
* 1. `discoverPersonaYamls(root)` — recursively walks `root` and returns
|
|
345
|
+
* absolute paths for every `*.yaml` file found, regardless of nesting
|
|
346
|
+
* depth. Uses Node's built-in `fs.readdir` with `recursive: true`
|
|
347
|
+
* (available since Node 18.17). No glob library is required.
|
|
348
|
+
*
|
|
349
|
+
* 2. `loadMetadata(yamlPath)` — reads a single YAML file and parses it
|
|
350
|
+
* with `js-yaml` into a fully typed `PersonaMetadata` object.
|
|
351
|
+
*
|
|
352
|
+
* Path construction relies exclusively on `node:path` so the output is
|
|
353
|
+
* correct on both POSIX and Windows.
|
|
354
|
+
*/
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Recursively discover all `*.yaml` files under `root` and return their
|
|
358
|
+
* absolute paths sorted lexicographically.
|
|
359
|
+
*
|
|
360
|
+
* Uses `readdir` with `{ recursive: true }` (Node ≥ 18.17). Each returned
|
|
361
|
+
* path is normalised through `path.resolve` so callers always receive
|
|
362
|
+
* absolute, platform-consistent paths.
|
|
363
|
+
*
|
|
364
|
+
* @param root The directory to search (absolute or resolvable relative path).
|
|
365
|
+
* @returns Sorted array of absolute paths to every `*.yaml` file found.
|
|
366
|
+
*
|
|
367
|
+
* @example
|
|
368
|
+
* const yamls = await discoverPersonaYamls('/project/personas/ledger/src/meta');
|
|
369
|
+
* // ['/project/personas/ledger/src/meta/alpha.yaml', ...]
|
|
370
|
+
*/
|
|
371
|
+
declare function discoverPersonaYamls(root: string): Promise<string[]>;
|
|
372
|
+
/**
|
|
373
|
+
* Load and parse a single persona YAML file into a typed `PersonaMetadata`
|
|
374
|
+
* object.
|
|
375
|
+
*
|
|
376
|
+
* The YAML is parsed using `js-yaml`'s safe `load` function. The result
|
|
377
|
+
* is validated to be a non-null object; if the YAML is empty or does not
|
|
378
|
+
* parse to an object, an `Error` is thrown.
|
|
379
|
+
*
|
|
380
|
+
* `PersonaMetadata` requires a `name` field. If the YAML does not contain
|
|
381
|
+
* a `name` key the function throws an `Error` with a descriptive message.
|
|
382
|
+
*
|
|
383
|
+
* @param yamlPath Absolute path to the YAML file.
|
|
384
|
+
* @returns Parsed and validated `PersonaMetadata` object.
|
|
385
|
+
* @throws `Error` when the file is unparseable, not an object, or
|
|
386
|
+
* is missing the required `name` field.
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* const meta = await loadMetadata('/project/meta/my-persona.yaml');
|
|
390
|
+
* // { name: 'my-persona', description: '...', tools: [...] }
|
|
391
|
+
*/
|
|
392
|
+
declare function loadMetadata(yamlPath: string): Promise<PersonaMetadata>;
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* src/loaders/content-loader.ts
|
|
396
|
+
*
|
|
397
|
+
* File-system loader for persona Markdown content templates.
|
|
398
|
+
*
|
|
399
|
+
* Provides a single `loadContent` function that reads the raw string content
|
|
400
|
+
* of a persona Markdown file from disk. The content is returned exactly as
|
|
401
|
+
* stored — no template substitution, no post-processing. Those concerns
|
|
402
|
+
* belong to the engine layer.
|
|
403
|
+
*
|
|
404
|
+
* All I/O is asynchronous. Path construction uses `node:path` so the
|
|
405
|
+
* implementation is path-separator–agnostic.
|
|
406
|
+
*/
|
|
407
|
+
/**
|
|
408
|
+
* Read a persona Markdown content file and return its raw string content.
|
|
409
|
+
*
|
|
410
|
+
* The file is read with UTF-8 encoding. No parsing, template resolution,
|
|
411
|
+
* or post-processing is applied — that is the engine layer's responsibility.
|
|
412
|
+
*
|
|
413
|
+
* @param mdPath Absolute (or resolvable relative) path to the `.md` file.
|
|
414
|
+
* @returns Raw UTF-8 string content of the file.
|
|
415
|
+
* @throws An `ENOENT` error (from `fs/promises`) if the file does not
|
|
416
|
+
* exist, or any other I/O error the OS reports.
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* const body = await loadContent('/project/content/my-persona.md');
|
|
420
|
+
* // '{{> greeting}}\n\n## About\n\nThis is {{name}}...'
|
|
421
|
+
*/
|
|
422
|
+
declare function loadContent(mdPath: string): Promise<string>;
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* src/plugins/runner.ts
|
|
426
|
+
*
|
|
427
|
+
* Plugin runner — responsible for invoking plugin hooks in registration order.
|
|
428
|
+
*
|
|
429
|
+
* Each exported function corresponds to one lifecycle hook defined in
|
|
430
|
+
* PersonaBuildPlugin. The runner:
|
|
431
|
+
* - Skips plugins that do not implement the requested hook (hook is optional)
|
|
432
|
+
* - Invokes hooks in the order plugins are registered (first-in first-called)
|
|
433
|
+
* - For accumulating hooks (onBuildContext, onPostRender), each plugin
|
|
434
|
+
* receives the output of the previous plugin as its first argument
|
|
435
|
+
* - For collecting hooks (onValidate), results are concatenated into a
|
|
436
|
+
* flat array
|
|
437
|
+
*
|
|
438
|
+
* No file-system I/O. No async operations.
|
|
439
|
+
*/
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Invoke the `onSuiteInit` hook on every registered plugin.
|
|
443
|
+
*
|
|
444
|
+
* Each plugin may optionally implement this hook. Plugins are called in
|
|
445
|
+
* registration order. The hook receives the suite config and a mutable
|
|
446
|
+
* `sharedMeta` object — plugins may mutate `sharedMeta` in place; the
|
|
447
|
+
* same reference is passed to every subsequent plugin.
|
|
448
|
+
*
|
|
449
|
+
* @param plugins Ordered list of registered plugins
|
|
450
|
+
* @param suite The suite configuration object
|
|
451
|
+
* @param sharedMeta Mutable shared metadata object (mutated in place by plugins)
|
|
452
|
+
*/
|
|
453
|
+
declare function runSuiteInit(plugins: PersonaBuildPlugin[], suite: SuiteConfig, sharedMeta: Record<string, unknown>): void;
|
|
454
|
+
/**
|
|
455
|
+
* Invoke the `onBuildContext` hook on every registered plugin, accumulating
|
|
456
|
+
* context mutations sequentially.
|
|
457
|
+
*
|
|
458
|
+
* Each plugin receives the context returned by the previous plugin. If a
|
|
459
|
+
* plugin does not implement `onBuildContext`, the context passes through
|
|
460
|
+
* unchanged. The final accumulated context is returned.
|
|
461
|
+
*
|
|
462
|
+
* @param plugins Ordered list of registered plugins
|
|
463
|
+
* @param ctx Initial rendering context for this persona
|
|
464
|
+
* @param persona Typed metadata for the persona being built
|
|
465
|
+
* @param suite The suite configuration object
|
|
466
|
+
* @returns Accumulated rendering context after all plugins have run
|
|
467
|
+
*/
|
|
468
|
+
declare function runBuildContext(plugins: PersonaBuildPlugin[], ctx: Record<string, unknown>, persona: PersonaMetadata, suite: SuiteConfig): Record<string, unknown>;
|
|
469
|
+
/**
|
|
470
|
+
* Invoke the `onPostRender` hook on every registered plugin, chaining the
|
|
471
|
+
* output string sequentially.
|
|
472
|
+
*
|
|
473
|
+
* Each plugin receives the string returned by the previous plugin. If a
|
|
474
|
+
* plugin does not implement `onPostRender`, the string passes through
|
|
475
|
+
* unchanged. The final string is returned.
|
|
476
|
+
*
|
|
477
|
+
* @param plugins Ordered list of registered plugins
|
|
478
|
+
* @param rendered Initial rendered output string
|
|
479
|
+
* @param persona Typed metadata for the persona being built
|
|
480
|
+
* @param target The current build target
|
|
481
|
+
* @returns Final output string after all plugins have run
|
|
482
|
+
*/
|
|
483
|
+
declare function runPostRender(plugins: PersonaBuildPlugin[], rendered: string, persona: PersonaMetadata, target: TargetType): string;
|
|
484
|
+
/**
|
|
485
|
+
* Invoke the `onValidate` hook on every registered plugin and collect all
|
|
486
|
+
* returned ValidationResult objects into a single flat array.
|
|
487
|
+
*
|
|
488
|
+
* Plugins that do not implement `onValidate` contribute nothing to the result.
|
|
489
|
+
* The return value is always an array (never null/undefined).
|
|
490
|
+
*
|
|
491
|
+
* @param plugins Ordered list of registered plugins
|
|
492
|
+
* @param persona Typed metadata for the persona being built
|
|
493
|
+
* @param suite The suite configuration object
|
|
494
|
+
* @returns Flat array of all ValidationResult objects from all plugins
|
|
495
|
+
*/
|
|
496
|
+
declare function runValidate(plugins: PersonaBuildPlugin[], persona: PersonaMetadata, suite: SuiteConfig): ValidationResult[];
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* src/builders/types.ts
|
|
500
|
+
*
|
|
501
|
+
* Core types for the persona builder layer.
|
|
502
|
+
*
|
|
503
|
+
* Defines:
|
|
504
|
+
* - BuildConfig — typed configuration accepted by build()
|
|
505
|
+
* - BuildResult — outcome of building a single persona
|
|
506
|
+
* - BuildSummary — aggregated result returned by build()
|
|
507
|
+
*
|
|
508
|
+
* TargetType is re-exported from plugins/types so consumers can import
|
|
509
|
+
* everything builder-related from a single module.
|
|
510
|
+
*/
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Top-level configuration accepted by `build()`.
|
|
514
|
+
*
|
|
515
|
+
* At minimum, `suites` must be provided. All other fields have sensible
|
|
516
|
+
* defaults so a minimal configuration is:
|
|
517
|
+
*
|
|
518
|
+
* ```ts
|
|
519
|
+
* const summary = await build({
|
|
520
|
+
* suites: { my-suite: { srcDir: './src', outVscode: './out/vs', outClaudeCode: './out/cc' } },
|
|
521
|
+
* });
|
|
522
|
+
* ```
|
|
523
|
+
*/
|
|
524
|
+
interface BuildConfig {
|
|
525
|
+
/**
|
|
526
|
+
* Named map of suite configurations. Each key is a suite identifier; the
|
|
527
|
+
* value describes source and output directories for that suite.
|
|
528
|
+
*/
|
|
529
|
+
suites: Record<string, SuiteConfig>;
|
|
530
|
+
/**
|
|
531
|
+
* Absolute path to the shared partials directory. When provided, partials
|
|
532
|
+
* from this directory are loaded as the base layer before suite-local
|
|
533
|
+
* partials are overlaid. Optional.
|
|
534
|
+
*/
|
|
535
|
+
sharedPartialsDir?: string;
|
|
536
|
+
/**
|
|
537
|
+
* List of registered plugins. Plugins are invoked in array order for every
|
|
538
|
+
* hook. Defaults to `[]`.
|
|
539
|
+
*/
|
|
540
|
+
plugins?: PersonaBuildPlugin[];
|
|
541
|
+
/**
|
|
542
|
+
* Target output formats to build. Defaults to both `'vscode'` and
|
|
543
|
+
* `'claude-code'` when omitted.
|
|
544
|
+
*/
|
|
545
|
+
targets?: Array<'vscode' | 'claude-code'>;
|
|
546
|
+
/**
|
|
547
|
+
* When `true`, no files are written to disk. The build still renders all
|
|
548
|
+
* personas and collects ValidationResults, but all write operations are
|
|
549
|
+
* skipped. Defaults to `false`.
|
|
550
|
+
*/
|
|
551
|
+
check?: boolean;
|
|
552
|
+
/**
|
|
553
|
+
* When `true`, the build fails (throws or returns a failed summary) if any
|
|
554
|
+
* ValidationResult has severity `'error'` or `'warning'`. Defaults to
|
|
555
|
+
* `false`.
|
|
556
|
+
*/
|
|
557
|
+
strict?: boolean;
|
|
558
|
+
/**
|
|
559
|
+
* Optional map of default frontmatter templates, keyed by target type.
|
|
560
|
+
* These are used as library defaults and can be overridden by plugin
|
|
561
|
+
* `frontmatterTemplates`. When absent, built-in defaults from
|
|
562
|
+
* `src/builders/frontmatter.ts` are used.
|
|
563
|
+
*/
|
|
564
|
+
frontmatter?: Partial<Record<'vscode' | 'claude-code', string>>;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* The outcome of building a single persona for a single target.
|
|
568
|
+
*/
|
|
569
|
+
interface BuildResult {
|
|
570
|
+
/** The suite identifier this persona belongs to */
|
|
571
|
+
suite: string;
|
|
572
|
+
/** Target platform this result was generated for */
|
|
573
|
+
target: 'vscode' | 'claude-code';
|
|
574
|
+
/** Absolute path to the persona YAML source file */
|
|
575
|
+
personaYamlPath: string;
|
|
576
|
+
/** Absolute path to the output file (may not exist if check mode) */
|
|
577
|
+
outputPath: string;
|
|
578
|
+
/** The rendered persona content */
|
|
579
|
+
content: string;
|
|
580
|
+
/** Validation results collected from all plugins */
|
|
581
|
+
validationResults: ValidationResult[];
|
|
582
|
+
/** Whether the output file was written to disk (false in check mode) */
|
|
583
|
+
written: boolean;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Aggregated result returned by `build()` after processing all suites and
|
|
587
|
+
* targets.
|
|
588
|
+
*/
|
|
589
|
+
interface BuildSummary {
|
|
590
|
+
/** Whether the overall build succeeded */
|
|
591
|
+
success: boolean;
|
|
592
|
+
/** Individual results for each persona × target combination */
|
|
593
|
+
results: BuildResult[];
|
|
594
|
+
/**
|
|
595
|
+
* When `strict` mode is enabled and a failure was detected, this holds all
|
|
596
|
+
* ValidationResults with severity `'error'` or `'warning'` that caused the
|
|
597
|
+
* failure. Empty otherwise.
|
|
598
|
+
*/
|
|
599
|
+
strictFailures: ValidationResult[];
|
|
600
|
+
/** Total number of persona files processed */
|
|
601
|
+
totalBuilt: number;
|
|
602
|
+
/** Total number of output files written (0 in check mode) */
|
|
603
|
+
totalWritten: number;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* src/builders/frontmatter.ts
|
|
608
|
+
*
|
|
609
|
+
* Frontmatter template registry for @smor/persona-build.
|
|
610
|
+
*
|
|
611
|
+
* Ships two minimal default templates — one per target — that work for the
|
|
612
|
+
* "standalone" persona mode (simple personas without numbered workflows or
|
|
613
|
+
* MCP server blocks). Projects needing richer frontmatter register custom
|
|
614
|
+
* templates via the `PersonaBuildPlugin.frontmatterTemplates` property.
|
|
615
|
+
*
|
|
616
|
+
* Template rendering follows the same two-step sequence as body rendering:
|
|
617
|
+
* 1. resolveConditionals() — resolve {{#if flag}} blocks
|
|
618
|
+
* 2. resolveVariables() — substitute {{varName}} markers
|
|
619
|
+
*
|
|
620
|
+
* No partials in frontmatter — frontmatter is kept deliberately simple.
|
|
621
|
+
*/
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Default VS Code frontmatter template.
|
|
625
|
+
*
|
|
626
|
+
* Minimal fields that work for standalone personas. Projects using numbered
|
|
627
|
+
* workflows (e.g. ledger) should inject a richer template via a plugin.
|
|
628
|
+
*/
|
|
629
|
+
declare const DEFAULT_FRONTMATTER_VSCODE = "---\nname: '{{name}} v{{version}}'\ndescription: '{{description}}'\ntools: [{{tools_list}}]\n---";
|
|
630
|
+
/**
|
|
631
|
+
* Default Claude Code frontmatter template.
|
|
632
|
+
*
|
|
633
|
+
* Minimal fields that work for standalone personas. Projects using numbered
|
|
634
|
+
* workflows should inject a richer template via a plugin.
|
|
635
|
+
*/
|
|
636
|
+
declare const DEFAULT_FRONTMATTER_CLAUDE_CODE = "---\nname: {{cc_file_name_stem}}\npermissionMode: {{cc_permission_mode}}\nmodel: {{cc_model}}\nmemory: {{cc_memory}}\nallowedTools: [{{cc_tools_list}}]\n---";
|
|
637
|
+
/**
|
|
638
|
+
* Resolve frontmatter template precedence.
|
|
639
|
+
*
|
|
640
|
+
* Precedence order (highest wins):
|
|
641
|
+
* 1. Plugin `frontmatterTemplates` — the last plugin with a matching key
|
|
642
|
+
* wins (plugins are applied in reverse-registration order so the
|
|
643
|
+
* *first* registered plugin with a template takes precedence over later
|
|
644
|
+
* ones, matching the general plugin-chain contract).
|
|
645
|
+
* 2. `configTemplates` — templates passed via `BuildConfig.frontmatter`
|
|
646
|
+
* 3. Library defaults (`DEFAULT_FRONTMATTER_VSCODE` / `DEFAULT_FRONTMATTER_CLAUDE_CODE`)
|
|
647
|
+
*
|
|
648
|
+
* @param target The build target ('vscode' | 'claude-code')
|
|
649
|
+
* @param plugins Registered plugins (searched in order; first match wins)
|
|
650
|
+
* @param configTemplates Optional caller-supplied overrides from BuildConfig
|
|
651
|
+
* @returns The resolved template string
|
|
652
|
+
*/
|
|
653
|
+
declare function resolveFrontmatterTemplate(target: 'vscode' | 'claude-code', plugins: PersonaBuildPlugin[], configTemplates?: Partial<Record<'vscode' | 'claude-code', string>>): string;
|
|
654
|
+
/**
|
|
655
|
+
* Render a frontmatter template string against the given context.
|
|
656
|
+
*
|
|
657
|
+
* Applies the standard two-step template resolution:
|
|
658
|
+
* 1. `resolveConditionals` — `{{#if flag}}` blocks
|
|
659
|
+
* 2. `resolveVariables` — `{{varName}}` substitution
|
|
660
|
+
*
|
|
661
|
+
* @param template The raw frontmatter template string (may contain markers)
|
|
662
|
+
* @param context Key-value context for variable substitution
|
|
663
|
+
* @param filename Source filename used in warning messages
|
|
664
|
+
* @returns Rendered frontmatter string (ready to prepend to body)
|
|
665
|
+
*/
|
|
666
|
+
declare function renderFrontmatter(template: string, context: Record<string, unknown>, filename: string): string;
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* src/builders/persona-builder.ts
|
|
670
|
+
*
|
|
671
|
+
* Core build orchestrator for @smor/persona-build.
|
|
672
|
+
*
|
|
673
|
+
* Exports three public functions:
|
|
674
|
+
*
|
|
675
|
+
* 1. buildPersona(personaYamlPath, suiteName, suiteConfig, sharedMeta,
|
|
676
|
+
* partialsMap, config, plugins)
|
|
677
|
+
* — Builds a single persona for a single target. Returns a BuildResult.
|
|
678
|
+
*
|
|
679
|
+
* 2. buildSuite(suiteName, suiteConfig, config, plugins)
|
|
680
|
+
* — Discovers all persona YAMLs for a suite, fires onSuiteInit, maps
|
|
681
|
+
* buildPersona() over each, and returns BuildResult[].
|
|
682
|
+
*
|
|
683
|
+
* 3. build(config)
|
|
684
|
+
* — Top-level entry point. Iterates all suites × targets, calls
|
|
685
|
+
* buildSuite() for each combination, and returns a BuildSummary.
|
|
686
|
+
* Respects --check (no writes) and --strict (fail on warnings/errors).
|
|
687
|
+
*/
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Build a single persona for a single output target.
|
|
691
|
+
*
|
|
692
|
+
* Pipeline:
|
|
693
|
+
* 1. Load sharedMeta + personaMeta (callers supply pre-loaded values)
|
|
694
|
+
* 2. Build merged context
|
|
695
|
+
* 3. Run onBuildContext plugin hooks (context accumulation)
|
|
696
|
+
* 4. Resolve frontmatter template → render frontmatter
|
|
697
|
+
* 5. Load content template
|
|
698
|
+
* 6. Render body: partials → conditionals → variables → post-process
|
|
699
|
+
* 7. Assemble final output (frontmatter + body)
|
|
700
|
+
* 8. Run onPostRender plugin hooks (output chain)
|
|
701
|
+
* 9. Run onValidate plugin hooks (validation collection)
|
|
702
|
+
* 10. Determine output file path
|
|
703
|
+
* 11. Write output file (unless check mode)
|
|
704
|
+
* 12. Return BuildResult
|
|
705
|
+
*
|
|
706
|
+
* @param personaYamlPath Absolute path to the persona YAML source file
|
|
707
|
+
* @param suiteName Identifier for the suite this persona belongs to
|
|
708
|
+
* @param suiteConfig Suite configuration object
|
|
709
|
+
* @param sharedMeta Pre-loaded `_shared.yaml` contents
|
|
710
|
+
* @param partialsMap Pre-loaded partials map (shared + suite-local merged)
|
|
711
|
+
* @param config Top-level BuildConfig
|
|
712
|
+
* @param plugins Registered plugins
|
|
713
|
+
* @param target Target output format
|
|
714
|
+
* @returns BuildResult for this persona × target combination
|
|
715
|
+
*/
|
|
716
|
+
declare function buildPersona(personaYamlPath: string, suiteName: string, suiteConfig: SuiteConfig, sharedMeta: Record<string, unknown>, partialsMap: Record<string, string>, config: BuildConfig, plugins: PersonaBuildPlugin[], target: 'vscode' | 'claude-code'): Promise<BuildResult>;
|
|
717
|
+
/**
|
|
718
|
+
* Build all personas in a suite for a single output target.
|
|
719
|
+
*
|
|
720
|
+
* Pipeline:
|
|
721
|
+
* 1. Load `_shared.yaml` for the suite
|
|
722
|
+
* 2. Load merged partials (shared → suite-local)
|
|
723
|
+
* 3. Run `onSuiteInit` on all plugins
|
|
724
|
+
* 4. Discover all persona YAML files
|
|
725
|
+
* 5. Call `buildPersona()` for each
|
|
726
|
+
*
|
|
727
|
+
* @param suiteName Identifier for this suite
|
|
728
|
+
* @param suiteConfig Suite configuration
|
|
729
|
+
* @param config Top-level BuildConfig
|
|
730
|
+
* @param plugins Registered plugins
|
|
731
|
+
* @param target Target output format
|
|
732
|
+
* @returns Array of BuildResult objects, one per persona
|
|
733
|
+
*/
|
|
734
|
+
declare function buildSuite(suiteName: string, suiteConfig: SuiteConfig, config: BuildConfig, plugins: PersonaBuildPlugin[], target: 'vscode' | 'claude-code'): Promise<BuildResult[]>;
|
|
735
|
+
/**
|
|
736
|
+
* Top-level build orchestrator.
|
|
737
|
+
*
|
|
738
|
+
* Iterates all `config.suites × config.targets` combinations, calls
|
|
739
|
+
* `buildSuite()` for each, and aggregates the results into a `BuildSummary`.
|
|
740
|
+
*
|
|
741
|
+
* Modes:
|
|
742
|
+
* - Normal: renders and writes all personas.
|
|
743
|
+
* - `check: true`: renders without writing; useful for CI staleness checks.
|
|
744
|
+
* - `strict: true`: throws when any ValidationResult has severity `'error'`
|
|
745
|
+
* or `'warning'`. All suites are processed before the throw, so output
|
|
746
|
+
* files **will** be written to disk even when the build ultimately fails.
|
|
747
|
+
* **For CI usage, combine `strict: true` with `check: true`** to avoid
|
|
748
|
+
* leaving partial artefacts on disk when validation fails.
|
|
749
|
+
*
|
|
750
|
+
* @param config Typed build configuration
|
|
751
|
+
* @returns Aggregated BuildSummary
|
|
752
|
+
* @throws `Error` when `strict: true` and validation failures exist
|
|
753
|
+
*/
|
|
754
|
+
declare function build(config: BuildConfig): Promise<BuildSummary>;
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* src/validators/filename-validator.ts
|
|
758
|
+
*
|
|
759
|
+
* Validates persona output filenames against the project naming convention.
|
|
760
|
+
*
|
|
761
|
+
* Convention: kebab-case only — lowercase letters, digits, and hyphens.
|
|
762
|
+
* No spaces, no uppercase letters, no special characters other than hyphens
|
|
763
|
+
* and dots (for the file extension).
|
|
764
|
+
*
|
|
765
|
+
* This is a pure function: no file I/O, no process.exit, no side effects.
|
|
766
|
+
* It depends only on `ValidationResult` from `src/plugins/types.ts`.
|
|
767
|
+
*/
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Validate a persona filename against the project naming convention.
|
|
771
|
+
*
|
|
772
|
+
* Accepts either a bare filename (`my-persona.md`) or a full/relative path
|
|
773
|
+
* — only the basename (last path segment) is evaluated.
|
|
774
|
+
*
|
|
775
|
+
* @param filePath Filename or path to validate (only the basename is checked)
|
|
776
|
+
* @returns Empty array when the filename conforms; one ValidationResult
|
|
777
|
+
* per violated rule otherwise. Each result has severity "error".
|
|
778
|
+
*
|
|
779
|
+
* @example
|
|
780
|
+
* validateFileName('my-persona.md'); // []
|
|
781
|
+
* validateFileName('My Persona.md'); // [{severity:'error', message:'...'}]
|
|
782
|
+
* validateFileName('/abs/path/my-persona.md');// []
|
|
783
|
+
*/
|
|
784
|
+
declare function validateFileName(filePath: string): ValidationResult[];
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* src/validators/strict-validator.ts
|
|
788
|
+
*
|
|
789
|
+
* Validates that a set of required marker strings are present in a rendered
|
|
790
|
+
* persona output string.
|
|
791
|
+
*
|
|
792
|
+
* "Strict" mode in the build pipeline guards against incomplete renders —
|
|
793
|
+
* e.g. a required section marker (e.g. "{{ROLE}}") that was never resolved.
|
|
794
|
+
* This validator generalises that concept: callers supply the list of marker
|
|
795
|
+
* strings that *must* appear in the final rendered content.
|
|
796
|
+
*
|
|
797
|
+
* This is a pure function: no file I/O, no side effects.
|
|
798
|
+
* It depends only on `ValidationResult` from `src/plugins/types.ts`.
|
|
799
|
+
*/
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* Validate that every required marker string is present in the rendered output.
|
|
803
|
+
*
|
|
804
|
+
* Each absent marker produces one `ValidationResult` entry with severity
|
|
805
|
+
* `"error"` and a descriptive message identifying the missing marker.
|
|
806
|
+
*
|
|
807
|
+
* @param renderedContent The final rendered output string to inspect
|
|
808
|
+
* @param requiredMarkers Array of marker strings that must appear verbatim in
|
|
809
|
+
* `renderedContent`. An empty array always returns `[]`.
|
|
810
|
+
* @returns Empty array when all markers are found; one entry per
|
|
811
|
+
* absent marker otherwise. Each entry has severity "error".
|
|
812
|
+
*
|
|
813
|
+
* @example
|
|
814
|
+
* validateStrictMarkers('Hello world', ['Hello', 'world']); // []
|
|
815
|
+
* validateStrictMarkers('Hello world', ['{{MISSING}}']);
|
|
816
|
+
* // [{severity:'error', message:'Required marker "{{MISSING}}" is missing from the rendered output.'}]
|
|
817
|
+
*/
|
|
818
|
+
declare function validateStrictMarkers(renderedContent: string, requiredMarkers: string[]): ValidationResult[];
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* @smor/persona-build
|
|
822
|
+
*
|
|
823
|
+
* Public API barrel export.
|
|
824
|
+
* Feature modules will be exported from here as they are implemented in subsequent WPs.
|
|
825
|
+
*/
|
|
826
|
+
|
|
827
|
+
declare const VERSION: string;
|
|
828
|
+
|
|
829
|
+
export { type BuildConfig, type BuildResult, type BuildSummary, DEFAULT_FRONTMATTER_CLAUDE_CODE, DEFAULT_FRONTMATTER_VSCODE, type PersonaBuildPlugin, type PersonaMetadata, type SuiteConfig, type TargetType, VERSION, type ValidationResult, build, buildPersona, buildSuite, collapseBlankLines, discoverPersonaYamls, ensureBlankLineBeforeHeadings, loadContent, loadMetadata, loadPartials, normalizeNewlines, renderFrontmatter, resolveConditionals, resolveFrontmatterTemplate, resolvePartials, resolveVariables, runBuildContext, runPostRender, runSuiteInit, runValidate, serializeTools, serializeToolsList, validateFileName, validateStrictMarkers };
|