Skip to content

Improve Pi import follow-ups and add /tree branch navigation#1136

Open
kj1534 wants to merge 8 commits into
getpaseo:mainfrom
kj1534:pi-import-tree
Open

Improve Pi import follow-ups and add /tree branch navigation#1136
kj1534 wants to merge 8 commits into
getpaseo:mainfrom
kj1534:pi-import-tree

Conversation

@kj1534
Copy link
Copy Markdown
Contributor

@kj1534 kj1534 commented May 21, 2026

Linked issue

Closes #819

Type of change

  • Bug fix
  • New feature (with prior issue + design alignment)
  • Refactor / code improvement
  • Docs

What does this PR do

This PR builds on the Pi session import/RPC provider work from #1097. It adds follow-up fixes around that implementation, adds Pi /tree branch navigation in Paseo, and includes a few shared import/OOB improvements that also benefit other providers.

Shared Paseo improvements

Several changes in this PR are implemented in shared Paseo code and are not Pi-only:

  • Import matching now compares both sessionId and nativeHandle in the shared import path.
    • This benefits any provider that uses a stable native handle in addition to a provider session id.
  • Closed stored sessions no longer block importability in the shared import-session filtering path.
    • This helps any provider where a closed imported session should be importable again.
  • Archive/close flows now invalidate recent provider-session/import-session queries.
    • This keeps the import sheet fresher for all providers after agent close/archive actions.
  • AgentManager now serializes pending out-of-band provider commands and waits for them before starting a foreground turn.
    • This gives all providers that implement tryHandleOutOfBand a shared ordering guarantee between side-effect commands and normal user turns.
  • Provider registry wrapping preserves tryHandleOutOfBand, so wrapped/custom providers keep OOB command support.

Pi import follow-ups

  • Uses the Pi JSONL session file path as persistence.nativeHandle, so resume/import can reopen the exact native Pi session file.
  • Extracts Pi model and thinking metadata from JSONL/runtime state where available.
  • Preserves Pi model and thinking metadata more reliably across import, reload, and follow-up turns.
  • Fixes a fast-failure race where a Pi turn could fail before the foreground waiter was registered, which affected later /tree feedback/reload behavior.
  • Improves Pi persisted-session metadata and descriptor tests.

Pi /tree navigation

Adds provider slash-command support for Pi /tree:

  • /tree lists selectable Pi JSONL entries.
  • /tree <entryId> runs out-of-band through a temporary internal Paseo Pi extension.
  • The temporary extension calls Pi's native extension-context API: ctx.navigateTree(..., { summarize: false }).
  • Paseo then rehydrates the timeline and appends a local-only notice explaining what happened.

The user-facing semantics are:

  • Selecting a user prompt moves Pi to that prompt's parent branch point.
    • The next normal message creates a sibling branch next to the selected user prompt.
    • The selected prompt and its existing replies are not modified.
  • Selecting an assistant response moves Pi to that assistant entry.
    • The next normal message continues from that assistant response.

The notice is local to Paseo and is not written into the Pi session JSONL. The selected tree point is pending until the next normal message creates a new Pi JSONL entry; if the user reloads the agent before sending that message, Paseo may resume Pi's persisted leaf and clear the pending selection.

/tree autocomplete UX

  • Preserves Pi tree traversal order instead of alphabetically sorting entries.
  • Prioritizes the current active branch within sibling groups.
  • Filters noisy entries such as tool results, tool-call-only assistant entries, and thinking-only assistant entries.
  • Uses lightweight tree markers: current branch, current leaf, non-current branch entry, non-current branch body, and capped depth tracks.
  • Shows message previews in the description area.
  • Refreshes cached command candidates after /tree timeline rehydrate/new epoch so the current marker updates after navigation.
  • Adds hook/reducer tests covering command candidate ordering, local filtering, query invalidation, and stale-marker refresh behavior.

/treed

/treed is intentionally not exposed as a Paseo app command.

/treed is a third-party Pi tree-delete extension whose useful actions depend on highlighted-entry keyboard shortcuts in Pi's terminal UI. Paseo cannot pass those interactive delete actions as command arguments, so users are directed to use pi resume in a terminal when they need /treed.

Docs

Adds and updates docs for:

  • Pi provider/session import implementation notes.
  • Pi /tree branch navigation behavior.
  • Public user-facing Pi import and /tree guidance.
  • CLI Pi import syntax, including Windows path quoting.
  • /treed limitations.

Additional commits included

