diff --git a/relays/issue-62-authstorage/charter.md b/relays/issue-62-authstorage/charter.md new file mode 100644 index 0000000..961a1f1 --- /dev/null +++ b/relays/issue-62-authstorage/charter.md @@ -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/pi-coding-agent@0.80.8 + @earendil-works/pi-ai@0.80.8 @earendil-works/pi-agent-core@0.80.8`), 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. 1–4 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 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. diff --git a/relays/issue-62-authstorage/log.md b/relays/issue-62-authstorage/log.md new file mode 100644 index 0000000..f65bfee --- /dev/null +++ b/relays/issue-62-authstorage/log.md @@ -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.0–0.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. diff --git a/relays/issue-62-authstorage/status.md b/relays/issue-62-authstorage/status.md new file mode 100644 index 0000000..4cc88d7 --- /dev/null +++ b/relays/issue-62-authstorage/status.md @@ -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`; 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.