@mistralys/persona-builder 2.1.3 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -5
- package/dist/cli.cjs +217 -35
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +217 -35
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +225 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +313 -45
- package/dist/index.d.ts +313 -45
- package/dist/index.js +220 -36
- package/dist/index.js.map +1 -1
- package/package.json +53 -53
package/README.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# AI Persona Builder
|
|
2
2
|
|
|
3
|
-
Build AI persona instruction files for **VS Code Chat** and **
|
|
3
|
+
Build AI persona instruction files for **VS Code Chat**, **Claude Code** and **LangGraph Deep Agents** from YAML metadata and Markdown templates — with zero configuration friction.
|
|
4
4
|
|
|
5
5
|
Define your personas once as simple YAML + Markdown sources, and the library generates correctly formatted instruction files for both IDEs. A plugin system lets you inject custom frontmatter, run validators, or post-process output without touching the core engine.
|
|
6
6
|
|
|
7
7
|
## ✨ Features
|
|
8
8
|
|
|
9
|
-
- **
|
|
9
|
+
- **Multi-target output** — generates VS Code `.agent.md`, Claude Code `.md`, Deep Agents `.md`, and any custom format from a single source
|
|
10
|
+
- **Extensible target registry** — register custom targets via `TargetRegistry` without touching core code; each target declares its own output key, frontmatter template, and context flags
|
|
10
11
|
- **YAML + Markdown templating** — separate metadata from content; merge them at build time with `{{variables}}`, `{{> partials}}`, and `{{#if}}` conditionals
|
|
11
12
|
- **Shared + per-suite partials** — reuse content fragments across personas with local overrides
|
|
12
13
|
- **Plugin architecture** — hook into context building, post-rendering, validation, and frontmatter generation
|
|
@@ -24,6 +25,9 @@ Define your personas once as simple YAML + Markdown sources, and the library gen
|
|
|
24
25
|
npm install @mistralys/persona-builder
|
|
25
26
|
```
|
|
26
27
|
|
|
28
|
+
- View on NPM: https://www.npmjs.com/package/@mistralys/persona-builder
|
|
29
|
+
- View on Github: https://github.com/Mistralys/ai-persona-builder
|
|
30
|
+
|
|
27
31
|
### Programmatic API
|
|
28
32
|
|
|
29
33
|
```ts
|
|
@@ -34,8 +38,10 @@ const summary = await build({
|
|
|
34
38
|
suites: {
|
|
35
39
|
'my-suite': {
|
|
36
40
|
srcDir: path.resolve('./personas/my-suite'),
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
outputDirs: {
|
|
42
|
+
vscode: path.resolve('./dist/vscode'),
|
|
43
|
+
'claude-code': path.resolve('./dist/claude-code'),
|
|
44
|
+
},
|
|
39
45
|
},
|
|
40
46
|
},
|
|
41
47
|
sharedPartialsDir: path.resolve('./personas/shared/partials'),
|
|
@@ -75,6 +81,7 @@ See the [CLI docs](docs/cli.md) for config file format and all flags.
|
|
|
75
81
|
| [Configuration Reference](docs/configuration.md) | `BuildConfig`, `SuiteConfig`, and `BuildSummary` fields |
|
|
76
82
|
| [CLI Reference](docs/cli.md) | Command-line flags, config file format, and common patterns |
|
|
77
83
|
| [Public API](docs/api.md) | All exported types and functions |
|
|
84
|
+
| [Project Manifest](docs/agents/project-manifest/README.md) | Canonical documentation for AI agent sessions |
|
|
78
85
|
|
|
79
86
|
## 🔌 Plugins
|
|
80
87
|
|
|
@@ -96,7 +103,7 @@ MIT
|
|
|
96
103
|
|
|
97
104
|
## Release Workflow
|
|
98
105
|
|
|
99
|
-
1. Add changelog entries
|
|
106
|
+
1. Add changelog entries (do not change package.json version)
|
|
100
107
|
2. `npm version 0.0.0` - Updates package and lock versions + commit
|
|
101
108
|
3. `npm publish` - Publish version on NPM
|
|
102
109
|
4. `git push origin 0.0.0` - Add the tag in GIT
|
package/dist/cli.cjs
CHANGED
|
@@ -27,19 +27,48 @@ function resolvePartials(text, partialsMap, depth = 0) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
// src/engine/conditionals.ts
|
|
30
|
+
var NO_NESTED_IF = String.raw`(?:(?!\{\{#if\b)[\s\S])*?`;
|
|
31
|
+
var ELSE_IF_PATTERN = new RegExp(
|
|
32
|
+
String.raw`\{\{else if (\w+)\}\}(${NO_NESTED_IF})\{\{\/if\}\}`,
|
|
33
|
+
"g"
|
|
34
|
+
);
|
|
35
|
+
function resolveElseIf(text) {
|
|
36
|
+
if (!text.includes("{{else if ")) {
|
|
37
|
+
return text;
|
|
38
|
+
}
|
|
39
|
+
let result = text;
|
|
40
|
+
let prev;
|
|
41
|
+
do {
|
|
42
|
+
prev = result;
|
|
43
|
+
result = result.replace(
|
|
44
|
+
ELSE_IF_PATTERN,
|
|
45
|
+
(_match, flag, content) => `{{else}}{{#if ${flag}}}${content}{{/if}}{{/if}}`
|
|
46
|
+
);
|
|
47
|
+
} while (result !== prev);
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
30
50
|
function resolveConditionals(text, context) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
(
|
|
34
|
-
|
|
35
|
-
return "\n" + inner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
36
|
-
}
|
|
37
|
-
if (elseInner !== void 0) {
|
|
38
|
-
return "\n" + elseInner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
39
|
-
}
|
|
40
|
-
return "\n";
|
|
41
|
-
}
|
|
51
|
+
const normalized = resolveElseIf(text);
|
|
52
|
+
const pattern = new RegExp(
|
|
53
|
+
String.raw`\n*\{\{#if (\w+)\}\}(${NO_NESTED_IF})` + String.raw`(?:\{\{else\}\}(${NO_NESTED_IF}))?\{\{\/if\}\}\n*`,
|
|
54
|
+
"g"
|
|
42
55
|
);
|
|
56
|
+
const resolve = (_match, flag, inner, elseInner) => {
|
|
57
|
+
if (context[flag]) {
|
|
58
|
+
return "\n" + inner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
59
|
+
}
|
|
60
|
+
if (elseInner !== void 0) {
|
|
61
|
+
return "\n" + elseInner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
62
|
+
}
|
|
63
|
+
return "\n";
|
|
64
|
+
};
|
|
65
|
+
let result = normalized;
|
|
66
|
+
let prev;
|
|
67
|
+
do {
|
|
68
|
+
prev = result;
|
|
69
|
+
result = result.replace(pattern, resolve);
|
|
70
|
+
} while (result !== prev);
|
|
71
|
+
return result;
|
|
43
72
|
}
|
|
44
73
|
|
|
45
74
|
// src/engine/variables.ts
|
|
@@ -98,11 +127,11 @@ function runSuiteInit(plugins, suite, sharedMeta) {
|
|
|
98
127
|
}
|
|
99
128
|
}
|
|
100
129
|
}
|
|
101
|
-
function runBuildContext(plugins, ctx, persona, suite) {
|
|
130
|
+
function runBuildContext(plugins, ctx, persona, suite, target) {
|
|
102
131
|
let accumulated = ctx;
|
|
103
132
|
for (const plugin of plugins) {
|
|
104
133
|
if (typeof plugin.onBuildContext === "function") {
|
|
105
|
-
accumulated = plugin.onBuildContext(accumulated, persona, suite);
|
|
134
|
+
accumulated = plugin.onBuildContext(accumulated, persona, suite, target);
|
|
106
135
|
}
|
|
107
136
|
}
|
|
108
137
|
return accumulated;
|
|
@@ -127,7 +156,10 @@ function runValidate(plugins, persona, suite, target) {
|
|
|
127
156
|
return results;
|
|
128
157
|
}
|
|
129
158
|
|
|
130
|
-
// src/
|
|
159
|
+
// src/targets/types.ts
|
|
160
|
+
var TARGET_VSCODE = "vscode";
|
|
161
|
+
var TARGET_CLAUDE_CODE = "claude-code";
|
|
162
|
+
var TARGET_DEEP_AGENTS = "deep-agents";
|
|
131
163
|
var DEFAULT_FRONTMATTER_VSCODE = `---
|
|
132
164
|
name: '{{name}} v{{version}}'
|
|
133
165
|
description: '{{description}}'
|
|
@@ -140,7 +172,13 @@ model: {{cc_model}}
|
|
|
140
172
|
memory: {{cc_memory}}
|
|
141
173
|
allowedTools: [{{cc_tools_list}}]
|
|
142
174
|
---`;
|
|
143
|
-
|
|
175
|
+
var DEFAULT_FRONTMATTER_DEEP_AGENTS = `---
|
|
176
|
+
name: {{name}}
|
|
177
|
+
description: {{description}}
|
|
178
|
+
---`;
|
|
179
|
+
|
|
180
|
+
// src/builders/frontmatter.ts
|
|
181
|
+
function resolveFrontmatterTemplate(target, plugins, configTemplates, registry) {
|
|
144
182
|
for (const plugin of plugins) {
|
|
145
183
|
if (plugin.frontmatterTemplates && target in plugin.frontmatterTemplates) {
|
|
146
184
|
const tpl = plugin.frontmatterTemplates[target];
|
|
@@ -151,7 +189,10 @@ function resolveFrontmatterTemplate(target, plugins, configTemplates) {
|
|
|
151
189
|
const tpl = configTemplates[target];
|
|
152
190
|
if (tpl !== void 0) return tpl;
|
|
153
191
|
}
|
|
154
|
-
|
|
192
|
+
if (registry && registry.has(target)) {
|
|
193
|
+
return registry.get(target).defaultFrontmatter;
|
|
194
|
+
}
|
|
195
|
+
return DEFAULT_FRONTMATTER_VSCODE;
|
|
155
196
|
}
|
|
156
197
|
function renderFrontmatter(template, context, filename) {
|
|
157
198
|
let rendered = resolveConditionals(template, context);
|
|
@@ -159,6 +200,112 @@ function renderFrontmatter(template, context, filename) {
|
|
|
159
200
|
return rendered;
|
|
160
201
|
}
|
|
161
202
|
|
|
203
|
+
// src/targets/registry.ts
|
|
204
|
+
var TargetRegistry = class _TargetRegistry {
|
|
205
|
+
// Map preserves insertion order — names() and allDefinitions() are
|
|
206
|
+
// therefore deterministic and match registration sequence. This is
|
|
207
|
+
// intentional: the built-in registry guarantees ['vscode', 'claude-code']
|
|
208
|
+
// ordering for the default targets (AC-2).
|
|
209
|
+
_definitions = /* @__PURE__ */ new Map();
|
|
210
|
+
/**
|
|
211
|
+
* Register a new target definition.
|
|
212
|
+
*
|
|
213
|
+
* @param definition The target descriptor to register.
|
|
214
|
+
* @throws {Error} If a target with the same `name` is already registered.
|
|
215
|
+
*/
|
|
216
|
+
register(definition) {
|
|
217
|
+
if (this._definitions.has(definition.name)) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`TargetRegistry: target "${definition.name}" is already registered. Use a unique name or remove the existing registration first.`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
this._definitions.set(definition.name, definition);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Retrieve a registered target definition by name.
|
|
226
|
+
*
|
|
227
|
+
* Returns a shallow copy — mutating the returned object does not affect
|
|
228
|
+
* the registry's internal state.
|
|
229
|
+
*
|
|
230
|
+
* @param name The target name to look up.
|
|
231
|
+
* @returns A shallow copy of the matching TargetDefinition.
|
|
232
|
+
* @throws {Error} If no target with the given name is registered.
|
|
233
|
+
*/
|
|
234
|
+
get(name) {
|
|
235
|
+
const def = this._definitions.get(name);
|
|
236
|
+
if (!def) {
|
|
237
|
+
const known = this.names().join(", ") || "(none)";
|
|
238
|
+
throw new Error(
|
|
239
|
+
`TargetRegistry: target "${name}" is not registered. Registered targets: ${known}.`
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
return { ...def };
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Returns `true` if a target with the given name is registered.
|
|
246
|
+
*
|
|
247
|
+
* @param name The target name to check.
|
|
248
|
+
*/
|
|
249
|
+
has(name) {
|
|
250
|
+
return this._definitions.has(name);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Returns the names of all registered targets, in registration order.
|
|
254
|
+
*/
|
|
255
|
+
names() {
|
|
256
|
+
return Array.from(this._definitions.keys());
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Returns all registered TargetDefinition objects, in registration order.
|
|
260
|
+
*
|
|
261
|
+
* Returns shallow copies — mutating a returned definition does not affect
|
|
262
|
+
* the registry's internal state.
|
|
263
|
+
*/
|
|
264
|
+
allDefinitions() {
|
|
265
|
+
return Array.from(this._definitions.values()).map((def) => ({ ...def }));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Returns a new TargetRegistry pre-populated with the same definitions.
|
|
269
|
+
*
|
|
270
|
+
* Useful for test isolation: clone the `defaultRegistry` to get an
|
|
271
|
+
* independent copy that can be mutated without affecting the singleton.
|
|
272
|
+
*/
|
|
273
|
+
clone() {
|
|
274
|
+
const copy = new _TargetRegistry();
|
|
275
|
+
for (const def of this._definitions.values()) {
|
|
276
|
+
copy.register({ ...def });
|
|
277
|
+
}
|
|
278
|
+
return copy;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// src/targets/built-in.ts
|
|
283
|
+
var defaultRegistry = new TargetRegistry();
|
|
284
|
+
defaultRegistry.register({
|
|
285
|
+
name: TARGET_VSCODE,
|
|
286
|
+
outputDirKey: "vscode",
|
|
287
|
+
filenameContextKey: "vs_file_name",
|
|
288
|
+
defaultFrontmatter: DEFAULT_FRONTMATTER_VSCODE,
|
|
289
|
+
contextFlags: { target_vscode: true },
|
|
290
|
+
defaultEnabled: true
|
|
291
|
+
});
|
|
292
|
+
defaultRegistry.register({
|
|
293
|
+
name: TARGET_CLAUDE_CODE,
|
|
294
|
+
outputDirKey: "claude-code",
|
|
295
|
+
filenameContextKey: "cc_file_name",
|
|
296
|
+
defaultFrontmatter: DEFAULT_FRONTMATTER_CLAUDE_CODE,
|
|
297
|
+
contextFlags: { target_claude_code: true },
|
|
298
|
+
defaultEnabled: true
|
|
299
|
+
});
|
|
300
|
+
defaultRegistry.register({
|
|
301
|
+
name: TARGET_DEEP_AGENTS,
|
|
302
|
+
outputDirKey: "deep-agents",
|
|
303
|
+
filenameContextKey: "da_file_name",
|
|
304
|
+
defaultFrontmatter: DEFAULT_FRONTMATTER_DEEP_AGENTS,
|
|
305
|
+
contextFlags: { target_deep_agents: true },
|
|
306
|
+
defaultEnabled: false
|
|
307
|
+
});
|
|
308
|
+
|
|
162
309
|
// src/builders/persona-builder.ts
|
|
163
310
|
async function discoverSuitePersonaYamls(suiteConfig) {
|
|
164
311
|
const metaSubdir = suiteConfig.metaSubdir ?? "meta";
|
|
@@ -186,6 +333,18 @@ async function loadPersonaYaml(yamlPath) {
|
|
|
186
333
|
}
|
|
187
334
|
return record;
|
|
188
335
|
}
|
|
336
|
+
function resolveOutputDir(target, suiteConfig, definition) {
|
|
337
|
+
const merged = {};
|
|
338
|
+
if (suiteConfig.outVscode) merged["vscode"] = suiteConfig.outVscode;
|
|
339
|
+
if (suiteConfig.outClaudeCode) merged["claude-code"] = suiteConfig.outClaudeCode;
|
|
340
|
+
if (suiteConfig.outputDirs) Object.assign(merged, suiteConfig.outputDirs);
|
|
341
|
+
const lookupKey = definition?.outputDirKey ?? target;
|
|
342
|
+
const dir = merged[lookupKey];
|
|
343
|
+
if (dir) return dir;
|
|
344
|
+
throw new Error(
|
|
345
|
+
`buildPersona: no output directory configured for target "${target}". Add outputDirs['${lookupKey}'] to the suite config, or, for the built-in targets, provide the outVscode / outClaudeCode fields.`
|
|
346
|
+
);
|
|
347
|
+
}
|
|
189
348
|
async function buildAgentNameMap(config) {
|
|
190
349
|
const agentMap = {};
|
|
191
350
|
for (const [, suiteConfig] of Object.entries(config.suites)) {
|
|
@@ -199,13 +358,16 @@ async function buildAgentNameMap(config) {
|
|
|
199
358
|
const slug = typeof persona["slug"] === "string" ? persona["slug"] : path2__default.default.basename(yamlPath, ".yaml");
|
|
200
359
|
const name = typeof persona["name"] === "string" ? persona["name"] : slug;
|
|
201
360
|
const version = typeof persona["version"] === "string" ? persona["version"] : defaultVersion;
|
|
202
|
-
const
|
|
361
|
+
const underscoredSlug = slug.replace(/-/g, "_");
|
|
362
|
+
const key = `agent_${underscoredSlug}`;
|
|
203
363
|
agentMap[key] = `${name} v${version}`;
|
|
364
|
+
const slugKey = `agent_slug_${underscoredSlug}`;
|
|
365
|
+
agentMap[slugKey] = slug;
|
|
204
366
|
}
|
|
205
367
|
}
|
|
206
368
|
return agentMap;
|
|
207
369
|
}
|
|
208
|
-
function buildContext(personaMeta, sharedMeta, agentMap = {}) {
|
|
370
|
+
function buildContext(personaMeta, sharedMeta, agentMap = {}, target, registry) {
|
|
209
371
|
const version = typeof personaMeta["version"] === "string" ? personaMeta["version"] : typeof sharedMeta["default_version"] === "string" ? sharedMeta["default_version"] : "0.0.0";
|
|
210
372
|
const merged = {
|
|
211
373
|
...sharedMeta,
|
|
@@ -230,19 +392,42 @@ function buildContext(personaMeta, sharedMeta, agentMap = {}) {
|
|
|
230
392
|
const ccFileName = merged["cc_file_name"];
|
|
231
393
|
merged["cc_file_name_stem"] = ccFileName.replace(/\.md$/, "");
|
|
232
394
|
}
|
|
395
|
+
if (!("da_file_name_stem" in merged) && typeof merged["da_file_name"] === "string") {
|
|
396
|
+
const daFileName = merged["da_file_name"];
|
|
397
|
+
merged["da_file_name_stem"] = daFileName.replace(/\.md$/, "");
|
|
398
|
+
}
|
|
399
|
+
if (typeof merged["da_file_name"] === "string") {
|
|
400
|
+
const daTools = Array.isArray(merged["da_tools"]) ? merged["da_tools"] : tools;
|
|
401
|
+
if (!("da_tools_list" in merged)) {
|
|
402
|
+
merged["da_tools_list"] = serializeToolsList(daTools);
|
|
403
|
+
}
|
|
404
|
+
if (!("da_tools_json" in merged)) {
|
|
405
|
+
merged["da_tools_json"] = serializeTools(daTools);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
233
408
|
for (const [key, value] of Object.entries(agentMap)) {
|
|
234
409
|
if (!(key in merged)) {
|
|
235
410
|
merged[key] = value;
|
|
236
411
|
}
|
|
237
412
|
}
|
|
413
|
+
if (target !== void 0) {
|
|
414
|
+
if (registry && registry.has(target)) {
|
|
415
|
+
const flags = registry.get(target).contextFlags ?? {};
|
|
416
|
+
for (const [key, value] of Object.entries(flags)) {
|
|
417
|
+
merged[key] = value;
|
|
418
|
+
}
|
|
419
|
+
} else {
|
|
420
|
+
merged[`target_${target.replace(/-/g, "_")}`] = true;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
238
423
|
return merged;
|
|
239
424
|
}
|
|
240
|
-
async function buildPersona(personaYamlPath, suiteName, suiteConfig, sharedMeta, partialsMap, config, plugins, target, agentMap = {}) {
|
|
425
|
+
async function buildPersona(personaYamlPath, suiteName, suiteConfig, sharedMeta, partialsMap, config, plugins, target, agentMap = {}, registry = defaultRegistry) {
|
|
241
426
|
const personaMeta = await loadPersonaYaml(personaYamlPath);
|
|
242
|
-
let context = buildContext(personaMeta, sharedMeta, agentMap);
|
|
427
|
+
let context = buildContext(personaMeta, sharedMeta, agentMap, target, registry);
|
|
243
428
|
const personaMetaTyped = personaMeta;
|
|
244
|
-
context = runBuildContext(plugins, context, personaMetaTyped, suiteConfig);
|
|
245
|
-
const fmTemplate = resolveFrontmatterTemplate(target, plugins, config.frontmatter);
|
|
429
|
+
context = runBuildContext(plugins, context, personaMetaTyped, suiteConfig, target);
|
|
430
|
+
const fmTemplate = resolveFrontmatterTemplate(target, plugins, config.frontmatter, registry);
|
|
246
431
|
const contentBasename = path2__default.default.basename(personaYamlPath, ".yaml") + ".md";
|
|
247
432
|
const frontmatter = renderFrontmatter(fmTemplate, context, contentBasename);
|
|
248
433
|
const contentSubdir = suiteConfig.contentSubdir ?? "content";
|
|
@@ -260,15 +445,10 @@ ${body}
|
|
|
260
445
|
`);
|
|
261
446
|
output = runPostRender(plugins, output, personaMetaTyped, target);
|
|
262
447
|
const validationResults = runValidate(plugins, personaMetaTyped, suiteConfig, target);
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
} else if (target === "claude-code" && typeof context["cc_file_name"] === "string") {
|
|
268
|
-
outputBasename = context["cc_file_name"];
|
|
269
|
-
} else {
|
|
270
|
-
outputBasename = contentBasename;
|
|
271
|
-
}
|
|
448
|
+
const def = registry.has(target) ? registry.get(target) : void 0;
|
|
449
|
+
const outputDir = resolveOutputDir(target, suiteConfig, def);
|
|
450
|
+
const fnKey = def?.filenameContextKey;
|
|
451
|
+
const outputBasename = fnKey && typeof context[fnKey] === "string" ? context[fnKey] : contentBasename;
|
|
272
452
|
const outputPath = path2__default.default.join(outputDir, outputBasename);
|
|
273
453
|
const check = config.check ?? false;
|
|
274
454
|
let written = false;
|
|
@@ -287,7 +467,7 @@ ${body}
|
|
|
287
467
|
written
|
|
288
468
|
};
|
|
289
469
|
}
|
|
290
|
-
async function buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap = {}) {
|
|
470
|
+
async function buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap = {}, registry = defaultRegistry) {
|
|
291
471
|
const metaSubdir = suiteConfig.metaSubdir ?? "meta";
|
|
292
472
|
const sharedYamlPath = path2__default.default.join(suiteConfig.srcDir, metaSubdir, "_shared.yaml");
|
|
293
473
|
const sharedMeta = await loadRawYaml(sharedYamlPath);
|
|
@@ -313,7 +493,8 @@ async function buildSuite(suiteName, suiteConfig, config, plugins, target, agent
|
|
|
313
493
|
config,
|
|
314
494
|
plugins,
|
|
315
495
|
target,
|
|
316
|
-
agentMap
|
|
496
|
+
agentMap,
|
|
497
|
+
registry
|
|
317
498
|
);
|
|
318
499
|
results.push(result);
|
|
319
500
|
}
|
|
@@ -321,12 +502,13 @@ async function buildSuite(suiteName, suiteConfig, config, plugins, target, agent
|
|
|
321
502
|
}
|
|
322
503
|
async function build(config) {
|
|
323
504
|
const plugins = config.plugins ?? [];
|
|
324
|
-
const
|
|
505
|
+
const registry = config.targetRegistry ?? defaultRegistry;
|
|
506
|
+
const targets = config.targets ?? registry.names().filter((n) => registry.get(n).defaultEnabled !== false);
|
|
325
507
|
const allResults = [];
|
|
326
508
|
const agentMap = await buildAgentNameMap(config);
|
|
327
509
|
for (const [suiteName, suiteConfig] of Object.entries(config.suites)) {
|
|
328
510
|
for (const target of targets) {
|
|
329
|
-
const suiteResults = await buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap);
|
|
511
|
+
const suiteResults = await buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap, registry);
|
|
330
512
|
allResults.push(...suiteResults);
|
|
331
513
|
}
|
|
332
514
|
}
|