This PR also includes two small supporting commits:

  • fbcbdab and 4bfa399 supplements the previous Windows session import path fix. It tightens path equivalence behavior for Windows import/session matching edge cases that were missed when the earlier PR was conflict-resolved.
  • 1cd0b53 adds repository line-ending normalization:
    • .gitattributes
    • oxfmt ignores for AGENTS-style files that otherwise produced line-ending-only churn

How did you verify it

Automated validation run locally after rebasing onto latest upstream/main:

npx vitest run packages/server/src/server/agent/providers/pi/agent.test.ts packages/server/src/server/agent/providers/pi/tree-navigation.test.ts packages/server/src/server/agent/providers/pi/cli-runtime.test.ts packages/server/src/server/agent/providers/pi/session-descriptor.test.ts packages/server/src/server/agent/agent-manager.test.ts packages/server/src/server/agent/import-sessions.test.ts packages/server/src/server/agent/agent-storage.test.ts packages/app/src/components/import-session-sheet.test.tsx packages/app/src/hooks/use-archive-agent.test.ts packages/app/src/timeline/session-stream-reducers.test.ts packages/app/src/hooks/use-agent-commands-query.test.ts packages/app/src/hooks/use-agent-autocomplete.test.ts --bail=1

Result:

  • 12 test files passed
  • 244 tests passed

Also run:

npm run typecheck
npm run lint
git diff --check

Manual validation:

  • Imported Pi sessions on Windows web.
  • Imported Pi sessions from mobile web connected to the dev daemon.
  • Closed a Pi agent and imported it again.
  • Verified imported Pi session model and thinking strength.
  • Used /tree to select user entries and create sibling branches.
  • Used /tree to select assistant entries and continue from that assistant response.
  • Verified /tree current marker refresh behavior after command-cache invalidation changes.

Checklist

  • One focused change. Unrelated cleanups split out.
  • npm run typecheck passes
  • npm run lint passes
  • npm run format ran (Biome)
  • UI changes include screenshots or video for every affected platform
  • Tests added or updated where it made sense

@kj1534 kj1534 marked this pull request as ready for review May 21, 2026 16:40
Copilot AI review requested due to automatic review settings May 21, 2026 16:40
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR adds Pi session import + tree navigation support (including /tree out-of-band navigation), updates command schemas/UI autocomplete to support command argument options, and improves cross-platform path/agent persistence handling.

Changes:

  • Add Pi tree navigation (/tree) via a temporary Pi RPC extension bridge, plus UI autocomplete for selecting tree entries.
  • Improve agent import/resume logic (reuse stored agent IDs, force timeline hydration) and refresh command lists on timeline epoch resets.
  • Harden persistence operations (Windows path comparisons, atomic rename retry, pending-write recovery) and enrich Pi resume metadata (model/thinking).

Reviewed changes

