Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/PHASED_IMPLEMENTATION.md
Original file line number Diff line number Diff line change
@@ -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):
Expand Down
2 changes: 1 addition & 1 deletion docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---
Expand Down
11 changes: 11 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
},
],
},
],
},
},
{
Expand Down
6 changes: 4 additions & 2 deletions openapi-ts.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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 },
],
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/routes/Contribute.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<MemoryRouter initialEntries={options.initialEntries ?? ['/contribute']}>
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/routes/CreateBundle.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<MemoryRouter initialEntries={['/bundles/new']}>
Expand Down Expand Up @@ -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(
<MemoryRouter
Expand Down
3 changes: 2 additions & 1 deletion src/lib/api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
* with a stable `code`, an HTTP `status`, and a message the UI can show.
*
* Nothing outside this module may import the generated default client in
* `api/client.gen.ts`; it points at production and carries no auth.
* `api/client.gen.ts`; it is generated without a base URL or auth, and an
* ESLint `no-restricted-imports` rule enforces this.
*/

import type { ApiErrorDetail } from './api/types.gen';
Expand Down
2 changes: 1 addition & 1 deletion src/lib/api/client.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ import type { ClientOptions as ClientOptions2 } from './types.gen';
*/
export type CreateClientConfig<T extends ClientOptions = ClientOptions2> = (override?: Config<ClientOptions & T>) => Config<Required<ClientOptions> & T>;

export const client: Client = createClient(createConfig<ClientOptions2>({ baseUrl: 'https://func-atk-prod.azurewebsites.net' }));
export const client: Client = createClient(createConfig<ClientOptions2>());
2 changes: 0 additions & 2 deletions src/providers/SessionProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export interface SessionContextValue {
}

export interface SessionUser {
avatarUrl: null | string;
login: string;
name: null | string;
}
Expand All @@ -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,
};
Expand Down
Loading