feat: AI-powered merge via pi agent
This commit is contained in:
@@ -1 +1 @@
|
||||
export { createServer } from "./server.js";
|
||||
export { createServer, type ServerOptions } from "./server.js";
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Router } from "express";
|
||||
import type { TaskStore, Column } from "@hai/core";
|
||||
import type { TaskStore, Column, MergeResult } from "@hai/core";
|
||||
import { COLUMNS } from "@hai/core";
|
||||
import type { ServerOptions } from "./server.js";
|
||||
|
||||
export function createApiRoutes(store: TaskStore): Router {
|
||||
export function createApiRoutes(store: TaskStore, options?: ServerOptions): Router {
|
||||
const router = Router();
|
||||
|
||||
// List all tasks
|
||||
@@ -54,13 +55,15 @@ export function createApiRoutes(store: TaskStore): Router {
|
||||
});
|
||||
|
||||
// Merge task (in-review → done, merges branch + cleans worktree)
|
||||
// Uses AI merge handler if provided, falls back to store.mergeTask
|
||||
router.post("/tasks/:id/merge", async (req, res) => {
|
||||
try {
|
||||
const result = await store.mergeTask(req.params.id);
|
||||
const merge = options?.onMerge ?? ((id: string) => store.mergeTask(id));
|
||||
const result = await merge(req.params.id);
|
||||
res.json(result);
|
||||
} catch (err: any) {
|
||||
const status = err.message.includes("Cannot merge") ? 400
|
||||
: err.message.includes("Merge conflict") ? 409
|
||||
: err.message.includes("conflict") ? 409
|
||||
: 500;
|
||||
res.status(status).json({ error: err.message });
|
||||
}
|
||||
|
||||
@@ -2,13 +2,18 @@ import express from "express";
|
||||
import { join, dirname } from "node:path";
|
||||
import { existsSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import type { TaskStore } from "@hai/core";
|
||||
import type { TaskStore, MergeResult } from "@hai/core";
|
||||
import { createApiRoutes } from "./routes.js";
|
||||
import { createSSE } from "./sse.js";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export function createServer(store: TaskStore): ReturnType<typeof express> {
|
||||
export interface ServerOptions {
|
||||
/** Custom merge handler — when provided, used instead of store.mergeTask */
|
||||
onMerge?: (taskId: string) => Promise<MergeResult>;
|
||||
}
|
||||
|
||||
export function createServer(store: TaskStore, options?: ServerOptions): ReturnType<typeof express> {
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
@@ -25,7 +30,7 @@ export function createServer(store: TaskStore): ReturnType<typeof express> {
|
||||
app.get("/api/events", createSSE(store));
|
||||
|
||||
// REST API
|
||||
app.use("/api", createApiRoutes(store));
|
||||
app.use("/api", createApiRoutes(store, options));
|
||||
|
||||
// SPA fallback
|
||||
app.get("/{*splat}", (_req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user