@mistralys/persona-builder 2.1.3 → 2.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/README.md +7 -3
- package/dist/cli.cjs +197 -35
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +197 -35
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +205 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +307 -45
- package/dist/index.d.ts +307 -45
- package/dist/index.js +200 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -28,18 +28,27 @@ function resolvePartials(text, partialsMap, depth = 0) {
|
|
|
28
28
|
|
|
29
29
|
// src/engine/conditionals.ts
|
|
30
30
|
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
|
-
}
|
|
31
|
+
const noNestedIf = String.raw`(?:(?!\{\{#if\b)[\s\S])*?`;
|
|
32
|
+
const pattern = new RegExp(
|
|
33
|
+
String.raw`\n*\{\{#if (\w+)\}\}(${noNestedIf})` + String.raw`(?:\{\{else\}\}(${noNestedIf}))?\{\{\/if\}\}\n*`,
|
|
34
|
+
"g"
|
|
42
35
|
);
|
|
36
|
+
const resolve = (_match, flag, inner, elseInner) => {
|
|
37
|
+
if (context[flag]) {
|
|
38
|
+
return "\n" + inner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
39
|
+
}
|
|
40
|
+
if (elseInner !== void 0) {
|
|
41
|
+
return "\n" + elseInner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
42
|
+
}
|
|
43
|
+
return "\n";
|
|
44
|
+
};
|
|
45
|
+
let result = text;
|
|
46
|
+
let prev;
|
|
47
|
+
do {
|
|
48
|
+
prev = result;
|
|
49
|
+
result = result.replace(pattern, resolve);
|
|
50
|
+
} while (result !== prev);
|
|
51
|
+
return result;
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
// src/engine/variables.ts
|
|
@@ -124,11 +133,11 @@ function runSuiteInit(plugins, suite, sharedMeta) {
|
|
|
124
133
|
}
|
|
125
134
|
}
|
|
126
135
|
}
|
|
127
|
-
function runBuildContext(plugins, ctx, persona, suite) {
|
|
136
|
+
function runBuildContext(plugins, ctx, persona, suite, target) {
|
|
128
137
|
let accumulated = ctx;
|
|
129
138
|
for (const plugin of plugins) {
|
|
130
139
|
if (typeof plugin.onBuildContext === "function") {
|
|
131
|
-
accumulated = plugin.onBuildContext(accumulated, persona, suite);
|
|
140
|
+
accumulated = plugin.onBuildContext(accumulated, persona, suite, target);
|
|
132
141
|
}
|
|
133
142
|
}
|
|
134
143
|
return accumulated;
|
|
@@ -153,7 +162,10 @@ function runValidate(plugins, persona, suite, target) {
|
|
|
153
162
|
return results;
|
|
154
163
|
}
|
|
155
164
|
|
|
156
|
-
// src/
|
|
165
|
+
// src/targets/types.ts
|
|
166
|
+
var TARGET_VSCODE = "vscode";
|
|
167
|
+
var TARGET_CLAUDE_CODE = "claude-code";
|
|
168
|
+
var TARGET_DEEP_AGENTS = "deep-agents";
|
|
157
169
|
var DEFAULT_FRONTMATTER_VSCODE = `---
|
|
158
170
|
name: '{{name}} v{{version}}'
|
|
159
171
|
description: '{{description}}'
|
|
@@ -166,7 +178,13 @@ model: {{cc_model}}
|
|
|
166
178
|
memory: {{cc_memory}}
|
|
167
179
|
allowedTools: [{{cc_tools_list}}]
|
|
168
180
|
---`;
|
|
169
|
-
|
|
181
|
+
var DEFAULT_FRONTMATTER_DEEP_AGENTS = `---
|
|
182
|
+
name: {{name}}
|
|
183
|
+
description: {{description}}
|
|
184
|
+
---`;
|
|
185
|
+
|
|
186
|
+
// src/builders/frontmatter.ts
|
|
187
|
+
function resolveFrontmatterTemplate(target, plugins, configTemplates, registry) {
|
|
170
188
|
for (const plugin of plugins) {
|
|
171
189
|
if (plugin.frontmatterTemplates && target in plugin.frontmatterTemplates) {
|
|
172
190
|
const tpl = plugin.frontmatterTemplates[target];
|
|
@@ -177,13 +195,124 @@ function resolveFrontmatterTemplate(target, plugins, configTemplates) {
|
|
|
177
195
|
const tpl = configTemplates[target];
|
|
178
196
|
if (tpl !== void 0) return tpl;
|
|
179
197
|
}
|
|
180
|
-
|
|
198
|
+
if (registry && registry.has(target)) {
|
|
199
|
+
return registry.get(target).defaultFrontmatter;
|
|
200
|
+
}
|
|
201
|
+
return DEFAULT_FRONTMATTER_VSCODE;
|
|
181
202
|
}
|
|
182
203
|
function renderFrontmatter(template, context, filename) {
|
|
183
204
|
let rendered = resolveConditionals(template, context);
|
|
184
205
|
rendered = resolveVariables(rendered, context, filename);
|
|
185
206
|
return rendered;
|
|
186
207
|
}
|
|
208
|
+
|
|
209
|
+
// src/targets/registry.ts
|
|
210
|
+
var TargetRegistry = class _TargetRegistry {
|
|
211
|
+
// Map preserves insertion order — names() and allDefinitions() are
|
|
212
|
+
// therefore deterministic and match registration sequence. This is
|
|
213
|
+
// intentional: the built-in registry guarantees ['vscode', 'claude-code']
|
|
214
|
+
// ordering for the default targets (AC-2).
|
|
215
|
+
_definitions = /* @__PURE__ */ new Map();
|
|
216
|
+
/**
|
|
217
|
+
* Register a new target definition.
|
|
218
|
+
*
|
|
219
|
+
* @param definition The target descriptor to register.
|
|
220
|
+
* @throws {Error} If a target with the same `name` is already registered.
|
|
221
|
+
*/
|
|
222
|
+
register(definition) {
|
|
223
|
+
if (this._definitions.has(definition.name)) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
`TargetRegistry: target "${definition.name}" is already registered. Use a unique name or remove the existing registration first.`
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
this._definitions.set(definition.name, definition);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Retrieve a registered target definition by name.
|
|
232
|
+
*
|
|
233
|
+
* Returns a shallow copy — mutating the returned object does not affect
|
|
234
|
+
* the registry's internal state.
|
|
235
|
+
*
|
|
236
|
+
* @param name The target name to look up.
|
|
237
|
+
* @returns A shallow copy of the matching TargetDefinition.
|
|
238
|
+
* @throws {Error} If no target with the given name is registered.
|
|
239
|
+
*/
|
|
240
|
+
get(name) {
|
|
241
|
+
const def = this._definitions.get(name);
|
|
242
|
+
if (!def) {
|
|
243
|
+
const known = this.names().join(", ") || "(none)";
|
|
244
|
+
throw new Error(
|
|
245
|
+
`TargetRegistry: target "${name}" is not registered. Registered targets: ${known}.`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
return { ...def };
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Returns `true` if a target with the given name is registered.
|
|
252
|
+
*
|
|
253
|
+
* @param name The target name to check.
|
|
254
|
+
*/
|
|
255
|
+
has(name) {
|
|
256
|
+
return this._definitions.has(name);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Returns the names of all registered targets, in registration order.
|
|
260
|
+
*/
|
|
261
|
+
names() {
|
|
262
|
+
return Array.from(this._definitions.keys());
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Returns all registered TargetDefinition objects, in registration order.
|
|
266
|
+
*
|
|
267
|
+
* Returns shallow copies — mutating a returned definition does not affect
|
|
268
|
+
* the registry's internal state.
|
|
269
|
+
*/
|
|
270
|
+
allDefinitions() {
|
|
271
|
+
return Array.from(this._definitions.values()).map((def) => ({ ...def }));
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Returns a new TargetRegistry pre-populated with the same definitions.
|
|
275
|
+
*
|
|
276
|
+
* Useful for test isolation: clone the `defaultRegistry` to get an
|
|
277
|
+
* independent copy that can be mutated without affecting the singleton.
|
|
278
|
+
*/
|
|
279
|
+
clone() {
|
|
280
|
+
const copy = new _TargetRegistry();
|
|
281
|
+
for (const def of this._definitions.values()) {
|
|
282
|
+
copy.register({ ...def });
|
|
283
|
+
}
|
|
284
|
+
return copy;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// src/targets/built-in.ts
|
|
289
|
+
var defaultRegistry = new TargetRegistry();
|
|
290
|
+
defaultRegistry.register({
|
|
291
|
+
name: TARGET_VSCODE,
|
|
292
|
+
outputDirKey: "vscode",
|
|
293
|
+
filenameContextKey: "vs_file_name",
|
|
294
|
+
defaultFrontmatter: DEFAULT_FRONTMATTER_VSCODE,
|
|
295
|
+
contextFlags: { target_vscode: true },
|
|
296
|
+
defaultEnabled: true
|
|
297
|
+
});
|
|
298
|
+
defaultRegistry.register({
|
|
299
|
+
name: TARGET_CLAUDE_CODE,
|
|
300
|
+
outputDirKey: "claude-code",
|
|
301
|
+
filenameContextKey: "cc_file_name",
|
|
302
|
+
defaultFrontmatter: DEFAULT_FRONTMATTER_CLAUDE_CODE,
|
|
303
|
+
contextFlags: { target_claude_code: true },
|
|
304
|
+
defaultEnabled: true
|
|
305
|
+
});
|
|
306
|
+
defaultRegistry.register({
|
|
307
|
+
name: TARGET_DEEP_AGENTS,
|
|
308
|
+
outputDirKey: "deep-agents",
|
|
309
|
+
filenameContextKey: "da_file_name",
|
|
310
|
+
defaultFrontmatter: DEFAULT_FRONTMATTER_DEEP_AGENTS,
|
|
311
|
+
contextFlags: { target_deep_agents: true },
|
|
312
|
+
defaultEnabled: false
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// src/builders/persona-builder.ts
|
|
187
316
|
async function discoverSuitePersonaYamls(suiteConfig) {
|
|
188
317
|
const metaSubdir = suiteConfig.metaSubdir ?? "meta";
|
|
189
318
|
const metaDir = path4__default.default.join(suiteConfig.srcDir, metaSubdir);
|
|
@@ -210,6 +339,18 @@ async function loadPersonaYaml(yamlPath) {
|
|
|
210
339
|
}
|
|
211
340
|
return record;
|
|
212
341
|
}
|
|
342
|
+
function resolveOutputDir(target, suiteConfig, definition) {
|
|
343
|
+
const merged = {};
|
|
344
|
+
if (suiteConfig.outVscode) merged["vscode"] = suiteConfig.outVscode;
|
|
345
|
+
if (suiteConfig.outClaudeCode) merged["claude-code"] = suiteConfig.outClaudeCode;
|
|
346
|
+
if (suiteConfig.outputDirs) Object.assign(merged, suiteConfig.outputDirs);
|
|
347
|
+
const lookupKey = definition?.outputDirKey ?? target;
|
|
348
|
+
const dir = merged[lookupKey];
|
|
349
|
+
if (dir) return dir;
|
|
350
|
+
throw new Error(
|
|
351
|
+
`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.`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
213
354
|
async function buildAgentNameMap(config) {
|
|
214
355
|
const agentMap = {};
|
|
215
356
|
for (const [, suiteConfig] of Object.entries(config.suites)) {
|
|
@@ -223,13 +364,16 @@ async function buildAgentNameMap(config) {
|
|
|
223
364
|
const slug = typeof persona["slug"] === "string" ? persona["slug"] : path4__default.default.basename(yamlPath, ".yaml");
|
|
224
365
|
const name = typeof persona["name"] === "string" ? persona["name"] : slug;
|
|
225
366
|
const version = typeof persona["version"] === "string" ? persona["version"] : defaultVersion;
|
|
226
|
-
const
|
|
367
|
+
const underscoredSlug = slug.replace(/-/g, "_");
|
|
368
|
+
const key = `agent_${underscoredSlug}`;
|
|
227
369
|
agentMap[key] = `${name} v${version}`;
|
|
370
|
+
const slugKey = `agent_slug_${underscoredSlug}`;
|
|
371
|
+
agentMap[slugKey] = slug;
|
|
228
372
|
}
|
|
229
373
|
}
|
|
230
374
|
return agentMap;
|
|
231
375
|
}
|
|
232
|
-
function buildContext(personaMeta, sharedMeta, agentMap = {}) {
|
|
376
|
+
function buildContext(personaMeta, sharedMeta, agentMap = {}, target, registry) {
|
|
233
377
|
const version = typeof personaMeta["version"] === "string" ? personaMeta["version"] : typeof sharedMeta["default_version"] === "string" ? sharedMeta["default_version"] : "0.0.0";
|
|
234
378
|
const merged = {
|
|
235
379
|
...sharedMeta,
|
|
@@ -254,19 +398,42 @@ function buildContext(personaMeta, sharedMeta, agentMap = {}) {
|
|
|
254
398
|
const ccFileName = merged["cc_file_name"];
|
|
255
399
|
merged["cc_file_name_stem"] = ccFileName.replace(/\.md$/, "");
|
|
256
400
|
}
|
|
401
|
+
if (!("da_file_name_stem" in merged) && typeof merged["da_file_name"] === "string") {
|
|
402
|
+
const daFileName = merged["da_file_name"];
|
|
403
|
+
merged["da_file_name_stem"] = daFileName.replace(/\.md$/, "");
|
|
404
|
+
}
|
|
405
|
+
if (typeof merged["da_file_name"] === "string") {
|
|
406
|
+
const daTools = Array.isArray(merged["da_tools"]) ? merged["da_tools"] : tools;
|
|
407
|
+
if (!("da_tools_list" in merged)) {
|
|
408
|
+
merged["da_tools_list"] = serializeToolsList(daTools);
|
|
409
|
+
}
|
|
410
|
+
if (!("da_tools_json" in merged)) {
|
|
411
|
+
merged["da_tools_json"] = serializeTools(daTools);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
257
414
|
for (const [key, value] of Object.entries(agentMap)) {
|
|
258
415
|
if (!(key in merged)) {
|
|
259
416
|
merged[key] = value;
|
|
260
417
|
}
|
|
261
418
|
}
|
|
419
|
+
if (target !== void 0) {
|
|
420
|
+
if (registry && registry.has(target)) {
|
|
421
|
+
const flags = registry.get(target).contextFlags ?? {};
|
|
422
|
+
for (const [key, value] of Object.entries(flags)) {
|
|
423
|
+
merged[key] = value;
|
|
424
|
+
}
|
|
425
|
+
} else {
|
|
426
|
+
merged[`target_${target.replace(/-/g, "_")}`] = true;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
262
429
|
return merged;
|
|
263
430
|
}
|
|
264
|
-
async function buildPersona(personaYamlPath, suiteName, suiteConfig, sharedMeta, partialsMap, config, plugins, target, agentMap = {}) {
|
|
431
|
+
async function buildPersona(personaYamlPath, suiteName, suiteConfig, sharedMeta, partialsMap, config, plugins, target, agentMap = {}, registry = defaultRegistry) {
|
|
265
432
|
const personaMeta = await loadPersonaYaml(personaYamlPath);
|
|
266
|
-
let context = buildContext(personaMeta, sharedMeta, agentMap);
|
|
433
|
+
let context = buildContext(personaMeta, sharedMeta, agentMap, target, registry);
|
|
267
434
|
const personaMetaTyped = personaMeta;
|
|
268
|
-
context = runBuildContext(plugins, context, personaMetaTyped, suiteConfig);
|
|
269
|
-
const fmTemplate = resolveFrontmatterTemplate(target, plugins, config.frontmatter);
|
|
435
|
+
context = runBuildContext(plugins, context, personaMetaTyped, suiteConfig, target);
|
|
436
|
+
const fmTemplate = resolveFrontmatterTemplate(target, plugins, config.frontmatter, registry);
|
|
270
437
|
const contentBasename = path4__default.default.basename(personaYamlPath, ".yaml") + ".md";
|
|
271
438
|
const frontmatter = renderFrontmatter(fmTemplate, context, contentBasename);
|
|
272
439
|
const contentSubdir = suiteConfig.contentSubdir ?? "content";
|
|
@@ -284,15 +451,10 @@ ${body}
|
|
|
284
451
|
`);
|
|
285
452
|
output = runPostRender(plugins, output, personaMetaTyped, target);
|
|
286
453
|
const validationResults = runValidate(plugins, personaMetaTyped, suiteConfig, target);
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
} else if (target === "claude-code" && typeof context["cc_file_name"] === "string") {
|
|
292
|
-
outputBasename = context["cc_file_name"];
|
|
293
|
-
} else {
|
|
294
|
-
outputBasename = contentBasename;
|
|
295
|
-
}
|
|
454
|
+
const def = registry.has(target) ? registry.get(target) : void 0;
|
|
455
|
+
const outputDir = resolveOutputDir(target, suiteConfig, def);
|
|
456
|
+
const fnKey = def?.filenameContextKey;
|
|
457
|
+
const outputBasename = fnKey && typeof context[fnKey] === "string" ? context[fnKey] : contentBasename;
|
|
296
458
|
const outputPath = path4__default.default.join(outputDir, outputBasename);
|
|
297
459
|
const check = config.check ?? false;
|
|
298
460
|
let written = false;
|
|
@@ -311,7 +473,7 @@ ${body}
|
|
|
311
473
|
written
|
|
312
474
|
};
|
|
313
475
|
}
|
|
314
|
-
async function buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap = {}) {
|
|
476
|
+
async function buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap = {}, registry = defaultRegistry) {
|
|
315
477
|
const metaSubdir = suiteConfig.metaSubdir ?? "meta";
|
|
316
478
|
const sharedYamlPath = path4__default.default.join(suiteConfig.srcDir, metaSubdir, "_shared.yaml");
|
|
317
479
|
const sharedMeta = await loadRawYaml(sharedYamlPath);
|
|
@@ -337,7 +499,8 @@ async function buildSuite(suiteName, suiteConfig, config, plugins, target, agent
|
|
|
337
499
|
config,
|
|
338
500
|
plugins,
|
|
339
501
|
target,
|
|
340
|
-
agentMap
|
|
502
|
+
agentMap,
|
|
503
|
+
registry
|
|
341
504
|
);
|
|
342
505
|
results.push(result);
|
|
343
506
|
}
|
|
@@ -345,12 +508,13 @@ async function buildSuite(suiteName, suiteConfig, config, plugins, target, agent
|
|
|
345
508
|
}
|
|
346
509
|
async function build(config) {
|
|
347
510
|
const plugins = config.plugins ?? [];
|
|
348
|
-
const
|
|
511
|
+
const registry = config.targetRegistry ?? defaultRegistry;
|
|
512
|
+
const targets = config.targets ?? registry.names().filter((n) => registry.get(n).defaultEnabled !== false);
|
|
349
513
|
const allResults = [];
|
|
350
514
|
const agentMap = await buildAgentNameMap(config);
|
|
351
515
|
for (const [suiteName, suiteConfig] of Object.entries(config.suites)) {
|
|
352
516
|
for (const target of targets) {
|
|
353
|
-
const suiteResults = await buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap);
|
|
517
|
+
const suiteResults = await buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap, registry);
|
|
354
518
|
allResults.push(...suiteResults);
|
|
355
519
|
}
|
|
356
520
|
}
|
|
@@ -439,12 +603,18 @@ var _pkgRequire = module$1.createRequire((typeof document === 'undefined' ? requ
|
|
|
439
603
|
var VERSION = _pkgRequire("../package.json").version;
|
|
440
604
|
|
|
441
605
|
exports.DEFAULT_FRONTMATTER_CLAUDE_CODE = DEFAULT_FRONTMATTER_CLAUDE_CODE;
|
|
606
|
+
exports.DEFAULT_FRONTMATTER_DEEP_AGENTS = DEFAULT_FRONTMATTER_DEEP_AGENTS;
|
|
442
607
|
exports.DEFAULT_FRONTMATTER_VSCODE = DEFAULT_FRONTMATTER_VSCODE;
|
|
608
|
+
exports.TARGET_CLAUDE_CODE = TARGET_CLAUDE_CODE;
|
|
609
|
+
exports.TARGET_DEEP_AGENTS = TARGET_DEEP_AGENTS;
|
|
610
|
+
exports.TARGET_VSCODE = TARGET_VSCODE;
|
|
611
|
+
exports.TargetRegistry = TargetRegistry;
|
|
443
612
|
exports.VERSION = VERSION;
|
|
444
613
|
exports.build = build;
|
|
445
614
|
exports.buildPersona = buildPersona;
|
|
446
615
|
exports.buildSuite = buildSuite;
|
|
447
616
|
exports.collapseBlankLines = collapseBlankLines;
|
|
617
|
+
exports.defaultRegistry = defaultRegistry;
|
|
448
618
|
exports.discoverPersonaYamls = discoverPersonaYamls;
|
|
449
619
|
exports.ensureBlankLineBeforeHeadings = ensureBlankLineBeforeHeadings;
|
|
450
620
|
exports.escapeRegExp = escapeRegExp;
|