From 842e6516587ce3f81fdf283f050e7a73598b22cf Mon Sep 17 00:00:00 2001 From: Federico Jaramillo Martinez Date: Fri, 17 Jul 2026 20:54:56 +0200 Subject: [PATCH] relay issue-62-authstorage: leg 2 status/log (slice 1 done) --- relays/issue-62-authstorage/log.md | 82 ++++++++++++++++++++++ relays/issue-62-authstorage/status.md | 99 +++++++++++++++++---------- 2 files changed, 145 insertions(+), 36 deletions(-) diff --git a/relays/issue-62-authstorage/log.md b/relays/issue-62-authstorage/log.md index 6effecc..001d77b 100644 --- a/relays/issue-62-authstorage/log.md +++ b/relays/issue-62-authstorage/log.md @@ -87,3 +87,85 @@ onward once `sessiond.ts` changes land). **Handoff:** spawning leg 2 (slice 1). + +--- + +## Leg 2 — slice 1: `authService.ts` core migration (commit `e37148c`) + +**What I did:** migrated `src/server/sessions/authService.ts` off the removed +`AuthStorage` / `ModelRegistry.create` surface onto the async `ModelRuntime` +API, and propagated the async construction into the session daemon. + +- `authService.ts`: + - Imports `ModelRuntime` from `@earendil-works/pi-coding-agent` and + `AuthInteraction` (type) from `@earendil-works/pi-ai`. Dropped + `AuthStorage` / `ModelRegistry`. + - `createModelRegistryForAgentDir` → `createModelRuntimeForAgentDir(agentDir)` + returning `ModelRuntime.create({ authPath: /auth.json, modelsPath: + /models.json })`. + - Construction is now async: private constructor + static + `AuthService.create({ agentDir? | runtime? | authFlows? })`. `runtime` dep + replaces the old `modelRegistry` dep; no-agentDir fallback is + `ModelRuntime.create({})`. + - Public field `readonly runtime: ModelRuntime` replaces `modelRegistry`. + - `saveApiKey` → `runtime.login(providerId, "api_key", interaction)` where + `interaction` is a non-interactive `AuthInteraction` (`prompt: async () => + key`, `notify: () => {}`). Verified against pi-ai `envApiKeyAuth().login`, + which calls `interaction.prompt({ type: "secret" })` and persists the + returned `{ type:"api_key", key }` through `credentials.modify` inside + `Models.login`. This is the credential-persistence path the assessment + (§5.1) called for. + - `logoutProvider` → `await runtime.logout(providerId)`. + - `refreshAuthState` → `await runtime.refresh()` (no more `authStorage.reload()` + — the file store is re-read by the runtime). Now async. + - `authProviders` and `requireOAuthLoginProvider` became async, awaiting + `runtime.refresh()` and the now-async `getLogin/LogoutProviderOptions`. + - `startOAuthLogin` passes `runtime: this.runtime` into + `OAuthLoginFlowService.start` (slice 3 will consume it via `runtime.login`). +- `sessiond.ts`: `createRuntime()` is now `async`; `new AuthService(...)` → + `await AuthService.create({ agentDir })`; `PiSessionService` now receives + `modelRuntime: auth.runtime` instead of `modelRegistry: auth.modelRegistry`. +- `sessiond/sessionDaemonStartup.ts`: `createRuntime` may now return + `Runtime | Promise` and `runSessionDaemonStartup` `await`s it. The + existing sync test doubles still satisfy the widened type. + +**Decisions:** +- **saveApiKey via `runtime.login("api_key", …)`** rather than reaching for a + raw `CredentialStore.modify`: the pi-ai `CredentialStore` is not exposed off + `ModelRuntime` publicly, and the provider's own api-key `login` is the + intended persistence entry point (it writes through `credentials.modify`). + Feeding the key back through a non-interactive `AuthInteraction.prompt` keeps + us on the supported public surface. This matches assessment §5.1's + "credential persistence via the pi-ai CredentialStore.modify path" without + depending on unexported internals. +- Kept `AuthService` construction async via a static factory (private ctor) + rather than an `init()` method — cleaner async boundary, single valid + construction path (code-quality-architecture skill). +- Did NOT touch `authProviderOptions.ts`, `oauthLoginFlowService.ts`, + `piSessionService.ts`, or any test/support files — strictly slice 1 scope. + The async call sites I introduced (`await getLoginProviderOptions(...)`, + `runtime:` in `authFlows.start`, `modelRuntime:` in PiSessionService deps) + deliberately point at the interfaces slices 2–4 will expose. + +**Typecheck state:** `npx tsc --noEmit` = 31 errors (was 24 at slice 0). The +increase is expected and honest: the migrated authService now calls +runtime-based interfaces that slices 2/3/4 have not migrated yet. All remaining +`authService.ts` / `sessiond.ts` errors are cross-slice (authProviderOptions +shape → slice 2; OAuthLoginFlowService.start `runtime` param → slice 3; +`PiSessionServiceDependencies.modelRuntime` → slice 4). Test/support files +(slice 5) still import the removed `AuthStorage`. + +**Artifacts changed:** `src/server/sessions/authService.ts`, +`src/server/sessiond.ts`, `src/server/sessiond/sessionDaemonStartup.ts` +(commit `e37148c`); `relays/issue-62-authstorage/{status,log}.md`. + +**Status update:** last completed leg 2, next leg 3 = charter slice 2 +(`authProviderOptions.ts` migration). + +**Blockers:** none. **Sessiond restart now ACTIVE-pending** — slice 1 changed +`sessiond.ts` and the daemon auth construction path; the human must manually +restart the sessiond service once the migration lands (noted in status.md). +Also: human confirmed `/tmp` is usable again, so the `TMPDIR` install +workaround is no longer required (status.md updated). + +**Handoff:** spawning leg 3 (slice 2). diff --git a/relays/issue-62-authstorage/status.md b/relays/issue-62-authstorage/status.md index e04a387..1b4fdf3 100644 --- a/relays/issue-62-authstorage/status.md +++ b/relays/issue-62-authstorage/status.md @@ -1,44 +1,69 @@ # Relay status — issue-62-authstorage ## Current position -Bootstrap (slice 0) complete and committed (`0fa9d0e`). Deps are installed in the -worktree at **0.80.10** (all three `@earendil-works/*`), `package.json` ranges -corrected, and the new export surface is confirmed resolvable -(`ModelRuntime`, `readStoredCredential` present; `AuthStorage` gone; pi-ai -`InMemoryCredentialStore` present). `npx tsc --noEmit` now reports **24 errors**, -all in `src/server/sessions/` at the expected migration sites (no crash — the -removed `AuthStorage` import and `ModelRegistry.create/inMemory` calls). The -migration itself has not started. +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`. `saveApiKey` → `runtime.login(id, "api_key", +nonInteractive)`, `logoutProvider` → `runtime.logout`, `refreshAuthState` → +`await 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 2–4 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:** 1 (slice 0 Bootstrap — deps + range correction). -- **Next leg to run:** 2. +- **Last completed leg:** 2 (slice 1 — authService.ts core migration + sessiond + async construction). +- **Next leg to run:** 3. ## Next task -Run **charter slice 1 (`authService.ts` core migration)** as leg 2: -- Move `authService.ts` to `ModelRuntime` (async construction via - `ModelRuntime.create({ authPath, modelsPath })`), migrate - `saveApiKey` / `logoutProvider` / `refreshAuthState` / credential access off - the removed `authStorage`/`ModelRegistry.create` surface (see assessment §5.1 - for the concrete mapping). -- Propagate the now-async construction to `src/server/sessiond.ts`. -- **Sessiond path:** this slice touches session-daemon code → note in - status/handoff that a manual sessiond restart will be needed once landed. -- Slice 1 depends only on slice 0 (done). The tree will still not fully - typecheck after this leg (slices 2–4 remain); that is expected — leave an - honest status. +Run **charter slice 2 (`authProviderOptions.ts` migration)** as leg 3: +- Rederive login/logout provider options from `runtime.getProviders()` + (`{ id, name, auth: { apiKey?, oauth? } }`) + `runtime.listCredentials()` + (`{ providerId, type }[]`) / `runtime.getProviderAuthStatus(id)` instead of + `authStorage.getOAuthProviders()/list()/get()` + `getAll()` + + `getProviderDisplayName()`. +- The functions are already **called as async** from `authService.ts` + (`await getLoginProviderOptions(this.runtime, authType)` etc.) — make them + async and change their parameter type from `AuthProviderModelRegistry` to a + runtime-shaped interface (e.g. `AuthProviderRuntime` = `Pick` or a + structural equivalent). Update the structural interface + `authProviderOptions.test.ts` + test double accordingly. +- See assessment §5.2 / §3.3 for the new API shapes. Provider display names come + from `Provider.name`; OAuth-capable providers are those with `auth.oauth`, + api-key providers those with `auth.apiKey` (respect the existing + `OAUTH_ONLY_PROVIDERS` / `isApiKeyLoginProvider` logic). -If slice 1 is already done when you arrive, apply the charter's task-selection -policy: pick the lowest-numbered incomplete slice (2 → 6). +If slice 2 is already done when you arrive, apply the charter's task-selection +policy: pick the lowest-numbered incomplete slice (3 → 6). Slices 3 and 4 +unblock the remaining `authService.ts` / `sessiond.ts` cross-slice errors. ### Build/tooling note (important for every leg) -Installs and any native rebuild must set `TMPDIR` to a path inside the worktree, -e.g. `TMPDIR="$PWD/.tmp-build" npm install` (remove the dir after). `/tmp` is a -5.8G tmpfs at ~81% and node-gyp's `node-pty` build fails there with "Disk quota -exceeded". `.tmp-build` is scratch — do not commit it. 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. +**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 @@ -65,10 +90,12 @@ charter's Handover section. ## Blockers / intervention state None. Known constraints: -- **Sessiond restart pending** once slices touching `sessiond.ts` / session - runtime land (starts with slice 1/leg 2) — the human must manually restart the - sessiond service; keep this note current when it applies. -- `/tmp` disk-quota issue is real — see the Build/tooling note above; always set - `TMPDIR` into the worktree for installs/native rebuilds. +- **Sessiond restart pending (ACTIVE):** slice 1 (leg 2, commit `e37148c`) + changed `sessiond.ts` + the session-daemon auth construction path. 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.