| 147 |
147
|
|
expect(painted).toContain("\x1b[2m\x1b[3mI should check first.\x1b[0m");
|
| 148 |
148
|
|
});
|
| 149 |
149
|
|
|
|
150
|
+ |
it("counts the streaming turn, so the bar never reads zero under a live reply", async () => {
|
|
151
|
+ |
const stdin = new FakeIn();
|
|
152
|
+ |
const stdout = new FakeOut();
|
|
153
|
+ |
let release = () => {};
|
|
154
|
+ |
const held = new Promise<void>((resolve) => {
|
|
155
|
+ |
release = resolve;
|
|
156
|
+ |
});
|
|
157
|
+ |
const paused: ReplySource = {
|
|
158
|
+ |
model: "scripted",
|
|
159
|
+ |
async *reply() {
|
|
160
|
+ |
yield { type: "text", value: "still arriving" } as const;
|
|
161
|
+ |
await held;
|
|
162
|
+ |
},
|
|
163
|
+ |
};
|
|
164
|
+ |
|
|
165
|
+ |
const session = new CoderSession(paused, "repo", "main");
|
|
166
|
+ |
const running = runCoderUi(session, {
|
|
167
|
+ |
stdin: stdin as unknown as NodeJS.ReadStream,
|
|
168
|
+ |
stdout: stdout as unknown as NodeJS.WriteStream,
|
|
169
|
+ |
});
|
|
170
|
+ |
const turn = session.submit("go");
|
|
171
|
+ |
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
172
|
+ |
|
|
173
|
+ |
expect(session.snapshot().running).toBe(true);
|
|
174
|
+ |
const bar = screen(stdout.written).at(-1) ?? "";
|
|
175
|
+ |
expect(bar).toContain("1 reply this run");
|
|
176
|
+ |
expect(bar).not.toContain("0 replies");
|
|
177
|
+ |
|
|
178
|
+ |
release();
|
|
179
|
+ |
await turn;
|
|
180
|
+ |
stdin.emit("data", "\x04");
|
|
181
|
+ |
await running;
|
|
182
|
+ |
});
|
|
183
|
+ |
|
|
184
|
+ |
it("labels the count as this run's, because the conversation is not", async () => {
|
|
185
|
+ |
const { rows } = await drive([{ type: "text", value: "hello" }]);
|
|
186
|
+ |
expect(rows.at(-1)).toContain("1 reply this run");
|
|
187
|
+ |
});
|
|
188
|
+ |
|
|
189
|
+ |
it("says once where the turns are recorded when the source is not private", async () => {
|
|
190
|
+ |
const stdin = new FakeIn();
|
|
191
|
+ |
const stdout = new FakeOut();
|
|
192
|
+ |
const session = new CoderSession(
|
|
193
|
+ |
{ ...source([{ type: "text", value: "hi" }]), scopeNotice: "shared with /chat" },
|
|
194
|
+ |
"repo",
|
|
195
|
+ |
"main",
|
|
196
|
+ |
);
|
|
197
|
+ |
const running = runCoderUi(session, {
|
|
198
|
+ |
stdin: stdin as unknown as NodeJS.ReadStream,
|
|
199
|
+ |
stdout: stdout as unknown as NodeJS.WriteStream,
|
|
200
|
+ |
});
|
|
201
|
+ |
await session.submit("go");
|
|
202
|
+ |
const rows = screen(stdout.written);
|
|
203
|
+ |
stdin.emit("data", "\x04");
|
|
204
|
+ |
await running;
|
|
205
|
+ |
|
|
206
|
+ |
const notes = rows.filter((row) => row.includes("shared with /chat"));
|
|
207
|
+ |
expect(notes).toHaveLength(1);
|
|
208
|
+ |
expect(notes[0]).toContain("note");
|
|
209
|
+ |
});
|
|
210
|
+ |
|
|
211
|
+ |
it("says nothing about scope when the source keeps its turns to itself", async () => {
|
|
212
|
+ |
const { rows } = await drive([{ type: "text", value: "hello" }]);
|
|
213
|
+ |
expect(rows.join("\n")).not.toContain("shared with");
|
|
214
|
+ |
});
|
|
215
|
+ |
|
| 150 |
216
|
|
it("offers no key in the bottom bar that does nothing in that state", async () => {
|
| 151 |
217
|
|
const { rows } = await drive([{ type: "text", value: "hello" }]);
|
| 152 |
218
|
|
const bar = rows.at(-1) ?? "";
|