chore: reconcile publish/agent surfaces after PR batch

- agent.yaml: register epic-* commands (#2236) and vue-review (#2241)
- package.json files: drop stray skills/ml-adoption-playbook entry (follows orphan-skill publish pattern; not in install-modules.json)
- unicode-safety: strip decorative emoji from dashboard-web.js (#2100) and brand-discovery refs (#2221) to pass the CI gate
- agent-compress: raise catalog token canary 5000 -> 6000 for the 67-agent catalog

Full suite green (2836/2836).
This commit is contained in:
Affaan Mustafa 2026-06-15 14:21:28 -04:00
parent 141286a02a
commit 6e2544ffa2
15 changed files with 320 additions and 245 deletions

View File

@ -33,9 +33,7 @@
1. 1.
2. 2.
3. 3. ### Open questions / threads to pursue in later modules
### Open questions / threads to pursue in later modules
### Contradictions or tensions between participants (multi-founder only) ### Contradictions or tensions between participants (multi-founder only)

View File

@ -37,9 +37,7 @@
### Alternative framings (vary the category or the differentiator) ### Alternative framings (vary the category or the differentiator)
1. 1.
2. 2. ### White-space hypothesis (what no competitor is claiming that this brand could own)
### White-space hypothesis (what no competitor is claiming that this brand could own)
### Open questions / ambiguities ### Open questions / ambiguities

View File

@ -52,8 +52,6 @@
1. 1.
2. 2.
3. 3. ### What the brand must never sound or look like (the anti-personality)
### What the brand must never sound or look like (the anti-personality)
### Open questions / tensions with Module 50 Voice ### Open questions / tensions with Module 50 Voice

View File

@ -56,6 +56,4 @@
1. 1.
2. 2.
3. 3. ### Open questions / tensions with Module 40 Personality
### Open questions / tensions with Module 40 Personality

View File

@ -32,15 +32,11 @@
### Trueline draft (Neumeier: "[Brand] is the only [category] that [unique claim].") ### Trueline draft (Neumeier: "[Brand] is the only [category] that [unique claim].")
> > ### Alternative truelines (23 variations, vary level of abstraction)
### Alternative truelines (23 variations, vary level of abstraction)
1. 1.
2. 2.
3. 3. ### Brand story arc
### Brand story arc
| Beat | Content | | Beat | Content |
|---|---| |---|---|

View File

@ -166,6 +166,13 @@ commands:
- cpp-review - cpp-review
- cpp-test - cpp-test
- ecc-guide - ecc-guide
- epic-claim
- epic-decompose
- epic-publish
- epic-review
- epic-sync
- epic-unblock
- epic-validate
- evolve - evolve
- fastapi-review - fastapi-review
- feature-dev - feature-dev
@ -240,6 +247,7 @@ commands:
- test-coverage - test-coverage
- update-codemaps - update-codemaps
- update-docs - update-docs
- vue-review
tags: tags:
- agent-harness - agent-harness
- developer-tools - developer-tools

View File

@ -25,7 +25,7 @@ Invoke the `orch-build-mvp` skill with `$ARGUMENTS` as the doc path. The skill
(via the shared `orch-pipeline` engine, full pipeline incl. Scaffold) will: (via the shared `orch-pipeline` engine, full pipeline incl. Scaffold) will:
1. Read the spec; extract scope, locked decisions, and a feature list ordered as 1. Read the spec; extract scope, locked decisions, and a feature list ordered as
**thin vertical slices** (one end-to-end path first). → **GATE 1** (approve slice plan). **thin vertical slices** (one end-to-end path first). → **GATE 1** (approve slice plan).
2. Scaffold the first end-to-end slice. 2. Scaffold the first end-to-end slice.
3. Reuse the GAN harness: translate the SDD into `gan-harness/spec.md` + 3. Reuse the GAN harness: translate the SDD into `gan-harness/spec.md` +
`eval-rubric.md`, then drive `/gan-build "<brief>" --skip-planner` `eval-rubric.md`, then drive `/gan-build "<brief>" --skip-planner`

View File

@ -232,7 +232,6 @@
"skills/mcp-server-patterns/", "skills/mcp-server-patterns/",
"skills/messages-ops/", "skills/messages-ops/",
"skills/mle-workflow/", "skills/mle-workflow/",
"skills/ml-adoption-playbook/",
"skills/motion-ui/", "skills/motion-ui/",
"skills/mysql-patterns/", "skills/mysql-patterns/",
"skills/nanoclaw-repl/", "skills/nanoclaw-repl/",

View File

@ -363,20 +363,20 @@ function renderHTML(data) {
<div class="suggest" id="suggest"></div> <div class="suggest" id="suggest"></div>
</div> </div>
<div class="lang-wrap"> <div class="lang-wrap">
<button class="lang-btn" onclick="toggleLang()">🌐 <span id="lang-label">EN</span></button> <button class="lang-btn" onclick="toggleLang()"> <span id="lang-label">EN</span></button>
<div class="lang-drop" id="lang-drop"></div> <div class="lang-drop" id="lang-drop"></div>
</div> </div>
<button class="icon-btn" onclick="toggleTheme()" title="Toggle theme"></button> <button class="icon-btn" onclick="toggleTheme()" title="Toggle theme"></button>
</div> </div>
</div> </div>
<div class="nav" id="nav"> <div class="nav" id="nav">
<button class="nav-it active" data-tab="agents" onclick="showTab('agents',this)"><span id="nav-agents">🤖 Agents</span> <span class="ct" id="nav-ct-agents"></span></button> <button class="nav-it active" data-tab="agents" onclick="showTab('agents',this)"><span id="nav-agents"> Agents</span> <span class="ct" id="nav-ct-agents"></span></button>
<button class="nav-it" data-tab="skills" onclick="showTab('skills',this)"><span id="nav-skills">📚 Skills</span> <span class="ct" id="nav-ct-skills"></span></button> <button class="nav-it" data-tab="skills" onclick="showTab('skills',this)"><span id="nav-skills"> Skills</span> <span class="ct" id="nav-ct-skills"></span></button>
<button class="nav-it" data-tab="commands" onclick="showTab('commands',this)"><span id="nav-commands"> Commands</span> <span class="ct" id="nav-ct-commands"></span></button> <button class="nav-it" data-tab="commands" onclick="showTab('commands',this)"><span id="nav-commands"> Commands</span> <span class="ct" id="nav-ct-commands"></span></button>
<button class="nav-it" data-tab="rules" onclick="showTab('rules',this)"><span id="nav-rules">📏 Rules</span> <span class="ct" id="nav-ct-rules"></span></button> <button class="nav-it" data-tab="rules" onclick="showTab('rules',this)"><span id="nav-rules"> Rules</span> <span class="ct" id="nav-ct-rules"></span></button>
<button class="nav-it" data-tab="mcps" onclick="showTab('mcps',this)"><span id="nav-mcps">🔌 MCPs</span> <span class="ct" id="nav-ct-mcps"></span></button> <button class="nav-it" data-tab="mcps" onclick="showTab('mcps',this)"><span id="nav-mcps"> MCPs</span> <span class="ct" id="nav-ct-mcps"></span></button>
<button class="nav-it" data-tab="hooks" onclick="showTab('hooks',this)"><span id="nav-hooks">🪝 Hooks</span> <span class="ct" id="nav-ct-hooks"></span></button> <button class="nav-it" data-tab="hooks" onclick="showTab('hooks',this)"><span id="nav-hooks"> Hooks</span> <span class="ct" id="nav-ct-hooks"></span></button>
</div> </div>
<div class="out" id="app"></div> <div class="out" id="app"></div>
@ -456,12 +456,12 @@ function applyLang() {
document.getElementById('t-contribution').textContent = t('contribution'); document.getElementById('t-contribution').textContent = t('contribution');
document.getElementById('search').placeholder = t('search'); document.getElementById('search').placeholder = t('search');
// Update label text only — counter spans are separate siblings // Update label text only — counter spans are separate siblings
document.getElementById('nav-agents').childNodes[0].textContent = '🤖 ' + t('agents'); document.getElementById('nav-agents').childNodes[0].textContent = ' ' + t('agents');
document.getElementById('nav-skills').childNodes[0].textContent = '📚 ' + t('skills'); document.getElementById('nav-skills').childNodes[0].textContent = ' ' + t('skills');
document.getElementById('nav-commands').childNodes[0].textContent = ' ' + t('commands'); document.getElementById('nav-commands').childNodes[0].textContent = ' ' + t('commands');
document.getElementById('nav-rules').childNodes[0].textContent = '📏 ' + t('rules'); document.getElementById('nav-rules').childNodes[0].textContent = ' ' + t('rules');
document.getElementById('nav-mcps').childNodes[0].textContent = '🔌 ' + t('mcps'); document.getElementById('nav-mcps').childNodes[0].textContent = ' ' + t('mcps');
document.getElementById('nav-hooks').childNodes[0].textContent = '🪝 ' + t('hooks'); document.getElementById('nav-hooks').childNodes[0].textContent = ' ' + t('hooks');
// Update counter spans by their own IDs (avoids duplicate IDs in DOM) // Update counter spans by their own IDs (avoids duplicate IDs in DOM)
document.getElementById('nav-ct-agents').textContent = AGENTS.length; document.getElementById('nav-ct-agents').textContent = AGENTS.length;
document.getElementById('nav-ct-skills').textContent = SKILLS.length; document.getElementById('nav-ct-skills').textContent = SKILLS.length;
@ -514,7 +514,7 @@ function renderMain() {
const recent = recents().filter(r => r.n && /^[\\w\\-./@]+$/.test(r.n)); const recent = recents().filter(r => r.n && /^[\\w\\-./@]+$/.test(r.n));
if (recent.length) { if (recent.length) {
const icons = {agents:'🤖',skills:'📚',commands:'',rules:'📏',mcps:'🔌',hooks:'🪝'}; const icons = {agents:'',skills:'',commands:'',rules:'',mcps:'',hooks:''};
const rb = document.createElement('div'); const rb = document.createElement('div');
rb.className = 'recent-bar'; rb.className = 'recent-bar';
rb.innerHTML = '<span class="rb-lbl">'+t('recentlyViewed')+'</span><span class="rb-items"></span><span class="rb-clear" onclick="clearRecents()">✕ '+t('clearHistory')+'</span>'; rb.innerHTML = '<span class="rb-lbl">'+t('recentlyViewed')+'</span><span class="rb-items"></span><span class="rb-clear" onclick="clearRecents()">✕ '+t('clearHistory')+'</span>';
@ -551,21 +551,21 @@ function renderAgents(list) {
const el = document.getElementById('panel-agents'); const el = document.getElementById('panel-agents');
if (!el) return; if (!el) return;
const cats = ['all','reviewer','builder','architect','security']; const cats = ['all','reviewer','builder','architect','security'];
const lbls = [t('all'),'👁️ '+t('reviewers'),'🔧 '+t('buildResolvers'),'🏗️ '+t('architects'),'🔒 '+t('security')]; const lbls = [t('all'),' '+t('reviewers'),' '+t('buildResolvers'),' '+t('architects'),' '+t('security')];
el.innerHTML = '<div class="filters" id="af">'+cats.map((c,i)=>'<button'+(i===0?' class="active"':'')+' onclick="filterAgents(\\''+c+'\\',this)">'+lbls[i]+'</button>').join('')+ el.innerHTML = '<div class="filters" id="af">'+cats.map((c,i)=>'<button'+(i===0?' class="active"':'')+' onclick="filterAgents(\\''+c+'\\',this)">'+lbls[i]+'</button>').join('')+
'</div><div class="grid" id="ag">'+ '</div><div class="grid" id="ag">'+
list.map((a,i)=>{const m=(a.m||'').toLowerCase(),bd=m.includes('opus')?'opus':m.includes('sonnet')?'sonnet':m.includes('haiku')?'haiku':'';const tag=aType(a.n),ic=tag==='reviewer'?0:tag==='builder'?1:tag==='architect'?2:tag==='security'?3:4; list.map((a,i)=>{const m=(a.m||'').toLowerCase(),bd=m.includes('opus')?'opus':m.includes('sonnet')?'sonnet':m.includes('haiku')?'haiku':'';const tag=aType(a.n),ic=tag==='reviewer'?0:tag==='builder'?1:tag==='architect'?2:tag==='security'?3:4;
return '<div class="card" data-tag="'+tag+'" data-model="'+a.m+'" onclick="location.hash=\\'#/agents/'+encodeURIComponent(a.n)+'\\'">'+ return '<div class="card" data-tag="'+tag+'" data-model="'+a.m+'" onclick="location.hash=\\'#/agents/'+encodeURIComponent(a.n)+'\\'">'+
'<div class="top"><div class="il"><div class="ic '+iBg(ic)+'">'+ICONS[ic]+'</div><span class="nm">'+esc(a.n)+'</span></div>'+(bd?'<span class="bd '+bd+'">'+a.m+'</span>':'')+'</div>'+ '<div class="top"><div class="il"><div class="ic '+iBg(ic)+'">'+ICONS[ic]+'</div><span class="nm">'+esc(a.n)+'</span></div>'+(bd?'<span class="bd '+bd+'">'+a.m+'</span>':'')+'</div>'+
'<div class="desc">'+esc(a.d.slice(0,150))+'</div>'+ '<div class="desc">'+esc(a.d.slice(0,150))+'</div>'+
'<div class="tags">'+a.t.slice(0,5).map(t=>'<span class="t">'+esc(t)+'</span>').join('')+'</div><span class="ar"></span></div>';}).join('')+'</div>'; '<div class="tags">'+a.t.slice(0,5).map(t=>'<span class="t">'+esc(t)+'</span>').join('')+'</div><span class="ar"></span></div>';}).join('')+'</div>';
} }
function renderSkills(list) { function renderSkills(list) {
const el = document.getElementById('panel-skills'); if (!el) return; const el = document.getElementById('panel-skills'); if (!el) return;
el.innerHTML = '<div class="filters" id="sf">'+['all','sec','test','pattern','design','research','data','agent','devops'].map((c,i)=>'<button'+(i===0?' class="active"':'')+' onclick="filterSkills(\\''+c+'\\',this)">'+[t('all'),'🔒 '+t('security'),'🧪 '+t('testing'),'📐 '+t('patterns'),'🎨 '+t('design'),'🔬 '+t('research'),'🗄️ '+t('data'),'🤖 '+t('agent'),'⚙️ '+t('devops')][i]+'</button>').join('')+ el.innerHTML = '<div class="filters" id="sf">'+['all','sec','test','pattern','design','research','data','agent','devops'].map((c,i)=>'<button'+(i===0?' class="active"':'')+' onclick="filterSkills(\\''+c+'\\',this)">'+[t('all'),' '+t('security'),' '+t('testing'),' '+t('patterns'),' '+t('design'),' '+t('research'),' '+t('data'),' '+t('agent'),' '+t('devops')][i]+'</button>').join('')+
'</div><div class="grid" id="sg">'+list.map((s,i)=>'<div class="card" onclick="location.hash=\\'#/skills/'+encodeURIComponent(s.n)+'\\'">'+ '</div><div class="grid" id="sg">'+list.map((s,i)=>'<div class="card" onclick="location.hash=\\'#/skills/'+encodeURIComponent(s.n)+'\\'">'+
'<div class="top"><div class="il"><div class="ic '+iBg(i%6)+'">'+ICONS[i%6]+'</div><span class="nm">'+esc(s.n)+'</span></div></div>'+ '<div class="top"><div class="il"><div class="ic '+iBg(i%6)+'">'+ICONS[i%6]+'</div><span class="nm">'+esc(s.n)+'</span></div></div>'+
'<div class="desc">'+esc(s.d||'—')+'</div><span class="ar"></span></div>').join('')+'</div>'; '<div class="desc">'+esc(s.d||'—')+'</div><span class="ar"></span></div>').join('')+'</div>';
} }
function renderCommands(list) { function renderCommands(list) {
const el = document.getElementById('panel-commands'); if (!el) return; const el = document.getElementById('panel-commands'); if (!el) return;
@ -616,19 +616,19 @@ function renderRules(list) {
} }
function renderMcps(list) { function renderMcps(list) {
const el = document.getElementById('panel-mcps'); if (!el) return; const el = document.getElementById('panel-mcps'); if (!el) return;
if (!list.length) { el.innerHTML = '<div class="empty"><div class="eic">🔌</div><h3>'+esc(t('noMcps'))+'</h3><p>'+esc(t('checkMcps'))+'</p></div>'; return; } if (!list.length) { el.innerHTML = '<div class="empty"><div class="eic"></div><h3>'+esc(t('noMcps'))+'</h3><p>'+esc(t('checkMcps'))+'</p></div>'; return; }
const grid = document.createElement('div'); grid.className = 'mcp-grid'; const grid = document.createElement('div'); grid.className = 'mcp-grid';
list.forEach(m => { list.forEach(m => {
const div = document.createElement('div'); div.className = 'mcp-cd'; const div = document.createElement('div'); div.className = 'mcp-cd';
div.onclick = () => { location.hash = '#/mcps/'+encodeURIComponent(m.f); }; div.onclick = () => { location.hash = '#/mcps/'+encodeURIComponent(m.f); };
div.innerHTML = '<h3>📄 '+esc(m.f)+'</h3>'+m.s.map(s => '<span class="st">'+esc(s.n)+' <small>'+esc((s.cmd||'').slice(0,40))+'</small></span>').join(''); div.innerHTML = '<h3> '+esc(m.f)+'</h3>'+m.s.map(s => '<span class="st">'+esc(s.n)+' <small>'+esc((s.cmd||'').slice(0,40))+'</small></span>').join('');
grid.appendChild(div); grid.appendChild(div);
}); });
el.innerHTML = ''; el.appendChild(grid); el.innerHTML = ''; el.appendChild(grid);
} }
function renderHooks(list) { function renderHooks(list) {
const el = document.getElementById('panel-hooks'); if (!el) return; const el = document.getElementById('panel-hooks'); if (!el) return;
if (!list.length) { el.innerHTML = '<div class="empty"><div class="eic">🪝</div><h3>'+esc(t('noHooks'))+'</h3></div>'; return; } if (!list.length) { el.innerHTML = '<div class="empty"><div class="eic"></div><h3>'+esc(t('noHooks'))+'</h3></div>'; return; }
const wrap = document.createElement('div'); wrap.className = 'hw'; const wrap = document.createElement('div'); wrap.className = 'hw';
const tbl = document.createElement('table'); tbl.className = 'ht'; const tbl = document.createElement('table'); tbl.className = 'ht';
tbl.innerHTML = '<thead><tr><th>'+esc(t('event'))+'</th><th>'+esc(t('matcher'))+'</th><th>'+esc(t('description'))+'</th><th>'+esc(t('id'))+'</th></tr></thead><tbody></tbody>'; tbl.innerHTML = '<thead><tr><th>'+esc(t('event'))+'</th><th>'+esc(t('matcher'))+'</th><th>'+esc(t('description'))+'</th><th>'+esc(t('id'))+'</th></tr></thead><tbody></tbody>';
@ -730,7 +730,7 @@ function showSuggestions() {
const groups = {}; const groups = {};
results.forEach(r=>{if(!groups[r.t])groups[r.t]=[];groups[r.t].push(r);}); results.forEach(r=>{if(!groups[r.t])groups[r.t]=[];groups[r.t].push(r);});
sug.innerHTML = Object.entries(groups).map(([type,items]) => sug.innerHTML = Object.entries(groups).map(([type,items]) =>
'<div class="sg"><div class="sg-label">'+(type==='agents'?'🤖 '+t('agents'):type==='skills'?'📚 '+t('skills'):' '+t('commands'))+'</div>'+ '<div class="sg"><div class="sg-label">'+(type==='agents'?' '+t('agents'):type==='skills'?' '+t('skills'):' '+t('commands'))+'</div>'+
items.map(r=>'<div class="si" onclick="location.hash=\\'#/'+r.t+'/'+encodeURIComponent(r.n)+'\\';document.getElementById(\\'suggest\\').classList.remove(\\'show\\');document.getElementById(\\'search\\').blur()">'+ items.map(r=>'<div class="si" onclick="location.hash=\\'#/'+r.t+'/'+encodeURIComponent(r.n)+'\\';document.getElementById(\\'suggest\\').classList.remove(\\'show\\');document.getElementById(\\'search\\').blur()">'+
'<span class="ic '+r.ic+'">'+r.e+'</span><span class="sn">'+esc(r.n)+'</span><span class="sd">'+esc(r.d)+'</span></div>').join('')+'</div>' '<span class="ic '+r.ic+'">'+r.e+'</span><span class="sn">'+esc(r.n)+'</span><span class="sd">'+esc(r.d)+'</span></div>').join('')+'</div>'
).join(''); ).join('');
@ -767,7 +767,7 @@ const server = http.createServer((req, res) => {
if (require.main === module) { if (require.main === module) {
server.listen(PORT, () => { server.listen(PORT, () => {
console.log(`\n 🧩 ECC Capabilities → http://localhost:${PORT}\n`); console.log(`\n ECC Capabilities → http://localhost:${PORT}\n`);
try { const { spawn } = require('child_process'); const p = process.platform; const c = p === 'darwin' ? 'open' : p === 'win32' ? 'start' : 'xdg-open'; if (c === 'start') spawn('cmd', ['/c', 'start', `http://localhost:${PORT}`], { stdio: 'ignore' }); else spawn(c, [`http://localhost:${PORT}`], { stdio: 'ignore' }); } catch { /* best-effort auto-open */ } try { const { spawn } = require('child_process'); const p = process.platform; const c = p === 'darwin' ? 'open' : p === 'win32' ? 'start' : 'xdg-open'; if (c === 'start') spawn('cmd', ['/c', 'start', `http://localhost:${PORT}`], { stdio: 'ignore' }); else spawn(c, [`http://localhost:${PORT}`], { stdio: 'ignore' }); } catch { /* best-effort auto-open */ }
}); });
} }

View File

@ -33,9 +33,7 @@
1. 1.
2. 2.
3. 3. ### Open questions / threads to pursue in later modules
### Open questions / threads to pursue in later modules
### Contradictions or tensions between participants (multi-founder only) ### Contradictions or tensions between participants (multi-founder only)

View File

@ -37,9 +37,7 @@
### Alternative framings (vary the category or the differentiator) ### Alternative framings (vary the category or the differentiator)
1. 1.
2. 2. ### White-space hypothesis (what no competitor is claiming that this brand could own)
### White-space hypothesis (what no competitor is claiming that this brand could own)
### Open questions / ambiguities ### Open questions / ambiguities

View File

@ -52,8 +52,6 @@
1. 1.
2. 2.
3. 3. ### What the brand must never sound or look like (the anti-personality)
### What the brand must never sound or look like (the anti-personality)
### Open questions / tensions with Module 50 Voice ### Open questions / tensions with Module 50 Voice

View File

@ -56,6 +56,4 @@
1. 1.
2. 2.
3. 3. ### Open questions / tensions with Module 40 Personality
### Open questions / tensions with Module 40 Personality

View File

@ -32,15 +32,11 @@
### Trueline draft (Neumeier: "[Brand] is the only [category] that [unique claim].") ### Trueline draft (Neumeier: "[Brand] is the only [category] that [unique claim].")
> > ### Alternative truelines (23 variations, vary level of abstraction)
### Alternative truelines (23 variations, vary level of abstraction)
1. 1.
2. 2.
3. 3. ### Brand story arc
### Brand story arc
| Beat | Content | | Beat | Content |
|---|---| |---|---|

View File

@ -9,16 +9,7 @@ const path = require('path');
const fs = require('fs'); const fs = require('fs');
const os = require('os'); const os = require('os');
const { const { parseFrontmatter, extractSummary, loadAgent, loadAgents, compressToCatalog, compressToSummary, buildAgentCatalog, lazyLoadAgent } = require('../../scripts/lib/agent-compress');
parseFrontmatter,
extractSummary,
loadAgent,
loadAgents,
compressToCatalog,
compressToSummary,
buildAgentCatalog,
lazyLoadAgent,
} = require('../../scripts/lib/agent-compress');
function test(name, fn) { function test(name, fn) {
try { try {
@ -40,81 +31,125 @@ function runTests() {
// --- parseFrontmatter --- // --- parseFrontmatter ---
if (test('parseFrontmatter extracts YAML frontmatter and body', () => { if (
const content = '---\nname: test-agent\ndescription: A test\ntools: ["Read", "Grep"]\nmodel: sonnet\n---\n\nBody text here.'; test('parseFrontmatter extracts YAML frontmatter and body', () => {
const { frontmatter, body } = parseFrontmatter(content); const content = '---\nname: test-agent\ndescription: A test\ntools: ["Read", "Grep"]\nmodel: sonnet\n---\n\nBody text here.';
assert.strictEqual(frontmatter.name, 'test-agent'); const { frontmatter, body } = parseFrontmatter(content);
assert.strictEqual(frontmatter.description, 'A test'); assert.strictEqual(frontmatter.name, 'test-agent');
assert.deepStrictEqual(frontmatter.tools, ['Read', 'Grep']); assert.strictEqual(frontmatter.description, 'A test');
assert.strictEqual(frontmatter.model, 'sonnet'); assert.deepStrictEqual(frontmatter.tools, ['Read', 'Grep']);
assert.ok(body.includes('Body text here.')); assert.strictEqual(frontmatter.model, 'sonnet');
})) passed++; else failed++; assert.ok(body.includes('Body text here.'));
})
)
passed++;
else failed++;
if (test('parseFrontmatter handles content without frontmatter', () => { if (
const content = 'Just a regular markdown file.'; test('parseFrontmatter handles content without frontmatter', () => {
const { frontmatter, body } = parseFrontmatter(content); const content = 'Just a regular markdown file.';
assert.deepStrictEqual(frontmatter, {}); const { frontmatter, body } = parseFrontmatter(content);
assert.strictEqual(body, content); assert.deepStrictEqual(frontmatter, {});
})) passed++; else failed++; assert.strictEqual(body, content);
})
)
passed++;
else failed++;
if (test('parseFrontmatter handles colons in values', () => { if (
const content = '---\nname: test\ndescription: Use this: it works\n---\n\nBody.'; test('parseFrontmatter handles colons in values', () => {
const { frontmatter } = parseFrontmatter(content); const content = '---\nname: test\ndescription: Use this: it works\n---\n\nBody.';
assert.strictEqual(frontmatter.description, 'Use this: it works'); const { frontmatter } = parseFrontmatter(content);
})) passed++; else failed++; assert.strictEqual(frontmatter.description, 'Use this: it works');
})
)
passed++;
else failed++;
if (test('parseFrontmatter strips surrounding quotes', () => { if (
const content = '---\nname: "quoted-name"\n---\n\nBody.'; test('parseFrontmatter strips surrounding quotes', () => {
const { frontmatter } = parseFrontmatter(content); const content = '---\nname: "quoted-name"\n---\n\nBody.';
assert.strictEqual(frontmatter.name, 'quoted-name'); const { frontmatter } = parseFrontmatter(content);
})) passed++; else failed++; assert.strictEqual(frontmatter.name, 'quoted-name');
})
)
passed++;
else failed++;
if (test('parseFrontmatter handles content ending right after closing ---', () => { if (
const content = '---\nname: test\ndescription: No body\n---'; test('parseFrontmatter handles content ending right after closing ---', () => {
const { frontmatter, body } = parseFrontmatter(content); const content = '---\nname: test\ndescription: No body\n---';
assert.strictEqual(frontmatter.name, 'test'); const { frontmatter, body } = parseFrontmatter(content);
assert.strictEqual(frontmatter.description, 'No body'); assert.strictEqual(frontmatter.name, 'test');
assert.strictEqual(body, ''); assert.strictEqual(frontmatter.description, 'No body');
})) passed++; else failed++; assert.strictEqual(body, '');
})
)
passed++;
else failed++;
// --- extractSummary --- // --- extractSummary ---
if (test('extractSummary returns the first paragraph of the body', () => { if (
const body = '# Heading\n\nThis is the first paragraph. It has two sentences.\n\nSecond paragraph.'; test('extractSummary returns the first paragraph of the body', () => {
const summary = extractSummary(body); const body = '# Heading\n\nThis is the first paragraph. It has two sentences.\n\nSecond paragraph.';
assert.strictEqual(summary, 'This is the first paragraph.'); const summary = extractSummary(body);
})) passed++; else failed++; assert.strictEqual(summary, 'This is the first paragraph.');
})
)
passed++;
else failed++;
if (test('extractSummary returns empty string for empty body', () => { if (
assert.strictEqual(extractSummary(''), ''); test('extractSummary returns empty string for empty body', () => {
assert.strictEqual(extractSummary('# Only Headings\n\n## Another'), ''); assert.strictEqual(extractSummary(''), '');
})) passed++; else failed++; assert.strictEqual(extractSummary('# Only Headings\n\n## Another'), '');
})
)
passed++;
else failed++;
if (test('extractSummary skips code blocks', () => { if (
const body = '```\ncode here\n```\n\nActual summary sentence.'; test('extractSummary skips code blocks', () => {
const summary = extractSummary(body); const body = '```\ncode here\n```\n\nActual summary sentence.';
assert.strictEqual(summary, 'Actual summary sentence.'); const summary = extractSummary(body);
})) passed++; else failed++; assert.strictEqual(summary, 'Actual summary sentence.');
})
)
passed++;
else failed++;
if (test('extractSummary respects maxSentences', () => { if (
const body = 'First sentence. Second sentence. Third sentence.'; test('extractSummary respects maxSentences', () => {
const one = extractSummary(body, 1); const body = 'First sentence. Second sentence. Third sentence.';
const two = extractSummary(body, 2); const one = extractSummary(body, 1);
assert.strictEqual(one, 'First sentence.'); const two = extractSummary(body, 2);
assert.strictEqual(two, 'First sentence. Second sentence.'); assert.strictEqual(one, 'First sentence.');
})) passed++; else failed++; assert.strictEqual(two, 'First sentence. Second sentence.');
})
)
passed++;
else failed++;
if (test('extractSummary skips plain bullet items', () => { if (
const body = '- plain bullet\n- another bullet\n\nActual paragraph here.'; test('extractSummary skips plain bullet items', () => {
const summary = extractSummary(body); const body = '- plain bullet\n- another bullet\n\nActual paragraph here.';
assert.strictEqual(summary, 'Actual paragraph here.'); const summary = extractSummary(body);
})) passed++; else failed++; assert.strictEqual(summary, 'Actual paragraph here.');
})
)
passed++;
else failed++;
if (test('extractSummary skips asterisk bullets and numbered lists', () => { if (
const body = '* star bullet\n1. numbered item\n2. second item\n\nReal paragraph.'; test('extractSummary skips asterisk bullets and numbered lists', () => {
const summary = extractSummary(body); const body = '* star bullet\n1. numbered item\n2. second item\n\nReal paragraph.';
assert.strictEqual(summary, 'Real paragraph.'); const summary = extractSummary(body);
})) passed++; else failed++; assert.strictEqual(summary, 'Real paragraph.');
})
)
passed++;
else failed++;
// --- loadAgent / loadAgents --- // --- loadAgent / loadAgents ---
@ -124,142 +159,199 @@ function runTests() {
fs.writeFileSync(path.join(tmpDir, 'test-agent.md'), agentContent); fs.writeFileSync(path.join(tmpDir, 'test-agent.md'), agentContent);
fs.writeFileSync(path.join(tmpDir, 'not-an-agent.txt'), 'ignored'); fs.writeFileSync(path.join(tmpDir, 'not-an-agent.txt'), 'ignored');
if (test('loadAgent reads and parses a single agent file', () => { if (
const agent = loadAgent(path.join(tmpDir, 'test-agent.md')); test('loadAgent reads and parses a single agent file', () => {
assert.strictEqual(agent.name, 'test-agent'); const agent = loadAgent(path.join(tmpDir, 'test-agent.md'));
assert.strictEqual(agent.description, 'A test agent'); assert.strictEqual(agent.name, 'test-agent');
assert.deepStrictEqual(agent.tools, ['Read']); assert.strictEqual(agent.description, 'A test agent');
assert.strictEqual(agent.model, 'haiku'); assert.deepStrictEqual(agent.tools, ['Read']);
assert.ok(agent.body.includes('Test agent body paragraph')); assert.strictEqual(agent.model, 'haiku');
assert.strictEqual(agent.fileName, 'test-agent'); assert.ok(agent.body.includes('Test agent body paragraph'));
assert.ok(agent.byteSize > 0); assert.strictEqual(agent.fileName, 'test-agent');
})) passed++; else failed++; assert.ok(agent.byteSize > 0);
})
)
passed++;
else failed++;
if (test('loadAgents reads all .md files from a directory', () => { if (
const agents = loadAgents(tmpDir); test('loadAgents reads all .md files from a directory', () => {
assert.strictEqual(agents.length, 1); const agents = loadAgents(tmpDir);
assert.strictEqual(agents[0].name, 'test-agent'); assert.strictEqual(agents.length, 1);
})) passed++; else failed++; assert.strictEqual(agents[0].name, 'test-agent');
})
)
passed++;
else failed++;
if (test('loadAgents returns empty array for non-existent directory', () => { if (
const agents = loadAgents(path.join(os.tmpdir(), 'does-not-exist-agent-compress-test')); test('loadAgents returns empty array for non-existent directory', () => {
assert.deepStrictEqual(agents, []); const agents = loadAgents(path.join(os.tmpdir(), 'does-not-exist-agent-compress-test'));
})) passed++; else failed++; assert.deepStrictEqual(agents, []);
})
)
passed++;
else failed++;
// --- compressToCatalog / compressToSummary --- // --- compressToCatalog / compressToSummary ---
const sampleAgent = loadAgent(path.join(tmpDir, 'test-agent.md')); const sampleAgent = loadAgent(path.join(tmpDir, 'test-agent.md'));
if (test('compressToCatalog strips body and keeps only metadata', () => { if (
const catalog = compressToCatalog(sampleAgent); test('compressToCatalog strips body and keeps only metadata', () => {
assert.strictEqual(catalog.name, 'test-agent'); const catalog = compressToCatalog(sampleAgent);
assert.strictEqual(catalog.description, 'A test agent'); assert.strictEqual(catalog.name, 'test-agent');
assert.deepStrictEqual(catalog.tools, ['Read']); assert.strictEqual(catalog.description, 'A test agent');
assert.strictEqual(catalog.model, 'haiku'); assert.deepStrictEqual(catalog.tools, ['Read']);
assert.strictEqual(catalog.body, undefined); assert.strictEqual(catalog.model, 'haiku');
assert.strictEqual(catalog.byteSize, undefined); assert.strictEqual(catalog.body, undefined);
})) passed++; else failed++; assert.strictEqual(catalog.byteSize, undefined);
})
)
passed++;
else failed++;
if (test('compressToSummary includes first paragraph summary', () => { if (
const summary = compressToSummary(sampleAgent); test('compressToSummary includes first paragraph summary', () => {
assert.strictEqual(summary.name, 'test-agent'); const summary = compressToSummary(sampleAgent);
assert.ok(summary.summary.includes('Test agent body paragraph')); assert.strictEqual(summary.name, 'test-agent');
assert.strictEqual(summary.body, undefined); assert.ok(summary.summary.includes('Test agent body paragraph'));
})) passed++; else failed++; assert.strictEqual(summary.body, undefined);
})
)
passed++;
else failed++;
// --- buildAgentCatalog --- // --- buildAgentCatalog ---
if (test('buildAgentCatalog in catalog mode produces minimal output with stats', () => { if (
const result = buildAgentCatalog(tmpDir, { mode: 'catalog' }); test('buildAgentCatalog in catalog mode produces minimal output with stats', () => {
assert.strictEqual(result.agents.length, 1); const result = buildAgentCatalog(tmpDir, { mode: 'catalog' });
assert.strictEqual(result.agents[0].body, undefined); assert.strictEqual(result.agents.length, 1);
assert.strictEqual(result.stats.totalAgents, 1); assert.strictEqual(result.agents[0].body, undefined);
assert.strictEqual(result.stats.mode, 'catalog'); assert.strictEqual(result.stats.totalAgents, 1);
assert.ok(result.stats.originalBytes > 0); assert.strictEqual(result.stats.mode, 'catalog');
assert.ok(result.stats.compressedBytes < result.stats.originalBytes); assert.ok(result.stats.originalBytes > 0);
assert.ok(result.stats.compressedTokenEstimate > 0); assert.ok(result.stats.compressedBytes < result.stats.originalBytes);
})) passed++; else failed++; assert.ok(result.stats.compressedTokenEstimate > 0);
})
)
passed++;
else failed++;
if (test('buildAgentCatalog in summary mode includes summaries', () => { if (
const result = buildAgentCatalog(tmpDir, { mode: 'summary' }); test('buildAgentCatalog in summary mode includes summaries', () => {
assert.ok(result.agents[0].summary); const result = buildAgentCatalog(tmpDir, { mode: 'summary' });
assert.strictEqual(result.agents[0].body, undefined); assert.ok(result.agents[0].summary);
})) passed++; else failed++; assert.strictEqual(result.agents[0].body, undefined);
})
)
passed++;
else failed++;
if (test('buildAgentCatalog in full mode preserves body', () => { if (
const result = buildAgentCatalog(tmpDir, { mode: 'full' }); test('buildAgentCatalog in full mode preserves body', () => {
assert.ok(result.agents[0].body); const result = buildAgentCatalog(tmpDir, { mode: 'full' });
})) passed++; else failed++; assert.ok(result.agents[0].body);
})
)
passed++;
else failed++;
if (test('buildAgentCatalog throws on invalid mode', () => { if (
assert.throws( test('buildAgentCatalog throws on invalid mode', () => {
() => buildAgentCatalog(tmpDir, { mode: 'invalid' }), assert.throws(() => buildAgentCatalog(tmpDir, { mode: 'invalid' }), /Invalid mode "invalid"/);
/Invalid mode "invalid"/ })
); )
})) passed++; else failed++; passed++;
else failed++;
if (test('buildAgentCatalog supports filter function', () => { if (
// Add a second agent test('buildAgentCatalog supports filter function', () => {
fs.writeFileSync( // Add a second agent
path.join(tmpDir, 'other-agent.md'), fs.writeFileSync(path.join(tmpDir, 'other-agent.md'), '---\nname: other\ndescription: Other agent\ntools: ["Bash"]\nmodel: opus\n---\n\nOther body.');
'---\nname: other\ndescription: Other agent\ntools: ["Bash"]\nmodel: opus\n---\n\nOther body.' const result = buildAgentCatalog(tmpDir, {
); filter: a => a.model === 'opus'
const result = buildAgentCatalog(tmpDir, { });
filter: a => a.model === 'opus', assert.strictEqual(result.agents.length, 1);
}); assert.strictEqual(result.agents[0].name, 'other');
assert.strictEqual(result.agents.length, 1); // Clean up
assert.strictEqual(result.agents[0].name, 'other'); fs.unlinkSync(path.join(tmpDir, 'other-agent.md'));
// Clean up })
fs.unlinkSync(path.join(tmpDir, 'other-agent.md')); )
})) passed++; else failed++; passed++;
else failed++;
// --- lazyLoadAgent --- // --- lazyLoadAgent ---
if (test('lazyLoadAgent loads a single agent by name', () => { if (
const agent = lazyLoadAgent(tmpDir, 'test-agent'); test('lazyLoadAgent loads a single agent by name', () => {
assert.ok(agent); const agent = lazyLoadAgent(tmpDir, 'test-agent');
assert.strictEqual(agent.name, 'test-agent'); assert.ok(agent);
assert.ok(agent.body.includes('Test agent body paragraph')); assert.strictEqual(agent.name, 'test-agent');
})) passed++; else failed++; assert.ok(agent.body.includes('Test agent body paragraph'));
})
)
passed++;
else failed++;
if (test('lazyLoadAgent returns null for non-existent agent', () => { if (
const agent = lazyLoadAgent(tmpDir, 'does-not-exist'); test('lazyLoadAgent returns null for non-existent agent', () => {
assert.strictEqual(agent, null); const agent = lazyLoadAgent(tmpDir, 'does-not-exist');
})) passed++; else failed++; assert.strictEqual(agent, null);
})
)
passed++;
else failed++;
if (test('lazyLoadAgent rejects path traversal attempts', () => { if (
const agent = lazyLoadAgent(tmpDir, '../etc/passwd'); test('lazyLoadAgent rejects path traversal attempts', () => {
assert.strictEqual(agent, null); const agent = lazyLoadAgent(tmpDir, '../etc/passwd');
})) passed++; else failed++; assert.strictEqual(agent, null);
})
)
passed++;
else failed++;
if (test('lazyLoadAgent rejects names with invalid characters', () => { if (
const agent = lazyLoadAgent(tmpDir, 'foo/bar'); test('lazyLoadAgent rejects names with invalid characters', () => {
assert.strictEqual(agent, null); const agent = lazyLoadAgent(tmpDir, 'foo/bar');
const agent2 = lazyLoadAgent(tmpDir, 'foo bar'); assert.strictEqual(agent, null);
assert.strictEqual(agent2, null); const agent2 = lazyLoadAgent(tmpDir, 'foo bar');
})) passed++; else failed++; assert.strictEqual(agent2, null);
})
)
passed++;
else failed++;
// --- Real agents directory --- // --- Real agents directory ---
const realAgentsDir = path.resolve(__dirname, '../../agents'); const realAgentsDir = path.resolve(__dirname, '../../agents');
if (test('buildAgentCatalog works with real agents directory', () => { if (
if (!fs.existsSync(realAgentsDir)) return; // skip if not present test('buildAgentCatalog works with real agents directory', () => {
const result = buildAgentCatalog(realAgentsDir, { mode: 'catalog' }); if (!fs.existsSync(realAgentsDir)) return; // skip if not present
assert.ok(result.agents.length > 0, 'Should find at least one agent'); const result = buildAgentCatalog(realAgentsDir, { mode: 'catalog' });
assert.ok(result.stats.compressedBytes < result.stats.originalBytes, 'Catalog should be smaller than original'); assert.ok(result.agents.length > 0, 'Should find at least one agent');
// Verify significant compression ratio assert.ok(result.stats.compressedBytes < result.stats.originalBytes, 'Catalog should be smaller than original');
const ratio = result.stats.compressedBytes / result.stats.originalBytes; // Verify significant compression ratio
assert.ok(ratio < 0.5, `Compression ratio ${ratio.toFixed(2)} should be < 0.5`); const ratio = result.stats.compressedBytes / result.stats.originalBytes;
})) passed++; else failed++; assert.ok(ratio < 0.5, `Compression ratio ${ratio.toFixed(2)} should be < 0.5`);
})
)
passed++;
else failed++;
if (test('catalog mode token estimate is under 5000 for real agents', () => { if (
if (!fs.existsSync(realAgentsDir)) return; test('catalog mode token estimate is under 6000 for real agents', () => {
const result = buildAgentCatalog(realAgentsDir, { mode: 'catalog' }); if (!fs.existsSync(realAgentsDir)) return;
assert.ok( const result = buildAgentCatalog(realAgentsDir, { mode: 'catalog' });
result.stats.compressedTokenEstimate < 5000, // Canary tracks catalog growth: raised 5000 -> 6000 for the 67-agent catalog
`Token estimate ${result.stats.compressedTokenEstimate} exceeds 5000` // after adding spec-miner (#2253), agent-evaluator (#2220), vue-reviewer (#2241).
); assert.ok(result.stats.compressedTokenEstimate < 6000, `Token estimate ${result.stats.compressedTokenEstimate} exceeds 6000`);
})) passed++; else failed++; })
)
passed++;
else failed++;
// Cleanup // Cleanup
fs.rmSync(tmpDir, { recursive: true, force: true }); fs.rmSync(tmpDir, { recursive: true, force: true });