diff options
| author | soryu <soryu@soryu.co> | 2026-02-05 00:48:38 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-05 00:48:38 +0000 |
| commit | 0302b4596e14210884df5d645df9a179d8f0c1c6 (patch) | |
| tree | 46efe027dffa25a30e4eab87fd62de249c3075ad /makima/frontend/src/lib/api.ts | |
| parent | e16d49b52a393aa9a762edf57f93434a4bd7844e (diff) | |
| download | soryu-0302b4596e14210884df5d645df9a179d8f0c1c6.tar.gz soryu-0302b4596e14210884df5d645df9a179d8f0c1c6.zip | |
Add multi-repository support for chains
Chains can now have multiple repositories attached, with one marked as
primary. Repositories are used by contracts created from chain definitions.
Backend changes:
- Add chain_repositories table migration
- Add ChainRepository model with CRUD operations
- Add API endpoints for listing, adding, deleting repositories
- Add endpoint to set a repository as primary
- Update Chain and ChainEditorData models to use repositories
- Update chain parser to support repositories in YAML format
- Remove deprecated repository_url/local_path from Chain
Frontend changes:
- Add ChainRepository interface and API functions
- Add repository section to ChainEditor showing attached repos
- Add modal for adding new repositories (remote or local)
- Support setting primary repository and removing repositories
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/frontend/src/lib/api.ts')
| -rw-r--r-- | makima/frontend/src/lib/api.ts | 89 |
1 files changed, 85 insertions, 4 deletions
diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts index d68c1ad..2f4ee62 100644 --- a/makima/frontend/src/lib/api.ts +++ b/makima/frontend/src/lib/api.ts @@ -3025,6 +3025,20 @@ export interface ChainSummary { updatedAt: string; } +/** Chain repository */ +export interface ChainRepository { + id: string; + chainId: string; + name: string; + repositoryUrl: string | null; + localPath: string | null; + sourceType: string; + status: string; + isPrimary: boolean; + createdAt: string; + updatedAt: string; +} + /** Full chain with contracts */ export interface Chain { id: string; @@ -3036,8 +3050,6 @@ export interface Chain { loopMaxIterations: number | null; loopCurrentIteration: number | null; loopProgressCheck: string | null; - repositoryUrl: string | null; - localPath: string | null; version: number; createdAt: string; updatedAt: string; @@ -3061,6 +3073,7 @@ export interface ChainContractDetail { /** Chain with contracts (chain fields are flattened via serde(flatten)) */ export interface ChainWithContracts extends Chain { contracts: ChainContractDetail[]; + repositories: ChainRepository[]; } /** Node in chain graph visualization */ @@ -3105,12 +3118,20 @@ export interface ChainListResponse { total: number; } +/** Add chain repository request */ +export interface AddChainRepositoryRequest { + name: string; + repositoryUrl?: string; + localPath?: string; + sourceType?: string; + isPrimary?: boolean; +} + /** Create chain request */ export interface CreateChainRequest { name: string; description?: string; - repositoryUrl?: string; - localPath?: string; + repositories?: AddChainRepositoryRequest[]; loopEnabled?: boolean; loopMaxIterations?: number; loopProgressCheck?: string; @@ -3446,3 +3467,63 @@ export async function stopChain(chainId: string): Promise<{ stopped: boolean; st } return res.json(); } + +// ============================================================================ +// Chain Repository Operations +// ============================================================================ + +/** List repositories for a chain */ +export async function listChainRepositories(chainId: string): Promise<ChainRepository[]> { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/repositories`); + if (!res.ok) { + throw new Error(`Failed to list chain repositories: ${res.statusText}`); + } + return res.json(); +} + +/** Add a repository to a chain */ +export async function addChainRepository( + chainId: string, + req: AddChainRepositoryRequest +): Promise<ChainRepository> { + const res = await authFetch(`${API_BASE}/api/v1/chains/${chainId}/repositories`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(req), + }); + if (!res.ok) { + const error = await res.json().catch(() => ({ message: res.statusText })); + throw new Error(error.message || `Failed to add chain repository: ${res.statusText}`); + } + return res.json(); +} + +/** Delete a repository from a chain */ +export async function deleteChainRepository( + chainId: string, + repositoryId: string +): Promise<{ deleted: boolean }> { + const res = await authFetch( + `${API_BASE}/api/v1/chains/${chainId}/repositories/${repositoryId}`, + { method: "DELETE" } + ); + if (!res.ok) { + throw new Error(`Failed to delete chain repository: ${res.statusText}`); + } + return res.json(); +} + +/** Set a repository as primary for a chain */ +export async function setChainRepositoryPrimary( + chainId: string, + repositoryId: string +): Promise<ChainRepository> { + const res = await authFetch( + `${API_BASE}/api/v1/chains/${chainId}/repositories/${repositoryId}/primary`, + { method: "PUT" } + ); + if (!res.ok) { + throw new Error(`Failed to set chain repository as primary: ${res.statusText}`); + } + return res.json(); +} |
