@mistralys/persona-builder 2.1.2 → 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 +17 -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.js
CHANGED
|
@@ -20,18 +20,27 @@ function resolvePartials(text, partialsMap, depth = 0) {
|
|
|
20
20
|
|
|
21
21
|
// src/engine/conditionals.ts
|
|
22
22
|
function resolveConditionals(text, context) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
(
|
|
26
|
-
|
|
27
|
-
return "\n" + inner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
28
|
-
}
|
|
29
|
-
if (elseInner !== void 0) {
|
|
30
|
-
return "\n" + elseInner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
31
|
-
}
|
|
32
|
-
return "\n";
|
|
33
|
-
}
|
|
23
|
+
const noNestedIf = String.raw`(?:(?!\{\{#if\b)[\s\S])*?`;
|
|
24
|
+
const pattern = new RegExp(
|
|
25
|
+
String.raw`\n*\{\{#if (\w+)\}\}(${noNestedIf})` + String.raw`(?:\{\{else\}\}(${noNestedIf}))?\{\{\/if\}\}\n*`,
|
|
26
|
+
"g"
|
|
34
27
|
);
|
|
28
|
+
const resolve = (_match, flag, inner, elseInner) => {
|
|
29
|
+
if (context[flag]) {
|
|
30
|
+
return "\n" + inner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
31
|
+
}
|
|
32
|
+
if (elseInner !== void 0) {
|
|
33
|
+
return "\n" + elseInner.replace(/^\n+/, "").replace(/\n+$/, "") + "\n";
|
|
34
|
+
}
|
|
35
|
+
return "\n";
|
|
36
|
+
};
|
|
37
|
+
let result = text;
|
|
38
|
+
let prev;
|
|
39
|
+
do {
|
|
40
|
+
prev = result;
|
|
41
|
+
result = result.replace(pattern, resolve);
|
|
42
|
+
} while (result !== prev);
|
|
43
|
+
return result;
|
|
35
44
|
}
|
|
36
45
|
|
|
37
46
|
// src/engine/variables.ts
|
|
@@ -116,11 +125,11 @@ function runSuiteInit(plugins, suite, sharedMeta) {
|
|
|
116
125
|
}
|
|
117
126
|
}
|
|
118
127
|
}
|
|
119
|
-
function runBuildContext(plugins, ctx, persona, suite) {
|
|
128
|
+
function runBuildContext(plugins, ctx, persona, suite, target) {
|
|
120
129
|
let accumulated = ctx;
|
|
121
130
|
for (const plugin of plugins) {
|
|
122
131
|
if (typeof plugin.onBuildContext === "function") {
|
|
123
|
-
accumulated = plugin.onBuildContext(accumulated, persona, suite);
|
|
132
|
+
accumulated = plugin.onBuildContext(accumulated, persona, suite, target);
|
|
124
133
|
}
|
|
125
134
|
}
|
|
126
135
|
return accumulated;
|
|
@@ -145,7 +154,10 @@ function runValidate(plugins, persona, suite, target) {
|
|
|
145
154
|
return results;
|
|
146
155
|
}
|
|
147
156
|
|
|
148
|
-
// src/
|
|
157
|
+
// src/targets/types.ts
|
|
158
|
+
var TARGET_VSCODE = "vscode";
|
|
159
|
+
var TARGET_CLAUDE_CODE = "claude-code";
|
|
160
|
+
var TARGET_DEEP_AGENTS = "deep-agents";
|
|
149
161
|
var DEFAULT_FRONTMATTER_VSCODE = `---
|
|
150
162
|
name: '{{name}} v{{version}}'
|
|
151
163
|
description: '{{description}}'
|
|
@@ -158,7 +170,13 @@ model: {{cc_model}}
|
|
|
158
170
|
memory: {{cc_memory}}
|
|
159
171
|
allowedTools: [{{cc_tools_list}}]
|
|
160
172
|
---`;
|
|
161
|
-
|
|
173
|
+
var DEFAULT_FRONTMATTER_DEEP_AGENTS = `---
|
|
174
|
+
name: {{name}}
|
|
175
|
+
description: {{description}}
|
|
176
|
+
---`;
|
|
177
|
+
|
|
178
|
+
// src/builders/frontmatter.ts
|
|
179
|
+
function resolveFrontmatterTemplate(target, plugins, configTemplates, registry) {
|
|
162
180
|
for (const plugin of plugins) {
|
|
163
181
|
if (plugin.frontmatterTemplates && target in plugin.frontmatterTemplates) {
|
|
164
182
|
const tpl = plugin.frontmatterTemplates[target];
|
|
@@ -169,13 +187,124 @@ function resolveFrontmatterTemplate(target, plugins, configTemplates) {
|
|
|
169
187
|
const tpl = configTemplates[target];
|
|
170
188
|
if (tpl !== void 0) return tpl;
|
|
171
189
|
}
|
|
172
|
-
|
|
190
|
+
if (registry && registry.has(target)) {
|
|
191
|
+
return registry.get(target).defaultFrontmatter;
|
|
192
|
+
}
|
|
193
|
+
return DEFAULT_FRONTMATTER_VSCODE;
|
|
173
194
|
}
|
|
174
195
|
function renderFrontmatter(template, context, filename) {
|
|
175
196
|
let rendered = resolveConditionals(template, context);
|
|
176
197
|
rendered = resolveVariables(rendered, context, filename);
|
|
177
198
|
return rendered;
|
|
178
199
|
}
|
|
200
|
+
|
|
201
|
+
// src/targets/registry.ts
|
|
202
|
+
var TargetRegistry = class _TargetRegistry {
|
|
203
|
+
// Map preserves insertion order — names() and allDefinitions() are
|
|
204
|
+
// therefore deterministic and match registration sequence. This is
|
|
205
|
+
// intentional: the built-in registry guarantees ['vscode', 'claude-code']
|
|
206
|
+
// ordering for the default targets (AC-2).
|
|
207
|
+
_definitions = /* @__PURE__ */ new Map();
|
|
208
|
+
/**
|
|
209
|
+
* Register a new target definition.
|
|
210
|
+
*
|
|
211
|
+
* @param definition The target descriptor to register.
|
|
212
|
+
* @throws {Error} If a target with the same `name` is already registered.
|
|
213
|
+
*/
|
|
214
|
+
register(definition) {
|
|
215
|
+
if (this._definitions.has(definition.name)) {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`TargetRegistry: target "${definition.name}" is already registered. Use a unique name or remove the existing registration first.`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
this._definitions.set(definition.name, definition);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Retrieve a registered target definition by name.
|
|
224
|
+
*
|
|
225
|
+
* Returns a shallow copy — mutating the returned object does not affect
|
|
226
|
+
* the registry's internal state.
|
|
227
|
+
*
|
|
228
|
+
* @param name The target name to look up.
|
|
229
|
+
* @returns A shallow copy of the matching TargetDefinition.
|
|
230
|
+
* @throws {Error} If no target with the given name is registered.
|
|
231
|
+
*/
|
|
232
|
+
get(name) {
|
|
233
|
+
const def = this._definitions.get(name);
|
|
234
|
+
if (!def) {
|
|
235
|
+
const known = this.names().join(", ") || "(none)";
|
|
236
|
+
throw new Error(
|
|
237
|
+
`TargetRegistry: target "${name}" is not registered. Registered targets: ${known}.`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
return { ...def };
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Returns `true` if a target with the given name is registered.
|
|
244
|
+
*
|
|
245
|
+
* @param name The target name to check.
|
|
246
|
+
*/
|
|
247
|
+
has(name) {
|
|
248
|
+
return this._definitions.has(name);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Returns the names of all registered targets, in registration order.
|
|
252
|
+
*/
|
|
253
|
+
names() {
|
|
254
|
+
return Array.from(this._definitions.keys());
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Returns all registered TargetDefinition objects, in registration order.
|
|
258
|
+
*
|
|
259
|
+
* Returns shallow copies — mutating a returned definition does not affect
|
|
260
|
+
* the registry's internal state.
|
|
261
|
+
*/
|
|
262
|
+
allDefinitions() {
|
|
263
|
+
return Array.from(this._definitions.values()).map((def) => ({ ...def }));
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Returns a new TargetRegistry pre-populated with the same definitions.
|
|
267
|
+
*
|
|
268
|
+
* Useful for test isolation: clone the `defaultRegistry` to get an
|
|
269
|
+
* independent copy that can be mutated without affecting the singleton.
|
|
270
|
+
*/
|
|
271
|
+
clone() {
|
|
272
|
+
const copy = new _TargetRegistry();
|
|
273
|
+
for (const def of this._definitions.values()) {
|
|
274
|
+
copy.register({ ...def });
|
|
275
|
+
}
|
|
276
|
+
return copy;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// src/targets/built-in.ts
|
|
281
|
+
var defaultRegistry = new TargetRegistry();
|
|
282
|
+
defaultRegistry.register({
|
|
283
|
+
name: TARGET_VSCODE,
|
|
284
|
+
outputDirKey: "vscode",
|
|
285
|
+
filenameContextKey: "vs_file_name",
|
|
286
|
+
defaultFrontmatter: DEFAULT_FRONTMATTER_VSCODE,
|
|
287
|
+
contextFlags: { target_vscode: true },
|
|
288
|
+
defaultEnabled: true
|
|
289
|
+
});
|
|
290
|
+
defaultRegistry.register({
|
|
291
|
+
name: TARGET_CLAUDE_CODE,
|
|
292
|
+
outputDirKey: "claude-code",
|
|
293
|
+
filenameContextKey: "cc_file_name",
|
|
294
|
+
defaultFrontmatter: DEFAULT_FRONTMATTER_CLAUDE_CODE,
|
|
295
|
+
contextFlags: { target_claude_code: true },
|
|
296
|
+
defaultEnabled: true
|
|
297
|
+
});
|
|
298
|
+
defaultRegistry.register({
|
|
299
|
+
name: TARGET_DEEP_AGENTS,
|
|
300
|
+
outputDirKey: "deep-agents",
|
|
301
|
+
filenameContextKey: "da_file_name",
|
|
302
|
+
defaultFrontmatter: DEFAULT_FRONTMATTER_DEEP_AGENTS,
|
|
303
|
+
contextFlags: { target_deep_agents: true },
|
|
304
|
+
defaultEnabled: false
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// src/builders/persona-builder.ts
|
|
179
308
|
async function discoverSuitePersonaYamls(suiteConfig) {
|
|
180
309
|
const metaSubdir = suiteConfig.metaSubdir ?? "meta";
|
|
181
310
|
const metaDir = path4.join(suiteConfig.srcDir, metaSubdir);
|
|
@@ -202,6 +331,18 @@ async function loadPersonaYaml(yamlPath) {
|
|
|
202
331
|
}
|
|
203
332
|
return record;
|
|
204
333
|
}
|
|
334
|
+
function resolveOutputDir(target, suiteConfig, definition) {
|
|
335
|
+
const merged = {};
|
|
336
|
+
if (suiteConfig.outVscode) merged["vscode"] = suiteConfig.outVscode;
|
|
337
|
+
if (suiteConfig.outClaudeCode) merged["claude-code"] = suiteConfig.outClaudeCode;
|
|
338
|
+
if (suiteConfig.outputDirs) Object.assign(merged, suiteConfig.outputDirs);
|
|
339
|
+
const lookupKey = definition?.outputDirKey ?? target;
|
|
340
|
+
const dir = merged[lookupKey];
|
|
341
|
+
if (dir) return dir;
|
|
342
|
+
throw new Error(
|
|
343
|
+
`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.`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
205
346
|
async function buildAgentNameMap(config) {
|
|
206
347
|
const agentMap = {};
|
|
207
348
|
for (const [, suiteConfig] of Object.entries(config.suites)) {
|
|
@@ -215,13 +356,16 @@ async function buildAgentNameMap(config) {
|
|
|
215
356
|
const slug = typeof persona["slug"] === "string" ? persona["slug"] : path4.basename(yamlPath, ".yaml");
|
|
216
357
|
const name = typeof persona["name"] === "string" ? persona["name"] : slug;
|
|
217
358
|
const version = typeof persona["version"] === "string" ? persona["version"] : defaultVersion;
|
|
218
|
-
const
|
|
359
|
+
const underscoredSlug = slug.replace(/-/g, "_");
|
|
360
|
+
const key = `agent_${underscoredSlug}`;
|
|
219
361
|
agentMap[key] = `${name} v${version}`;
|
|
362
|
+
const slugKey = `agent_slug_${underscoredSlug}`;
|
|
363
|
+
agentMap[slugKey] = slug;
|
|
220
364
|
}
|
|
221
365
|
}
|
|
222
366
|
return agentMap;
|
|
223
367
|
}
|
|
224
|
-
function buildContext(personaMeta, sharedMeta, agentMap = {}) {
|
|
368
|
+
function buildContext(personaMeta, sharedMeta, agentMap = {}, target, registry) {
|
|
225
369
|
const version = typeof personaMeta["version"] === "string" ? personaMeta["version"] : typeof sharedMeta["default_version"] === "string" ? sharedMeta["default_version"] : "0.0.0";
|
|
226
370
|
const merged = {
|
|
227
371
|
...sharedMeta,
|
|
@@ -246,19 +390,42 @@ function buildContext(personaMeta, sharedMeta, agentMap = {}) {
|
|
|
246
390
|
const ccFileName = merged["cc_file_name"];
|
|
247
391
|
merged["cc_file_name_stem"] = ccFileName.replace(/\.md$/, "");
|
|
248
392
|
}
|
|
393
|
+
if (!("da_file_name_stem" in merged) && typeof merged["da_file_name"] === "string") {
|
|
394
|
+
const daFileName = merged["da_file_name"];
|
|
395
|
+
merged["da_file_name_stem"] = daFileName.replace(/\.md$/, "");
|
|
396
|
+
}
|
|
397
|
+
if (typeof merged["da_file_name"] === "string") {
|
|
398
|
+
const daTools = Array.isArray(merged["da_tools"]) ? merged["da_tools"] : tools;
|
|
399
|
+
if (!("da_tools_list" in merged)) {
|
|
400
|
+
merged["da_tools_list"] = serializeToolsList(daTools);
|
|
401
|
+
}
|
|
402
|
+
if (!("da_tools_json" in merged)) {
|
|
403
|
+
merged["da_tools_json"] = serializeTools(daTools);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
249
406
|
for (const [key, value] of Object.entries(agentMap)) {
|
|
250
407
|
if (!(key in merged)) {
|
|
251
408
|
merged[key] = value;
|
|
252
409
|
}
|
|
253
410
|
}
|
|
411
|
+
if (target !== void 0) {
|
|
412
|
+
if (registry && registry.has(target)) {
|
|
413
|
+
const flags = registry.get(target).contextFlags ?? {};
|
|
414
|
+
for (const [key, value] of Object.entries(flags)) {
|
|
415
|
+
merged[key] = value;
|
|
416
|
+
}
|
|
417
|
+
} else {
|
|
418
|
+
merged[`target_${target.replace(/-/g, "_")}`] = true;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
254
421
|
return merged;
|
|
255
422
|
}
|
|
256
|
-
async function buildPersona(personaYamlPath, suiteName, suiteConfig, sharedMeta, partialsMap, config, plugins, target, agentMap = {}) {
|
|
423
|
+
async function buildPersona(personaYamlPath, suiteName, suiteConfig, sharedMeta, partialsMap, config, plugins, target, agentMap = {}, registry = defaultRegistry) {
|
|
257
424
|
const personaMeta = await loadPersonaYaml(personaYamlPath);
|
|
258
|
-
let context = buildContext(personaMeta, sharedMeta, agentMap);
|
|
425
|
+
let context = buildContext(personaMeta, sharedMeta, agentMap, target, registry);
|
|
259
426
|
const personaMetaTyped = personaMeta;
|
|
260
|
-
context = runBuildContext(plugins, context, personaMetaTyped, suiteConfig);
|
|
261
|
-
const fmTemplate = resolveFrontmatterTemplate(target, plugins, config.frontmatter);
|
|
427
|
+
context = runBuildContext(plugins, context, personaMetaTyped, suiteConfig, target);
|
|
428
|
+
const fmTemplate = resolveFrontmatterTemplate(target, plugins, config.frontmatter, registry);
|
|
262
429
|
const contentBasename = path4.basename(personaYamlPath, ".yaml") + ".md";
|
|
263
430
|
const frontmatter = renderFrontmatter(fmTemplate, context, contentBasename);
|
|
264
431
|
const contentSubdir = suiteConfig.contentSubdir ?? "content";
|
|
@@ -276,15 +443,10 @@ ${body}
|
|
|
276
443
|
`);
|
|
277
444
|
output = runPostRender(plugins, output, personaMetaTyped, target);
|
|
278
445
|
const validationResults = runValidate(plugins, personaMetaTyped, suiteConfig, target);
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
} else if (target === "claude-code" && typeof context["cc_file_name"] === "string") {
|
|
284
|
-
outputBasename = context["cc_file_name"];
|
|
285
|
-
} else {
|
|
286
|
-
outputBasename = contentBasename;
|
|
287
|
-
}
|
|
446
|
+
const def = registry.has(target) ? registry.get(target) : void 0;
|
|
447
|
+
const outputDir = resolveOutputDir(target, suiteConfig, def);
|
|
448
|
+
const fnKey = def?.filenameContextKey;
|
|
449
|
+
const outputBasename = fnKey && typeof context[fnKey] === "string" ? context[fnKey] : contentBasename;
|
|
288
450
|
const outputPath = path4.join(outputDir, outputBasename);
|
|
289
451
|
const check = config.check ?? false;
|
|
290
452
|
let written = false;
|
|
@@ -303,7 +465,7 @@ ${body}
|
|
|
303
465
|
written
|
|
304
466
|
};
|
|
305
467
|
}
|
|
306
|
-
async function buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap = {}) {
|
|
468
|
+
async function buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap = {}, registry = defaultRegistry) {
|
|
307
469
|
const metaSubdir = suiteConfig.metaSubdir ?? "meta";
|
|
308
470
|
const sharedYamlPath = path4.join(suiteConfig.srcDir, metaSubdir, "_shared.yaml");
|
|
309
471
|
const sharedMeta = await loadRawYaml(sharedYamlPath);
|
|
@@ -329,7 +491,8 @@ async function buildSuite(suiteName, suiteConfig, config, plugins, target, agent
|
|
|
329
491
|
config,
|
|
330
492
|
plugins,
|
|
331
493
|
target,
|
|
332
|
-
agentMap
|
|
494
|
+
agentMap,
|
|
495
|
+
registry
|
|
333
496
|
);
|
|
334
497
|
results.push(result);
|
|
335
498
|
}
|
|
@@ -337,12 +500,13 @@ async function buildSuite(suiteName, suiteConfig, config, plugins, target, agent
|
|
|
337
500
|
}
|
|
338
501
|
async function build(config) {
|
|
339
502
|
const plugins = config.plugins ?? [];
|
|
340
|
-
const
|
|
503
|
+
const registry = config.targetRegistry ?? defaultRegistry;
|
|
504
|
+
const targets = config.targets ?? registry.names().filter((n) => registry.get(n).defaultEnabled !== false);
|
|
341
505
|
const allResults = [];
|
|
342
506
|
const agentMap = await buildAgentNameMap(config);
|
|
343
507
|
for (const [suiteName, suiteConfig] of Object.entries(config.suites)) {
|
|
344
508
|
for (const target of targets) {
|
|
345
|
-
const suiteResults = await buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap);
|
|
509
|
+
const suiteResults = await buildSuite(suiteName, suiteConfig, config, plugins, target, agentMap, registry);
|
|
346
510
|
allResults.push(...suiteResults);
|
|
347
511
|
}
|
|
348
512
|
}
|
|
@@ -430,6 +594,6 @@ function escapeRegExp(str) {
|
|
|
430
594
|
var _pkgRequire = createRequire(import.meta.url);
|
|
431
595
|
var VERSION = _pkgRequire("../package.json").version;
|
|
432
596
|
|
|
433
|
-
export { DEFAULT_FRONTMATTER_CLAUDE_CODE, DEFAULT_FRONTMATTER_VSCODE, VERSION, build, buildPersona, buildSuite, collapseBlankLines, discoverPersonaYamls, ensureBlankLineBeforeHeadings, escapeRegExp, loadContent, loadMetadata, loadPartials, normalizeNewlines, renderFrontmatter, resolveConditionals, resolveFrontmatterTemplate, resolvePartials, resolveVariables, runBuildContext, runPostRender, runSuiteInit, runValidate, serializeTools, serializeToolsList, validateFileName, validateStrictMarkers };
|
|
597
|
+
export { DEFAULT_FRONTMATTER_CLAUDE_CODE, DEFAULT_FRONTMATTER_DEEP_AGENTS, DEFAULT_FRONTMATTER_VSCODE, TARGET_CLAUDE_CODE, TARGET_DEEP_AGENTS, TARGET_VSCODE, TargetRegistry, VERSION, 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 };
|
|
434
598
|
//# sourceMappingURL=index.js.map
|
|
435
599
|
//# sourceMappingURL=index.js.map
|