Repository navigation
fix(agent-runtime): discover native sessions in configured sessionDir - #1764
Conversation
Pi stores sessions in a project or global sessionDir when that setting is set. Desktop only walked ~/.pi/agent/sessions, so those files never appeared in history and could not be opened. Resolve the same setting the Pi CLI uses and scan those directories for known projects, while keeping the default session root. fixes vastsa#1732
An in-root *.jsonl symlink was scanned as a second file. Both names resolved to one stable id, dedup deleted that record, and detail returned NOT_FOUND. A later list with an empty project path list also rebuilt containment from that snapshot, so an already admitted custom directory failed closed with PERMISSION_DENIED. Scan only regular files, keep the winner when a duplicate summary uses its id, and remember directories that already admitted a file. Log unreadable sessionDir settings and a failed projects.list without failing the Desktop list. Attach session-list handlers in the same turn as the project-path fetch.
|
Reviewed in an isolated worktree: This is the right fix for the issue I verified earlier — the desktop never consulted Resolution is delegated to Pi, not re-implemented. Containment is preserved. Degradation is sane. An unreadable settings file logs once per path and still lists the default root; a missing configured dir contributes no files and no containment root. Two non-blocking notes:
Nothing blocking from my side. |
list() stored the caller's project paths on the service, so a second list() could replace them before discovery finished and scan the other caller's sessionDir. Keep the paths on the call, and keep admitted roots so a later empty project list can still open and fork a session that was already found. A configured sessionDir is a flat scan. Note in the code and in the sessionDir docs that sessions in its subdirectories are ignored.
vastsa
left a comment
There was a problem hiding this comment.
Confirmed #1732 against the base: native session discovery only walked the default root, while Pi writes configured sessionDir sessions elsewhere. This change resolves settings through Pi's SettingsManager, forwards local project paths from the existing session list/search/live-work entry points, and keeps the configured scan limited to top-level regular JSONL files. Trust/read-only behavior remains in place.
Independent local validation on this head: native-pi-session.test.ts 46/46, Desktop session/live-work targeted tests 32/32, agent-runtime TypeScript check passed, and git diff --check passed. I approve this fix.
Summary
Fixes #1732
When Pi is configured with a
sessionDir(project.pi/settings.jsonor global~/.pi/agent/settings.json), new sessions are written there, but Desktop only discovered native sessions under~/.pi/agent/sessions. Those sessions therefore disappeared from history after a restart and could not be reopened.Root cause: native session discovery in
packages/agent-runtime/src/native-pi-session.tswalked only the default session root and never resolved thesessionDirsetting that the Pi CLI uses.Fix:
sessionDirthrough the pinned coding-agentSettingsManager.getSessionDir()(same resolution and~expansion as the Pi CLI). An absolute globalsessionDiris scanned even with no project; a relative one is resolved against each known local project path.remote-project:ids are skipped and the project list is capped at 500. The default session root is always kept.*.jsonlfiles only, so nested files outside the default root and symlinks (including an in-directory alias of another session file) are not listed. Native-id dedup emits each id once.detailandforkof that session keep working if a later list call passes an empty project list.session-search.ts,session-ipc.ts,live-work-backend-port.ts,sidecar.ts). A failingprojects.listis logged and falls back to[](default root and absolute globalsessionDirstill list);session.listhandlers are attached in the same turn so a fast host rejection is not an unhandled rejection. UnreadablesessionDirsettings are logged once per path per scan.Specs / ADRs / E2E
sessionDirdiscovery.docs/spec/03-runtime/04-data-storage.md§12 anddocs/spec/05-security/01-security.md: discovery roots, top-level/regular-file rule, trust gate.E2E-SESSION-native-pi-project-session-dirindocs/spec/06-delivery/04-e2e-test-plan.md; source-regression covered by the unit tests below, full Desktop journey marked Draft.Tests
New cases were written failing first, then fixed:
packages/agent-runtime/src/native-pi-session.test.ts(45 pass): project-localsessionDir, absolute globalsessionDirwith no project, relative globalsessionDironly for a known local project, remote project id ignored, nested file and escaping symlink excluded, in-root*.jsonlalias listed once and openable, default root still listed, detail/fork after an empty follow-up list, unreadable settings, fork byte identity, untrusted project stays read-only.apps/desktop/test/native-pi-sessions.test.mjsandapps/desktop/test/live-work-scope.test.mjs: project path forwarding, failedprojects.list, same-turn rejection handling, live-work forwarding.Local run of the PR workflows (
ci.ymljobsjs,rust,trusted-extensions-e2e,pr-base.yml, anddocs-check.yml) on head0b0e83e47, which contains latestupstream/main87a48b953; Node 24.21.0, pnpm 12.8.1,CI=true:pnpm check:pr-baseancestry + its unit testpnpm install --frozen-lockfile,pnpm build:jspnpm lint, architecture check,pi-patch-hashcargo fmt --all -- --check,cargo clippy --workspace --all-targets --all-featuresSUMMARY 57/57 passedpnpm -r --if-present testcargo test -p host-core --lockedPre-existing local failures (same on merge-base)
Both failing steps were re-run on the merge-base
87a48b953(currentupstream/main) and fail identically there:pnpm -r --if-present test— the same 12apps/desktop*-user-path/plugin-view-bounds-synctests fail on both trees withElectron binary missingfromscripts/e2e/boot.mjs:pnpm install --frozen-lockfiledoes not download the Electron binary, andci.ymlinstalls it later in the E2E job. Head 4113 / 4094 / 12; base 4109 / 4090 / 12. The extra head tests (4 desktop, 6agent-runtime) all pass.cargo test -p host-core --locked—tools::tests::bash_inherits_user_login_pathfails withevery injected login-PATH entry is presenton both trees (963 passed, 1 failed, 1 ignored each), because this host's login shell PATH does not satisfy the test. This PR changes nothing undercrates/.NOT RUN
ci.yml/rust-windows(windows-latest) — no Windows host locally. The diff touches no Rust code; the Ubuntu host-core suite ran. Remaining risk is low.Compatibility / security
No migration. Users without a
sessionDirsetting see the same list as before. Discovery in configured directories is top-level and regular-file only, symlinks are not followed for listing, and every opened file must still resolve inside an allowed session root, so the change does not widen file access beyond the directories Pi itself writes sessions to.AI disclosure
This change was prepared with AI assistance (code, tests, docs, and this description). The diff was reviewed, and every check listed above was actually run locally; nothing is reported as passing that was not executed.