@codex-ultra/cxu 0.2.31 → 0.2.35
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/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/postinstall.js +1 -1
- package/package.json +1 -1
- package/server-bundle/index.js +2521 -1969
- package/server-bundle/sa-vm-mcp.mjs +367 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import readline from "node:readline";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_PORTS = [43110, 43120, 43121, 43122];
|
|
5
|
+
let activeServerUrl = process.env.CODEX_UI_API_URL || null;
|
|
6
|
+
const TOKEN = process.env.CODEX_UI_TOKEN || "";
|
|
7
|
+
|
|
8
|
+
const rl = readline.createInterface({
|
|
9
|
+
input: process.stdin,
|
|
10
|
+
output: process.stdout,
|
|
11
|
+
terminal: false,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
function send(msg) {
|
|
15
|
+
process.stdout.write(JSON.stringify(msg) + "\n");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function logError(msg) {
|
|
19
|
+
process.stderr.write(`[sa-vm-mcp] ${msg}\n`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const SA_VM_ACTIONS = [
|
|
23
|
+
"apply_patch",
|
|
24
|
+
"edit_file",
|
|
25
|
+
"write_file",
|
|
26
|
+
"ensure_dir",
|
|
27
|
+
"mkdir",
|
|
28
|
+
"read_file",
|
|
29
|
+
"read_lines",
|
|
30
|
+
"read_file_tail",
|
|
31
|
+
"count_lines",
|
|
32
|
+
"find_files",
|
|
33
|
+
"list_dir",
|
|
34
|
+
"grep_search",
|
|
35
|
+
"grep_search_async",
|
|
36
|
+
"delete_file",
|
|
37
|
+
"safe_delete",
|
|
38
|
+
"move_file",
|
|
39
|
+
"copy_file",
|
|
40
|
+
"file_info",
|
|
41
|
+
"stat",
|
|
42
|
+
"test_path",
|
|
43
|
+
"file_exists",
|
|
44
|
+
"exists",
|
|
45
|
+
"vm-read",
|
|
46
|
+
"vm_read",
|
|
47
|
+
"git_status",
|
|
48
|
+
"git_diff",
|
|
49
|
+
"clear_tool_history",
|
|
50
|
+
"find_references",
|
|
51
|
+
"find_implementations",
|
|
52
|
+
"find_impl",
|
|
53
|
+
"implementations",
|
|
54
|
+
"file_outline",
|
|
55
|
+
"workspace_outline",
|
|
56
|
+
"repo_map",
|
|
57
|
+
"code_graph",
|
|
58
|
+
"relation_graph",
|
|
59
|
+
"symbol_graph",
|
|
60
|
+
"read_many",
|
|
61
|
+
"verify_loop",
|
|
62
|
+
"verify_changed",
|
|
63
|
+
"rename_symbol",
|
|
64
|
+
"move_file_with_imports",
|
|
65
|
+
"find_definition",
|
|
66
|
+
"extract_to_file",
|
|
67
|
+
"add_import",
|
|
68
|
+
"get_diagnostics",
|
|
69
|
+
"workspace_diagnostics",
|
|
70
|
+
"organize_imports",
|
|
71
|
+
"analyze_scope",
|
|
72
|
+
"run_bun",
|
|
73
|
+
"run_project_check",
|
|
74
|
+
"run_host",
|
|
75
|
+
"exec_host",
|
|
76
|
+
"host",
|
|
77
|
+
"run_js",
|
|
78
|
+
"run_py",
|
|
79
|
+
"http_fetch",
|
|
80
|
+
"jev_choose",
|
|
81
|
+
"jev_checklist",
|
|
82
|
+
"jev_evaluate",
|
|
83
|
+
"jev_thinking",
|
|
84
|
+
"jev_redteam",
|
|
85
|
+
"jev_rank",
|
|
86
|
+
"jev_scope",
|
|
87
|
+
"jev_consistency",
|
|
88
|
+
"jev_done",
|
|
89
|
+
"jev_diagnose",
|
|
90
|
+
"jev_edge_cases",
|
|
91
|
+
"jev_blast_radius",
|
|
92
|
+
"save_note",
|
|
93
|
+
"add_note",
|
|
94
|
+
"read_notes",
|
|
95
|
+
"read_note",
|
|
96
|
+
"list_notes",
|
|
97
|
+
"delete_note",
|
|
98
|
+
"remove_note",
|
|
99
|
+
"clear_notes",
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
const SA_VM_TOOL_DEFINITION = {
|
|
103
|
+
name: "sa_vm_run",
|
|
104
|
+
description: `HIGHEST PRIORITY tool for workspace code reading, slicing, line counting, fast grep searching, directory listing, AST refactoring, and code edits: ${SA_VM_ACTIONS.map((a) => `'${a}'`).join(", ")}. Always prefer sa_vm_run over terminal commands (Get-Content, Select-String, Get-ChildItem, Test-Path, cat, grep) because it runs in-process natively in milliseconds, eliminates Windows encoding corruption, and provides automatic token protection.`,
|
|
105
|
+
inputSchema: {
|
|
106
|
+
type: "object",
|
|
107
|
+
required: ["action"],
|
|
108
|
+
properties: {
|
|
109
|
+
action: {
|
|
110
|
+
type: "string",
|
|
111
|
+
enum: SA_VM_ACTIONS,
|
|
112
|
+
description: "Action shortcut: 'read_file', 'read_lines', 'read_many', 'read_file_tail', 'count_lines', 'test_path', 'file_exists', 'exists', 'file_info', 'stat', 'ensure_dir', 'mkdir', 'git_status', 'git_diff', 'edit_file', 'write_file', 'apply_patch', 'find_files', 'list_dir', 'grep_search', 'grep_search_async', 'delete_file', 'safe_delete', 'move_file', 'copy_file', 'find_references', 'find_implementations', 'file_outline', 'workspace_outline', 'repo_map', 'code_graph', 'relation_graph', 'symbol_graph', 'rename_symbol', 'move_file_with_imports', 'find_definition', 'extract_to_file', 'add_import', 'get_diagnostics', 'workspace_diagnostics', 'verify_loop', 'verify_changed', 'save_note', 'read_notes', 'delete_note', 'organize_imports', 'analyze_scope', 'run_host', 'run_bun', 'run_project_check', 'run_js', 'run_py', 'http_fetch', 'jev_choose', 'jev_checklist', 'jev_evaluate', 'jev_thinking', 'jev_redteam', 'jev_rank', 'jev_scope', 'jev_consistency', 'jev_done', 'jev_diagnose', 'jev_edge_cases', 'jev_blast_radius'."
|
|
113
|
+
},
|
|
114
|
+
path: { type: "string", description: "Target file or directory path relative to workspace (e.g. 'src/main.ts')." },
|
|
115
|
+
file: { type: "string", description: "Target single file path for 'grep_search', 'read_file', 'read_lines', or 'count_lines' (alias of 'path')." },
|
|
116
|
+
dir: { type: "string", description: "Target directory path for 'list_dir', 'grep_search', 'find_files', or 'workspace_diagnostics' (default '.')." },
|
|
117
|
+
type: { type: "string", enum: ["all", "file", "directory"], description: "Filter entries by type for 'list_dir' ('all', 'file', or 'directory')." },
|
|
118
|
+
depth: { type: "integer", description: "Recursion depth for 'list_dir' (default 1; set 2 or 3 to inspect nested subdirectories in a single call)." },
|
|
119
|
+
max_entries: { type: "integer", description: "Maximum entries to return for 'list_dir' or 'find_files' (default 200)." },
|
|
120
|
+
max_files: { type: "integer", description: "Maximum files to scan for 'workspace_diagnostics' (default 100)." },
|
|
121
|
+
max_errors: { type: "integer", description: "Maximum errors to collect for 'workspace_diagnostics' (default 50)." },
|
|
122
|
+
detail: { type: "boolean", description: "Return detailed diagnostics if true, or compact 'path:Lx:Cy:code' if false (default false)." },
|
|
123
|
+
check_references: { type: "boolean", description: "Check symbol references before deleting for 'safe_delete' (default true)." },
|
|
124
|
+
force: { type: "boolean", description: "Force delete for 'safe_delete' even if references exist (default false)." },
|
|
125
|
+
content: { type: "string", description: "File content to write for 'write_file', or script code for 'run_js'/'run_py'." },
|
|
126
|
+
patch: { type: "string", description: "Unified diff patch starting with '*** Begin Patch' and ending with '*** End Patch' for 'apply_patch'." },
|
|
127
|
+
old_text: { type: "string", description: "Exact text to find and replace for 'edit_file'." },
|
|
128
|
+
new_text: { type: "string", description: "Replacement text for 'edit_file'." },
|
|
129
|
+
start_line: { type: "integer", description: "1-based starting line number for 'read_file' / 'read_lines'." },
|
|
130
|
+
end_line: { type: "integer", description: "1-based ending line number for 'read_file' / 'read_lines'." },
|
|
131
|
+
lines: { type: "integer", description: "Trailing lines count for 'read_file_tail' (default 100)." },
|
|
132
|
+
max_tokens: { type: "integer", description: "Max token limit for 'read_file' (default 4000)." },
|
|
133
|
+
numbered: { type: "boolean", description: "Prepend line numbers to read_file output (default true)." },
|
|
134
|
+
pattern: { type: "string", description: "Search glob pattern for 'find_files' (e.g. '*.ts') or search pattern for 'grep_search'." },
|
|
135
|
+
query: { type: "string", description: "Search query text or regex for 'grep_search'." },
|
|
136
|
+
is_regex: { type: "boolean", description: "Set true if query is a regular expression for 'grep_search' (e.g. '^\\\\s+(load|store)')." },
|
|
137
|
+
queries: { type: "array", items: { type: "string" }, description: "Batch search queries for 'grep_search_async'." },
|
|
138
|
+
symbol: { type: "string", description: "Target symbol name for 'find_definition', 'rename_symbol', or 'file_outline'." },
|
|
139
|
+
old_name: { type: "string", description: "Old symbol name for 'rename_symbol'." },
|
|
140
|
+
new_name: { type: "string", description: "New replacement symbol name for 'rename_symbol'." },
|
|
141
|
+
source: { type: "string", description: "Extraction source file path or SLA bytecode source." },
|
|
142
|
+
target: { type: "string", description: "Target file path for 'extract_to_file' or destination, or symbol/module path for 'code_graph'/'relation_graph'/'symbol_graph' (e.g. class, function, or src/index.ts), or plan/decision under review for 'jev_redteam'." },
|
|
143
|
+
statement: { type: "string", description: "Import statement for 'add_import' (e.g. 'import { t } from \"./i18n\";')." },
|
|
144
|
+
component_name: { type: "string", description: "Component name for 'analyze_scope' or 'extract_to_file'." },
|
|
145
|
+
profile: { type: "string", description: "Predefined project check profile (e.g. 'web-typecheck', 'server-typecheck')." },
|
|
146
|
+
subcommand: { type: "string", description: "Subcommand for 'run_bun' (e.g. 'test', 'build')." },
|
|
147
|
+
exe: { type: "string", description: "Target executable binary for 'run_host' ('sa', 'sla', 'zig', or workspace-internal path)." },
|
|
148
|
+
args: { type: "array", items: { type: "string" }, description: "Command-line arguments for 'run_host'." },
|
|
149
|
+
head_lines: { type: "integer", description: "First N lines of output to retain for 'run_host'." },
|
|
150
|
+
tail_lines: { type: "integer", description: "Last N lines of output to retain for 'run_host'." },
|
|
151
|
+
env: { type: "object", description: "Allowlisted environment variables for 'run_host' (e.g. SA_PLUGIN_DEV, ZIG_EXE, NO_COLOR)." },
|
|
152
|
+
key: { type: "string", description: "Identifier key for 'save_note', 'read_notes', or 'delete_note' (e.g. 'test_rule')." },
|
|
153
|
+
fact: { type: "string", description: "Fact or note content for 'save_note' (alias of 'content')." },
|
|
154
|
+
level: { type: "string", enum: ["low", "normal", "important", "critical"], description: "Priority level for 'save_note' ('low', 'normal', 'important', 'critical'; default 'normal'). Higher priority notes are sorted first and protected from eviction." },
|
|
155
|
+
all: { type: "boolean", description: "Clear all notes for 'delete_note' (default false)." },
|
|
156
|
+
from: { type: "string", description: "Source path for 'move_file' or 'move_file_with_imports'." },
|
|
157
|
+
to: { type: "string", description: "Target path for 'move_file' or 'move_file_with_imports'." },
|
|
158
|
+
cwd: { type: "string", description: "Workspace directory root. Defaults to current working directory." },
|
|
159
|
+
threadId: { type: "string", description: "Optional conversation thread ID if known." },
|
|
160
|
+
question: { type: "string", description: "Decision question for 'jev_choose' (2-8 options), goal fallback for 'jev_thinking'." },
|
|
161
|
+
options: { type: "object", description: "Choice options map for 'jev_choose' (e.g. { a: 'desc A', b: 'desc B' }).", additionalProperties: true },
|
|
162
|
+
checks: { type: "object", description: "Checklist items map for 'jev_checklist' (e.g. { no_placeholders: '...' }).", additionalProperties: true },
|
|
163
|
+
questions: { type: "object", description: "Custom questions map for 'jev_evaluate' passthrough.", additionalProperties: true },
|
|
164
|
+
goal: { type: "string", description: "Thinking goal for 'jev_thinking'." },
|
|
165
|
+
thoughts: { type: "object", description: "Candidate lines of thought for 'jev_thinking' (1-4 entries; '__act_now' brake is built in).", additionalProperties: true },
|
|
166
|
+
context: { type: "string", description: "Supporting context for jev_* advisory actions (falls back to 'content')." },
|
|
167
|
+
items: { type: "object", description: "Items map to rank for 'jev_rank' (2-6 entries).", additionalProperties: true },
|
|
168
|
+
criterion: { type: "string", description: "Ranking criterion for 'jev_rank' (e.g. 'ROI')." },
|
|
169
|
+
task: { type: "string", description: "Task under scope triage for 'jev_scope'." },
|
|
170
|
+
phases: { type: "object", description: "Candidate split phases for 'jev_scope' (up to 6 entries).", additionalProperties: true },
|
|
171
|
+
plan: { type: "string", description: "Plan under consistency audit for 'jev_consistency'." },
|
|
172
|
+
constraints: { type: "object", description: "Hard constraints map for 'jev_consistency' (1-8 entries).", additionalProperties: true },
|
|
173
|
+
user_request: { type: "string", description: "Original user request for 'jev_done'." },
|
|
174
|
+
actual_work: { type: "string", description: "Actual work performed for 'jev_done'." },
|
|
175
|
+
evidence: { type: "string", description: "Verification evidence for 'jev_done'." },
|
|
176
|
+
error_summary: { type: "string", description: "Error or failure summary for 'jev_diagnose'." },
|
|
177
|
+
hypotheses: { type: "object", description: "Root-cause hypotheses map for 'jev_diagnose' (2-4 entries).", additionalProperties: true },
|
|
178
|
+
proposed_fix: { type: "string", description: "Proposed fix under judgment for 'jev_diagnose'." },
|
|
179
|
+
code: { type: "string", description: "Code under boundary review for 'jev_edge_cases'." },
|
|
180
|
+
diff: { type: "string", description: "Unified diff under blast-radius review for 'jev_blast_radius'." },
|
|
181
|
+
target_component: { type: "string", description: "Target component of the diff for 'jev_blast_radius'." },
|
|
182
|
+
mode: { type: "string", description: "Code graph mode for 'code_graph'/'relation_graph'/'symbol_graph' ('symbol_hierarchy', 'module_dependency'/'module_deps', 'call_flow')." },
|
|
183
|
+
direction: { type: "string", description: "Dependency direction for 'code_graph' module_dependency ('upstream', 'downstream', 'both')." },
|
|
184
|
+
format: { type: "string", description: "Output format for 'code_graph' ('dot', 'py_stub', 'networkx')." },
|
|
185
|
+
output_file: { type: "string", description: "Optional output file for 'code_graph' (default pure memory)." },
|
|
186
|
+
candidate_files: { type: "array", items: { type: "string" }, description: "Optional candidate files to restrict 'code_graph' scope." },
|
|
187
|
+
files: { type: "array", items: { type: "string" }, description: "File list for 'read_many' (max 10 files in one call)." },
|
|
188
|
+
staged: { type: "boolean", description: "Show staged changes for 'git_diff' (default unstaged+untracked summary)." },
|
|
189
|
+
stat_only: { type: "boolean", description: "Only file stats for 'git_diff'." },
|
|
190
|
+
pathspec: { type: "string", description: "Path filter for 'git_diff' (single file/dir)." },
|
|
191
|
+
context: { type: "integer", description: "Diff context lines for 'git_diff' (0-10)." }
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
async function fetchSaVmEndpoint(effectiveArgs) {
|
|
197
|
+
const headers = { "Content-Type": "application/json" };
|
|
198
|
+
if (TOKEN) {
|
|
199
|
+
headers["Authorization"] = `Bearer ${TOKEN}`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const urlsToTry = [];
|
|
203
|
+
if (activeServerUrl) {
|
|
204
|
+
urlsToTry.push(activeServerUrl);
|
|
205
|
+
}
|
|
206
|
+
for (const port of DEFAULT_PORTS) {
|
|
207
|
+
const candidate = `http://127.0.0.1:${port}`;
|
|
208
|
+
if (!urlsToTry.includes(candidate)) {
|
|
209
|
+
urlsToTry.push(candidate);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let lastError = null;
|
|
214
|
+
for (const baseUrl of urlsToTry) {
|
|
215
|
+
try {
|
|
216
|
+
const controller = new AbortController();
|
|
217
|
+
const timer = setTimeout(() => controller.abort(), 2000);
|
|
218
|
+
const res = await fetch(`${baseUrl}/api/tools/sa_vm_run`, {
|
|
219
|
+
method: "POST",
|
|
220
|
+
headers,
|
|
221
|
+
body: JSON.stringify(effectiveArgs),
|
|
222
|
+
signal: controller.signal
|
|
223
|
+
});
|
|
224
|
+
clearTimeout(timer);
|
|
225
|
+
if (res.status !== 404 && res.status !== 502 && res.status !== 503) {
|
|
226
|
+
activeServerUrl = baseUrl;
|
|
227
|
+
return { response: res, url: baseUrl };
|
|
228
|
+
}
|
|
229
|
+
} catch (err) {
|
|
230
|
+
lastError = err;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
throw lastError || new Error(`Unable to connect to Codex Ultra server on any candidate port (${DEFAULT_PORTS.join(", ")})`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
rl.on("line", async (line) => {
|
|
238
|
+
const trimmed = line.trim();
|
|
239
|
+
if (!trimmed) return;
|
|
240
|
+
|
|
241
|
+
let req;
|
|
242
|
+
try {
|
|
243
|
+
req = JSON.parse(trimmed);
|
|
244
|
+
} catch (err) {
|
|
245
|
+
logError(`Invalid JSON: ${err.message}`);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const { id, method, params } = req;
|
|
250
|
+
// If no id, it's a notification, ignore per JSON-RPC 2.0
|
|
251
|
+
if (id === undefined || id === null) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (method === "initialize") {
|
|
256
|
+
send({
|
|
257
|
+
jsonrpc: "2.0",
|
|
258
|
+
id,
|
|
259
|
+
result: {
|
|
260
|
+
protocolVersion: "2024-11-05",
|
|
261
|
+
capabilities: {
|
|
262
|
+
tools: { listChanged: false }
|
|
263
|
+
},
|
|
264
|
+
serverInfo: {
|
|
265
|
+
name: "sa-vm",
|
|
266
|
+
version: "1.0.0"
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (method === "ping") {
|
|
274
|
+
send({ jsonrpc: "2.0", id, result: {} });
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (method === "tools/list") {
|
|
279
|
+
send({
|
|
280
|
+
jsonrpc: "2.0",
|
|
281
|
+
id,
|
|
282
|
+
result: {
|
|
283
|
+
tools: [SA_VM_TOOL_DEFINITION]
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (method === "tools/call") {
|
|
290
|
+
if (params?.name !== "sa_vm_run") {
|
|
291
|
+
send({
|
|
292
|
+
jsonrpc: "2.0",
|
|
293
|
+
id,
|
|
294
|
+
error: { code: -32601, message: `Tool '${params?.name}' not found` }
|
|
295
|
+
});
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const rawArgs = params.arguments || {};
|
|
300
|
+
const effectiveArgs = {
|
|
301
|
+
...rawArgs,
|
|
302
|
+
cwd: rawArgs.cwd || process.cwd()
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
const { response, url: connectedUrl } = await fetchSaVmEndpoint(effectiveArgs);
|
|
307
|
+
|
|
308
|
+
const resJson = await response.json().catch(() => ({}));
|
|
309
|
+
const data = resJson?.data;
|
|
310
|
+
|
|
311
|
+
let outputText = "";
|
|
312
|
+
if (typeof data?.stdout === "string" && data.stdout) {
|
|
313
|
+
outputText = data.stdout;
|
|
314
|
+
if (data.stderr) {
|
|
315
|
+
outputText += `\n[stderr]\n${data.stderr}`;
|
|
316
|
+
}
|
|
317
|
+
} else if (typeof data?.output === "string") {
|
|
318
|
+
outputText = data.output;
|
|
319
|
+
} else if (resJson?.error) {
|
|
320
|
+
outputText = `Error: ${resJson.error} (code: ${resJson.code || "UNKNOWN"})`;
|
|
321
|
+
} else {
|
|
322
|
+
outputText = JSON.stringify(data || resJson, null, 2);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const isError = !response.ok || data?.ok === false || data?.kind === "sa_error" || data?.kind === "capability_denied";
|
|
326
|
+
|
|
327
|
+
send({
|
|
328
|
+
jsonrpc: "2.0",
|
|
329
|
+
id,
|
|
330
|
+
result: {
|
|
331
|
+
content: [
|
|
332
|
+
{
|
|
333
|
+
type: "text",
|
|
334
|
+
text: outputText
|
|
335
|
+
}
|
|
336
|
+
],
|
|
337
|
+
isError
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
} catch (err) {
|
|
341
|
+
logError(`Fetch failed: ${err.message}`);
|
|
342
|
+
send({
|
|
343
|
+
jsonrpc: "2.0",
|
|
344
|
+
id,
|
|
345
|
+
result: {
|
|
346
|
+
content: [
|
|
347
|
+
{
|
|
348
|
+
type: "text",
|
|
349
|
+
text: `[SA-VM Connection Failure]: Unable to reach Codex Ultra server at ${activeServerUrl || "http://127.0.0.1:43110"} (${err.message}).\nPlease ensure the Codex Ultra service is running.`
|
|
350
|
+
}
|
|
351
|
+
],
|
|
352
|
+
isError: true
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
send({
|
|
360
|
+
jsonrpc: "2.0",
|
|
361
|
+
id,
|
|
362
|
+
error: {
|
|
363
|
+
code: -32601,
|
|
364
|
+
message: `Method '${method}' not supported`
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
});
|