mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 18:39:33 +01:00
fix(story-mode): appends without invented line numbers, printed files you can open, whose words start a turn
The rest of review round 5 (a phone with touch): - Text appended with `cat >> f <<EOF` or `echo x >> f` was drawn as lines 1 to 8 of the file; where an append lands is not in the command, so the diff now says "Added at the end of the file (8 lines)" with no numbers. - A command that prints a file and does something else (`cat textstats.py && pytest`) kept no record of the file; it is now on the event, resolved against the command's own folder, and the output drawer offers "Open textstats.py". (A file rewritten by a python here-document still cannot be diffed from the command alone; Claude Code's own "modified" note, when it comes, is used.) - A background job's report that starts a turn was a balloon credited to "you" in the API (the page already drew it as a note); its speaker is now "note". - The output drawer tagged a command still running in the background "ok"; it says "in the background". - The Header buttons hint says that on a phone, Story Mode opens from Session Options. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
76d5c61eda
commit
6a1bac6ebe
7 files changed
+119
-15
No files matched your search
@@ -535,6 +535,34 @@ describe('story-mode.js overlay', () => {
|
||||
expect($$('.story-ln--add').map((l) => l.textContent)).toEqual(['1+const a = 1;']);
|
||||
});
|
||||
|
||||
it('an append draws without line numbers, and a check offers the file it printed', async () => {
|
||||
const lines = [
|
||||
prompt('add and test'),
|
||||
...bash(
|
||||
'b1',
|
||||
"cat >> notes.md <<'EOF'\nmore\nEOF\ncat stats.py && pytest -q",
|
||||
'Append, show and test',
|
||||
'def f(): pass\n5 passed in 0.1s'
|
||||
),
|
||||
end(1000),
|
||||
];
|
||||
(lines[1] as { cwd?: string }).cwd = '/work/demo-shop';
|
||||
boot(storyOf(lines));
|
||||
app.openStoryMode(SID);
|
||||
await settle();
|
||||
sizeAndDraw();
|
||||
$('.story-panel[data-kind="check"] .story-hit')!.click();
|
||||
const open = $$('.story-drawer-body .story-out-files button');
|
||||
expect(open.map((b) => b.textContent)).toEqual(['Open stats.py']);
|
||||
open[0].click();
|
||||
expect(app.openFilePreview).toHaveBeenLastCalledWith('/work/demo-shop/stats.py', SID);
|
||||
$$('.story-drawer-body button')
|
||||
.find((b) => b.textContent === 'See the file it wrote')!
|
||||
.click();
|
||||
expect($('.story-ln--hunk')!.textContent).toBe('Added at the end of the file (1 line)');
|
||||
expect($$('.story-ln--add').map((l) => l.textContent)).toEqual(['+more']);
|
||||
});
|
||||
|
||||
it('while a question waits, the pencils say so; the chosen answer is marked, not struck', async () => {
|
||||
const ask = (answered: boolean) =>
|
||||
storyOf([
|
||||
|
||||
@@ -975,6 +975,46 @@ describe('buildStoryPage', () => {
|
||||
expect(heredocWrites('tee -a notes.md <<EOF\nx\nEOF', '/w').map((d) => d.file)).toEqual(['/w/notes.md']);
|
||||
});
|
||||
|
||||
it('an append has no line numbers it cannot know; a whole-file write starts at line 1', () => {
|
||||
const [append] = heredocWrites("cat >> notes.md <<'EOF'\none\ntwo\nEOF", '/w');
|
||||
expect(append.hunks[0]).toMatchObject({ atEnd: true, newStart: 0, newLines: 2 });
|
||||
const [echoed] = heredocWrites('echo "more" >> notes.md', '/w');
|
||||
expect(echoed.hunks[0]).toMatchObject({ atEnd: true, newStart: 0 });
|
||||
const [whole] = heredocWrites("cat > notes.md <<'EOF'\none\nEOF", '/w');
|
||||
expect(whole.hunks[0]).toMatchObject({ newStart: 1, newLines: 1 });
|
||||
expect(whole.hunks[0].atEnd).toBeUndefined();
|
||||
});
|
||||
|
||||
it('files a command prints are on its event, resolved against its cwd, whatever it does', () => {
|
||||
const lines = [
|
||||
prompt('rewrite and test'),
|
||||
...bash('b1', 'cat textstats.py && python3 -m pytest -q', 'Show and test', 'def f(): pass\n5 passed in 0.1s'),
|
||||
end(1000),
|
||||
];
|
||||
(lines[1] as { cwd?: string }).cwd = '/w';
|
||||
const page = pageOf(lines);
|
||||
expect(page.events[1]).toMatchObject({ intent: 'test', files: ['/w/textstats.py'] });
|
||||
});
|
||||
|
||||
it('words that start a turn but are not yours are a note, not your balloon', () => {
|
||||
const turns = buildStoryTurns(
|
||||
entriesOf([
|
||||
prompt('go'),
|
||||
end(1000),
|
||||
prompt(
|
||||
'<task-notification>\n<task-id>bg1</task-id>\n<status>completed</status>\n<summary>Background command \"Run tests\" completed (exit code 0)</summary>\n</task-notification>',
|
||||
{ turnOrigin: 'task_notification' }
|
||||
),
|
||||
said('All good.'),
|
||||
end(1000),
|
||||
])
|
||||
);
|
||||
expect(buildStoryPage(turns[0]).panels[0].balloon?.who).toBe('you');
|
||||
const report = buildStoryPage(turns[1]).panels[0];
|
||||
expect(report.caption.story).toBe('A background job reports back.');
|
||||
expect(report.balloon?.who).toBe('note');
|
||||
});
|
||||
|
||||
it('a loop keeps every run: a lint failure inside a round that passed in the end still shows', () => {
|
||||
const page = pageOf([
|
||||
prompt('build'),
|
||||
|
||||
Reference in new issue
Block a user