diff --git a/docs/PHASED_IMPLEMENTATION.md b/docs/PHASED_IMPLEMENTATION.md index d8da7f4..fdc0da0 100644 --- a/docs/PHASED_IMPLEMENTATION.md +++ b/docs/PHASED_IMPLEMENTATION.md @@ -1,5 +1,7 @@ # Agentic Toolkit Web — Phased Implementation Plan +> **Historical.** This was the MVP build plan. It is kept for the record and is not maintained. Where it disagrees with the code, the code wins; in particular the in-repo `auth-function` and the Octokit data layer it describes were replaced by the shared ATK API in September 2026 (web PR #2). `PROJECT_OVERVIEW.md` describes the current architecture. + This document breaks the ATK Web MVP into ordered phases. Each phase delivers a testable slice of functionality and must be validated before the next phase begins. The ordering deliberately front-loads foundational, auth-free work so early phases can be developed and tested against fixture data, then layers authentication and contribution workflows on top once the read-only surface is stable. Resolved decisions informing this plan (from PROJECT_OVERVIEW.md §10): diff --git a/docs/deployment.md b/docs/deployment.md index 20e5190..7675ee9 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -10,7 +10,7 @@ The SPA deploys automatically on pushes to `main`. There is only one SPA environ Related docs: - `docs/OAUTH_APP_SETUP.md` — full step-by-step OAuth App registration playbook (dev and prod). -- `docs/PHASED_IMPLEMENTATION.md` — project-wide implementation phases. +- `docs/PHASED_IMPLEMENTATION.md` — the original MVP build plan (historical, not maintained). - `docs/Direction.md` and `docs/design/ClientContract.md` in the `Emergent.AgenticToolkit` monorepo — the API's contract and roadmap. --- diff --git a/eslint.config.js b/eslint.config.js index 74c58d7..34c81e3 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -29,6 +29,17 @@ export default tseslint.config( ], 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn', + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['**/api/client.gen', '**/api/client.gen.ts'], + message: 'Use createApiClient from src/lib/api-client.ts; the generated default client has no base URL or auth.', + }, + ], + }, + ], }, }, { diff --git a/openapi-ts.config.ts b/openapi-ts.config.ts index 5cdb095..c60149e 100644 --- a/openapi-ts.config.ts +++ b/openapi-ts.config.ts @@ -6,7 +6,9 @@ import { defineConfig } from '@hey-api/openapi-ts'; * - `pnpm refresh-openapi` re-downloads the contract from the API. * - `pnpm generate-api` regenerates `src/lib/api/` (committed; do not edit by hand). * - * Only `src/lib/api-client.ts` may import the generated default client. + * The generated default client (`client.gen.ts`) is created without a base URL + * on purpose: every SDK call must go through `src/lib/api-client.ts`, which + * sets the base URL and auth. ESLint blocks importing `client.gen` elsewhere. */ export default defineConfig({ input: './openapi/openapi.json', @@ -15,7 +17,7 @@ export default defineConfig({ postProcess: [], }, plugins: [ - { name: '@hey-api/client-fetch', throwOnError: false }, + { baseUrl: false, name: '@hey-api/client-fetch', throwOnError: false }, { name: '@hey-api/sdk', operations: { strategy: 'flat' }, responseStyle: 'fields', throwOnError: false }, { name: '@hey-api/typescript', enums: false }, ], diff --git a/src/__tests__/routes/Contribute.test.tsx b/src/__tests__/routes/Contribute.test.tsx index 55350d3..d5f8edf 100644 --- a/src/__tests__/routes/Contribute.test.tsx +++ b/src/__tests__/routes/Contribute.test.tsx @@ -115,7 +115,7 @@ function renderContribute(login = 'test-user', options: { api?: ApiClient | null const session = makeSessionValue({ api: options.api ?? null, status: 'member', - user: { avatarUrl: null, login, name: null }, + user: { login, name: null }, }); return render( diff --git a/src/__tests__/routes/CreateBundle.test.tsx b/src/__tests__/routes/CreateBundle.test.tsx index 880389e..c0057c8 100644 --- a/src/__tests__/routes/CreateBundle.test.tsx +++ b/src/__tests__/routes/CreateBundle.test.tsx @@ -34,7 +34,7 @@ function renderCreateBundle(api: ApiClient | null = makeTestApiClient()) { const session = makeSessionValue({ api, status: 'member', - user: { avatarUrl: null, login: 'test-user', name: null }, + user: { login: 'test-user', name: null }, }); return render( @@ -225,7 +225,7 @@ describe('CreateBundle — wizard flow', () => { const session = makeSessionValue({ api: makeTestApiClient(), status: 'member', - user: { avatarUrl: null, login: 'test-user', name: null }, + user: { login: 'test-user', name: null }, }); render( = (override?: Config) => Config & T>; -export const client: Client = createClient(createConfig({ baseUrl: 'https://func-atk-prod.azurewebsites.net' })); +export const client: Client = createClient(createConfig()); diff --git a/src/providers/SessionProvider.tsx b/src/providers/SessionProvider.tsx index 8108698..6127653 100644 --- a/src/providers/SessionProvider.tsx +++ b/src/providers/SessionProvider.tsx @@ -31,7 +31,6 @@ export interface SessionContextValue { } export interface SessionUser { - avatarUrl: null | string; login: string; name: null | string; } @@ -58,7 +57,6 @@ export function SessionProvider({ children }: SessionProviderProps) { if (!api) throw new Error('API client not initialized'); const principal = unwrap(await me({ client: api, signal }), 'your GitHub account'); return { - avatarUrl: principal.avatarUrl ?? null, login: principal.login, name: principal.name ?? null, };