This repository has been archived on 2026-08-23. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
pi-web/relays/issue-62-authstorage/status.md
T

15 KiB
Raw Blame History

Relay status — issue-62-authstorage

Current position

Slice 5 (tests + testSupport) complete and committed (d0cc55c). npm run verify is fully GREEN — typecheck + lint + knip + 1390 tests pass (2 skipped). All production code and all test/support code are now off the removed AuthStorage / ModelRegistry.create|inMemory surface. Goal criteria 1, 2, 5 are met; criteria 3 (dep ranges) was done in slice 0/1; only criterion 4 (changeset) remains — that is slice 6.

What slice 5 changed (all under src/server/sessions/):

  • piSessionService.testSupport.ts (central helper): dropped AuthStorage/ModelRegistry imports; added pi-ai InMemoryCredentialStore. New seams: createTestModelRuntime(credentials?) (wraps ModelRuntime.create({ credentials })), a shared testModelRuntime (top-level await createTestModelRuntime() — the common no-auth catalog runtime), and seedCredential(store, providerId, credential) (writes via the CredentialStore.modify path). fakeRuntime session now carries modelRuntime: testModelRuntime; testModel() reads testModelRuntime.getModel(...).
  • Threaded modelRuntime: testModelRuntime into every new PiSessionService(...) (now a required dep) across archiveCleanup/lifecycle/promptQueue/ spawnSession/spawnSubsession/sessionRoutes tests, importing testModelRuntime in each.
  • piSessionService.promptQueue.test.ts auth-loss test rewritten: builds a live InMemoryCredentialStore + createTestModelRuntime(credentials), and simulates auth changes via credentials.delete/seedCredential + modelRuntime.refresh() + applyAuthChange(...) (matching AuthService's real refresh-then-emit sequence). Removed the modelRegistry dep line.
  • piSessionService.warnings.test.ts: anthropicSubscriptionWarning now reads readStoredCredential("anthropic", authPath), so the test seam is a temp auth.json written per case (helper anthropicAuthPath(...)), passed as the 2nd arg. SubscriptionSession type narrowed to Pick<PiAgentSession, "model" | "settingsManager">. The "no credential" case points at a temp dir with no auth.json (deterministic).
  • authService.test.ts fully reworked to the async AuthService.create({ runtime | agentDir }) + InMemoryCredentialStore model. saveApiKey/ logoutProvider/startOAuthLogin are awaited; OAuth-complete test asserts startOptions.runtime === runtime and uses vi.waitFor for the async refresh; credential assertions go through credentials.read(...).
  • Lint fixes surfaced by running lint green for the first time this relay: getLoginProviderOptions made synchronous (it did no async work) and its call sites in authService.ts + authProviderOptions.test.ts de-awaited; authRoutes.ts handlers now return await ... (return-await rule); authService.ts api-key interaction uses () => Promise.resolve(key) / notify: () => undefined; test modify arrows use () => Promise.resolve(...).

SDK behavior verified empirically before writing doubles (throwaway probe scripts, since removed): ModelRuntime.create({ credentials }) exposes 36 providers / 1072 models; login(id, "api_key", interaction) persists to the store; getModel("anthropic", "claude-sonnet-4-5-20250929") resolves; hasConfiguredAuth flips correctly across delete/modify + refresh; readStoredCredential(id, authPath) reads a temp auth.json and returns undefined for a missing file.

Prior position (slice 4, leg 5, commit 4ccd4f8)

Slice 4 (piSessionService.ts migration) complete and committed (4ccd4f8). piSessionService.ts now uses the new ModelRuntime API end to end:

  • createDefaultRuntimeFactory(modelRuntime, ...) passes modelRuntime to createAgentSessionServices({ cwd, agentDir, modelRuntime }) (no more authStorage + modelRegistry).
  • PiAgentSession.modelRegistryPiAgentSession.modelRuntime: ModelRuntime.
  • anthropicSubscriptionWarning(session, authPath?) now reads via readStoredCredential("anthropic", authPath) (sync); warningsForSession passes join(this.agentDir, "auth.json"). Its session param narrowed to Pick<PiAgentSession, "model" | "settingsManager"> (no longer needs the registry).
  • Model reads rederived onto the runtime: availableModels/setModel use await modelRuntime.refresh() + getAvailableSnapshot() + getModel(...); syncCurrentModelAuthWarning uses getModel(...) + hasConfiguredAuth(providerId).
  • applyAuthChange no longer refreshes a registry (the shared runtime is refreshed by AuthService before it emits, and all sessions share that runtime), so the auth.subscribe callback stays synchronous.
  • modelRuntime is now a REQUIRED PiSessionServiceDependencies field (the old modelRegistry? fallback used a sync ModelRegistry.create; a ModelRuntime can only be built by the async ModelRuntime.create, which can't run inside a constructor). sessiond.ts already injects modelRuntime: auth.runtime (slice 1), so it typechecks unchanged.
  • Dropped the AuthStorage / ModelRegistry imports and the createModelRegistryForAgentDir import (only AuthChange is still imported from authService.js).

npx tsc --noEmit: sessiond.ts and piSessionService.ts are at 0 errors (production code is fully migrated; grep -vE '\.test\.ts|testSupport\.ts' on tsc output is empty). All remaining errors are slice-5 test/support files. piSessionService.ts lints clean.

Prior position (slice 3, leg 4, commit 1c3d6db)

Slice 3 (oauthLoginFlowService.ts migration) complete and committed (1c3d6db). OAuthLoginFlowService is reimplemented against the pi-ai AuthInteraction contract ({ signal?, prompt(AuthPrompt), notify(AuthEvent) }); the old OAuthLoginCallbacks/AuthStorage imports are gone. start() now takes a ModelRuntime (narrowed to Pick<ModelRuntime, "login">) instead of authStorage, and drives login via runtime.login(providerId, "oauth", interaction). Mapping: AuthPrompt text/secret/manual_code → web-UI prompt (kind prompt, manual_code → kind manual); select → web-UI select (options {id,label}{value,label}, returns chosen id); AuthEvent auth_urlauth: {url, instructions?}; device_code → reuse auth field (url: verificationUri, instructions: "Enter code: <userCode>"); info/progress → append message to progress. Per-prompt AuthPrompt.signal now aborts just that pending request (rejects "Prompt cancelled") without ending the overall flow — needed because a manual_code prompt can race a callback server. oauthLoginFlowService.test.ts rewritten to the new contract via a fakeRuntime login double; 9 tests pass, files lint clean.

npx tsc --noEmit now reports 26 errors (down from 28). authService.ts is now at 0 errors (as predicted). Remaining errors are all slice 4/5: sessiond.ts (1) + piSessionService.ts (6) = slice 4; authService.test.ts (10), piSessionService.testSupport.ts (3), .promptQueue.test.ts (2), .warnings.test.ts (4) = slice 5.

Prior position (slice 2, leg 3, commit d09d7cc)

Slice 2 (authProviderOptions.ts migration) complete and committed (d09d7cc). authProviderOptions.ts now derives options from a runtime-shaped AuthProviderRuntime interface (getProviders() + listCredentials() + getProviderAuthStatus()). getLoginProviderOptions/getLogoutProviderOptions are now async (matching the await call sites already in authService.ts). The old AuthProviderModelRegistry interface is gone; a real ModelRuntime satisfies AuthProviderRuntime structurally. The test double in authProviderOptions.test.ts was rewritten to the runtime shape and its 3 tests pass. OAuth-capable = auth.oauth present; api-key = auth.apiKey present; OAUTH_ONLY_PROVIDERS / isApiKeyLoginProvider logic preserved; display names come from Provider.name.

npx tsc --noEmit now reports 28 errors (down from 31). No authProviderOptions errors remain and the getLoginProviderOptions / getLogoutProviderOptions call sites in authService.ts typecheck cleanly. Remaining errors are all cross-slice: authService.ts (1: line-83 OAuthLoginFlowService.start still expects authStorage not runtime — slice 3), sessiond.ts (1) + piSessionService.ts (6, slice 4), and the test/support files (slice 5): authService.test.ts (9), oauthLoginFlowService.ts/.test.ts (1+1, slice 3), piSessionService.testSupport.ts (3), .promptQueue.test.ts (2), .warnings.test.ts (4).

Prior position (slice 1, leg 2, commit e37148c)

Slice 1 (authService.ts core migration) complete and committed (e37148c). authService.ts now uses the async ModelRuntime API: AuthService.create({ agentDir | runtime }) factory wraps ModelRuntime.create({ authPath, modelsPath }); createModelRuntimeForAgentDir replaces createModelRegistryForAgentDir. saveApiKeyruntime.login(id, "api_key", nonInteractive), logoutProviderruntime.logout, refreshAuthStateawait runtime.refresh(). authProviders / requireOAuthLoginProvider are now async. startOAuthLogin passes runtime into OAuthLoginFlowService.start. sessiond.ts uses async createRuntime, AuthService.create, and passes modelRuntime: auth.runtime to PiSessionService; sessionDaemonStartup now awaits createRuntime.

npx tsc --noEmit reports 31 errors (up from 24 — expected: the migrated authService now calls the runtime-based interfaces that slices 24 haven't exposed yet). Slice-1 files are internally consistent; every remaining error in authService.ts / sessiond.ts is a cross-slice dependency:

  • authService.ts: getLoginProviderOptions/getLogoutProviderOptions still take the old AuthProviderModelRegistry shape (fixed in slice 2); OAuthLoginFlowService.start still expects authStorage not runtime (fixed in slice 3).
  • sessiond.ts: PiSessionServiceDependencies still expects modelRegistry not modelRuntime (fixed in slice 4). Remaining errors otherwise live in slices 2/3/4 files and all test/support files (slice 5).

Leg tracking

  • Last completed leg: 6 (slice 5 — tests + testSupport migration).
  • Next leg to run: 7.

Next task

Run charter slice 6 (changeset + final verify + cleanup) as leg 7. This is the closing leg:

  1. Add a .changeset/*.md fragment for @jmfederico/pi-web describing the user-visible fix (session daemon crash with Pi 0.80.8+ fixed by migrating to the new ModelRuntime API; requires Pi >=0.80.8). Use the changeset-changelog skill. Do not edit CHANGELOG.md directly. The maintainer's call on patch vs minor — the assessment §5 suggests patch or minor; a minor is defensible since the supported Pi range narrows (>=0.80.8 <0.81, dropping 0.80.00.80.7), but follow the changeset skill and keep it a single fragment.
  2. Re-run the full npm run verify to confirm still green.
  3. Confirm the goal criteria in charter.md are all met (1 no AuthStorage/ registry use — done; 2 auth surfaces on new APIs — done; 3 dep ranges — already corrected in slice 0/1, double-check package.json peer/dev ranges; 4 changeset — this leg; 5 verify green — confirm).
  4. Cleanup: ASSESSMENT-issue-62.md stays (it's the plan of record). /srv/dev/pi-inspect is outside the repo, not ours to touch. Confirm no scratch files were left in the repo (e.g. no stray probe*.mjs, .tmp-build/).
  5. Do NOT open a PR (explicitly out of scope for this relay).

This is the finish line. After confirming everything, the goal is reached: update status.md/log.md, commit, and per the charter stop (the goal is reached) — or if you prefer, hand off a final "relay complete" confirmation leg. Either way, surface to the human that the sessiond restart is still pending (see Blockers) and a PR was intentionally not opened.

Verification already passing as of slice 5 (leg 6): npm run verify green (typecheck + lint + knip + 1390 tests, 2 skipped).

Build/tooling note (important for every leg)

Update (leg 2): the human reports /tmp is now fully usable again, so the previous TMPDIR workaround is no longer required — plain npm install should work. (If a disk-quota error resurfaces, fall back to TMPDIR="$PWD/.tmp-build" npm install and remove .tmp-build after; it is scratch, do not commit it.) node_modules is already installed at 0.80.10, so a fresh install is only needed if node_modules is cleared. The pre-commit hook runs a whole-project typecheck; while the migration is incomplete, commit relay work with git commit --no-verify (the charter permits legs that aren't verify-green). Node: v24.18.0.

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.
  • Changeset skill: .agents/skills/changeset-changelog/SKILL.md (and changeset-changelog in the skills list). Follow it for the fragment format.
  • The migration is done — slice 6 is docs/changeset + confirmation only. No further source changes are expected; if you find yourself editing src/, re-check whether that's really in scope.
  • 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. Known constraints:

  • Sessiond restart pending (ACTIVE): slice 1 (leg 2, commit e37148c) changed sessiond.ts + the session-daemon auth construction path; slice 4 (leg 5, commit 4ccd4f8) added piSessionService.ts (a session-daemon path) to this surface. Per AGENTS.md the human must manually restart the sessiond service for these changes to take effect once the migration lands. Keep this note until the human confirms the restart.
  • /tmp disk-quota issue is resolved (human confirmed usable) — see the Build/tooling note above.
  • node_modules is installed (gitignored) at 0.80.10; a fresh npm install is only needed if node_modules is cleared.