mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 19:05:11 +00:00
Rename session from /resume session list (#863)
* Add session renaming in interactive mode resume picker Session list now displays last message timestamp as modified time instead of file mtime. Ctrl+N enters rename mode in the interactive resume picker, allowing quick session renaming without leaving the selector. Rename hint is shown only in interactive mode, not in the CLI --resume picker./ * Add docs entry for renaming in picker * Update shortcut to ctrl+r for session renaming
This commit is contained in:
parent
676de103e1
commit
b5873507c1
7 changed files with 449 additions and 89 deletions
101
packages/coding-agent/test/session-selector-rename.test.ts
Normal file
101
packages/coding-agent/test/session-selector-rename.test.ts
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import type { SessionInfo } from "../src/core/session-manager.js";
|
||||
import { SessionSelectorComponent } from "../src/modes/interactive/components/session-selector.js";
|
||||
import { initTheme } from "../src/modes/interactive/theme/theme.js";
|
||||
|
||||
async function flushPromises(): Promise<void> {
|
||||
await new Promise<void>((resolve) => {
|
||||
setImmediate(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function makeSession(overrides: Partial<SessionInfo> & { id: string }): SessionInfo {
|
||||
return {
|
||||
path: overrides.path ?? `/tmp/${overrides.id}.jsonl`,
|
||||
id: overrides.id,
|
||||
cwd: overrides.cwd ?? "",
|
||||
name: overrides.name,
|
||||
created: overrides.created ?? new Date(0),
|
||||
modified: overrides.modified ?? new Date(0),
|
||||
messageCount: overrides.messageCount ?? 1,
|
||||
firstMessage: overrides.firstMessage ?? "hello",
|
||||
allMessagesText: overrides.allMessagesText ?? "hello",
|
||||
};
|
||||
}
|
||||
|
||||
// Kitty keyboard protocol encoding for Ctrl+R
|
||||
const CTRL_R = "\x1b[114;5u";
|
||||
|
||||
describe("session selector rename", () => {
|
||||
beforeAll(() => {
|
||||
initTheme("dark");
|
||||
});
|
||||
|
||||
it("shows rename hint in interactive /resume picker configuration", async () => {
|
||||
const sessions = [makeSession({ id: "a" })];
|
||||
const selector = new SessionSelectorComponent(
|
||||
async () => sessions,
|
||||
async () => [],
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
{ showRenameHint: true },
|
||||
);
|
||||
await flushPromises();
|
||||
|
||||
const output = selector.render(120).join("\n");
|
||||
expect(output).toContain("ctrl+r");
|
||||
expect(output).toContain("rename");
|
||||
});
|
||||
|
||||
it("does not show rename hint in --resume picker configuration", async () => {
|
||||
const sessions = [makeSession({ id: "a" })];
|
||||
const selector = new SessionSelectorComponent(
|
||||
async () => sessions,
|
||||
async () => [],
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
{ showRenameHint: false },
|
||||
);
|
||||
await flushPromises();
|
||||
|
||||
const output = selector.render(120).join("\n");
|
||||
expect(output).not.toContain("ctrl+r");
|
||||
expect(output).not.toContain("rename");
|
||||
});
|
||||
|
||||
it("enters rename mode on Ctrl+R and submits with Enter", async () => {
|
||||
const sessions = [makeSession({ id: "a", name: "Old" })];
|
||||
const renameSession = vi.fn(async () => {});
|
||||
|
||||
const selector = new SessionSelectorComponent(
|
||||
async () => sessions,
|
||||
async () => [],
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
{ renameSession, showRenameHint: true },
|
||||
);
|
||||
await flushPromises();
|
||||
|
||||
selector.getSessionList().handleInput(CTRL_R);
|
||||
await flushPromises();
|
||||
|
||||
// Rename mode layout
|
||||
const output = selector.render(120).join("\n");
|
||||
expect(output).toContain("Rename Session");
|
||||
expect(output).not.toContain("Resume Session");
|
||||
|
||||
// Type and submit
|
||||
selector.handleInput("X");
|
||||
selector.handleInput("\r");
|
||||
await flushPromises();
|
||||
|
||||
expect(renameSession).toHaveBeenCalledTimes(1);
|
||||
expect(renameSession).toHaveBeenCalledWith(sessions[0]!.path, "XOld");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue