docs(issue-62): add relay plan for AuthStorage->ModelRuntime migration

This commit is contained in:
Federico Jaramillo Martinez
2026-07-17 20:29:21 +02:00
parent 9436c308c3
commit 8225cf6fcd
3 changed files with 235 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
# Relay charter — issue-62-authstorage
## Relay identity
- **Name:** `issue-62-authstorage`
- **Root path:** `relays/issue-62-authstorage/` (in the repo, on branch
`fix/issue-62-authstorage`, worktree `/srv/dev/pi-web-issue-62`)
- **Packet files:** `charter.md`, `status.md`, `log.md` (this directory).
## Background (read once, do not re-derive)
The full technical assessment lives at the worktree root:
`ASSESSMENT-issue-62.md`. Read it once at the start of your leg for the API
migration details; do not re-investigate the SDK from scratch. Short version:
Pi `@earendil-works/pi-coding-agent` 0.80.8 removed the `AuthStorage` export and
replaced the auth/model plumbing with an async `ModelRuntime` + pi-ai
`CredentialStore` model. Pi Web imports `AuthStorage` statically and crashes at
module load with any Pi 0.80.8+. The agreed fix is a **clean migration to the
new `ModelRuntime` API** (no dual-version shim) plus dependency-range
correction, tests, and a changeset. Rationale and the per-file migration shape
are in `ASSESSMENT-issue-62.md` §5.
## Goal / finish line
Pi Web builds, typechecks, lints, and passes its full test suite against Pi
`@earendil-works/pi-coding-agent` **0.80.8+** (target the installed 0.80.8/0.80.10
line), with:
1. No remaining import or use of the removed `AuthStorage` export (and no
reliance on `ModelRegistry.create(authStorage)` / `.inMemory(authStorage)` /
`modelRegistry.authStorage`).
2. Auth, OAuth login, API-key save/logout, provider enumeration, and the
Anthropic subscription warning all working through the new `ModelRuntime` /
`readStoredCredential` / pi-ai `CredentialStore` APIs.
3. `package.json` peerDependencies and devDependencies for the three
`@earendil-works/*` packages corrected so npm cannot resolve an unsupported
release (target range `>=0.80.8 <0.81`; devDeps on a matching `^0.80.8`).
4. A `.changeset/*.md` fragment describing the user-visible fix (no direct
`CHANGELOG.md` edit).
5. `npm run verify` (typecheck + lint + knip + test) passing.
Finish line reached = all of the above true and committed on the branch. **Do
not open a PR** (out of scope for this relay).
## Sizing — one leg
One leg = **one coherent slice** from the plan below that leaves the tree in a
committed, describable state. Prefer the pre-broken-out slices in `status.md`.
A leg does not have to leave `npm run verify` fully green (the migration is
interdependent), but it MUST:
- leave a clear, honest `status.md` describing what compiles/what doesn't yet,
- commit its work with a clear message,
- not expand scope beyond its slice ("just a bit more" is the main failure mode
here — the auth surfaces are interconnected; resist rewriting everything in
one leg).
If a slice turns out bigger than expected, split it and hand off mid-plan with
an updated `status.md` — that is expected and fine.
## Suggested slice breakdown (task selection default)
Follow `status.md`'s named next task. If none is named, pick the lowest-numbered
incomplete slice here:
0. **Bootstrap:** `npm install` in the worktree pinning the three `@earendil-works/*`
packages to 0.80.8+ (e.g. `npm i -D @earendil-works/[email protected]
@earendil-works/[email protected] @earendil-works/[email protected]`), and
correct the peerDependencies range to `>=0.80.8 <0.81`. Confirm the crash
reproduces / the new exports resolve. Commit. (Install in the worktree, NOT
`/tmp``/tmp` has a disk quota problem, see assessment §8.)
1. **`authService.ts` core migration:** move to `ModelRuntime` (async
construction via `ModelRuntime.create({ authPath, modelsPath })`), migrate
saveApiKey/logout/refresh/credential access. Propagate async construction to
`sessiond.ts`. (Session-daemon path — see restart note.)
2. **`authProviderOptions.ts` migration:** rederive login/logout provider
options from `runtime.getProviders()` + `listCredentials()` /
`getProviderAuthStatus()`; update its structural interface + test double.
3. **`oauthLoginFlowService.ts` migration:** reimplement against pi-ai
`AuthInteraction` (`prompt`/`notify`) instead of `OAuthLoginCallbacks`; wire
`runtime.login(providerId, "oauth", interaction)`. (Riskiest slice — verify
prompt/select/device-code/auth_url mapping.)
4. **`piSessionService.ts` migration:** pass `modelRuntime` to
`createAgentSessionServices`; update `PiAgentSession` type; switch
`anthropicSubscriptionWarning` to `readStoredCredential`.
5. **Tests + testSupport:** migrate all test doubles to `InMemoryCredentialStore`
+ `ModelRuntime.create`; get `npm run verify` green. Follow the testing-guide
skill.
6. **Changeset + final verify + cleanup:** add `.changeset/*.md`; run full
`npm run verify`; remove scratch (`ASSESSMENT` stays, `/srv/dev/pi-inspect`
is outside the repo). Confirm goal, hand off to a final confirmation/stop.
Slices may merge or split. 14 depend on 0. Slice 5 finalizes; slice 6 closes.
## Handover
When handing off, `spawn_session` **once** with a prompt whose first line is:
`Relay "issue-62-authstorage" leg <N> begins now.` followed by the standard
Relay handoff body pointing at:
- `relays/issue-62-authstorage/charter.md`
- `relays/issue-62-authstorage/status.md`
Tell the next runner not to read `log.md` end-to-end. Make all work durable
(update `status.md`, append `log.md`, commit) **before** spawning.
## Intervention signal — stop and get the human when:
- The new SDK API does not actually provide an operation the migration needs
(e.g. no viable credential persistence path for API-key save), i.e. the
assessment's assumed mapping is wrong.
- A slice would require changing the charter's goal or the agreed "clean
migration, no shim" decision.
- `npm install` / registry access fails and cannot be resolved in-leg.
- Charter churn: if you find yourself needing to edit this charter to proceed,
stop and involve the human instead.
To raise it: set a clear `## BLOCKED` section at the top of `status.md`, append a
`log.md` entry explaining the blocker and what decision is needed, do **not**
spawn the next leg, and end your run.
## Reading discipline
Read, in order: this `charter.md`, then `status.md`, then `ASSESSMENT-issue-62.md`
(once), then only the specific `src/server/sessions/*` files your slice touches.
Do **not** read `log.md` end-to-end — only targeted entries if `status.md` points
you there. Do not re-extract SDK tarballs unless the assessment is contradicted
by reality.
## Standing constraints (project conventions)
- Session-daemon changes (`sessiond.ts`, session runtime / auth construction
loaded by the daemon) require the human to **manually restart the sessiond
service** to take effect. Call this out in `status.md`/handoff whenever a leg
changes that path so the human knows a restart is pending.
- Follow the skills: `code-quality-architecture` (DI, async boundaries,
testable seams), `testing-guide` (test layers, no over-mocking), and
`changeset-changelog` (changeset not CHANGELOG edit).
- Keep changes scoped to the fix; do not opportunistically refactor unrelated
code.
+47
View File
@@ -0,0 +1,47 @@
# Relay log — issue-62-authstorage
Append-only. One concise entry per leg. Do not read end-to-end for orientation;
use `status.md`. Targeted lookups only.
---
## Leg 0 — Planning (assessment + relay packet)
**Did:**
- Read issue #62 and confirmed the crash: static `import { AuthStorage }` fails
at ESM load with Pi 0.80.8+.
- Investigated all `AuthStorage`/`ModelRegistry` usage in `src/` (3 production
files + 5 test/support files under `src/server/sessions/`; other
pi-coding-agent imports unaffected).
- Downloaded and diffed real npm tarballs (pi-coding-agent 0.80.7/0.80.8/0.80.10
and pi-ai 0.80.7/0.80.8) into `/srv/dev/pi-inspect` (scratch, outside repo) to
establish the exact new export surface: `AuthStorage` and its backends removed
from exports; new `ModelRuntime` (async) + `readStoredCredential`; changed
`ModelRegistry` (constructed from a runtime, `refresh()` now async, no
`authStorage`); pi-ai `CredentialStore`/`InMemoryCredentialStore`/
`AuthInteraction` model. Confirmed 0.80.8 and 0.80.10 `.d.ts` are identical
for the affected files (stable target).
- Wrote `ASSESSMENT-issue-62.md` (root).
**Decisions:**
- **Clean migration to `ModelRuntime`, no dual-version compat shim.** Rationale:
sync→async, credential-store contract change, OAuth callback contract change,
and session-services option change span both surfaces with no small clean
adapter; 0.80.00.80.7 is already broken/superseded (`latest` = 0.80.10).
- **Dep range fix:** peerDeps `>=0.80.0 <1``>=0.80.8 <0.81` for all three
`@earendil-works/*` packages; upper bound `<0.81` because this line ships
breaking changes within `0.80.x`.
- Relay packet placed under `relays/issue-62-authstorage/` (committed; not in
`package.json` `files`, so not published; `.pi-web/` is gitignored so not used).
**Artifacts changed:** `ASSESSMENT-issue-62.md`;
`relays/issue-62-authstorage/{charter,status,log}.md`.
**Status update:** last completed leg 0, next leg 1 = charter slice 0
(Bootstrap: install Pi 0.80.8+, correct dep ranges).
**Blockers:** none. Noted `/tmp` disk-quota issue (install in worktree) and the
pending sessiond restart for later daemon-path slices.
**Handoff:** Planning only — NOT auto-spawning the first implementation leg.
Assessment + relay plan are laid out ready to be kicked off by the user.
+61
View File
@@ -0,0 +1,61 @@
# Relay status — issue-62-authstorage
## Current position
Relay planned and packet created. Assessment complete and committed
(`ASSESSMENT-issue-62.md`). No fix work has started. The worktree has **no
`node_modules` installed yet** — the first implementation leg must install deps
(pinned to Pi 0.80.8+) before anything typechecks.
## Leg tracking
- **Last completed leg:** 0 (planning — this packet + assessment).
- **Next leg to run:** 1.
## Next task
Run **charter slice 0 (Bootstrap)** as leg 1:
1. In the worktree (`/srv/dev/pi-web-issue-62`), install deps pinning the three
`@earendil-works/*` packages to 0.80.8+ (0.80.8 or current 0.80.10):
`@earendil-works/pi-coding-agent`, `@earendil-works/pi-ai`,
`@earendil-works/pi-agent-core`. Install in the worktree, **not `/tmp`**
(`/tmp` has a disk-quota problem; see assessment §8).
2. Correct `package.json`: peerDependencies for the three packages
`>=0.80.0 <1``>=0.80.8 <0.81`; devDependencies `^0.80.6``^0.80.8`.
3. Confirm the new export surface resolves (`readStoredCredential`,
`ModelRuntime` present; `AuthStorage` gone) — e.g. a quick node/tsx check or
just observe the typecheck errors now point at the migration sites.
4. Commit (e.g. `chore(deps): require pi 0.80.8+ and correct dep ranges (issue #62)`).
5. Update this `status.md` + append `log.md`, then hand off to leg 2 (charter
slice 1: `authService.ts` core migration).
If slice 0 is already done when you arrive, apply the charter's task-selection
policy: pick the lowest-numbered incomplete slice (1 → 6).
## Relevant context for the next runner
- **Plan of record:** `ASSESSMENT-issue-62.md` (root) — read once. §5 has the
per-file migration shape; §3 has the exact new API shapes; §6 the dep ranges.
- **Files to change** (all under `src/server/sessions/` unless noted):
`authService.ts`, `authProviderOptions.ts`, `oauthLoginFlowService.ts`,
`piSessionService.ts`, plus `src/server/sessiond.ts` (async auth
construction), and the test/support files listed in assessment §2.
- **New API cheat-sheet:** `ModelRuntime.create({ authPath, modelsPath,
credentials? }): Promise<ModelRuntime>`; credential persistence via the
pi-ai `CredentialStore.modify` path; `runtime.login(providerId, type,
AuthInteraction)`; `runtime.logout`; `runtime.getProviders()` /
`listCredentials()` / `getProviderAuthStatus()`; `readStoredCredential(
providerId, authPath?)` for the sync anthropic warning; pi-ai
`InMemoryCredentialStore` for tests.
- **Decision already made:** clean migration, **no dual-version compat shim**
(assessment §4/§5). Do not reopen this without the intervention signal.
## Progress documentation expectations
Every leg: update this `status.md` (current position, leg tracking, next task,
context, blockers), append a concise `log.md` entry, make work durable, and
commit before handing off. Hand off with `spawn_session` **once** per the
charter's Handover section.
## Blockers / intervention state
None currently. Known constraints:
- **Sessiond restart pending** once slices touching `sessiond.ts` / session
runtime land — the human must manually restart the sessiond service; note it
here when it applies.
- `/tmp` disk-quota issue observed during assessment — do dependency installs in
the worktree.