doer-agent 0.6.6 → 0.6.7
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/dist/agent-codex-cli.js +21 -1
- package/dist/agent.js +4 -0
- package/dist/codex-app-server-manager.js +21 -1
- package/dist/mobile-mcp-server.js +254 -0
- package/package.json +1 -1
package/dist/agent-codex-cli.js
CHANGED
|
@@ -55,6 +55,22 @@ export function buildDaemonMcpConfigArgs(args) {
|
|
|
55
55
|
workspaceRootEnvName: "DOER_DAEMON_WORKSPACE_ROOT",
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
+
export function buildMobileMcpConfigArgs(args) {
|
|
59
|
+
return buildWorkspaceMcpConfigArgs({
|
|
60
|
+
agentProjectDir: args.agentProjectDir,
|
|
61
|
+
workspaceRoot: args.workspaceRoot,
|
|
62
|
+
serverName: args.serverName?.trim() || "doer_mobile",
|
|
63
|
+
distEntryRelativePath: path.join("dist", "mobile-mcp-server.js"),
|
|
64
|
+
srcEntryRelativePath: path.join("src", "mobile-mcp-server.ts"),
|
|
65
|
+
workspaceRootEnvName: "DOER_MOBILE_WORKSPACE_ROOT",
|
|
66
|
+
env: {
|
|
67
|
+
DOER_MOBILE_SERVER_BASE_URL: args.serverBaseUrl,
|
|
68
|
+
DOER_MOBILE_USER_ID: args.userId,
|
|
69
|
+
DOER_MOBILE_AGENT_ID: args.agentId,
|
|
70
|
+
DOER_AGENT_TOKEN: args.agentToken,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
58
74
|
function buildWorkspaceMcpConfigArgs(args) {
|
|
59
75
|
const serverName = args.serverName.trim();
|
|
60
76
|
const distEntry = path.join(args.agentProjectDir, args.distEntryRelativePath);
|
|
@@ -64,7 +80,7 @@ function buildWorkspaceMcpConfigArgs(args) {
|
|
|
64
80
|
const commandArgs = existsSync(distEntry)
|
|
65
81
|
? [distEntry, "--workspace-root", args.workspaceRoot]
|
|
66
82
|
: ["--import", tsxLoaderPath, srcEntry, "--workspace-root", args.workspaceRoot];
|
|
67
|
-
|
|
83
|
+
const configArgs = [
|
|
68
84
|
"--config",
|
|
69
85
|
`mcp_servers.${serverName}.command=${toTomlStringLiteral(command)}`,
|
|
70
86
|
"--config",
|
|
@@ -74,6 +90,10 @@ function buildWorkspaceMcpConfigArgs(args) {
|
|
|
74
90
|
"--config",
|
|
75
91
|
`mcp_servers.${serverName}.enabled=true`,
|
|
76
92
|
];
|
|
93
|
+
for (const [key, value] of Object.entries(args.env ?? {})) {
|
|
94
|
+
configArgs.push("--config", `mcp_servers.${serverName}.env.${key}=${toTomlStringLiteral(value)}`);
|
|
95
|
+
}
|
|
96
|
+
return configArgs;
|
|
77
97
|
}
|
|
78
98
|
export function buildLocalCodexCliCommand(args) {
|
|
79
99
|
const quotedArgs = args.map(shellSingleQuote).join(" ");
|
package/dist/agent.js
CHANGED
|
@@ -224,10 +224,14 @@ async function main() {
|
|
|
224
224
|
heartbeatAgentSession: heartbeatSession,
|
|
225
225
|
subscribeAll: () => {
|
|
226
226
|
const codexAppServerManager = createCodexAppServerManager({
|
|
227
|
+
agentId: initialAgentId,
|
|
228
|
+
agentToken,
|
|
227
229
|
workspaceRoot: resolveWorkspaceRoot(),
|
|
228
230
|
agentProjectDir: AGENT_PROJECT_DIR,
|
|
231
|
+
serverBaseUrl,
|
|
229
232
|
resolveCodexHomePath: runtimeEnvHelpers.resolveCodexHomePath,
|
|
230
233
|
readAgentSettingsConfig,
|
|
234
|
+
userId,
|
|
231
235
|
onLog: writeAgentInfo,
|
|
232
236
|
onNotification: (method, params) => {
|
|
233
237
|
if (!shouldForwardCodexAppNotification(method)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildAgentSettingsEnvPatch, readAgentModelInstructions, resolveAgentModelInstructionsFilePath, } from "./agent-settings.js";
|
|
2
|
-
import { buildDaemonMcpConfigArgs } from "./agent-codex-cli.js";
|
|
2
|
+
import { buildDaemonMcpConfigArgs, buildMobileMcpConfigArgs } from "./agent-codex-cli.js";
|
|
3
3
|
import { CodexAppServerClient } from "./codex-app-server-client.js";
|
|
4
4
|
function toTomlStringLiteral(value) {
|
|
5
5
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
@@ -32,6 +32,14 @@ async function buildCodexAppServerArgs(args) {
|
|
|
32
32
|
agentProjectDir: args.agentProjectDir,
|
|
33
33
|
workspaceRoot: args.workspaceRoot,
|
|
34
34
|
}),
|
|
35
|
+
...buildMobileMcpConfigArgs({
|
|
36
|
+
agentId: args.agentId,
|
|
37
|
+
agentProjectDir: args.agentProjectDir,
|
|
38
|
+
agentToken: args.agentToken,
|
|
39
|
+
serverBaseUrl: args.serverBaseUrl,
|
|
40
|
+
userId: args.userId,
|
|
41
|
+
workspaceRoot: args.workspaceRoot,
|
|
42
|
+
}),
|
|
35
43
|
...buildFeatureArg(true, "goals"),
|
|
36
44
|
...buildFeatureArg(args.settings.codex.computerUseEnabled, "computer_use"),
|
|
37
45
|
...buildFeatureArg(args.settings.codex.browserUseEnabled, "browser_use"),
|
|
@@ -44,6 +52,10 @@ async function buildCodexAppServerEnv(args) {
|
|
|
44
52
|
...process.env,
|
|
45
53
|
...buildAgentSettingsEnvPatch(args.settings),
|
|
46
54
|
CODEX_HOME: args.resolveCodexHomePath(),
|
|
55
|
+
DOER_AGENT_TOKEN: args.agentToken,
|
|
56
|
+
DOER_MOBILE_AGENT_ID: args.agentId,
|
|
57
|
+
DOER_MOBILE_SERVER_BASE_URL: args.serverBaseUrl,
|
|
58
|
+
DOER_MOBILE_USER_ID: args.userId,
|
|
47
59
|
};
|
|
48
60
|
}
|
|
49
61
|
export function createCodexAppServerManager(args) {
|
|
@@ -53,14 +65,22 @@ export function createCodexAppServerManager(args) {
|
|
|
53
65
|
const createClient = async () => {
|
|
54
66
|
const settings = await args.readAgentSettingsConfig({ workspaceRoot: args.workspaceRoot });
|
|
55
67
|
const appServerArgs = await buildCodexAppServerArgs({
|
|
68
|
+
agentId: args.agentId,
|
|
69
|
+
agentToken: args.agentToken,
|
|
56
70
|
workspaceRoot: args.workspaceRoot,
|
|
57
71
|
agentProjectDir: args.agentProjectDir,
|
|
72
|
+
serverBaseUrl: args.serverBaseUrl,
|
|
58
73
|
settings,
|
|
74
|
+
userId: args.userId,
|
|
59
75
|
});
|
|
60
76
|
const env = await buildCodexAppServerEnv({
|
|
77
|
+
agentId: args.agentId,
|
|
78
|
+
agentToken: args.agentToken,
|
|
61
79
|
workspaceRoot: args.workspaceRoot,
|
|
80
|
+
serverBaseUrl: args.serverBaseUrl,
|
|
62
81
|
resolveCodexHomePath: args.resolveCodexHomePath,
|
|
63
82
|
settings,
|
|
83
|
+
userId: args.userId,
|
|
64
84
|
});
|
|
65
85
|
args.onLog?.(`starting codex app-server model=${settings.codex.model} reasoningEffort=${settings.codex.reasoningEffort} personality=${settings.general.personality} computerUse=${settings.codex.computerUseEnabled} browserUse=${settings.codex.browserUseEnabled}`);
|
|
66
86
|
return new CodexAppServerClient({
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import * as z from "zod/v4";
|
|
4
|
+
function env(name) {
|
|
5
|
+
const value = process.env[name]?.trim() || "";
|
|
6
|
+
if (!value) {
|
|
7
|
+
throw new Error(`${name} is required`);
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
function optionalEnv(name) {
|
|
12
|
+
return process.env[name]?.trim() || "";
|
|
13
|
+
}
|
|
14
|
+
function formatJson(value) {
|
|
15
|
+
return JSON.stringify(value, null, 2);
|
|
16
|
+
}
|
|
17
|
+
function normalizeLimit(value, fallback, max) {
|
|
18
|
+
if (!Number.isFinite(value) || !value) {
|
|
19
|
+
return fallback;
|
|
20
|
+
}
|
|
21
|
+
return Math.min(max, Math.max(1, Math.trunc(value)));
|
|
22
|
+
}
|
|
23
|
+
function getConfig() {
|
|
24
|
+
return {
|
|
25
|
+
agentId: env("DOER_MOBILE_AGENT_ID"),
|
|
26
|
+
agentToken: env("DOER_AGENT_TOKEN"),
|
|
27
|
+
serverBaseUrl: env("DOER_MOBILE_SERVER_BASE_URL").replace(/\/$/, ""),
|
|
28
|
+
userId: env("DOER_MOBILE_USER_ID"),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function requestJson(path) {
|
|
32
|
+
const config = getConfig();
|
|
33
|
+
const response = await fetch(`${config.serverBaseUrl}${path}`, {
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: `Bearer ${config.agentToken}`,
|
|
36
|
+
Accept: "application/json",
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
const data = await response.json().catch(() => ({}));
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
throw new Error(typeof data.error === "string" ? data.error : `Doer server returned ${response.status}`);
|
|
42
|
+
}
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
async function listMobileAgents() {
|
|
46
|
+
const config = getConfig();
|
|
47
|
+
const data = await requestJson(`/api/users/${encodeURIComponent(config.userId)}/agents/${encodeURIComponent(config.agentId)}/mobile-agents`);
|
|
48
|
+
return Array.isArray(data.mobileAgents) ? data.mobileAgents : [];
|
|
49
|
+
}
|
|
50
|
+
async function resolveDeviceId(deviceId) {
|
|
51
|
+
const normalized = deviceId?.trim() || "";
|
|
52
|
+
if (normalized) {
|
|
53
|
+
return normalized;
|
|
54
|
+
}
|
|
55
|
+
const mobileAgents = await listMobileAgents();
|
|
56
|
+
const first = mobileAgents[0]?.deviceId?.trim() || "";
|
|
57
|
+
if (!first) {
|
|
58
|
+
throw new Error("No mobile agents registered");
|
|
59
|
+
}
|
|
60
|
+
return first;
|
|
61
|
+
}
|
|
62
|
+
async function getMobileInfo(deviceId) {
|
|
63
|
+
const config = getConfig();
|
|
64
|
+
const resolvedDeviceId = await resolveDeviceId(deviceId);
|
|
65
|
+
return await requestJson(`/api/users/${encodeURIComponent(config.userId)}/agents/${encodeURIComponent(config.agentId)}/mobile-agents/${encodeURIComponent(resolvedDeviceId)}/info`);
|
|
66
|
+
}
|
|
67
|
+
async function getMobileLogs(args) {
|
|
68
|
+
const config = getConfig();
|
|
69
|
+
const resolvedDeviceId = await resolveDeviceId(args.deviceId);
|
|
70
|
+
const qs = new URLSearchParams({
|
|
71
|
+
limit: String(normalizeLimit(args.limit, 100, 1000)),
|
|
72
|
+
});
|
|
73
|
+
if (Number.isInteger(args.beforeSeq)) {
|
|
74
|
+
qs.set("beforeSeq", String(args.beforeSeq));
|
|
75
|
+
}
|
|
76
|
+
if (Number.isInteger(args.afterSeq)) {
|
|
77
|
+
qs.set("afterSeq", String(args.afterSeq));
|
|
78
|
+
}
|
|
79
|
+
const data = await requestJson(`/api/users/${encodeURIComponent(config.userId)}/agents/${encodeURIComponent(config.agentId)}/mobile-agents/${encodeURIComponent(resolvedDeviceId)}/events?${qs.toString()}`);
|
|
80
|
+
return {
|
|
81
|
+
events: Array.isArray(data.events) ? data.events : [],
|
|
82
|
+
hasMore: data.hasMore === true,
|
|
83
|
+
latestSeq: typeof data.latestSeq === "number" ? data.latestSeq : null,
|
|
84
|
+
nextBeforeSeq: typeof data.nextBeforeSeq === "number" ? data.nextBeforeSeq : null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async function searchMobileLogs(args) {
|
|
88
|
+
const config = getConfig();
|
|
89
|
+
const resolvedDeviceId = await resolveDeviceId(args.deviceId);
|
|
90
|
+
const qs = new URLSearchParams({
|
|
91
|
+
limit: String(normalizeLimit(args.limit, 100, 1000)),
|
|
92
|
+
});
|
|
93
|
+
if (args.kind?.trim()) {
|
|
94
|
+
qs.set("kind", args.kind.trim());
|
|
95
|
+
}
|
|
96
|
+
if (args.query?.trim()) {
|
|
97
|
+
qs.set("query", args.query.trim());
|
|
98
|
+
}
|
|
99
|
+
if (args.since?.trim()) {
|
|
100
|
+
qs.set("since", args.since.trim());
|
|
101
|
+
}
|
|
102
|
+
if (args.until?.trim()) {
|
|
103
|
+
qs.set("until", args.until.trim());
|
|
104
|
+
}
|
|
105
|
+
if (Number.isInteger(args.beforeSeq)) {
|
|
106
|
+
qs.set("beforeSeq", String(args.beforeSeq));
|
|
107
|
+
}
|
|
108
|
+
if (Number.isInteger(args.afterSeq)) {
|
|
109
|
+
qs.set("afterSeq", String(args.afterSeq));
|
|
110
|
+
}
|
|
111
|
+
const data = await requestJson(`/api/users/${encodeURIComponent(config.userId)}/agents/${encodeURIComponent(config.agentId)}/mobile-agents/${encodeURIComponent(resolvedDeviceId)}/events?${qs.toString()}`);
|
|
112
|
+
return {
|
|
113
|
+
events: Array.isArray(data.events) ? data.events : [],
|
|
114
|
+
hasMore: data.hasMore === true,
|
|
115
|
+
latestSeq: typeof data.latestSeq === "number" ? data.latestSeq : null,
|
|
116
|
+
nextBeforeSeq: typeof data.nextBeforeSeq === "number" ? data.nextBeforeSeq : null,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function extractLatestLocation(events) {
|
|
120
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
121
|
+
const event = events[index];
|
|
122
|
+
if (event?.kind === "location.current" || event?.kind === "location.changed") {
|
|
123
|
+
return event;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
function extractLocationEvents(events) {
|
|
129
|
+
return events.filter((event) => event.kind.startsWith("location."));
|
|
130
|
+
}
|
|
131
|
+
function extractNotifications(events) {
|
|
132
|
+
return events.filter((event) => event.kind.startsWith("notification."));
|
|
133
|
+
}
|
|
134
|
+
async function main() {
|
|
135
|
+
const server = new McpServer({
|
|
136
|
+
name: "doer-mobile",
|
|
137
|
+
version: "0.1.0",
|
|
138
|
+
}, {
|
|
139
|
+
capabilities: {
|
|
140
|
+
tools: {},
|
|
141
|
+
},
|
|
142
|
+
instructions: "Inspect mobile agents paired with the current Doer agent. Use these tools to list devices, poll cursor-based logs, and inspect latest location/notification context.",
|
|
143
|
+
});
|
|
144
|
+
server.registerTool("mobile_list", {
|
|
145
|
+
description: "List mobile agents paired with the current Doer agent.",
|
|
146
|
+
inputSchema: {},
|
|
147
|
+
}, async () => {
|
|
148
|
+
const mobileAgents = await listMobileAgents();
|
|
149
|
+
return {
|
|
150
|
+
content: [{ type: "text", text: formatJson({ mobileAgents }) }],
|
|
151
|
+
structuredContent: { mobileAgents },
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
server.registerTool("mobile_info", {
|
|
155
|
+
description: "Read info for a mobile agent. Defaults to the first registered device.",
|
|
156
|
+
inputSchema: {
|
|
157
|
+
deviceId: z.string().optional().describe("Mobile device id. Defaults to the first registered mobile agent."),
|
|
158
|
+
},
|
|
159
|
+
}, async ({ deviceId }) => {
|
|
160
|
+
const result = await getMobileInfo(deviceId);
|
|
161
|
+
return {
|
|
162
|
+
content: [{ type: "text", text: formatJson(result) }],
|
|
163
|
+
structuredContent: result,
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
server.registerTool("mobile_logs", {
|
|
167
|
+
description: "Read a cursor-based page of mobile log events from the device-local SQLite log.",
|
|
168
|
+
inputSchema: {
|
|
169
|
+
afterSeq: z.number().int().min(0).optional().describe("Return events newer than this seq, in ascending order."),
|
|
170
|
+
beforeSeq: z.number().int().min(1).optional().describe("Return events older than this seq, in ascending order."),
|
|
171
|
+
deviceId: z.string().optional().describe("Mobile device id. Defaults to the first registered mobile agent."),
|
|
172
|
+
limit: z.number().int().min(1).max(1000).optional().describe("Maximum number of recent events."),
|
|
173
|
+
},
|
|
174
|
+
}, async ({ afterSeq, beforeSeq, deviceId, limit }) => {
|
|
175
|
+
const page = await getMobileLogs({ afterSeq, beforeSeq, deviceId, limit });
|
|
176
|
+
return {
|
|
177
|
+
content: [{ type: "text", text: formatJson(page) }],
|
|
178
|
+
structuredContent: page,
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
server.registerTool("mobile_search_logs", {
|
|
182
|
+
description: "Search the device-local mobile SQLite event log by kind, text query, cursor, and observed time range.",
|
|
183
|
+
inputSchema: {
|
|
184
|
+
afterSeq: z.number().int().min(0).optional().describe("Return matching events newer than this seq, in ascending order."),
|
|
185
|
+
beforeSeq: z.number().int().min(1).optional().describe("Return matching events older than this seq, in ascending order."),
|
|
186
|
+
deviceId: z.string().optional().describe("Mobile device id. Defaults to the first registered mobile agent."),
|
|
187
|
+
kind: z.string().optional().describe("Event kind or kind prefix, such as location.current or notification."),
|
|
188
|
+
query: z.string().optional().describe("Case-insensitive text to search in the event kind or payload."),
|
|
189
|
+
since: z.string().optional().describe("Inclusive ISO timestamp lower bound."),
|
|
190
|
+
until: z.string().optional().describe("Inclusive ISO timestamp upper bound."),
|
|
191
|
+
limit: z.number().int().min(1).max(1000).optional().describe("Maximum number of matching events."),
|
|
192
|
+
},
|
|
193
|
+
}, async ({ afterSeq, beforeSeq, deviceId, kind, query, since, until, limit }) => {
|
|
194
|
+
const page = await searchMobileLogs({ afterSeq, beforeSeq, deviceId, kind, query, since, until, limit });
|
|
195
|
+
return {
|
|
196
|
+
content: [{ type: "text", text: formatJson(page) }],
|
|
197
|
+
structuredContent: page,
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
server.registerTool("mobile_latest_location", {
|
|
201
|
+
description: "Return the latest location event from recent mobile logs.",
|
|
202
|
+
inputSchema: {
|
|
203
|
+
deviceId: z.string().optional().describe("Mobile device id. Defaults to the first registered mobile agent."),
|
|
204
|
+
limit: z.number().int().min(1).max(1000).optional().describe("How many recent events to scan."),
|
|
205
|
+
},
|
|
206
|
+
}, async ({ deviceId, limit }) => {
|
|
207
|
+
const page = await searchMobileLogs({ deviceId, kind: "location.", limit: limit ?? 200 });
|
|
208
|
+
const location = extractLatestLocation(page.events);
|
|
209
|
+
return {
|
|
210
|
+
content: [{ type: "text", text: formatJson({ location }) }],
|
|
211
|
+
structuredContent: { location },
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
server.registerTool("mobile_location_history", {
|
|
215
|
+
description: "Return time-range location events recorded by the mobile agent.",
|
|
216
|
+
inputSchema: {
|
|
217
|
+
afterSeq: z.number().int().min(0).optional().describe("Return location events newer than this seq, in ascending order."),
|
|
218
|
+
beforeSeq: z.number().int().min(1).optional().describe("Return location events older than this seq, in ascending order."),
|
|
219
|
+
deviceId: z.string().optional().describe("Mobile device id. Defaults to the first registered mobile agent."),
|
|
220
|
+
since: z.string().optional().describe("Inclusive ISO timestamp lower bound."),
|
|
221
|
+
until: z.string().optional().describe("Inclusive ISO timestamp upper bound."),
|
|
222
|
+
limit: z.number().int().min(1).max(1000).optional().describe("Maximum number of matching location events."),
|
|
223
|
+
},
|
|
224
|
+
}, async ({ afterSeq, beforeSeq, deviceId, since, until, limit }) => {
|
|
225
|
+
const page = await searchMobileLogs({ afterSeq, beforeSeq, deviceId, kind: "location.", since, until, limit: limit ?? 200 });
|
|
226
|
+
const events = extractLocationEvents(page.events);
|
|
227
|
+
const result = { ...page, events };
|
|
228
|
+
return {
|
|
229
|
+
content: [{ type: "text", text: formatJson(result) }],
|
|
230
|
+
structuredContent: result,
|
|
231
|
+
};
|
|
232
|
+
});
|
|
233
|
+
server.registerTool("mobile_notifications", {
|
|
234
|
+
description: "Return recent notification events from mobile logs.",
|
|
235
|
+
inputSchema: {
|
|
236
|
+
deviceId: z.string().optional().describe("Mobile device id. Defaults to the first registered mobile agent."),
|
|
237
|
+
limit: z.number().int().min(1).max(1000).optional().describe("How many recent events to scan."),
|
|
238
|
+
},
|
|
239
|
+
}, async ({ deviceId, limit }) => {
|
|
240
|
+
const page = await searchMobileLogs({ deviceId, kind: "notification.", limit: limit ?? 200 });
|
|
241
|
+
const events = extractNotifications(page.events);
|
|
242
|
+
return {
|
|
243
|
+
content: [{ type: "text", text: formatJson({ events }) }],
|
|
244
|
+
structuredContent: { events },
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
const transport = new StdioServerTransport();
|
|
248
|
+
await server.connect(transport);
|
|
249
|
+
}
|
|
250
|
+
main().catch((error) => {
|
|
251
|
+
const message = error instanceof Error ? error.stack || error.message : String(error);
|
|
252
|
+
process.stderr.write(`${message}\n`);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
});
|