@anyi61/codex-claude-delegate-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +262 -0
- package/dist/claude-cli.d.ts +84 -0
- package/dist/claude-cli.js +3123 -0
- package/dist/claude-cli.js.map +1 -0
- package/dist/cli.d.ts +61 -0
- package/dist/cli.js +334 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-config.d.ts +104 -0
- package/dist/codex-config.js +446 -0
- package/dist/codex-config.js.map +1 -0
- package/dist/guard.d.ts +27 -0
- package/dist/guard.js +229 -0
- package/dist/guard.js.map +1 -0
- package/dist/job-runner.d.ts +13 -0
- package/dist/job-runner.js +75 -0
- package/dist/job-runner.js.map +1 -0
- package/dist/jobs.d.ts +46 -0
- package/dist/jobs.js +175 -0
- package/dist/jobs.js.map +1 -0
- package/dist/package-info.d.ts +4 -0
- package/dist/package-info.js +14 -0
- package/dist/package-info.js.map +1 -0
- package/dist/schema.d.ts +779 -0
- package/dist/schema.js +325 -0
- package/dist/schema.js.map +1 -0
- package/dist/server.d.ts +1142 -0
- package/dist/server.js +693 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +35 -0
- package/dist/session.js +109 -0
- package/dist/session.js.map +1 -0
- package/package.json +49 -0
- package/plugins/codex-claude-delegate/.codex-plugin/plugin.json +36 -0
- package/plugins/codex-claude-delegate/.mcp.json +9 -0
- package/plugins/codex-claude-delegate/hooks/hooks.json +16 -0
- package/plugins/codex-claude-delegate/hooks/review-gate-stop.mjs +66 -0
- package/plugins/codex-claude-delegate/server/job-runner.js +16999 -0
- package/plugins/codex-claude-delegate/server/server.js +28048 -0
- package/plugins/codex-claude-delegate/skills/claude-delegate.md +30 -0
- package/plugins/codex-claude-delegate/skills/claude-rescue.md +52 -0
- package/plugins/codex-claude-delegate/skills/claude-review.md +25 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { validateCwd, validateFilesWithinCwd, checkRecursion, MAX_BRIDGE_DEPTH } from "./guard.js";
|
|
8
|
+
import { getPackageInfo } from "./package-info.js";
|
|
9
|
+
import { configureCodexAllowRoot } from "./codex-config.js";
|
|
10
|
+
import { cancelBackgroundJob, checkClaudeStatus, cleanupBackgroundJobs, getClaudeResult, getBackgroundJobResult, getRunLogById, manageClaudeReviewGate, runClaudeSetup, runClaudeTask, runClaudeApply, runClaudeCleanup, getRecentRunsSummary, listBackgroundJobs, listRunLogs, startBackgroundApply, startBackgroundCleanup, startBackgroundImplement, startBackgroundQuery, startBackgroundReview, getWorkspaceStatus, waitForBackgroundJob, } from "./claude-cli.js";
|
|
11
|
+
import { claudeApplyInputSchema, claudeCleanupInputSchema, claudeImplementInputSchema, claudeJobCancelInputSchema, claudeJobCleanupInputSchema, claudeJobResultInputSchema, claudeJobWaitInputSchema, claudeJobsInputSchema, claudeQueryInputSchema, claudeResultInputSchema, claudeRunInspectInputSchema, claudeReviewInputSchema, claudeReviewGateInputSchema, claudeRunsInputSchema, claudeSetupInputSchema, claudeStatusInputSchema, claudeTaskInputSchema, claudeWorkspaceStatusInputSchema, errorResult, jsonResult, localExecution, StructuredToolError, validationErrorMessage, withInteraction, } from "./schema.js";
|
|
12
|
+
export const TOOL_DEFINITIONS = [
|
|
13
|
+
{
|
|
14
|
+
name: "claude_status",
|
|
15
|
+
description: "Advanced / Debug. Check Claude Code CLI availability, auth status, git worktree support, and environment readiness.",
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: "object",
|
|
18
|
+
required: ["cwd"],
|
|
19
|
+
properties: {
|
|
20
|
+
cwd: { type: "string", description: "Working directory to check" },
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: "claude_setup",
|
|
26
|
+
description: "Default tool. Check workspace readiness for the high-level workflow layer, including review-gate hook installability and current gate state.",
|
|
27
|
+
inputSchema: {
|
|
28
|
+
type: "object",
|
|
29
|
+
required: ["cwd"],
|
|
30
|
+
properties: {
|
|
31
|
+
cwd: { type: "string", description: "Working directory to inspect and prepare" },
|
|
32
|
+
configure_allow_root: {
|
|
33
|
+
type: "boolean",
|
|
34
|
+
description: "When true, add cwd to CODEX_CLAUDE_ALLOW_ROOTS in the Codex config and update this MCP process so setup can continue.",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "claude_runs",
|
|
41
|
+
description: "Advanced / Debug. Inspect recent delegated run logs for this repository. Use to trace implement/apply/cleanup history without reading raw JSON files.",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: "object",
|
|
44
|
+
required: ["cwd"],
|
|
45
|
+
properties: {
|
|
46
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
47
|
+
limit: { type: "number", description: "Maximum number of recent runs to return (default 20)" },
|
|
48
|
+
type: { type: "string", enum: ["query", "review", "implement", "apply", "cleanup"], description: "Filter by tool type" },
|
|
49
|
+
status: { type: "string", enum: ["success", "failed", "partial", "needs_user", "unknown"], description: "Filter by derived run status" },
|
|
50
|
+
worktree_name: { type: "string", description: "Filter by delegated worktree name" },
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "claude_run_inspect",
|
|
56
|
+
description: "Advanced / Debug. Inspect a single delegated run log by run id, including normalized details and lifecycle metadata.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
required: ["cwd", "run_id"],
|
|
60
|
+
properties: {
|
|
61
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
62
|
+
run_id: { type: "string", description: "Run log id without the .json suffix" },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "claude_result",
|
|
68
|
+
description: "Default tool. Resolve the most relevant finished job or run for this workspace and return a normalized summary, session, and next actions.",
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: "object",
|
|
71
|
+
required: ["cwd"],
|
|
72
|
+
properties: {
|
|
73
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
74
|
+
job_id: { type: "string", description: "Explicit background job id to resolve first" },
|
|
75
|
+
run_id: { type: "string", description: "Explicit run id to resolve if no job id is provided" },
|
|
76
|
+
prefer: { type: "string", enum: ["latest-job", "latest-run", "latest-implement", "latest-review"], description: "How to choose the latest result when no explicit id is provided" },
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "claude_workspace_status",
|
|
82
|
+
description: "Advanced / Debug. Show a workspace-centric view of current jobs, recent runs, recent sessions, delegated worktrees, and attention items.",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
required: ["cwd"],
|
|
86
|
+
properties: {
|
|
87
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
88
|
+
limit: { type: "number", description: "Maximum number of recent jobs, runs, and sessions to include (default 10)" },
|
|
89
|
+
include_terminal: { type: "boolean", description: "Include recent terminal background jobs in the aggregated status view (default true)" },
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "claude_task",
|
|
95
|
+
description: "Default tool. High-level rescue/task entrypoint that routes to query, review, or implement and returns a background job for polling. Does not accept max_turns \u2014 use Advanced/Debug tools (claude_query, claude_review, claude_implement) for explicit turn caps.",
|
|
96
|
+
inputSchema: {
|
|
97
|
+
type: "object",
|
|
98
|
+
required: ["cwd", "task"],
|
|
99
|
+
properties: {
|
|
100
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
101
|
+
task: { type: "string", description: "High-level task to delegate" },
|
|
102
|
+
mode: { type: "string", enum: ["auto", "read", "review", "write"], description: "Routing mode. auto infers from diff/task wording." },
|
|
103
|
+
background: { type: "boolean", description: "Queue the delegated task as a persistent background job" },
|
|
104
|
+
resume_latest: { type: "boolean", description: "For write mode, resume the latest implement session for this repository." },
|
|
105
|
+
instruction_files: { type: "array", items: { type: "string" }, description: "Task instruction/context files. These are not apply scope limits." },
|
|
106
|
+
files: { type: "array", items: { type: "string" }, description: "Deprecated for claude_task: treated as instruction_files, not apply scope." },
|
|
107
|
+
constraints: { type: "array", items: { type: "string" }, description: "Implementation constraints for write mode" },
|
|
108
|
+
diff: { type: "string", description: "Diff to review. Presence strongly biases auto mode toward review." },
|
|
109
|
+
timeout_sec: { type: "number", description: "Timeout in seconds for the delegated task" },
|
|
110
|
+
dirty_policy: { type: "string", enum: ["ask", "committed", "snapshot"], description: "Write-mode handling for uncommitted main-workspace changes: ask (default), committed (ignore dirty changes and use HEAD), or snapshot (copy dirty files into the delegated worktree)." },
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "claude_review_gate",
|
|
116
|
+
description: "Advanced / Debug. Inspect, enable, or disable the review gate for the current workspace. Enable persists a repo-local gate flag and ensures the stop-hook manifest is present.",
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: "object",
|
|
119
|
+
required: ["cwd", "action"],
|
|
120
|
+
properties: {
|
|
121
|
+
cwd: { type: "string", description: "Working directory for the repo-local review gate state" },
|
|
122
|
+
action: { type: "string", enum: ["status", "enable", "disable"], description: "Review gate action" },
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "claude_query",
|
|
128
|
+
description: "Advanced / Debug. Ask Claude a read-only question as a persistent background job. Claude can read files and run safe git commands but cannot modify anything.",
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: "object",
|
|
131
|
+
required: ["task", "cwd"],
|
|
132
|
+
properties: {
|
|
133
|
+
task: { type: "string", description: "The question or analysis task" },
|
|
134
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
135
|
+
instruction_files: { type: "array", items: { type: "string" }, description: "Task instruction/context files for the query" },
|
|
136
|
+
timeout_sec: { type: "number", description: "Timeout in seconds (default 120)" },
|
|
137
|
+
max_turns: { type: "number", description: "Maximum Claude turns for this query. Omitted means no explicit turn cap; fast=true uses 2 unless max_turns is provided." },
|
|
138
|
+
fast: {
|
|
139
|
+
type: "boolean",
|
|
140
|
+
description: "Use a lower-latency query mode with smaller turn budget and concise prompt guidance.",
|
|
141
|
+
},
|
|
142
|
+
resume: {
|
|
143
|
+
type: "boolean",
|
|
144
|
+
description: "Control query session resume behavior. Defaults to true, but fast mode defaults to false.",
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: "claude_review",
|
|
151
|
+
description: "Advanced / Debug. Have Claude Code review code changes as a persistent background job. Claude runs in read-only mode. Provide a diff and/or file list for context.",
|
|
152
|
+
inputSchema: {
|
|
153
|
+
type: "object",
|
|
154
|
+
required: ["task", "cwd"],
|
|
155
|
+
properties: {
|
|
156
|
+
task: { type: "string", description: "Review instructions (what to look for)" },
|
|
157
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
158
|
+
instruction_files: { type: "array", items: { type: "string" }, description: "Review instruction/context files" },
|
|
159
|
+
diff: { type: "string", description: "The diff to review (optional; Claude can also git diff itself)" },
|
|
160
|
+
files: { type: "array", items: { type: "string" }, description: "Specific files to focus on" },
|
|
161
|
+
timeout_sec: { type: "number", description: "Timeout in seconds (default 180)" },
|
|
162
|
+
max_turns: { type: "number", description: "Maximum Claude turns for this review. Omitted means no explicit turn cap." },
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "claude_implement",
|
|
168
|
+
description: "Advanced / Debug. Delegate an implementation task to Claude Code as a persistent background job. Claude runs in an isolated git worktree and does NOT modify the main working tree.",
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: "object",
|
|
171
|
+
required: ["task", "cwd"],
|
|
172
|
+
properties: {
|
|
173
|
+
task: { type: "string", description: "Implementation task description" },
|
|
174
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots and a git repo)" },
|
|
175
|
+
files: { type: "array", items: { type: "string" }, description: "Relevant files for context" },
|
|
176
|
+
constraints: { type: "array", items: { type: "string" }, description: "Constraints (e.g. 'do not modify tests')" },
|
|
177
|
+
timeout_sec: { type: "number", description: "Timeout in seconds (default 600)" },
|
|
178
|
+
max_turns: { type: "number", description: "Maximum Claude turns for this implementation. Omitted means no explicit turn cap." },
|
|
179
|
+
session_key: { type: "string", description: "Resume an existing Claude session by ID (implement does NOT auto-resume)" },
|
|
180
|
+
fork_session: { type: "boolean", description: "When used with session_key, fork the session instead of continuing it" },
|
|
181
|
+
resume_latest: { type: "boolean", description: "Resume the latest implement session recorded for this repository. Cannot be combined with session_key." },
|
|
182
|
+
max_cost_usd: { type: "number", description: "Maximum USD budget for this task (passed as --max-budget-usd to Claude). Must be > 0 and <= 10." },
|
|
183
|
+
max_changed_files: { type: "number", description: "Warn if Claude changes more than this many files. Must be a positive integer <= 100." },
|
|
184
|
+
worktreeName: { type: "string", description: "Optional delegated worktree name override" },
|
|
185
|
+
dirty_policy: { type: "string", enum: ["ask", "committed", "snapshot"], description: "Handling for uncommitted main-workspace changes: ask (default), committed (ignore dirty changes and use HEAD), or snapshot (copy dirty files into the delegated worktree)." },
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: "claude_jobs",
|
|
191
|
+
description: "Advanced / Debug. List recent background review/implement jobs for this repository.",
|
|
192
|
+
inputSchema: {
|
|
193
|
+
type: "object",
|
|
194
|
+
required: ["cwd"],
|
|
195
|
+
properties: {
|
|
196
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
197
|
+
limit: { type: "number", description: "Maximum number of recent jobs to return (default 20)" },
|
|
198
|
+
status: { type: "string", enum: ["queued", "running", "succeeded", "failed", "cancelled"], description: "Filter by background job status" },
|
|
199
|
+
type: { type: "string", enum: ["query", "review", "implement", "apply", "cleanup"], description: "Filter by background job type" },
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: "claude_job_result",
|
|
205
|
+
description: "Advanced / Debug. Load one background job record, including process status, Claude result_status, and final result when available.",
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: "object",
|
|
208
|
+
required: ["cwd", "job_id"],
|
|
209
|
+
properties: {
|
|
210
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
211
|
+
job_id: { type: "string", description: "Background job id" },
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: "claude_job_cancel",
|
|
217
|
+
description: "Advanced / Debug. Cancel a running or queued background job by id.",
|
|
218
|
+
inputSchema: {
|
|
219
|
+
type: "object",
|
|
220
|
+
required: ["cwd", "job_id"],
|
|
221
|
+
properties: {
|
|
222
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
223
|
+
job_id: { type: "string", description: "Background job id" },
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: "claude_job_wait",
|
|
229
|
+
description: "Default tool. Wait for a background job process to reach a terminal state or timeout; inspect job.result_status for the Claude task outcome.",
|
|
230
|
+
inputSchema: {
|
|
231
|
+
type: "object",
|
|
232
|
+
required: ["cwd", "job_id"],
|
|
233
|
+
properties: {
|
|
234
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
235
|
+
job_id: { type: "string", description: "Background job id" },
|
|
236
|
+
not_before: { type: "string", description: "ISO timestamp; skip polling until this time to enforce recommended delays" },
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: "claude_job_cleanup",
|
|
242
|
+
description: "Advanced / Debug. Dry-run or remove old terminal background jobs for this repository.",
|
|
243
|
+
inputSchema: {
|
|
244
|
+
type: "object",
|
|
245
|
+
required: ["cwd"],
|
|
246
|
+
properties: {
|
|
247
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
248
|
+
older_than_hours: { type: "number", description: "Only target terminal jobs older than this many hours (default 24)" },
|
|
249
|
+
dry_run: { type: "boolean", description: "List matching jobs without removing them (default true)" },
|
|
250
|
+
limit: { type: "number", description: "Maximum number of matching jobs to inspect/remove (default 20)" },
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
name: "claude_apply",
|
|
256
|
+
description: "Default tool. Preview a delegated worktree diff, or apply it only after explicit user approval. Non-preview apply requires confirmed_by_user=true.",
|
|
257
|
+
inputSchema: {
|
|
258
|
+
type: "object",
|
|
259
|
+
required: ["cwd", "worktree_path"],
|
|
260
|
+
properties: {
|
|
261
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
262
|
+
worktree_path: { type: "string", description: "Path to worktree, e.g. .claude/worktrees/codex-delegated-xxx" },
|
|
263
|
+
cleanup: { type: "boolean", description: "Remove worktree after successful apply (default false)" },
|
|
264
|
+
preview: { type: "boolean", description: "Preview which files would be applied without modifying the main working tree" },
|
|
265
|
+
background: { type: "boolean", description: "Queue apply as a persistent background job" },
|
|
266
|
+
confirmed_by_user: {
|
|
267
|
+
type: "boolean",
|
|
268
|
+
description: "Required for non-preview apply after the user explicitly approves applying the previewed diff. Not required for preview=true.",
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
name: "claude_cleanup",
|
|
275
|
+
description: "Default tool. List and remove stale delegated worktrees. Defaults to dry-run. Use after verifying apply to clean up resources.",
|
|
276
|
+
inputSchema: {
|
|
277
|
+
type: "object",
|
|
278
|
+
required: ["cwd"],
|
|
279
|
+
properties: {
|
|
280
|
+
cwd: { type: "string", description: "Working directory (must be within allowed roots)" },
|
|
281
|
+
older_than_hours: { type: "number", description: "Only remove worktrees older than this many hours (0 = all delegated worktrees)" },
|
|
282
|
+
dry_run: { type: "boolean", description: "List worktrees without removing (default true)" },
|
|
283
|
+
background: { type: "boolean", description: "Queue cleanup as a persistent background job" },
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
];
|
|
288
|
+
export function registerToolDefinitions(server) {
|
|
289
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
290
|
+
tools: TOOL_DEFINITIONS,
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
293
|
+
export async function handleToolCall(name, args, runId = randomUUID()) {
|
|
294
|
+
try {
|
|
295
|
+
switch (name) {
|
|
296
|
+
case "claude_status": {
|
|
297
|
+
const startTime = Date.now();
|
|
298
|
+
const parsed = claudeStatusInputSchema.safeParse(args);
|
|
299
|
+
if (!parsed.success)
|
|
300
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
301
|
+
const { cwd } = parsed.data;
|
|
302
|
+
const check = await validateCwd(cwd);
|
|
303
|
+
if (!check.ok) {
|
|
304
|
+
return jsonResult({
|
|
305
|
+
cwd_valid: false,
|
|
306
|
+
cwd_is_git_repo: false,
|
|
307
|
+
errors: [check.error],
|
|
308
|
+
claude_available: false,
|
|
309
|
+
claude_version: null,
|
|
310
|
+
auth_status: null,
|
|
311
|
+
git_available: false,
|
|
312
|
+
worktree_capable: false,
|
|
313
|
+
execution: localExecution(startTime),
|
|
314
|
+
warnings: [check.error],
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
const status = await checkClaudeStatus(check.resolved);
|
|
318
|
+
return jsonResult({
|
|
319
|
+
...status,
|
|
320
|
+
recent_runs: await getRecentRunsSummary(check.resolved),
|
|
321
|
+
execution: localExecution(startTime),
|
|
322
|
+
warnings: status.errors,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
case "claude_setup": {
|
|
326
|
+
const parsed = claudeSetupInputSchema.safeParse(args);
|
|
327
|
+
if (!parsed.success)
|
|
328
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
329
|
+
let check = await validateCwd(parsed.data.cwd);
|
|
330
|
+
let allowRootConfiguration;
|
|
331
|
+
if (!check.ok && parsed.data.configure_allow_root) {
|
|
332
|
+
allowRootConfiguration = await configureCodexAllowRoot(parsed.data.cwd);
|
|
333
|
+
check = await validateCwd(parsed.data.cwd);
|
|
334
|
+
}
|
|
335
|
+
if (!check.ok) {
|
|
336
|
+
return jsonResult(withInteraction({
|
|
337
|
+
error: check.error,
|
|
338
|
+
next_actions: [
|
|
339
|
+
{
|
|
340
|
+
tool: "claude_setup",
|
|
341
|
+
args: { cwd: parsed.data.cwd, configure_allow_root: true },
|
|
342
|
+
reason: "Add this cwd to CODEX_CLAUDE_ALLOW_ROOTS in the Codex config, then retry setup in the same MCP process.",
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
config_hint: {
|
|
346
|
+
env_key: "CODEX_CLAUDE_ALLOW_ROOTS",
|
|
347
|
+
separator: process.platform === "win32" ? ";" : ":",
|
|
348
|
+
example: `/path/to/repo${process.platform === "win32" ? ";" : ":"}/path/to/another-repo`,
|
|
349
|
+
},
|
|
350
|
+
}, {
|
|
351
|
+
headline: "Claude delegation needs setup.",
|
|
352
|
+
state: "needs_attention",
|
|
353
|
+
next_step: "Add this repo to allow roots, restart Codex, then run claude_setup again.",
|
|
354
|
+
}));
|
|
355
|
+
}
|
|
356
|
+
const result = await runClaudeSetup({ cwd: check.resolved });
|
|
357
|
+
const needsAttention = result.errors.length > 0 || !result.claude_available;
|
|
358
|
+
const payload = allowRootConfiguration ? { ...result, allow_root_configuration: allowRootConfiguration } : result;
|
|
359
|
+
return jsonResult(withInteraction(payload, {
|
|
360
|
+
headline: needsAttention ? "Claude delegation needs setup." : "Claude delegation is ready.",
|
|
361
|
+
state: needsAttention ? "needs_attention" : "ready",
|
|
362
|
+
next_step: needsAttention ? "Fix the reported errors, then run claude_setup again." : "Use claude_task to delegate a read, review, or write task.",
|
|
363
|
+
}));
|
|
364
|
+
}
|
|
365
|
+
case "claude_runs": {
|
|
366
|
+
const parsed = claudeRunsInputSchema.safeParse(args);
|
|
367
|
+
if (!parsed.success)
|
|
368
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
369
|
+
const { cwd, limit, type, status, worktree_name } = parsed.data;
|
|
370
|
+
const check = await validateCwd(cwd);
|
|
371
|
+
if (!check.ok)
|
|
372
|
+
return errorResult(check.error);
|
|
373
|
+
return jsonResult(await listRunLogs({ cwd: check.resolved, limit, type, status, worktree_name }));
|
|
374
|
+
}
|
|
375
|
+
case "claude_run_inspect": {
|
|
376
|
+
const parsed = claudeRunInspectInputSchema.safeParse(args);
|
|
377
|
+
if (!parsed.success)
|
|
378
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
379
|
+
const check = await validateCwd(parsed.data.cwd);
|
|
380
|
+
if (!check.ok)
|
|
381
|
+
return errorResult(check.error);
|
|
382
|
+
const result = await getRunLogById({ cwd: check.resolved, run_id: parsed.data.run_id });
|
|
383
|
+
if (!result)
|
|
384
|
+
return errorResult(`Run not found: ${parsed.data.run_id}`);
|
|
385
|
+
return jsonResult(result);
|
|
386
|
+
}
|
|
387
|
+
case "claude_result": {
|
|
388
|
+
const parsed = claudeResultInputSchema.safeParse(args);
|
|
389
|
+
if (!parsed.success)
|
|
390
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
391
|
+
const check = await validateCwd(parsed.data.cwd);
|
|
392
|
+
if (!check.ok)
|
|
393
|
+
return errorResult(check.error);
|
|
394
|
+
const resultData = await getClaudeResult({ ...parsed.data, cwd: check.resolved });
|
|
395
|
+
const hasJobResult = resultData.job?.result_status === "success" || resultData.job?.result_status === "partial";
|
|
396
|
+
const hasRunResult = resultData.source_type === "run" && (resultData.run?.status === "success" || resultData.run?.status === "partial");
|
|
397
|
+
const hasResult = hasJobResult || hasRunResult;
|
|
398
|
+
return jsonResult(withInteraction(resultData, {
|
|
399
|
+
headline: hasResult ? "Claude result is ready." : "Claude result is not available.",
|
|
400
|
+
state: hasResult ? "result_ready" : "needs_attention",
|
|
401
|
+
next_step: hasResult ? "Preview the worktree changes with claude_apply preview=true." : "Check the job status with claude_job_wait.",
|
|
402
|
+
}));
|
|
403
|
+
}
|
|
404
|
+
case "claude_workspace_status": {
|
|
405
|
+
const parsed = claudeWorkspaceStatusInputSchema.safeParse(args);
|
|
406
|
+
if (!parsed.success)
|
|
407
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
408
|
+
const check = await validateCwd(parsed.data.cwd);
|
|
409
|
+
if (!check.ok)
|
|
410
|
+
return errorResult(check.error);
|
|
411
|
+
return jsonResult(await getWorkspaceStatus({ ...parsed.data, cwd: check.resolved }));
|
|
412
|
+
}
|
|
413
|
+
case "claude_task": {
|
|
414
|
+
const parsed = claudeTaskInputSchema.safeParse(args);
|
|
415
|
+
if (!parsed.success)
|
|
416
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
417
|
+
const { cwd, mode, files, instruction_files } = parsed.data;
|
|
418
|
+
const check = await validateCwd(cwd);
|
|
419
|
+
if (!check.ok)
|
|
420
|
+
return errorResult(check.error);
|
|
421
|
+
const fileCheck = await validateFilesWithinCwd(check.resolved, [
|
|
422
|
+
...(instruction_files ?? []),
|
|
423
|
+
...(files ?? []),
|
|
424
|
+
]);
|
|
425
|
+
if (!fileCheck.ok)
|
|
426
|
+
return errorResult(fileCheck.error);
|
|
427
|
+
if (mode === "write" || (mode === "auto" && (parsed.data.resume_latest || (parsed.data.constraints?.length ?? 0) > 0))) {
|
|
428
|
+
const { supportsWorktree } = await import("./guard.js");
|
|
429
|
+
const wtCapable = await supportsWorktree(check.resolved);
|
|
430
|
+
if (!wtCapable) {
|
|
431
|
+
return errorResult("claude_task write mode requires a git repository with worktree support");
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
const taskResult = await runClaudeTask({ ...parsed.data, cwd: check.resolved }, runId);
|
|
435
|
+
const hasJob = !!taskResult.job;
|
|
436
|
+
const needsUser = !hasJob && taskResult.next_actions.length === 0 && taskResult.result !== undefined;
|
|
437
|
+
const taskInteraction = needsUser
|
|
438
|
+
? { headline: "Write task needs a workspace decision before delegation.", state: "needs_user", next_step: "Commit or stash changes, or use dirty_policy=committed or dirty_policy=snapshot." }
|
|
439
|
+
: hasJob
|
|
440
|
+
? { headline: "Task delegated to Claude Code.", state: "delegated_execution", next_step: "Poll claude_job_wait with this job_id." }
|
|
441
|
+
: { headline: "Task completed.", state: "delegated_execution", next_step: "Review the result and proceed." };
|
|
442
|
+
return jsonResult(withInteraction(taskResult, taskInteraction));
|
|
443
|
+
}
|
|
444
|
+
case "claude_review_gate": {
|
|
445
|
+
const parsed = claudeReviewGateInputSchema.safeParse(args);
|
|
446
|
+
if (!parsed.success)
|
|
447
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
448
|
+
const check = await validateCwd(parsed.data.cwd);
|
|
449
|
+
if (!check.ok)
|
|
450
|
+
return errorResult(check.error);
|
|
451
|
+
return jsonResult(await manageClaudeReviewGate({ ...parsed.data, cwd: check.resolved }));
|
|
452
|
+
}
|
|
453
|
+
case "claude_query": {
|
|
454
|
+
const parsed = claudeQueryInputSchema.safeParse(args);
|
|
455
|
+
if (!parsed.success)
|
|
456
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
457
|
+
const { task, cwd, instruction_files, timeout_sec, max_turns, fast, resume } = parsed.data;
|
|
458
|
+
const resolvedTimeout = timeout_sec ?? (fast ? 45 : 120);
|
|
459
|
+
const resolvedMaxTurns = max_turns ?? (fast ? 2 : undefined);
|
|
460
|
+
const check = await validateCwd(cwd);
|
|
461
|
+
if (!check.ok)
|
|
462
|
+
return errorResult(check.error);
|
|
463
|
+
const fileCheck = await validateFilesWithinCwd(check.resolved, instruction_files);
|
|
464
|
+
if (!fileCheck.ok)
|
|
465
|
+
return errorResult(fileCheck.error);
|
|
466
|
+
return jsonResult(await startBackgroundQuery({
|
|
467
|
+
task,
|
|
468
|
+
cwd: check.resolved,
|
|
469
|
+
instruction_files,
|
|
470
|
+
timeout_sec: resolvedTimeout,
|
|
471
|
+
max_turns: resolvedMaxTurns,
|
|
472
|
+
fast,
|
|
473
|
+
resume,
|
|
474
|
+
}));
|
|
475
|
+
}
|
|
476
|
+
case "claude_review": {
|
|
477
|
+
const parsed = claudeReviewInputSchema.safeParse(args);
|
|
478
|
+
if (!parsed.success)
|
|
479
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
480
|
+
const { task, cwd, diff, instruction_files, files, timeout_sec, max_turns } = parsed.data;
|
|
481
|
+
const check = await validateCwd(cwd);
|
|
482
|
+
if (!check.ok)
|
|
483
|
+
return errorResult(check.error);
|
|
484
|
+
const mergedFiles = [...(files ?? []), ...(instruction_files ?? [])];
|
|
485
|
+
const fileCheck = await validateFilesWithinCwd(check.resolved, mergedFiles.length > 0 ? mergedFiles : undefined);
|
|
486
|
+
if (!fileCheck.ok)
|
|
487
|
+
return errorResult(fileCheck.error);
|
|
488
|
+
return jsonResult(await startBackgroundReview({ task, cwd: check.resolved, diff, instruction_files, files, timeout_sec, max_turns }));
|
|
489
|
+
}
|
|
490
|
+
case "claude_implement": {
|
|
491
|
+
const parsed = claudeImplementInputSchema.safeParse(args);
|
|
492
|
+
if (!parsed.success)
|
|
493
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
494
|
+
const { task, cwd, files, constraints, timeout_sec, max_turns, session_key, fork_session, resume_latest, max_cost_usd, max_changed_files, worktreeName, dirty_policy } = parsed.data;
|
|
495
|
+
const check = await validateCwd(cwd);
|
|
496
|
+
if (!check.ok)
|
|
497
|
+
return errorResult(check.error);
|
|
498
|
+
const fileCheck = await validateFilesWithinCwd(check.resolved, files);
|
|
499
|
+
if (!fileCheck.ok)
|
|
500
|
+
return errorResult(fileCheck.error);
|
|
501
|
+
// implement requires a git repo (for worktree)
|
|
502
|
+
const { supportsWorktree } = await import("./guard.js");
|
|
503
|
+
const wtCapable = await supportsWorktree(check.resolved);
|
|
504
|
+
if (!wtCapable) {
|
|
505
|
+
return errorResult("claude_implement requires a git repository with worktree support");
|
|
506
|
+
}
|
|
507
|
+
return jsonResult(await startBackgroundImplement({
|
|
508
|
+
task,
|
|
509
|
+
cwd: check.resolved,
|
|
510
|
+
files,
|
|
511
|
+
constraints,
|
|
512
|
+
timeout_sec,
|
|
513
|
+
max_turns,
|
|
514
|
+
session_key,
|
|
515
|
+
fork_session,
|
|
516
|
+
resume_latest,
|
|
517
|
+
max_cost_usd,
|
|
518
|
+
max_changed_files,
|
|
519
|
+
worktreeName,
|
|
520
|
+
dirty_policy,
|
|
521
|
+
}));
|
|
522
|
+
}
|
|
523
|
+
case "claude_jobs": {
|
|
524
|
+
const parsed = claudeJobsInputSchema.safeParse(args);
|
|
525
|
+
if (!parsed.success)
|
|
526
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
527
|
+
const check = await validateCwd(parsed.data.cwd);
|
|
528
|
+
if (!check.ok)
|
|
529
|
+
return errorResult(check.error);
|
|
530
|
+
return jsonResult(await listBackgroundJobs({ ...parsed.data, cwd: check.resolved }));
|
|
531
|
+
}
|
|
532
|
+
case "claude_job_result": {
|
|
533
|
+
const parsed = claudeJobResultInputSchema.safeParse(args);
|
|
534
|
+
if (!parsed.success)
|
|
535
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
536
|
+
const check = await validateCwd(parsed.data.cwd);
|
|
537
|
+
if (!check.ok)
|
|
538
|
+
return errorResult(check.error);
|
|
539
|
+
const result = await getBackgroundJobResult({ ...parsed.data, cwd: check.resolved });
|
|
540
|
+
if (!result)
|
|
541
|
+
return errorResult(`Job not found: ${parsed.data.job_id}`);
|
|
542
|
+
return jsonResult(result);
|
|
543
|
+
}
|
|
544
|
+
case "claude_job_cancel": {
|
|
545
|
+
const parsed = claudeJobCancelInputSchema.safeParse(args);
|
|
546
|
+
if (!parsed.success)
|
|
547
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
548
|
+
const check = await validateCwd(parsed.data.cwd);
|
|
549
|
+
if (!check.ok)
|
|
550
|
+
return errorResult(check.error);
|
|
551
|
+
const result = await cancelBackgroundJob({ ...parsed.data, cwd: check.resolved });
|
|
552
|
+
if (!result.cancelled && result.error) {
|
|
553
|
+
return errorResult(result.error);
|
|
554
|
+
}
|
|
555
|
+
return jsonResult(result);
|
|
556
|
+
}
|
|
557
|
+
case "claude_job_wait": {
|
|
558
|
+
const parsed = claudeJobWaitInputSchema.safeParse(args);
|
|
559
|
+
if (!parsed.success)
|
|
560
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
561
|
+
const check = await validateCwd(parsed.data.cwd);
|
|
562
|
+
if (!check.ok)
|
|
563
|
+
return errorResult(check.error);
|
|
564
|
+
const waitResult = await waitForBackgroundJob({ ...parsed.data, cwd: check.resolved });
|
|
565
|
+
let interaction;
|
|
566
|
+
if (waitResult.poll_too_soon) {
|
|
567
|
+
interaction = { headline: "Polling too soon.", state: "poll_too_soon", next_step: "Do not call claude_job_wait again before next_allowed_poll_at." };
|
|
568
|
+
}
|
|
569
|
+
else if (waitResult.stale_state === "stale") {
|
|
570
|
+
interaction = { headline: "Claude job appears stale.", state: "needs_attention", next_step: "Inspect this job result before starting a replacement." };
|
|
571
|
+
}
|
|
572
|
+
else if (waitResult.waiting) {
|
|
573
|
+
interaction = { headline: "Claude job is still running.", state: "waiting", next_step: "Wait until next_allowed_poll_at, then poll this same job_id." };
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
interaction = { headline: "Claude job completed.", state: "completed", next_step: "Use claude_result to inspect the result." };
|
|
577
|
+
}
|
|
578
|
+
return jsonResult(withInteraction(waitResult, interaction));
|
|
579
|
+
}
|
|
580
|
+
case "claude_job_cleanup": {
|
|
581
|
+
const parsed = claudeJobCleanupInputSchema.safeParse(args);
|
|
582
|
+
if (!parsed.success)
|
|
583
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
584
|
+
const check = await validateCwd(parsed.data.cwd);
|
|
585
|
+
if (!check.ok)
|
|
586
|
+
return errorResult(check.error);
|
|
587
|
+
return jsonResult(await cleanupBackgroundJobs({ ...parsed.data, cwd: check.resolved }));
|
|
588
|
+
}
|
|
589
|
+
case "claude_apply": {
|
|
590
|
+
const startTime = Date.now();
|
|
591
|
+
const parsed = claudeApplyInputSchema.safeParse(args);
|
|
592
|
+
if (!parsed.success)
|
|
593
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
594
|
+
const { cwd, worktree_path, cleanup, preview, background, confirmed_by_user } = parsed.data;
|
|
595
|
+
const check = await validateCwd(cwd);
|
|
596
|
+
if (!check.ok)
|
|
597
|
+
return errorResult(check.error);
|
|
598
|
+
if (background === true) {
|
|
599
|
+
return jsonResult(await startBackgroundApply({ cwd: check.resolved, worktree_path, cleanup, preview, background, confirmed_by_user }));
|
|
600
|
+
}
|
|
601
|
+
const result = await runClaudeApply({ cwd: check.resolved, worktree_path, cleanup, preview, confirmed_by_user }, runId);
|
|
602
|
+
const payload = {
|
|
603
|
+
...result,
|
|
604
|
+
execution: localExecution(startTime),
|
|
605
|
+
warnings: [...result.conflicts, ...(result.error ? [result.error] : [])],
|
|
606
|
+
};
|
|
607
|
+
let applyInteraction;
|
|
608
|
+
if (result.preview) {
|
|
609
|
+
applyInteraction = { headline: "Delegated changes are ready for review.", state: "apply_preview", next_step: "Review planned_changes. If safe, ask the user whether to apply these changes." };
|
|
610
|
+
}
|
|
611
|
+
else if (result.applied_files.length > 0) {
|
|
612
|
+
applyInteraction = { headline: "Delegated changes applied.", state: "applied", next_step: "Run project tests and review the final diff." };
|
|
613
|
+
}
|
|
614
|
+
else if (result.error) {
|
|
615
|
+
applyInteraction = { headline: "Apply refused.", state: "needs_user", next_step: "Show the preview to the user and ask for explicit approval before applying." };
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
applyInteraction = { headline: "Delegated changes are ready for review.", state: "apply_preview", next_step: "Review planned_changes. If safe, ask the user whether to apply these changes." };
|
|
619
|
+
}
|
|
620
|
+
return jsonResult(withInteraction(payload, applyInteraction));
|
|
621
|
+
}
|
|
622
|
+
case "claude_cleanup": {
|
|
623
|
+
const startTime = Date.now();
|
|
624
|
+
const parsed = claudeCleanupInputSchema.safeParse(args);
|
|
625
|
+
if (!parsed.success)
|
|
626
|
+
return errorResult(validationErrorMessage(parsed.error));
|
|
627
|
+
const { cwd, older_than_hours, dry_run, background } = parsed.data;
|
|
628
|
+
const check = await validateCwd(cwd);
|
|
629
|
+
if (!check.ok)
|
|
630
|
+
return errorResult(check.error);
|
|
631
|
+
if (background === true) {
|
|
632
|
+
return jsonResult(await startBackgroundCleanup({ cwd: check.resolved, older_than_hours, dry_run, background }));
|
|
633
|
+
}
|
|
634
|
+
const result = await runClaudeCleanup({ cwd: check.resolved, older_than_hours, dry_run }, runId);
|
|
635
|
+
const cleanupPayload = {
|
|
636
|
+
...result,
|
|
637
|
+
execution: localExecution(startTime),
|
|
638
|
+
warnings: result.entries.flatMap((entry) => entry.error ? [`${entry.worktree_name}: ${entry.error}`] : []),
|
|
639
|
+
};
|
|
640
|
+
return jsonResult(withInteraction(cleanupPayload, {
|
|
641
|
+
headline: dry_run ? "Delegated worktrees found." : "Delegated worktrees cleaned.",
|
|
642
|
+
state: dry_run ? "cleanup_preview" : "cleaned",
|
|
643
|
+
next_step: dry_run ? "Review entries. If these worktrees are no longer needed, call claude_cleanup with dry_run=false." : "Run claude_cleanup dry_run=true again only if you want to confirm no stale delegated worktrees remain.",
|
|
644
|
+
}));
|
|
645
|
+
}
|
|
646
|
+
default:
|
|
647
|
+
return errorResult(`Unknown tool: ${name}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
catch (err) {
|
|
651
|
+
if (err instanceof StructuredToolError) {
|
|
652
|
+
process.stderr.write(`[claude-delegate] ERROR (${name}): ${err.message}\n`);
|
|
653
|
+
return errorResult(err.payload);
|
|
654
|
+
}
|
|
655
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
656
|
+
process.stderr.write(`[claude-delegate] ERROR (${name}): ${msg}\n`);
|
|
657
|
+
return errorResult(msg);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
export function registerToolHandlers(server) {
|
|
661
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => (handleToolCall(request.params.name, request.params.arguments)));
|
|
662
|
+
}
|
|
663
|
+
export async function createServer() {
|
|
664
|
+
const info = await getPackageInfo();
|
|
665
|
+
const server = new Server({ name: info.name, version: info.version }, { capabilities: { tools: {} } });
|
|
666
|
+
registerToolDefinitions(server);
|
|
667
|
+
registerToolHandlers(server);
|
|
668
|
+
return server;
|
|
669
|
+
}
|
|
670
|
+
function assertCanStartServer() {
|
|
671
|
+
const bridgeDepth = checkRecursion();
|
|
672
|
+
if (bridgeDepth >= MAX_BRIDGE_DEPTH) {
|
|
673
|
+
process.stderr.write(`[claude-delegate] FATAL: BRIDGE_DEPTH=${bridgeDepth} >= ${MAX_BRIDGE_DEPTH}. Refusing to start MCP server to prevent recursive agent delegation.\n`);
|
|
674
|
+
process.exit(1);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
export async function main() {
|
|
678
|
+
assertCanStartServer();
|
|
679
|
+
const server = await createServer();
|
|
680
|
+
const transport = new StdioServerTransport();
|
|
681
|
+
await server.connect(transport);
|
|
682
|
+
process.stderr.write("[claude-delegate] MCP server started (stdio)\n");
|
|
683
|
+
}
|
|
684
|
+
export { main as startServer };
|
|
685
|
+
function isMainModule() {
|
|
686
|
+
if (!process.argv[1])
|
|
687
|
+
return false;
|
|
688
|
+
return fileURLToPath(import.meta.url) === resolve(process.argv[1]);
|
|
689
|
+
}
|
|
690
|
+
if (isMainModule()) {
|
|
691
|
+
await main();
|
|
692
|
+
}
|
|
693
|
+
//# sourceMappingURL=server.js.map
|