Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ changes will be called out under **Breaking changes**.

## Unreleased

## [0.18.2] — 2026-09-16

Full notes: [`docs/releases/0.18.2.md`](docs/releases/0.18.2.md).

### Fixed

- **Scroll history at an empty prompt.** Up/Down now scroll the conversation when the draft is empty, including wheel gestures that terminals translate into arrows. Ctrl+P/Ctrl+N recall submitted prompts; suggestions and multiline editing retain their controls.

## [0.18.1] — 2026-09-15

Full notes: [`docs/releases/0.18.1.md`](docs/releases/0.18.1.md).
Expand Down Expand Up @@ -562,6 +570,7 @@ Initial alpha. Core room protocol, SQLite-backed persistence, multi-process
contention coverage, MCP smoke coverage, human guardian flow, harness
installers, and the portable `talking-stick` skill.

[0.18.2]: https://github.com/mostlydev/talking-stick/releases/tag/v0.18.2
[0.18.1]: https://github.com/mostlydev/talking-stick/releases/tag/v0.18.1
[0.18.0]: https://github.com/mostlydev/talking-stick/releases/tag/v0.18.0
[0.17.0]: https://github.com/mostlydev/talking-stick/releases/tag/v0.17.0
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,9 @@ claude → you 12:05
3 members │ codex holding 12m · claude idle 3m
```

Scroll with Page Up/Page Down or Shift+Up/Down. The input stays fixed and editable. New messages do not pull you away from older history; a count appears in the footer. Ctrl+End or `/bottom` returns to live messages. The in-memory buffer retains up to 2,000 message/notice blocks and rewraps on resize. Mouse capture is off by default: drag to select text, double-click to select a word, and copy using your terminal's usual shortcut or menu. For wheel scrolling inside the conversation, opt in with `tt chat --mouse`; this captures mouse gestures, so native selection then requires your terminal's selection modifier (often Shift). `--no-mouse` explicitly restores the default and wins if both flags are supplied.
Scroll with Page Up/Page Down or Shift+Up/Down. With an empty draft, Up/Down also scroll the conversation; this supports terminals that translate the mouse wheel into arrow keys. Use Ctrl+P/Ctrl+N to recall submitted prompts. The input stays fixed and editable. New messages do not pull you away from older history; a count appears in the footer. Ctrl+End or `/bottom` returns to live messages. The in-memory buffer retains up to 2,000 message/notice blocks and rewraps on resize. Mouse capture is off by default: drag to select text, double-click to select a word, and copy using your terminal's usual shortcut or menu. For wheel scrolling inside the conversation, opt in with `tt chat --mouse`; this captures mouse gestures, so native selection then requires your terminal's selection modifier (often Shift). `--no-mouse` explicitly restores the default and wins if both flags are supplied.

Typing `/`, `@`, or `!@` opens a suggestion list drawn over the bottom of the conversation, so nothing moves while you type. Up/Down choose, Tab or Enter accept, and Enter still sends once the word is complete (an exact `/quit` still quits). Escape closes the list first and clears the draft on a second press; Ctrl+C clears the draft. Neither quits. Alt+Enter (or Shift+Enter where the terminal supports it) adds a new line, and with the list closed Up/Down move through a multi-line draft at the same column. Pasted multiline text stays in the draft until Enter. On exit, the console restores the original terminal screen.
Typing `/`, `@`, or `!@` opens a suggestion list drawn over the bottom of the conversation, so nothing moves while you type. Up/Down choose, Tab or Enter accept, and Enter still sends once the word is complete (an exact `/quit` still quits). Escape closes the list first and clears the draft on a second press; Ctrl+C clears the draft. Neither quits. Alt+Enter (or Shift+Enter where the terminal supports it) adds a new line, and with the list closed Up/Down move through a multi-line draft at the same column. On a nonempty single-line draft, Up/Down retain prompt-history navigation; empty-draft arrows scroll the conversation. Pasted multiline text stays in the draft until Enter. On exit, the console restores the original terminal screen.

History is split with Today, Yesterday, and date dividers. Earlier days are dimmed and their timestamps include the day. When someone joins after four quiet hours, everything before that is dimmed as an earlier conversation; this is a visual boundary, not a sign that a quiet agent has exited.

Expand Down
18 changes: 18 additions & 0 deletions docs/releases/0.18.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Talking Stick 0.18.2

Date: 2026-09-16

## Fixed

- **Scroll history at an empty prompt.** Up/Down now scroll the conversation when the draft is empty, including wheel gestures that terminals translate into arrows. Ctrl+P/Ctrl+N recall submitted prompts; suggestions and multiline editing retain their controls.

## Verification

```bash
npm run typecheck
npm test
npm run build
node dist/cli.js --help
git diff --check
npm pack --dry-run
```
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "talking-stick",
"version": "0.18.1",
"version": "0.18.2",
"description": "CLI coordination tool for path-scoped agent handoffs.",
"type": "module",
"bin": {
Expand Down
7 changes: 7 additions & 0 deletions src/cli/chat-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ export class ChatInputController {
this.selectedCompletion = (this.completionIndex + direction + count) % count;
return;
}
// With native selection enabled, terminals may translate wheel movement
// into ordinary arrows. At an empty prompt, navigate the conversation
// instead of replacing the draft with previously submitted messages.
if (this.draft.line.length === 0) {
this.options.onScroll("lines", direction);
return;
}
const moved = moveChatCursorVertical(this.draft, this.sink.columns, direction, this.verticalColumn);
if (moved) {
this.rl.cursor = moved.draft.cursor;
Expand Down
3 changes: 2 additions & 1 deletion src/cli/chat-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ export function formatChatHelp(width: number, color: boolean, keys = false): str
const entries: [string, string][] = keys ? [
["Enter", "Send; accept an incomplete suggestion first"],
["Tab", "Accept the selected suggestion"],
["↑ / ↓", "Choose a suggestion, or move through draft lines"],
["↑ / ↓", "Scroll when empty; choose suggestions or edit draft lines"],
["Ctrl+P / Ctrl+N", "Recall previous / next submitted prompt"],
["Alt+Enter", "Insert a new line"],
["Esc", "Dismiss suggestions; press again to clear"],
["Ctrl+C", "Clear the draft"],
Expand Down
19 changes: 18 additions & 1 deletion tests/chat-input.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe("full-screen chat input", () => {
expect(submit).not.toHaveBeenCalled();
input.write("\u0001\u0005\r");
expect(submit).toHaveBeenLastCalledWith(body);
input.write("\u001b[A");
input.write("\u0010");
expect(editor.draft.line).toBe(body);
input.write("\r");
expect(submit).toHaveBeenLastCalledWith(body);
Expand Down Expand Up @@ -197,3 +197,20 @@ describe("full-screen chat input", () => {
expect(input.setRawMode).toHaveBeenLastCalledWith(true);
});
});

test("empty-draft arrows scroll conversation without recalling prompts; Ctrl+P/N recall history", () => {
const { editor, input, scroll } = setup(true);
try {
input.write("earlier prompt\r");
input.write("\u001b[A\u001bOA\u001b[B\u001bOB");
expect(editor.draft).toEqual({ line: "", cursor: 0 });
expect(scroll.mock.calls).toEqual([["lines", -1], ["lines", -1], ["lines", 1], ["lines", 1]]);
input.write("\u0010");
expect(editor.draft.line).toBe("earlier prompt");
input.write("\u000e");
expect(editor.draft.line).toBe("");
input.write("@c\u001b[B");
expect(editor.completionIndex).toBe(1);
expect(scroll).toHaveBeenCalledTimes(4);
} finally { editor.close(); }
});
Loading