Copilot reviewed 40 out of 40 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
public-docs/supported-providers.md Documents Pi session import + /tree semantics and /treed exclusion.
public-docs/security.md Adds Pi authentication note.
public-docs/cli.md Documents paseo import usage including Pi JSONL path support.
packages/server/src/utils/path.ts Treats path comparisons as Windows on win32 and for definite Windows paths.
packages/server/src/shared/messages.ts Extends slash command schema with argument options for UI autocomplete.
packages/server/src/server/agent/providers/pi/tree-navigation.ts Implements Pi JSONL parsing and tree-entry listing/feedback formatting.
packages/server/src/server/agent/providers/pi/tree-navigation.test.ts Adds tests for Pi tree listing, labels, parsing, and feedback behavior.
packages/server/src/server/agent/providers/pi/test-utils/fake-pi.ts Adds fake Pi support for tree-nav bridge results and injected prompt failures.
packages/server/src/server/agent/providers/pi/session-descriptor.ts Captures Pi model/thinking metadata from JSONL head/tail for resume/import UI.
packages/server/src/server/agent/providers/pi/session-descriptor.test.ts Tests model/thinking metadata extraction.
packages/server/src/server/agent/providers/pi/runtime.ts Adds --extension support for Pi launches.
packages/server/src/server/agent/providers/pi/cli-runtime.test.ts Tests passing extension paths through the CLI runtime.
packages/server/src/server/agent/providers/pi/agent.ts Loads a temporary Pi extension, adds /tree command options, and out-of-band handling.
packages/server/src/server/agent/providers/pi/agent.test.ts Tests extension injection, persistence metadata, deferred prompt startup, and /tree behavior.
packages/server/src/server/agent/provider-registry.ts Wraps tryHandleOutOfBand so provider events are mapped correctly.
packages/server/src/server/agent/import-sessions.ts Reuses stored agent IDs on re-import, unarchives correctly, forces timeline hydration, applies better titles.
packages/server/src/server/agent/import-sessions.test.ts Tests re-import of closed/archived sessions and forced hydration.
packages/server/src/server/agent/agent-storage.ts Prevents failed writes from poisoning later writes; adds rename retry for transient FS errors.
packages/server/src/server/agent/agent-storage.test.ts Tests recovery after a failed atomic write.
packages/server/src/server/agent/agent-sdk-types.ts Adds command argument options + out-of-band run result type with timeline rehydration support.
packages/server/src/server/agent/agent-prompt.ts Waits for pending out-of-band runs before recording/sending new prompts.
packages/server/src/server/agent/agent-manager.ts Serializes out-of-band runs, supports forced timeline rehydration, keeps persistence/runtime info in sync.
packages/server/src/server/agent/agent-manager.test.ts Adds tests for out-of-band rehydration and foreground/out-of-band ordering.
packages/app/src/timeline/session-stream-reducers.ts Resets timeline on epoch changes and triggers command invalidation side effects.
packages/app/src/timeline/session-stream-reducers.test.ts Tests epoch reset behavior and command invalidation forwarding.
packages/app/src/hooks/use-archive-agent.ts Invalidates recent-provider-sessions cache on archive/close.
packages/app/src/hooks/use-archive-agent.test.ts Tests query invalidation changes.
packages/app/src/hooks/use-agent-commands-query.ts Adds argumentOptions, supports invalidation by root key, configurable staleness.
packages/app/src/hooks/use-agent-commands-query.test.ts Tests invalidating root key refreshes active command queries.
packages/app/src/hooks/use-agent-autocomplete.ts Adds argument autocomplete for slash commands (e.g., /tree <entryId>).
packages/app/src/hooks/use-agent-autocomplete.test.ts Tests /tree argument filtering, ordering preservation, and selection behavior.
packages/app/src/contexts/session-context.tsx Hooks epoch resets to invalidate agent command queries.
packages/app/src/components/ui/autocomplete.tsx Adds stacked layout for non-file options and expands description display.
packages/app/src/components/import-session-sheet.tsx Improves import UI to hide newly imported sessions immediately and update session store.
packages/app/src/components/import-session-sheet.test.tsx Tests Pi provider inclusion and post-import row removal.
docs/providers.md Documents Pi /tree handling via extension bridge and /treed rationale.
docs/development.md Adds Pi session JSONL location/scanning details.
docs/architecture.md Explains Pi out-of-band tree navigation in the architecture docs.
.oxfmtrc.json Extends formatter ignore patterns for AGENTS.md files.
.gitattributes Adds consistent EOL settings and marks AGENTS.md as non-text.
Comments suppressed due to low confidence (2)

packages/server/src/server/agent/providers/pi/agent.ts:1

  • The Pi extension command (/paseo_tree) accepts a base64 JSON payload that includes resultPath, and it writes to that path without validation. Even though the command is hidden from listCommands, a user can still manually invoke /paseo_tree ... and cause arbitrary file writes in their user context. Consider hardening by (mandatory): (1) generating a per-session random command name or including a per-session secret token in the payload and validating it inside the extension, and (2) restricting resultPath to a Paseo-created temp directory (e.g., reject absolute paths or paths outside the temp dir). Also wrap decodePayload in a try/catch so malformed args produce a controlled { ok: false, error: ... } response rather than throwing before writing a result.
import { randomUUID } from "node:crypto";

packages/server/src/server/agent/providers/pi/tree-navigation.ts:1

  • readPiTreeEntries uses synchronous I/O and parses the entire JSONL file, and it’s called by /tree listing and by buildPiTreeSlashCommand (which is included on every listCommands() call in the Pi session). For large Pi sessions, this can block the server event loop and make command refresh sluggish. Consider caching parsed results keyed by (sessionFile, mtime) or switching to async streaming reads; additionally, consider early-exiting once enough selectable entries are collected (since the UI caps to 500 options and listing caps to 80).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


this.pendingWrites.set(agentId, tracked);
return tracked;
return next;
Comment on lines +356 to +365
function hasPersistenceHandleChanged(
previous: AgentPersistenceHandle | null | undefined,
next: AgentPersistenceHandle,
): boolean {
return (
next.sessionId !== previous?.sessionId ||
next.nativeHandle !== previous?.nativeHandle ||
JSON.stringify(next.metadata ?? {}) !== JSON.stringify(previous?.metadata ?? {})
);
}
}

if (selected.type === "command_argument") {
setUserInput(`/${selected.commandName} ${selected.argumentValue}`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: rewind a pi session to an earlier message from inside Paseo

2 participants