1import { OrchestratorMcpFailure } from "@t3tools/contracts";
2import * as Option from "effect/Option";
3import * as GitWorkflow from "../../../git/GitWorkflowService.ts";
4import * as Project from "../../../project/ProjectService.ts";
5import { readThread, unavailable } from "../../threadAccess.ts";
6import * as Effect from "effect/Effect";
7
8import * as McpInvocationContext from "../../McpInvocationContext.ts";
9import * as McpToolAccess from "../../McpToolAccess.ts";
10import * as WorktreeMcpService from "../../WorktreeMcpService.ts";
11import { WorktreeToolkit } from "./tools.ts";
12
13const handlers = {
14 t3_worktree_list: McpToolAccess.reads((input) =>
15 Effect.gen(function* () {
16 const context = yield* McpInvocationContext.McpInvocationContext;
17 if (!context.capabilities.has("worktree"))
18 return yield* new OrchestratorMcpFailure({
19 code: "capability_denied",
20 message: "This credential cannot inspect worktrees.",
21 });
22 const { threadId, ...refs } = input;
23 const {
24 projection: { thread },
25 } = yield* readThread(threadId);
26 const projects = yield* Project.ProjectService;
27 const project = yield* projects.getById(thread.projectId).pipe(Effect.mapError(unavailable));
28 if (Option.isNone(project))
29 return yield* new OrchestratorMcpFailure({
30 code: "invalid_request",
31 message: "The project was not found.",
32 });
33 const git = yield* GitWorkflow.GitWorkflowService;
34 return yield* git
35 .listRefs({ ...refs, cwd: thread.worktreePath ?? project.value.workspaceRoot })
36 .pipe(Effect.mapError(unavailable));
37 }),
38 ),
39 t3_worktree_handoff: McpToolAccess.actsAsCaller((input) =>
40 Effect.gen(function* () {
41 const scope = yield* McpInvocationContext.McpInvocationContext;
42 const service = yield* WorktreeMcpService.WorktreeMcpService;
43 return yield* service.handoff(scope, input);
44 }),
45 ),
46 t3_worktree_status: McpToolAccess.readsAsCaller(() =>
47 Effect.gen(function* () {
48 const scope = yield* McpInvocationContext.McpInvocationContext;
49 const service = yield* WorktreeMcpService.WorktreeMcpService;
50 return yield* service.status(scope);
51 }),
52 ),
53} satisfies McpToolAccess.Handlers<typeof WorktreeToolkit.tools>;
54
55export const layer = McpToolAccess.toLayer(WorktreeToolkit, handlers);