Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/dev/shot_agentpane.mjs

5.5 KiB, 1 run

created by r2519314175:139, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1// shot_agentpane.mjs — visual + behavioural check of the agents panel's new
2// chips (parent Diamond, inherited tags, model) and its Diamonds-style search/filter.
3//
4// Drives the real UI: two tagged Diamonds, a small fan-out from each, then the search
5// box and a Diamond-chip filter. Needs dev/serve.mjs (DAIMOND_PORT, default 8777) +
6// dev/mockllm.mjs.
7import { open, shot } from './harness.mjs';
8
9const s = await open({ name: 'agentpane-shot', signIn: true, connect: true });
10const { page } = s;
11const pause = (ms) => page.waitForTimeout(ms);
12
13async function newDiamond(name) {
14 await page.click('#new-diamond-btn', { force: true });
15 await page.waitForSelector('.dlg-input', { timeout: 8000 });
16 await page.fill('.dlg-input', name);
17 await page.click('.dlg-ok');
18 await page.waitForSelector('#steer-input', { timeout: 10000 });
19 await pause(300);
20}
21
22async function addTags(tags) {
23 // The "# Tags" button on the Diamond command surface opens the tag editor.
24 await page.click('button.crystal-act:has-text("# Tags")', { force: true });
25 await page.waitForSelector('.tag-input', { timeout: 6000 });
26 for (const t of tags) {
27 await page.fill('.tag-input', t);
28 await page.click('button.crystal-act:has-text("+ Add")', { force: true });
29 await pause(250);
30 }
31}
32
33async function steer(text) {
34 await page.fill('#steer-input', text);
35 await page.click('#steer-send');
36 await pause(1200);
37}
38
39// ── Diamond A: Backend audit, tagged, two workers ─────────────────────────
40await newDiamond('Backend audit');
41await addTags(['rust', 'ledger']);
42// Back to the steer surface by re-selecting the Diamond in the rail.
43await page.click('.diamond-box:has-text("Backend audit")', { force: true });
44await page.waitForSelector('#steer-input', { timeout: 8000 });
45await steer('@tools spawn_agent {"name":"schema-check","task":"@text checked the schema"} '
46 + ';; spawn_agent {"name":"ledger-audit","task":"@text audited the ledger"}');
47
48// ── Diamond B: Frontend polish, tagged, two workers ───────────────────────
49await newDiamond('Frontend polish');
50await addTags(['css']);
51await page.click('.diamond-box:has-text("Frontend polish")', { force: true });
52await page.waitForSelector('#steer-input', { timeout: 8000 });
53await steer('@tools spawn_agent {"name":"chip-render","task":"@text rendered the chips"} '
54 + ';; spawn_agent {"name":"theme-sweep","task":"@text swept the themes"}');
55
56// Let the workers finish, then force the panel to repaint with fresh tags.
57await pause(2500);
58await page.fill('#agent-search', ' ');
59await page.fill('#agent-search', '');
60await pause(400);
61
62const summary = await page.evaluate(() => {
63 const cards = [...document.querySelectorAll('#agents-list .acard')];
64 return {
65 count: cards.length,
66 tiles: cards.map(c => ({
67 name: (c.querySelector('.an') || {}).textContent,
68 diamond: (c.querySelector('.diamond-chip') || {}).textContent,
69 tags: [...c.querySelectorAll('.tag-chip.tag-sm')].map(t => t.textContent),
70 model: (c.querySelector('.achip-model') || {}).textContent,
71 })),
72 };
73});
74console.log('TILES:', JSON.stringify(summary, null, 2));
75await shot(s, 'agentpane-all');
76
77// ── Search filters by Diamond name ────────────────────────────────────────
78await page.fill('#agent-search', 'backend');
79await pause(400);
80const afterSearch = await page.$$eval('#agents-list .acard', cs => cs.length);
81const searchMiss = await page.$eval('#agents-list', el => el.textContent.includes('No agents match') );
82console.log('after search "backend": cards =', afterSearch);
83await shot(s, 'agentpane-search-backend');
84await page.fill('#agent-search', '');
85await pause(300);
86
87// ── Clicking a Diamond chip filters to that Diamond, and shows a clear chip ──
88await page.click('.acard .diamond-chip:has-text("Frontend polish")', { force: true });
89await pause(400);
90const afterChip = await page.evaluate(() => ({
91 cards: document.querySelectorAll('#agents-list .acard').length,
92 filterChip: (document.querySelector('#agent-filter .tag-chip') || {}).textContent || '(none)',
93 filterShown: document.getElementById('agent-filter').style.display !== 'none',
94}));
95console.log('after Diamond-chip filter:', JSON.stringify(afterChip));
96await shot(s, 'agentpane-filter-frontend');
97
98// ── Clear the filter with the × ─────────────────────────────────────────
99await page.click('#agent-filter .tag-x', { force: true });
100await pause(400);
101const cleared = await page.$$eval('#agents-list .acard', cs => cs.length);
102console.log('after clearing filter: cards =', cleared);
103
104// ── Verdicts ────────────────────────────────────────────────────────────
105// The gateway is not run in this harness, so /api calls 502 by design; those
106// are not the pane's errors. Anything else is.
107const realErrs = s.errs.filter(e => !/502|Bad Gateway|\/api\b/.test(e));
108const ok = summary.count === 4
109 && summary.tiles.every(t => t.focus && t.model)
110 && summary.tiles.some(t => t.tags.length > 0)
111 && afterSearch === 2 && !searchMiss
112 && afterChip.cards === 2 && afterChip.filterShown
113 && cleared === 4
114 && realErrs.length === 0;
115console.log(ok ? '\n✅ PASS — chips, search and Diamond filter all work' : '\n❌ FAIL — see above');
116if (realErrs.length) console.log('PAGE ERRORS:', realErrs);
117await s.close();
118process.exit(ok ? 0 : 1);