@mistralys/persona-builder 2.3.0 → 2.4.1

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/dist/index.d.cts CHANGED
@@ -22,7 +22,12 @@
22
22
  *
23
23
  * @param text - Template string potentially containing {{> name}} markers
24
24
  * @param partialsMap - Map of partial name → partial content
25
- * @param depth - Current recursion depth (callers should omit; defaults to 0)
25
+ * @param depth - **Internal recursion counter callers must always omit this
26
+ * parameter.** It exists solely so the function can track its own
27
+ * nesting level across recursive calls. Passing a non-zero value
28
+ * bypasses the depth guard (e.g. `resolvePartials(text, map, 5)`
29
+ * expands nothing). This parameter will be removed from the public
30
+ * signature and marked `@internal` in a future release.
26
31
  * @returns The template string with partial markers replaced
27
32
  */
28
33
  declare function resolvePartials(text: string, partialsMap: Record<string, string>, depth?: number): string;
@@ -251,6 +256,14 @@ interface PersonaMetadata {
251
256
  version?: string;
252
257
  /** Ordered list of tool identifiers */
253
258
  tools?: string[];
259
+ /**
260
+ * Optional list of persona slugs this persona delegates to as sub-agents.
261
+ *
262
+ * Each entry is a kebab-case slug referencing another persona in any
263
+ * configured suite. Validated during build against the cross-suite agent
264
+ * map — an unknown slug produces an error-severity `ValidationResult`.
265
+ */
266
+ subagents?: string[];
254
267
  /** Free-form context variables available during template rendering */
255
268
  [key: string]: unknown;
256
269
  }
@@ -315,6 +328,26 @@ interface SuiteConfig {
315
328
  metaSubdir?: string;
316
329
  /** Sub-directory within srcDir that contains content Markdown files. Default: 'content' */
317
330
  contentSubdir?: string;
331
+ /**
332
+ * Optional map of suite-level template variables.
333
+ *
334
+ * These form the **second-lowest** layer (layer 2 of 7) in the merge chain
335
+ * used by `buildContext()`:
336
+ *
337
+ * 1. `BuildConfig.variables` — global defaults (lowest priority)
338
+ * 2. `SuiteConfig.variables` ← this field
339
+ * 3. `_shared.yaml` fields — shared metadata
340
+ * 4. Per-persona YAML fields — per-persona metadata
341
+ * 5. Derived fields — version fallback, tools serialisation, etc.
342
+ * 6. Cross-suite agent map — `agent_<slug>` entries
343
+ * 7. Target flags — `target_<name>` booleans (highest priority)
344
+ *
345
+ * Suite variables override any same-named entry in `BuildConfig.variables`,
346
+ * but are themselves overridden by `_shared.yaml` fields and per-persona
347
+ * YAML metadata. Use this field to inject suite-scoped defaults that apply
348
+ * to every persona in the suite without modifying shared YAML files.
349
+ */
350
+ variables?: Record<string, unknown>;
318
351
  }
319
352
  /**
320
353
  * A single validation outcome returned by a plugin's `onValidate` hook.
@@ -333,10 +366,12 @@ interface ValidationResult {
333
366
  * identification.
334
367
  *
335
368
  * Hook invocation order (per persona):
336
- * 1. onSuiteInit — once per suite, before any persona is built
337
- * 2. onBuildContext — per persona, before template rendering
338
- * 3. onPostRender — per persona, after body rendering
339
- * 4. onValidate — per persona, during the validation phase
369
+ * 1. onSuiteInit — once per suite, before any persona is built
370
+ * 2. onPartials once per suite, after partials are loaded
371
+ * 3. onBuildContext — per persona, before template rendering
372
+ * 4. onPersonaPartials — per persona, before template rendering (after onBuildContext)
373
+ * 5. onPostRender — per persona, after body rendering
374
+ * 6. onValidate — per persona, during the validation phase
340
375
  */
