summaryrefslogtreecommitdiff
path: root/makima/frontend/src/lib/api.ts
diff options
context:
space:
mode:
Diffstat (limited to 'makima/frontend/src/lib/api.ts')
-rw-r--r--makima/frontend/src/lib/api.ts215
1 files changed, 215 insertions, 0 deletions
diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts
index b3c18a5..7c9fcd6 100644
--- a/makima/frontend/src/lib/api.ts
+++ b/makima/frontend/src/lib/api.ts
@@ -811,6 +811,112 @@ export async function retryCompletionAction(
return res.json();
}
+// =============================================================================
+// Git Actions for Tasks (Manual)
+// =============================================================================
+
+/** Response from export patch */
+export interface ExportPatchResponse {
+ success: boolean;
+ taskId: string;
+ fileName: string;
+ filePath?: string;
+ patchSize?: number;
+ message: string;
+}
+
+/**
+ * Export a task's changes as a patch file.
+ * The patch will be saved to the contract's patch directory.
+ */
+export async function exportTaskPatch(
+ taskId: string,
+ fileName?: string
+): Promise<ExportPatchResponse> {
+ const body: Record<string, unknown> = {};
+ if (fileName) {
+ body.fileName = fileName;
+ }
+ const res = await authFetch(`${API_BASE}/api/v1/mesh/tasks/${taskId}/export-patch`, {
+ method: "POST",
+ body: JSON.stringify(body),
+ });
+ if (!res.ok) {
+ const errorText = await res.text();
+ throw new Error(`Failed to export patch: ${errorText || res.statusText}`);
+ }
+ return res.json();
+}
+
+/** Response from push branch */
+export interface PushBranchResponse {
+ success: boolean;
+ taskId: string;
+ branchName: string;
+ remote?: string;
+ message: string;
+}
+
+/**
+ * Push a task's changes to a remote branch.
+ * Creates a branch if it doesn't exist and pushes the commits.
+ */
+export async function pushTaskBranch(
+ taskId: string,
+ branchName?: string
+): Promise<PushBranchResponse> {
+ const body: Record<string, unknown> = {};
+ if (branchName) {
+ body.branchName = branchName;
+ }
+ const res = await authFetch(`${API_BASE}/api/v1/mesh/tasks/${taskId}/push-branch`, {
+ method: "POST",
+ body: JSON.stringify(body),
+ });
+ if (!res.ok) {
+ const errorText = await res.text();
+ throw new Error(`Failed to push branch: ${errorText || res.statusText}`);
+ }
+ return res.json();
+}
+
+/** Response from create PR */
+export interface CreatePRResponse {
+ success: boolean;
+ taskId: string;
+ prUrl?: string;
+ prNumber?: number;
+ branchName?: string;
+ message: string;
+}
+
+/**
+ * Create a pull request for a task's changes.
+ * First pushes the branch if needed, then creates the PR.
+ */
+export async function createTaskPR(
+ taskId: string,
+ title?: string,
+ body?: string
+): Promise<CreatePRResponse> {
+ const reqBody: Record<string, unknown> = {};
+ if (title) {
+ reqBody.title = title;
+ }
+ if (body) {
+ reqBody.body = body;
+ }
+ const res = await authFetch(`${API_BASE}/api/v1/mesh/tasks/${taskId}/create-pr`, {
+ method: "POST",
+ body: JSON.stringify(reqBody),
+ });
+ if (!res.ok) {
+ const errorText = await res.text();
+ throw new Error(`Failed to create PR: ${errorText || res.statusText}`);
+ }
+ return res.json();
+}
+
/** A suggested directory from a connected daemon */
export interface DaemonDirectory {
/** Path to the directory */
@@ -1567,6 +1673,8 @@ export interface ContractSummary {
status: ContractStatus;
/** Supervisor task ID for contract orchestration */
supervisorTaskId: string | null;
+ /** When true, tasks won't auto-push or create PRs - use patch files instead */
+ localOnly: boolean;
fileCount: number;
taskCount: number;
repositoryCount: number;
@@ -1589,6 +1697,8 @@ export interface Contract {
autonomousLoop: boolean;
/** Whether to wait for user confirmation before progressing to the next phase */
phaseGuard: boolean;
+ /** When true, tasks won't auto-push or create PRs - use patch files instead */
+ localOnly: boolean;
version: number;
createdAt: string;
updatedAt: string;
@@ -1622,6 +1732,8 @@ export interface CreateContractRequest {
contractType?: ContractType;
/** Initial phase to start in (defaults based on contract type) */
initialPhase?: ContractPhase;
+ /** When true, tasks won't auto-push or create PRs - use patch files instead */
+ localOnly?: boolean;
}
export interface UpdateContractRequest {
@@ -2710,3 +2822,106 @@ export function getSupervisorStatus(
export async function dismissTask(taskId: string): Promise<Task> {
return updateTask(taskId, { hidden: true });
}
+
+// =============================================================================
+// Worktree Info Types and Functions
+// =============================================================================
+
+/** File status in the worktree (git status) */
+export type FileStatus = "M" | "A" | "D" | "R" | "C" | "U" | "?" | "modified" | "added" | "deleted" | "renamed" | "copied" | "unmerged" | "untracked";
+
+/** A single changed file in the worktree */
+export interface WorktreeFile {
+ /** File path relative to worktree root */
+ path: string;
+ /** Git status code (M=modified, A=added, D=deleted, R=renamed, C=copied, U=unmerged, ?=untracked) */
+ status: FileStatus;
+ /** Lines added (0 if deleted or unavailable) */
+ linesAdded: number;
+ /** Lines removed (0 if added or unavailable) */
+ linesRemoved: number;
+}
+
+/** Statistics about worktree changes */
+export interface WorktreeStats {
+ /** Number of files changed */
+ filesChanged: number;
+ /** Total lines inserted */
+ insertions: number;
+ /** Total lines deleted */
+ deletions: number;
+}
+
+/** Worktree information for a task */
+export interface WorktreeInfo {
+ /** Task ID */
+ taskId: string;
+ /** Path to the worktree directory */
+ worktreePath: string | null;
+ /** Whether the worktree exists on the daemon */
+ exists: boolean;
+ /** Aggregate statistics */
+ stats: WorktreeStats;
+ /** Changed files list */
+ files: WorktreeFile[];
+ /** Current branch name */
+ branch: string | null;
+ /** Current HEAD commit SHA */
+ headSha: string | null;
+}
+
+/**
+ * Get worktree information for a task.
+ * Returns changed files, stats, and metadata about the worktree.
+ */
+export async function getWorktreeInfo(taskId: string): Promise<WorktreeInfo> {
+ const res = await authFetch(`${API_BASE}/api/v1/mesh/tasks/${taskId}/worktree-info`);
+ if (!res.ok) {
+ const errorText = await res.text();
+ throw new Error(`Failed to get worktree info: ${errorText || res.statusText}`);
+ }
+ return res.json();
+}
+
+// =============================================================================
+// Patch Types and Functions
+// =============================================================================
+
+/** Summary of a patch file (contract file of type "patch") */
+export interface PatchSummary {
+ /** Patch/file ID */
+ id: string;
+ /** Patch name */
+ name: string;
+ /** Optional description */
+ description: string | null;
+ /** Task ID this patch was created from */
+ taskId: string | null;
+ /** Contract ID */
+ contractId: string;
+ /** Number of files in the patch */
+ filesCount: number;
+ /** Total lines added */
+ linesAdded: number;
+ /** Total lines removed */
+ linesRemoved: number;
+ /** List of file paths in the patch (if available) */
+ files: string[] | null;
+ /** When the patch was created */
+ createdAt: string;
+ /** When the patch was last updated */
+ updatedAt: string;
+}
+
+/**
+ * List patches for a task.
+ * Returns contract files of type "patch" associated with the task.
+ */
+export async function listTaskPatches(taskId: string, contractId: string): Promise<PatchSummary[]> {
+ const res = await authFetch(`${API_BASE}/api/v1/mesh/tasks/${taskId}/patches?contractId=${contractId}`);
+ if (!res.ok) {
+ const errorText = await res.text();
+ throw new Error(`Failed to list patches: ${errorText || res.statusText}`);
+ }
+ return res.json();
+}