create-byan-agent 2.19.2 → 2.20.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/CHANGELOG.md +148 -0
- package/README.md +4 -4
- package/install/src/byan-v2/generation/templates/default-agent.md +1 -1
- package/install/templates/.claude/CLAUDE.md +1 -1
- package/install/templates/.claude/hooks/fd-phase-guard.js +2 -2
- package/install/templates/.claude/hooks/mantra-validate.js +16 -8
- package/install/templates/.claude/hooks/strict-scope-guard.js +25 -7
- package/install/templates/.claude/rules/native-workflows.md +32 -0
- package/install/templates/.claude/skills/byan-byan/SKILL.md +5 -5
- package/install/templates/.claude/skills/byan-mantra-audit/SKILL.md +53 -0
- package/install/templates/.claude/skills/byan-merise-agile/SKILL.md +2 -2
- package/install/templates/.claude/skills/byan-native-dev-story/SKILL.md +83 -0
- package/install/templates/.claude/workflows/INDEX.md +35 -0
- package/install/templates/.claude/workflows/check-implementation-readiness.js +280 -0
- package/install/templates/.claude/workflows/code-review.js +179 -0
- package/install/templates/.claude/workflows/create-excalidraw-dataflow.js +214 -0
- package/install/templates/.claude/workflows/create-excalidraw-diagram.js +188 -0
- package/install/templates/.claude/workflows/create-excalidraw-flowchart.js +225 -0
- package/install/templates/.claude/workflows/create-excalidraw-wireframe.js +192 -0
- package/install/templates/.claude/workflows/create-story.js +216 -0
- package/install/templates/.claude/workflows/dev-story.js +100 -0
- package/install/templates/.claude/workflows/document-project.js +455 -0
- package/install/templates/.claude/workflows/qa-automate.js +169 -0
- package/install/templates/.claude/workflows/quick-dev.js +273 -0
- package/install/templates/.claude/workflows/sprint-planning.js +261 -0
- package/install/templates/.claude/workflows/testarch-atdd.js +287 -0
- package/install/templates/.claude/workflows/testarch-automate.js +229 -0
- package/install/templates/.claude/workflows/testarch-ci.js +184 -0
- package/install/templates/.claude/workflows/testarch-framework.js +267 -0
- package/install/templates/.claude/workflows/testarch-nfr.js +316 -0
- package/install/templates/.claude/workflows/testarch-test-design.js +293 -0
- package/install/templates/.claude/workflows/testarch-test-review.js +321 -0
- package/install/templates/.claude/workflows/testarch-trace.js +316 -0
- package/install/templates/.githooks/pre-commit +49 -15
- package/install/templates/_byan/config.yaml +15 -5
- package/install/templates/_byan/mcp/byan-mcp-server/bin/byan-build-workflows.js +20 -0
- package/install/templates/_byan/mcp/byan-mcp-server/bin/byan-lint-workflows.js +57 -0
- package/install/templates/_byan/mcp/byan-mcp-server/lib/native-loop.js +39 -0
- package/install/templates/_byan/mcp/byan-mcp-server/lib/workflows-generator.js +149 -0
- package/install/templates/_byan/mcp/byan-mcp-server/lib/workflows-lint.js +113 -0
- package/install/templates/_byan/workflow/simple/byan/feature-workflow.md +14 -11
- package/install/templates/docs/native-workflows-contract.md +84 -0
- package/package.json +2 -2
- package/src/byan-v2/data/agent-scopes.json +46 -0
- package/src/byan-v2/data/mantras.json +194 -8
- package/src/byan-v2/generation/mantra-audit.js +147 -0
- package/src/byan-v2/generation/mantra-validator.js +56 -6
- package/src/byan-v2/generation/scope-resolver.js +102 -0
- package/src/byan-v2/generation/templates/default-agent.md +1 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//
|
|
3
|
+
// mantra-audit — semantic embodiment audit for BYAN personas (Option C, N2).
|
|
4
|
+
//
|
|
5
|
+
// Lives under src/byan-v2/generation/ so it ships with the v2 runtime (the
|
|
6
|
+
// installer copies src/ into the user project) next to the validator and
|
|
7
|
+
// scope-resolver it depends on. Invoke with:
|
|
8
|
+
// node src/byan-v2/generation/mantra-audit.js prepare <agentFile> [--json]
|
|
9
|
+
// node src/byan-v2/generation/mantra-audit.js score <agentFile> <verdicts.json>
|
|
10
|
+
//
|
|
11
|
+
// The pre-commit mantra gate is a fast, deterministic anti-stub FLOOR : it asks
|
|
12
|
+
// "does this persona contain the vocabulary of its domain mantras". That catches
|
|
13
|
+
// empty/zombie files but does NOT measure whether the agent genuinely EMBODIES a
|
|
14
|
+
// mantra. This tool is the deeper, out-of-band layer : it prepares a judgment
|
|
15
|
+
// packet (the applicable mantras + the persona + a rubric) for an LLM judge, then
|
|
16
|
+
// turns the judge's verdicts into an embodiment score. It is deliberately NOT in
|
|
17
|
+
// the commit path : the judgment is semantic (an LLM call), so it runs on demand
|
|
18
|
+
// or in CI, outside the commit path (a non-deterministic check must not block it).
|
|
19
|
+
//
|
|
20
|
+
// verdicts.json : { "<mantraId>": "embodied" | "partial" | "absent", ... }
|
|
21
|
+
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
const MantraValidator = require('./mantra-validator');
|
|
25
|
+
const resolver = require('./scope-resolver');
|
|
26
|
+
|
|
27
|
+
const VERDICT_WEIGHT = { embodied: 1, partial: 0.5, absent: 0 };
|
|
28
|
+
|
|
29
|
+
function buildPacket(agentFile) {
|
|
30
|
+
const content = fs.readFileSync(agentFile, 'utf8');
|
|
31
|
+
const name = path.basename(agentFile).replace(/\.md$/, '');
|
|
32
|
+
const scopes = resolver.resolveAgentScopes({ name, content });
|
|
33
|
+
const applicable = new MantraValidator().applicableMantras(scopes);
|
|
34
|
+
return {
|
|
35
|
+
agent: name,
|
|
36
|
+
file: agentFile,
|
|
37
|
+
scopes,
|
|
38
|
+
mantras: applicable.map(m => ({
|
|
39
|
+
id: m.id,
|
|
40
|
+
title: m.title,
|
|
41
|
+
description: m.description,
|
|
42
|
+
scope: m.scope || 'universal',
|
|
43
|
+
priority: m.priority,
|
|
44
|
+
})),
|
|
45
|
+
persona: content,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function buildPrompt(packet) {
|
|
50
|
+
const lines = [];
|
|
51
|
+
lines.push('You are auditing whether a BYAN agent persona EMBODIES its applicable mantras.');
|
|
52
|
+
lines.push('Judge embodiment, not vocabulary : a mantra is embodied when the persona\'s role,');
|
|
53
|
+
lines.push('instructions, and red-lines actually enact the principle, even if the exact keyword');
|
|
54
|
+
lines.push('is absent. For each mantra return one verdict : embodied | partial | absent.');
|
|
55
|
+
lines.push('');
|
|
56
|
+
lines.push(`Agent : ${packet.agent} Scopes : ${packet.scopes.join(', ')}`);
|
|
57
|
+
lines.push('');
|
|
58
|
+
lines.push('Applicable mantras :');
|
|
59
|
+
for (const m of packet.mantras) {
|
|
60
|
+
lines.push(`- ${m.id} (${m.scope}, ${m.priority}) : ${m.title} -- ${m.description}`);
|
|
61
|
+
}
|
|
62
|
+
lines.push('');
|
|
63
|
+
lines.push('Persona under audit :');
|
|
64
|
+
lines.push('"""');
|
|
65
|
+
lines.push(packet.persona.trim());
|
|
66
|
+
lines.push('"""');
|
|
67
|
+
lines.push('');
|
|
68
|
+
lines.push('Return strict JSON mapping every mantra id to its verdict, e.g.');
|
|
69
|
+
lines.push('{ "IA-16": "embodied", "M37": "partial", "IA-2": "absent" }');
|
|
70
|
+
return lines.join('\n');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function scoreVerdicts(packet, verdicts) {
|
|
74
|
+
const ids = packet.mantras.map(m => m.id);
|
|
75
|
+
let sum = 0;
|
|
76
|
+
const buckets = { embodied: [], partial: [], absent: [], unjudged: [] };
|
|
77
|
+
for (const id of ids) {
|
|
78
|
+
const v = verdicts[id];
|
|
79
|
+
if (v && Object.prototype.hasOwnProperty.call(VERDICT_WEIGHT, v)) {
|
|
80
|
+
sum += VERDICT_WEIGHT[v];
|
|
81
|
+
buckets[v].push(id);
|
|
82
|
+
} else {
|
|
83
|
+
buckets.unjudged.push(id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const total = ids.length;
|
|
87
|
+
const embodimentScore = total > 0 ? Math.round((sum / total) * 100) : 0;
|
|
88
|
+
return {
|
|
89
|
+
agent: packet.agent,
|
|
90
|
+
scopes: packet.scopes,
|
|
91
|
+
total,
|
|
92
|
+
embodimentScore,
|
|
93
|
+
embodied: buckets.embodied,
|
|
94
|
+
partial: buckets.partial,
|
|
95
|
+
absent: buckets.absent,
|
|
96
|
+
unjudged: buckets.unjudged,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function main(argv) {
|
|
101
|
+
const [cmd, agentFile, arg3] = argv;
|
|
102
|
+
|
|
103
|
+
if (!cmd || !agentFile || ['-h', '--help'].includes(cmd)) {
|
|
104
|
+
process.stdout.write(
|
|
105
|
+
'Usage :\n' +
|
|
106
|
+
' node src/byan-v2/generation/mantra-audit.js prepare <agentFile> [--json]\n' +
|
|
107
|
+
' node src/byan-v2/generation/mantra-audit.js score <agentFile> <verdicts.json>\n'
|
|
108
|
+
);
|
|
109
|
+
return cmd ? 0 : 1;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!fs.existsSync(agentFile)) {
|
|
113
|
+
process.stderr.write(`Agent file not found : ${agentFile}\n`);
|
|
114
|
+
return 1;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const packet = buildPacket(agentFile);
|
|
118
|
+
|
|
119
|
+
if (cmd === 'prepare') {
|
|
120
|
+
if (arg3 === '--json') {
|
|
121
|
+
process.stdout.write(JSON.stringify(packet, null, 2) + '\n');
|
|
122
|
+
} else {
|
|
123
|
+
process.stdout.write(buildPrompt(packet) + '\n');
|
|
124
|
+
}
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (cmd === 'score') {
|
|
129
|
+
if (!arg3 || !fs.existsSync(arg3)) {
|
|
130
|
+
process.stderr.write('A verdicts JSON file is required : score <agentFile> <verdicts.json>\n');
|
|
131
|
+
return 1;
|
|
132
|
+
}
|
|
133
|
+
const verdicts = JSON.parse(fs.readFileSync(arg3, 'utf8'));
|
|
134
|
+
const result = scoreVerdicts(packet, verdicts);
|
|
135
|
+
process.stdout.write(JSON.stringify(result, null, 2) + '\n');
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
process.stderr.write(`Unknown command : ${cmd}\n`);
|
|
140
|
+
return 1;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (require.main === module) {
|
|
144
|
+
process.exit(main(process.argv.slice(2)));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = { buildPacket, buildPrompt, scoreVerdicts, VERDICT_WEIGHT };
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
|
|
4
|
+
// Score bands, single source of truth (referenced by generateReport + export).
|
|
5
|
+
const PASS_THRESHOLD = 80;
|
|
6
|
+
const WARNING_THRESHOLD = 60;
|
|
7
|
+
|
|
4
8
|
class MantraValidator {
|
|
5
9
|
constructor(mantrasData = null) {
|
|
6
10
|
if (mantrasData) {
|
|
@@ -42,7 +46,28 @@ class MantraValidator {
|
|
|
42
46
|
return strictIds.length >= 3;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
// Normalize a caller-supplied scope (string | string[] | Set | null) into a
|
|
50
|
+
// Set, or null when no scope was given. Null means legacy all-mantras scoring.
|
|
51
|
+
_normalizeScope(scope) {
|
|
52
|
+
if (scope === null || scope === undefined) return null;
|
|
53
|
+
if (scope instanceof Set) return scope;
|
|
54
|
+
if (Array.isArray(scope)) return new Set(scope);
|
|
55
|
+
return new Set([scope]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// A mantra is applicable to a scoped run when it is universal (or unscoped)
|
|
59
|
+
// or its scope is in the requested set. Behavioral mantras are runtime-
|
|
60
|
+
// enforced (hooks / fact-check), not declared in a persona file, so they are
|
|
61
|
+
// excluded from scoped scoring. With no scope (null), every mantra applies.
|
|
62
|
+
_isApplicable(mantra, scopeSet) {
|
|
63
|
+
if (scopeSet === null) return true;
|
|
64
|
+
if (mantra.behavioral === true) return false;
|
|
65
|
+
const ms = mantra.scope || 'universal';
|
|
66
|
+
if (ms === 'universal') return true;
|
|
67
|
+
return scopeSet.has(ms);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
validate(agentDefinition, options = {}) {
|
|
46
71
|
if (agentDefinition === null || agentDefinition === undefined) {
|
|
47
72
|
throw new Error('Agent definition is required');
|
|
48
73
|
}
|
|
@@ -59,8 +84,16 @@ class MantraValidator {
|
|
|
59
84
|
this.mantras = this.personaMantras;
|
|
60
85
|
}
|
|
61
86
|
|
|
87
|
+
// Domain-aware scoring : when the caller passes a scope, only the mantras
|
|
88
|
+
// applicable to that scope are counted (universal always counts, behavioral
|
|
89
|
+
// runtime-enforced mantras are excluded). With no scope, every mantra in the
|
|
90
|
+
// chosen ruleset is scored, byte-identical to the legacy behavior.
|
|
91
|
+
const scopeSet = this._normalizeScope(options.scope);
|
|
92
|
+
const applicableMantras = this.mantras.filter(m => this._isApplicable(m, scopeSet));
|
|
93
|
+
|
|
62
94
|
this.results = {
|
|
63
|
-
totalMantras:
|
|
95
|
+
totalMantras: applicableMantras.length,
|
|
96
|
+
scope: scopeSet ? [...scopeSet] : null,
|
|
64
97
|
compliant: [],
|
|
65
98
|
nonCompliant: [],
|
|
66
99
|
warnings: [],
|
|
@@ -70,7 +103,7 @@ class MantraValidator {
|
|
|
70
103
|
|
|
71
104
|
const startTime = Date.now();
|
|
72
105
|
|
|
73
|
-
for (const mantra of
|
|
106
|
+
for (const mantra of applicableMantras) {
|
|
74
107
|
const result = this.checkMantra(mantra.id, agentDefinition);
|
|
75
108
|
|
|
76
109
|
if (result.compliant) {
|
|
@@ -154,8 +187,17 @@ class MantraValidator {
|
|
|
154
187
|
|
|
155
188
|
_validatePattern(content, validation, mantra) {
|
|
156
189
|
try {
|
|
190
|
+
// Some forbidden-pattern mantras (e.g. IA-23 no-emoji) must ignore
|
|
191
|
+
// declared zones such as an agent's icon="..." frontmatter attribute,
|
|
192
|
+
// where an emoji is a legitimate display glyph, not pollution.
|
|
193
|
+
let scanContent = content;
|
|
194
|
+
if (Array.isArray(validation.ignoreZones)) {
|
|
195
|
+
for (const zone of validation.ignoreZones) {
|
|
196
|
+
scanContent = scanContent.replace(new RegExp(zone, 'g'), '');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
157
199
|
const regex = new RegExp(validation.pattern, validation.flags || '');
|
|
158
|
-
const matches =
|
|
200
|
+
const matches = scanContent.match(regex);
|
|
159
201
|
const hasMatches = matches && matches.length > 0;
|
|
160
202
|
|
|
161
203
|
if (validation.mustNotMatch) {
|
|
@@ -255,7 +297,7 @@ class MantraValidator {
|
|
|
255
297
|
}
|
|
256
298
|
|
|
257
299
|
const score = this.results.score;
|
|
258
|
-
const level = score >=
|
|
300
|
+
const level = score >= PASS_THRESHOLD ? 'PASS' : score >= WARNING_THRESHOLD ? 'WARNING' : 'FAIL';
|
|
259
301
|
|
|
260
302
|
let report = '';
|
|
261
303
|
report += '='.repeat(60) + '\n';
|
|
@@ -424,7 +466,7 @@ class MantraValidator {
|
|
|
424
466
|
} else if (format === 'summary') {
|
|
425
467
|
return {
|
|
426
468
|
score: this.results.score,
|
|
427
|
-
status: this.results.score >=
|
|
469
|
+
status: this.results.score >= PASS_THRESHOLD ? 'PASS' : this.results.score >= WARNING_THRESHOLD ? 'WARNING' : 'FAIL',
|
|
428
470
|
compliant: this.results.compliant.length,
|
|
429
471
|
nonCompliant: this.results.nonCompliant.length,
|
|
430
472
|
criticalErrors: this.results.errors.length,
|
|
@@ -443,6 +485,14 @@ class MantraValidator {
|
|
|
443
485
|
return this.mantras.filter(m => m.category === category);
|
|
444
486
|
}
|
|
445
487
|
|
|
488
|
+
// The mantras that apply to a given scope (universal + the scope's domain,
|
|
489
|
+
// behavioral excluded). With no scope, every mantra in the current ruleset.
|
|
490
|
+
// Shared with the domain-aware path in validate() and the embodiment audit.
|
|
491
|
+
applicableMantras(scope) {
|
|
492
|
+
const scopeSet = this._normalizeScope(scope);
|
|
493
|
+
return this.mantras.filter(m => this._isApplicable(m, scopeSet));
|
|
494
|
+
}
|
|
495
|
+
|
|
446
496
|
getMantrasByPriority(priority) {
|
|
447
497
|
return this.mantras.filter(m => m.priority === priority);
|
|
448
498
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
// Domain-aware scope resolution for the mantra validator.
|
|
5
|
+
//
|
|
6
|
+
// The validator itself stays pure (it scores against a scope set it is given).
|
|
7
|
+
// This module owns the impure part : turning a persona FILE into its scope set,
|
|
8
|
+
// by reading a centralized map and, where present, an explicit frontmatter
|
|
9
|
+
// override. Callers (the pre-commit gate, the Stop hook, the FD VALIDATE step)
|
|
10
|
+
// resolve scopes here, then pass them to validator.validate(content, { scope }).
|
|
11
|
+
|
|
12
|
+
const VALID_SCOPES = ['universal', 'sdlc-process', 'sdlc-code', 'sdlc-ops', 'sdlc-modeling', 'sdlc-test', 'creative'];
|
|
13
|
+
const KNOWN_MODULES = ['bmm', 'cis', 'tea', 'bmb', 'core'];
|
|
14
|
+
|
|
15
|
+
function loadScopeMap(mapPath) {
|
|
16
|
+
const p = mapPath || path.join(__dirname, '../data/agent-scopes.json');
|
|
17
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// An explicit `mantra_scopes: [a, b]` in the persona (frontmatter or body) wins
|
|
21
|
+
// over every derived default. Returns the listed scopes, or null when absent.
|
|
22
|
+
function parseFrontmatterScopes(content) {
|
|
23
|
+
if (typeof content !== 'string') return null;
|
|
24
|
+
const m = content.match(/mantra_scopes\s*:\s*\[([^\]]*)\]/);
|
|
25
|
+
if (!m) return null;
|
|
26
|
+
const list = m[1]
|
|
27
|
+
.split(',')
|
|
28
|
+
.map(s => s.trim().replace(/^['"]|['"]$/g, ''))
|
|
29
|
+
.filter(Boolean);
|
|
30
|
+
return list.length ? list : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// A Gen3 agent loads exactly one _byan/<module>/config.yaml during activation,
|
|
34
|
+
// so the module is derivable from the persona content. Returns null if none.
|
|
35
|
+
function deriveModule(content) {
|
|
36
|
+
if (typeof content !== 'string') return null;
|
|
37
|
+
const m = content.match(/_byan\/(bmm|cis|tea|bmb|core)\/config\.yaml/);
|
|
38
|
+
return m ? m[1] : null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// The agent slug from a persona file path (basename without extension).
|
|
42
|
+
function agentNameFromPath(filePath) {
|
|
43
|
+
if (!filePath) return null;
|
|
44
|
+
return path.basename(filePath).replace(/\.md$/, '');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Force-union 'universal' and keep only known scope names, order-stable.
|
|
48
|
+
function normalizeScopes(scopes) {
|
|
49
|
+
const seen = new Set();
|
|
50
|
+
const out = [];
|
|
51
|
+
for (const s of ['universal', ...scopes]) {
|
|
52
|
+
if (VALID_SCOPES.includes(s) && !seen.has(s)) {
|
|
53
|
+
seen.add(s);
|
|
54
|
+
out.push(s);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Resolve the scope set for a persona. Precedence :
|
|
61
|
+
// 1. explicit frontmatter mantra_scopes
|
|
62
|
+
// 2. agentScopes[name] in the map
|
|
63
|
+
// 3. moduleScopes[module] derived from the content
|
|
64
|
+
// 4. fallback ['universal']
|
|
65
|
+
// 'universal' is always present in the result.
|
|
66
|
+
function resolveAgentScopes({ name = null, content = null, map = null } = {}) {
|
|
67
|
+
const scopeMap = map || loadScopeMap();
|
|
68
|
+
|
|
69
|
+
const explicit = parseFrontmatterScopes(content);
|
|
70
|
+
if (explicit) return normalizeScopes(explicit);
|
|
71
|
+
|
|
72
|
+
if (name && scopeMap.agentScopes && scopeMap.agentScopes[name]) {
|
|
73
|
+
return normalizeScopes(scopeMap.agentScopes[name]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const mod = deriveModule(content);
|
|
77
|
+
if (mod && scopeMap.moduleScopes && scopeMap.moduleScopes[mod]) {
|
|
78
|
+
return normalizeScopes(scopeMap.moduleScopes[mod]);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return ['universal'];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Convenience for file-based callers (the gate, the hooks) : read a persona
|
|
85
|
+
// file from disk and resolve its scopes in one call.
|
|
86
|
+
function resolveScopesForFile(filePath, map = null) {
|
|
87
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
88
|
+
const name = agentNameFromPath(filePath);
|
|
89
|
+
return resolveAgentScopes({ name, content, map });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
VALID_SCOPES,
|
|
94
|
+
KNOWN_MODULES,
|
|
95
|
+
loadScopeMap,
|
|
96
|
+
parseFrontmatterScopes,
|
|
97
|
+
deriveModule,
|
|
98
|
+
agentNameFromPath,
|
|
99
|
+
normalizeScopes,
|
|
100
|
+
resolveAgentScopes,
|
|
101
|
+
resolveScopesForFile,
|
|
102
|
+
};
|
|
@@ -16,7 +16,7 @@ You must fully embody this agent's persona and follow all activation instruction
|
|
|
16
16
|
<rules>
|
|
17
17
|
<r>Communicate in {communication_language}</r>
|
|
18
18
|
<r>Stay in character until EXIT</r>
|
|
19
|
-
<r>Apply Merise Agile + TDD +
|
|
19
|
+
<r>Apply Merise Agile + TDD + 71 mantras</r>
|
|
20
20
|
</rules>
|
|
21
21
|
</activation>
|
|
22
22
|
|