mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 10:39:32 +01:00
fix(story-mode): balloons over the speaker, honest boards, and drawers that keep up
From review round 1, checked against screenshots of the reviewers' real transcripts at desktop and phone width: - Claude's balloon is placed in the band above the head the scene drew, its tail pointing down at it, and clamped to stay inside the panel and off the head. Per-kind CSS offsets had covered the POW burst, the agent's head on a half-width fix panel and the first line of a terminal; a long prompt ran out of the mission panel. Save image clamps the same way. - A board only shows real counts; a check that reported none shows one verdict instead of 21 invented dots, and the loop shows its last run. - The mission panel opens the whole prompt, and on a task turn what the background job reported. - A background helper says "in the background" and "still working" until it reports back, its drawer keeps polling while it works, and the final panel counts helpers still out. - A fix made from the terminal opens what ran instead of an empty diff. - The wire files Claude's words under the panel that draws them, and its last words under the final panel. - A drawer follows its panel by the first event it showed when a refresh regroups panels (a check folding into a loop), not by kind. - Click regions reused for a new page get the new label; a new turn draws all its panels fresh. - Output links skip globs and paths a tool elided; prose links rooted paths only; paths inside the session folder read short (clicks keep the full path), and files Claude printed with cat open relative to that folder. - File cards keep a name's separators (rename_by_ / date.sh), code drops ligatures (`!==` stays three characters), counts drop "−0", and the turn picker's text stops before its chevron. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
38585a806b
commit
03cb3a5961
4 files changed
+391
-60
No files matched your search
@@ -409,6 +409,112 @@ describe('story-mode.js overlay', () => {
|
||||
expect(win.document.activeElement).toBe(controls[0]);
|
||||
});
|
||||
|
||||
it("the mission opens the whole prompt, and a task turn's mission opens what the job reported", async () => {
|
||||
const report = [
|
||||
'<task-notification>',
|
||||
'<tool-use-id>a1</tool-use-id>',
|
||||
'<status>completed</status>',
|
||||
'<summary>Agent "Docs" finished</summary>',
|
||||
'<result>I wrote /home/me/demo-shop/README.md. Names look like old.jpg -> new.jpg.</result>',
|
||||
'</task-notification>',
|
||||
].join('\n');
|
||||
boot(storyOf([prompt(report, { turnOrigin: 'task_notification' }), said('Thanks.'), end(1000)]));
|
||||
app.openStoryMode(SID);
|
||||
await settle();
|
||||
sizeAndDraw();
|
||||
const hit = $('.story-panel[data-kind="mission"] .story-hit')!;
|
||||
expect(hit.title).toBe('Read the report');
|
||||
hit.click();
|
||||
expect($('.story-drawer-kind')!.textContent).toBe('Report');
|
||||
expect($('.story-drawer-body')!.textContent).toContain('What it reported');
|
||||
const links = $$('.story-drawer-body .story-link');
|
||||
// In prose only rooted paths link: `old.jpg` is an example, not a file.
|
||||
expect(links.map((l) => l.textContent)).toEqual(['/home/me/demo-shop/README.md']);
|
||||
});
|
||||
|
||||
it("the wire files Claude's last words under the final panel", async () => {
|
||||
boot(storyOf([prompt('look'), ...read('r1', '/work/demo-shop/a.md'), said('All done here.'), end(1000)]));
|
||||
app.openStoryMode(SID);
|
||||
await settle();
|
||||
app._storySetDirector(true);
|
||||
const rows = $$('.story-wire li').map((li) => li.textContent || '');
|
||||
const lastGroup = [...rows].reverse().find((t) => t.startsWith('Panel'));
|
||||
expect(lastGroup).toMatch(/· The end$/);
|
||||
expect(rows[rows.length - 1]).toContain('All done here.');
|
||||
});
|
||||
|
||||
it('a fix made from the terminal opens what ran, not an empty diff', async () => {
|
||||
boot(
|
||||
storyOf([
|
||||
prompt('patch it'),
|
||||
...bash('b1', "sed -i 's/a/b/' app.py", 'Patch the file', ''),
|
||||
...bash('b2', 'printf x > notes.md', 'Write notes', ''),
|
||||
end(1000),
|
||||
])
|
||||
);
|
||||
app.openStoryMode(SID);
|
||||
await settle();
|
||||
sizeAndDraw();
|
||||
$('.story-panel[data-kind="fix"] .story-hit')!.click();
|
||||
expect($('.story-drawer-kind')!.textContent).toBe('Output');
|
||||
expect($('.story-drawer-body')!.textContent).toContain("sed -i 's/a/b/' app.py");
|
||||
expect($('.story-drawer-body')!.textContent).not.toContain('No changes');
|
||||
});
|
||||
|
||||
it('output links skip globs and paths a tool elided', async () => {
|
||||
boot(
|
||||
storyOf([
|
||||
prompt('test'),
|
||||
...bash('b1', 'pytest -q', 'Run tests', 'FAILED test_a.py::t - 2...rted_0/a.txt\nsee *.test.ts and src/app.py'),
|
||||
end(1000),
|
||||
])
|
||||
);
|
||||
app.openStoryMode(SID);
|
||||
await settle();
|
||||
sizeAndDraw();
|
||||
$('.story-panel[data-kind="check"] .story-hit')!.click();
|
||||
const links = $$('.story-drawer-body .story-link').map((l) => l.textContent);
|
||||
expect(links).toContain('src/app.py');
|
||||
expect(links.some((l) => /\.\.\.|\*/.test(l || ''))).toBe(false);
|
||||
expect(links).not.toContain('.test.ts');
|
||||
});
|
||||
|
||||
it('a helper still working in the background says so, in its drawer and on the final panel', async () => {
|
||||
boot(
|
||||
storyOf([
|
||||
prompt('docs'),
|
||||
tool('a1', 'Agent', { description: 'Write README', subagent_type: 'general-purpose', prompt: 'Write it' }),
|
||||
result('a1', 'Async agent launched successfully. agentId: h9', {
|
||||
toolUseResult: { isAsync: true, status: 'async_launched', agentId: 'h9' },
|
||||
}),
|
||||
end(1000),
|
||||
])
|
||||
);
|
||||
app.openStoryMode(SID);
|
||||
await settle();
|
||||
sizeAndDraw();
|
||||
expect($('.story-panel[data-kind="complete"] .story-chips')!.textContent).toContain('1 helper, 1 still working');
|
||||
$('.story-panel[data-kind="backup"] .story-hit')!.click();
|
||||
await settle();
|
||||
expect($('.story-drawer-sub')!.textContent).toContain('in the background');
|
||||
expect($('.story-drawer-body')!.textContent).toContain('Still working in the background.');
|
||||
expect($('.story-drawer-body')!.textContent).not.toContain('Async agent launched');
|
||||
});
|
||||
|
||||
it('a click region reused for a new page gets the new label', async () => {
|
||||
boot(storyOf([prompt('one'), ...read('r1', '/work/demo-shop/README.md'), end(1000)]));
|
||||
app.openStoryMode(SID);
|
||||
await settle();
|
||||
sizeAndDraw();
|
||||
expect($('.story-panel[data-kind="investigate"] .story-hit')!.title).toBe('Open README.md');
|
||||
const next = storyOf([prompt('one'), ...read('r1', '/work/demo-shop/rename_by_date.sh'), end(1000)]);
|
||||
next.page!.id = app._story.data.page.id;
|
||||
app._story.data = next;
|
||||
app._storyRender();
|
||||
sizeAndDraw();
|
||||
expect($('.story-panel[data-kind="investigate"] .story-hit')!.title).toBe('Open rename_by_date.sh');
|
||||
});
|
||||
|
||||
it('turning the setting off hides the button and closes an open story', async () => {
|
||||
boot(storyOf(demoTurn()));
|
||||
app.openStoryMode(SID);
|
||||
|
||||
Reference in new issue
Block a user