Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions packages/coding-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ pi --session a8ec1c2a # Resume by session ID (partial UUID)
In the `/resume` picker:
- `Ctrl+P` toggles display of the session `.jsonl` file path
- `Ctrl+D` deletes the selected session (inline confirmation; uses `trash` if available and cannot delete the active session)
- `Ctrl+N` opens `Rename Session` component, `Esc` cancels and returns to session list, `Enter` applies the new name and reloads the list.

**Resuming by session ID:** The `--session` flag accepts a session UUID (or prefix). Session IDs are visible in filenames under `~/.pi/agent/sessions/<project>/` (e.g., `2025-12-13T17-47-46-817Z_a8ec1c2a-5a5f-4699-88cb-03e7d3cb9292.jsonl`). The UUID is the part after the underscore. You can also search by session ID in the `pi -r` picker.

Expand Down
1 change: 1 addition & 0 deletions packages/coding-agent/src/cli/session-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export async function selectSession(
process.exit(0);
},
() => ui.requestRender(),
{ showRenameHint: false },
);

ui.addChild(selector);
Expand Down
42 changes: 41 additions & 1 deletion packages/coding-agent/src/core/session-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,44 @@ function extractTextContent(message: Message): string {
.join(" ");
}

function getLastActivityTime(entries: FileEntry[]): number | undefined {
let lastActivityTime: number | undefined;

for (const entry of entries) {
if (entry.type !== "message") continue;

const message = (entry as SessionMessageEntry).message;
if (!isMessageWithContent(message)) continue;
if (message.role !== "user" && message.role !== "assistant") continue;

const msgTimestamp = (message as { timestamp?: number }).timestamp;
if (typeof msgTimestamp === "number") {
lastActivityTime = Math.max(lastActivityTime ?? 0, msgTimestamp);
continue;
}

const entryTimestamp = (entry as SessionEntryBase).timestamp;
if (typeof entryTimestamp === "string") {
const t = new Date(entryTimestamp).getTime();
if (!Number.isNaN(t)) {
lastActivityTime = Math.max(lastActivityTime ?? 0, t);
}
}
}

return lastActivityTime;
}

function getSessionModifiedDate(entries: FileEntry[], header: SessionHeader, statsMtime: Date): Date {
const lastActivityTime = getLastActivityTime(entries);
if (typeof lastActivityTime === "number" && lastActivityTime > 0) {
return new Date(lastActivityTime);
}

const headerTime = typeof header.timestamp === "string" ? new Date(header.timestamp).getTime() : NaN;
return !Number.isNaN(headerTime) ? new Date(headerTime) : statsMtime;
}

async function buildSessionInfo(filePath: string): Promise<SessionInfo | null> {
try {
const content = await readFile(filePath, "utf8");
Expand Down Expand Up @@ -550,13 +588,15 @@ async function buildSessionInfo(filePath: string): Promise<SessionInfo | null> {

const cwd = typeof (header as SessionHeader).cwd === "string" ? (header as SessionHeader).cwd : "";

const modified = getSessionModifiedDate(entries, header as SessionHeader, stats.mtime);

return {
path: filePath,
id: (header as SessionHeader).id,
cwd,
name,
created: new Date((header as SessionHeader).timestamp),
modified: stats.mtime,
modified,
messageCount,
firstMessage: firstMessage || "(no messages)",
allMessagesText: allMessages.join(" "),
Expand Down
Loading