341
376
  interface PersonaBuildPlugin {
342
377
  /**
@@ -353,6 +388,21 @@ interface PersonaBuildPlugin {
353
388
  * @param sharedMeta Shared metadata merged from `_shared.yaml` (mutate in place if needed)
354
389
  */
355
390
  onSuiteInit?(suite: SuiteConfig, sharedMeta: Record<string, unknown>): void;
391
+ /**
392
+ * Called once per suite after partials are loaded from disk (and after any
393
+ * `BuildConfig.partials` inline map has been applied), but before any persona
394
+ * is rendered.
395
+ *
396
+ * Plugins are chained: each plugin receives the accumulated partials map
397
+ * returned by the previous plugin. Return the (possibly mutated or extended)
398
+ * map to pass it to the next plugin.
399
+ *
400
+ * @param partialsMap The current map of partial name → partial content
401
+ * @param suiteName The identifier of the current suite
402
+ * @param suite The suite configuration object
403
+ * @returns Updated partials map (must include all original keys)
404
+ */
405
+ onPartials?(partialsMap: Record<string, string>, suiteName: string, suite: SuiteConfig): Record<string, string>;
356
406
  /**
357
407
  * Called for each persona before template rendering.
358
408
  *
@@ -366,6 +416,34 @@ interface PersonaBuildPlugin {
366
416
  * @returns Updated rendering context (must include all original keys)
367
417
  */
368
418
  onBuildContext?(context: Record<string, unknown>, persona: PersonaMetadata, suite: SuiteConfig, target?: TargetType): Record<string, unknown>;
419
+ /**
420
+ * Called for each persona (and target) after `onBuildContext`, before
421
+ * template rendering.
422
+ *
423
+ * Allows plugins to inject or override partials on a per-persona basis.
424
+ * Plugins are chained: each plugin receives the accumulated partials map
425
+ * returned by the previous plugin. Return the (possibly mutated or extended)
426
+ * map to pass it to the next plugin.
427
+ *
428
+ * **Isolation guarantee:** The builder creates a shallow copy of the
429
+ * suite-level partials map before invoking the first plugin in the chain.
430
+ * The `partialsMap` argument you receive is already persona-scoped — changes
431
+ * to it (or to the map you return) are invisible to other personas in the
432
+ * same suite. Do **not** mutate `partialsMap` in place; instead, return a
433
+ * new map (e.g. `{ ...partialsMap, myPartial: '...' }`) so that each plugin
434
+ * in the chain receives an independent copy of the previous plugin's output.
435
+ *
436
+ * @param partialsMap The current persona-scoped map of partial name → content
437
+ * (a shallow copy of the suite-level map, isolated per persona)
438
+ * @param persona Typed metadata for the persona being built
439
+ * @param context The post-`onBuildContext` rendering context; persona
440
+ * metadata and any context keys injected by `onBuildContext`
441
+ * plugins are accessible here
442
+ * @param suite The suite configuration object
443
+ * @param target The current build target (optional)
444
+ * @returns Updated partials map (must include all original keys)
445
+ */
446
+ onPersonaPartials?(partialsMap: Record<string, string>, persona: PersonaMetadata, context: Record<string, unknown>, suite: SuiteConfig, target?: TargetType): Record<string, string>;
369
447
  /**
370
448
  * Called for each persona after body rendering.
371
449
  *
@@ -495,8 +573,9 @@ declare function loadContent(mdPath: string): Promise<string>;
495
573
  * PersonaBuildPlugin. The runner:
496
574
  * - Skips plugins that do not implement the requested hook (hook is optional)
497
575
  * - Invokes hooks in the order plugins are registered (first-in first-called)
498
- * - For accumulating hooks (onBuildContext, onPostRender), each plugin
499
- * receives the output of the previous plugin as its first argument
576
+ * - For accumulating hooks (onBuildContext, onPartials, onPersonaPartials,
577
+ * onPostRender), each plugin receives the output of the previous plugin
578
+ * as its first argument
500
579
  * - For collecting hooks (onValidate), results are concatenated into a
501
580
  * flat array
502
581
  *
@@ -547,6 +626,44 @@ declare function runBuildContext(plugins: PersonaBuildPlugin[], ctx: Record<stri
547
626
  * @returns Final output string after all plugins have run
548
627
  */
549
628
  declare function runPostRender(plugins: PersonaBuildPlugin[], rendered: string, persona: PersonaMetadata, target: TargetType): string;
629
+ /**
630
+ * Invoke the `onPartials` hook on every registered plugin, accumulating
631
+ * partials map mutations sequentially.
632
+ *
633
+ * Each plugin receives the partials map returned by the previous plugin. If a
634
+ * plugin does not implement `onPartials`, the map passes through unchanged.
635
+ * The final accumulated map is returned.
636
+ *
637
+ * Called once per suite after partials are loaded from disk, before any
638
+ * persona is rendered.
639
+ *
640
+ * @param plugins Ordered list of registered plugins
641
+ * @param partialsMap Initial map of partial name → partial content
642
+ * @param suiteName The identifier of the current suite
643
+ * @param suite The suite configuration object
644
+ * @returns Accumulated partials map after all plugins have run
645
+ */
646
+ declare function runPartials(plugins: PersonaBuildPlugin[], partialsMap: Record<string, string>, suiteName: string, suite: SuiteConfig): Record<string, string>;
647
+ /**
648
+ * Invoke the `onPersonaPartials` hook on every registered plugin, accumulating
649
+ * partials map mutations sequentially.
650
+ *
651
+ * Each plugin receives the partials map returned by the previous plugin. If a
652
+ * plugin does not implement `onPersonaPartials`, the map passes through
653
+ * unchanged. The final accumulated map is returned.
654
+ *
655
+ * Called for each persona (and target) after `onBuildContext`, before
656
+ * template rendering.
657
+ *
658
+ * @param plugins Ordered list of registered plugins
659
+ * @param partialsMap Initial map of partial name → partial content
660
+ * @param persona Typed metadata for the persona being built
661
+ * @param context The rendering context built by `onBuildContext`
662
+ * @param suite The suite configuration object
663
+ * @param target The current build target (optional)
664
+ * @returns Accumulated partials map after all plugins have run
665
+ */
666
+ declare function runPersonaPartials(plugins: PersonaBuildPlugin[], partialsMap: Record<string, string>, persona: PersonaMetadata, context: Record<string, unknown>, suite: SuiteConfig, target?: TargetType): Record<string, string>;
550
667
  /**
551
668
  * Invoke the `onValidate` hook on every registered plugin and collect all
552
669
  * returned ValidationResult objects into a single flat array.
@@ -745,9 +862,19 @@ interface BuildConfig {
745
862
  */
746
863
  suites: Record<string, SuiteConfig>;
747
864
  /**
748
- * Absolute path to the shared partials directory. When provided, partials
749
- * from this directory are loaded as the base layer before suite-local
750
- * partials are overlaid. Optional.
865
+ * Absolute path to the shared partials directory.
866
+ *
867
+ * When provided, partials from this directory form the **second** layer in
868
+ * the five-layer partials resolution order:
869
+ *
870
+ * 1. `BuildConfig.partials` — lowest precedence (inline map)
871
+ * 2. `sharedPartialsDir` — overlaid on top of inline partials (this field)
872
+ * 3. Suite-local partials — overlaid on top of shared partials
873
+ * 4. `onPartials` hooks — suite-level plugin-injected partials
874
+ * 5. `onPersonaPartials` — per-persona overrides (highest precedence)
875
+ *
876
+ * Later layers overlay earlier ones; a key present in multiple layers uses
877
+ * the value from the highest-precedence layer.
751
878
  */
752
879
  sharedPartialsDir?: string;
753
880
  /**
@@ -794,6 +921,43 @@ interface BuildConfig {
794
921
  * `TargetDefinition.defaultFrontmatter` are used.
795
922
  */
796
923
  frontmatter?: Record<string, string>;
924
+ /**
925
+ * Optional map of global template variables made available to every persona
926
+ * during rendering.
927
+ *
928
+ * These form the **lowest-priority** layer (layer 1 of 7) in the merge chain
929
+ * used by `buildContext()`:
930
+ *
931
+ * 1. `BuildConfig.variables` ← this field (lowest priority)
932
+ * 2. `SuiteConfig.variables` — suite-level overrides
933
+ * 3. `_shared.yaml` fields — shared metadata
934
+ * 4. Per-persona YAML fields — per-persona metadata
935
+ * 5. Derived fields — version fallback, tools serialisation, etc.
936
+ * 6. Cross-suite agent map — `agent_<slug>` entries
937
+ * 7. Target flags — `target_<name>` booleans (highest priority)
938
+ *
939
+ * Any key set here that also appears in a higher-priority layer will be
940
+ * overridden. Use this field for project-wide defaults that individual suites
941
+ * or personas can selectively override via `SuiteConfig.variables` or their
942
+ * own YAML metadata.
943
+ */
944
+ variables?: Record<string, unknown>;
945
+ /**
946
+ * Optional map of inline partials, keyed by partial name.
947
+ *
948
+ * These form the **lowest** layer in the five-layer partials resolution
949
+ * order:
950
+ *
951
+ * 1. `BuildConfig.partials` — lowest precedence (this field)
952
+ * 2. `sharedPartialsDir` — overlaid on top of inline partials
953
+ * 3. Suite-local partials — overlaid on top of shared partials
954
+ * 4. `onPartials` hooks — suite-level plugin-injected partials
955
+ * 5. `onPersonaPartials` — per-persona overrides (highest precedence)
956
+ *
957
+ * Later layers overlay earlier ones; a key present in multiple layers uses
958
+ * the value from the highest-precedence layer.
959
+ */
960
+ partials?: Record<string, string>;
797
961
  /**
798
962
  * Optional target registry to use for this build.
799
963
  *
@@ -915,6 +1079,21 @@ declare function renderFrontmatter(template: string, context: Record<string, unk
915
1079
  * agent name map, then iterates all suites × targets, calls
916
1080
  * buildSuite() for each combination, and returns a BuildSummary.
917
1081
  * Respects --check (no writes) and --strict (fail on warnings/errors).
1082
+ *
1083
+ * Template variable injection (7-layer merge order, later layers win):
1084
+ *
1085
+ * 1. BuildConfig.variables — global defaults; available to every suite
1086
+ * 2. SuiteConfig.variables — suite-level overrides
1087
+ * 3. _shared.yaml fields — shared metadata for the suite
1088
+ * 4. Per-persona YAML fields — per-persona metadata
1089
+ * 5. Derived fields — version fallback, tools serialisation, etc.
1090
+ * 6. Cross-suite agent map — agent_<slug> / agent_slug_<slug> entries
1091
+ * 7. Target flags — target_<name> booleans; always highest precedence
1092
+ *
1093
+ * Callers inject global or suite-scoped variables via `BuildConfig.variables`
1094
+ * and `SuiteConfig.variables` respectively. Both fields are forwarded by
1095
+ * buildPersona() to the internal buildContext() function as the two
1096
+ * lowest-priority layers in the merge chain.
918
1097
  */
919
1098
 
920
1099
  /**
@@ -924,22 +1103,39 @@ declare function renderFrontmatter(template: string, context: Record<string, unk
924
1103
  * 1. Load sharedMeta + personaMeta (callers supply pre-loaded values)
925
1104
  * 2. Build merged context
926
1105
  * 3. Run onBuildContext plugin hooks (context accumulation)
927
- * 4. Resolve frontmatter template render frontmatter
928
- * 5. Load content template
929
- * 6. Render body: partials → conditionals → variables → post-process
930
- * 7. Assemble final output (frontmatter + body)
931
- * 8. Run onPostRender plugin hooks (output chain)
932
- * 9. Run onValidate plugin hooks (validation collection)
933
- * 10. Determine output file path
934
- * 11. Write output file (unless check mode)
935
- * 12. Return BuildResult
1106
+ * 4. Run onPersonaPartials plugin hooks (shallow-copy partials map, persona-scoped)
1107
+ * 5. Render frontmatter template → render frontmatter
1108
+ * 6. Load content template
1109
+ * 7. Render body: partials conditionals → variables → post-process
1110
+ * 8. Assemble final output (frontmatter + body)
1111
+ * 9. Run onPostRender plugin hooks (output chain)
1112
+ * 10. Run onValidate plugin hooks (validation collection)
1113
+ * 11. Determine output file path
1114
+ * 12. Write output file (unless check mode)
1115
+ * 13. Return BuildResult
936
1116
  *
937
1117
  * @param personaYamlPath Absolute path to the persona YAML source file
938
1118
  * @param suiteName Identifier for the suite this persona belongs to
939
- * @param suiteConfig Suite configuration object
1119
+ * @param suiteConfig Suite configuration object. `suiteConfig.variables`
1120
+ * is forwarded to `buildContext()` as the
1121
+ * `suiteVariables` layer (layer 2 of 7) — these values
1122
+ * override any `config.variables` but are themselves
1123
+ * overridden by `_shared.yaml` and per-persona fields.
940
1124
  * @param sharedMeta Pre-loaded `_shared.yaml` contents
941
- * @param partialsMap Pre-loaded partials map (shared + suite-local merged)
942
- * @param config Top-level BuildConfig
1125
+ * @param partialsMap Pre-loaded partials map (shared + suite-local merged).
1126
+ * This map is **not** passed directly to rendering.
1127
+ * Instead, a shallow copy (`{ ...partialsMap }`) is
1128
+ * created at step 3b and passed to the `onPersonaPartials`
1129
+ * plugin hooks — the hooks' accumulated output map is what
1130
+ * reaches `resolvePartials`, not `partialsMap` itself.
1131
+ * This ensures that persona-level overrides or injections
1132
+ * do not leak back into the caller's reference or into
1133
+ * subsequent personas in the same suite.
1134
+ * @param config Top-level BuildConfig. `config.variables` is
1135
+ * forwarded to `buildContext()` as the
1136
+ * `configVariables` layer (layer 1 of 7, lowest
1137
+ * priority) — global defaults available to every
1138
+ * persona across all suites.
943
1139
  * @param plugins Registered plugins
944
1140
  * @param target Target output format
945
1141
  * @param agentMap Pre-built cross-suite agent name map
@@ -958,10 +1154,11 @@ declare function buildPersona(personaYamlPath: string, suiteName: string, suiteC
958
1154
  *
959
1155
  * Pipeline:
960
1156
  * 1. Load `_shared.yaml` for the suite
961
- * 2. Load merged partials (shared → suite-local)
1157
+ * 2. Load merged partials (config.partials → shared → suite-local)
962
1158
  * 3. Run `onSuiteInit` on all plugins
963
- * 4. Discover all persona YAML files
964
- * 5. Call `buildPersona()` for each
1159
+ * 4. Run `onPartials` on all plugins (highest priority: may override any file-based partial)
1160
+ * 5. Discover all persona YAML files
1161
+ * 6. Call `buildPersona()` for each
965
1162
  *
966
1163
  * @param suiteName Identifier for this suite
967
1164
  * @param suiteConfig Suite configuration
@@ -1119,4 +1316,4 @@ declare const defaultRegistry: TargetRegistry;
1119
1316
 
1120
1317
  declare const VERSION: string;
1121
1318
 
1122
- export { type BuildConfig, type BuildResult, type BuildSummary, DEFAULT_FRONTMATTER_CLAUDE_CODE, DEFAULT_FRONTMATTER_DEEP_AGENTS, DEFAULT_FRONTMATTER_VSCODE, type PersonaBuildPlugin, type PersonaMetadata, type SuiteConfig, TARGET_CLAUDE_CODE, TARGET_DEEP_AGENTS, TARGET_VSCODE, type TargetDefinition, TargetRegistry, type TargetType, VERSION, type ValidationResult, build, buildPersona, buildSuite, collapseBlankLines, defaultRegistry, discoverPersonaYamls, ensureBlankLineBeforeHeadings, escapeRegExp, loadContent, loadMetadata, loadPartials, normalizeNewlines, renderFrontmatter, resolveConditionals, resolveFrontmatterTemplate, resolvePartials, resolveVariables, runBuildContext, runPostRender, runSuiteInit, runValidate, serializeTools, serializeToolsList, validateFileName, validateStrictMarkers };
1319
+ export { type BuildConfig, type BuildResult, type BuildSummary, DEFAULT_FRONTMATTER_CLAUDE_CODE, DEFAULT_FRONTMATTER_DEEP_AGENTS, DEFAULT_FRONTMATTER_VSCODE, type PersonaBuildPlugin, type PersonaMetadata, type SuiteConfig, TARGET_CLAUDE_CODE, TARGET_DEEP_AGENTS, TARGET_VSCODE, type TargetDefinition, TargetRegistry, type TargetType, VERSION, type ValidationResult, build, buildPersona, buildSuite, collapseBlankLines, defaultRegistry, discoverPersonaYamls, ensureBlankLineBeforeHeadings, escapeRegExp, loadContent, loadMetadata, loadPartials, normalizeNewlines, renderFrontmatter, resolveConditionals, resolveFrontmatterTemplate, resolvePartials, resolveVariables, runBuildContext, runPartials, runPersonaPartials, runPostRender, runSuiteInit, runValidate, serializeTools, serializeToolsList, validateFileName, validateStrictMarkers };