@defai.digital/automatosx 12.1.1 → 12.3.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/CHANGELOG.md +23 -0
- package/README.md +1 -1
- package/dist/index.js +2223 -1715
- package/dist/mcp/index.js +485 -94
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -195,11 +195,7 @@ var init_logger = __esm({
|
|
|
195
195
|
message: entry.message,
|
|
196
196
|
context: entry.context
|
|
197
197
|
});
|
|
198
|
-
|
|
199
|
-
console.error(json);
|
|
200
|
-
} else {
|
|
201
|
-
console.log(json);
|
|
202
|
-
}
|
|
198
|
+
console.error(json);
|
|
203
199
|
return;
|
|
204
200
|
}
|
|
205
201
|
const timestamp = entry.timestamp.toISOString();
|
|
@@ -5367,7 +5363,7 @@ var PRECOMPILED_CONFIG = {
|
|
|
5367
5363
|
"enableFreeTierPrioritization": true,
|
|
5368
5364
|
"enableWorkloadAwareRouting": true
|
|
5369
5365
|
},
|
|
5370
|
-
"version": "12.
|
|
5366
|
+
"version": "12.3.0"
|
|
5371
5367
|
};
|
|
5372
5368
|
|
|
5373
5369
|
// src/core/config/schemas.ts
|
|
@@ -14153,6 +14149,7 @@ var ConversationContextStore = class {
|
|
|
14153
14149
|
storePath;
|
|
14154
14150
|
maxEntries;
|
|
14155
14151
|
ttlMs;
|
|
14152
|
+
destroyed = false;
|
|
14156
14153
|
constructor(options) {
|
|
14157
14154
|
this.storePath = options.storePath;
|
|
14158
14155
|
this.maxEntries = options.maxEntries ?? 100;
|
|
@@ -14189,6 +14186,9 @@ var ConversationContextStore = class {
|
|
|
14189
14186
|
* Initialize store (create directory if needed)
|
|
14190
14187
|
*/
|
|
14191
14188
|
async initialize() {
|
|
14189
|
+
if (this.destroyed) {
|
|
14190
|
+
throw new Error("Context store is destroyed");
|
|
14191
|
+
}
|
|
14192
14192
|
try {
|
|
14193
14193
|
await mkdir(this.storePath, { recursive: true });
|
|
14194
14194
|
logger.info("[ContextStore] Initialized", { storePath: this.storePath });
|
|
@@ -14201,6 +14201,9 @@ var ConversationContextStore = class {
|
|
|
14201
14201
|
* Save conversation context
|
|
14202
14202
|
*/
|
|
14203
14203
|
async save(context) {
|
|
14204
|
+
if (this.destroyed) {
|
|
14205
|
+
throw new Error("Context store is destroyed");
|
|
14206
|
+
}
|
|
14204
14207
|
await this.initialize();
|
|
14205
14208
|
const filePath = this.validateAndResolvePath(context.id);
|
|
14206
14209
|
const data = JSON.stringify(context, null, 2);
|
|
@@ -14244,6 +14247,9 @@ var ConversationContextStore = class {
|
|
|
14244
14247
|
* List all context entries (non-expired)
|
|
14245
14248
|
*/
|
|
14246
14249
|
async list(options) {
|
|
14250
|
+
if (this.destroyed) {
|
|
14251
|
+
return [];
|
|
14252
|
+
}
|
|
14247
14253
|
try {
|
|
14248
14254
|
const files = await readdir(this.storePath);
|
|
14249
14255
|
const contexts = [];
|
|
@@ -14346,6 +14352,9 @@ var ConversationContextStore = class {
|
|
|
14346
14352
|
* Get storage statistics
|
|
14347
14353
|
*/
|
|
14348
14354
|
async stats() {
|
|
14355
|
+
if (this.destroyed) {
|
|
14356
|
+
return { totalEntries: 0, bySource: {} };
|
|
14357
|
+
}
|
|
14349
14358
|
const contexts = await this.list();
|
|
14350
14359
|
const bySource = {};
|
|
14351
14360
|
for (const context of contexts) {
|
|
@@ -14358,6 +14367,12 @@ var ConversationContextStore = class {
|
|
|
14358
14367
|
newestEntry: contexts[0]?.timestamp
|
|
14359
14368
|
};
|
|
14360
14369
|
}
|
|
14370
|
+
/**
|
|
14371
|
+
* Destroy store (prevent further I/O)
|
|
14372
|
+
*/
|
|
14373
|
+
destroy() {
|
|
14374
|
+
this.destroyed = true;
|
|
14375
|
+
}
|
|
14361
14376
|
};
|
|
14362
14377
|
|
|
14363
14378
|
// src/mcp/tools/run-agent.ts
|
|
@@ -17134,7 +17149,7 @@ async function executeViaMcpPool(provider, agent, task, pool) {
|
|
|
17134
17149
|
pool.release(provider, client);
|
|
17135
17150
|
}
|
|
17136
17151
|
}
|
|
17137
|
-
async function executeViaCli(agent, task, actualProvider, no_memory, deps, isFallback) {
|
|
17152
|
+
async function executeViaCli(agent, task, actualProvider, no_memory, deps, isFallback, signal) {
|
|
17138
17153
|
const context = await deps.contextManager.createContext(agent, task, {
|
|
17139
17154
|
provider: actualProvider,
|
|
17140
17155
|
skipMemory: no_memory
|
|
@@ -17143,7 +17158,8 @@ async function executeViaCli(agent, task, actualProvider, no_memory, deps, isFal
|
|
|
17143
17158
|
const startTime = Date.now();
|
|
17144
17159
|
const result = await executor.execute(context, {
|
|
17145
17160
|
showProgress: false,
|
|
17146
|
-
verbose: false
|
|
17161
|
+
verbose: false,
|
|
17162
|
+
signal
|
|
17147
17163
|
});
|
|
17148
17164
|
const latencyMs = Date.now() - startTime;
|
|
17149
17165
|
const executionMode = isFallback ? "cli_fallback" : "cli_spawn";
|
|
@@ -17215,8 +17231,11 @@ async function buildAgentContext(agentName, task, deps, callerProvider, bestProv
|
|
|
17215
17231
|
};
|
|
17216
17232
|
}
|
|
17217
17233
|
function createRunAgentHandler(deps) {
|
|
17218
|
-
return async (input) => {
|
|
17234
|
+
return async (input, context) => {
|
|
17219
17235
|
const { agent, task, provider, no_memory, mode = "auto" } = input;
|
|
17236
|
+
if (context?.signal?.aborted) {
|
|
17237
|
+
throw new Error("Request was cancelled");
|
|
17238
|
+
}
|
|
17220
17239
|
validateAgentName(agent);
|
|
17221
17240
|
validateStringParameter(task, "task", {
|
|
17222
17241
|
required: true,
|
|
@@ -17243,6 +17262,9 @@ function createRunAgentHandler(deps) {
|
|
|
17243
17262
|
bestProvider = selectedProvider?.name || "claude-code";
|
|
17244
17263
|
}
|
|
17245
17264
|
const shouldReturnContext = mode === "context" || mode === "auto" && callerActual === bestProvider && callerProvider !== "unknown";
|
|
17265
|
+
if (context?.signal?.aborted) {
|
|
17266
|
+
throw new Error("Request was cancelled");
|
|
17267
|
+
}
|
|
17246
17268
|
logger.info("[Smart Routing] Decision", {
|
|
17247
17269
|
mode,
|
|
17248
17270
|
callerProvider,
|
|
@@ -17277,6 +17299,7 @@ function createRunAgentHandler(deps) {
|
|
|
17277
17299
|
const shouldTryMcp = !!deps.mcpPool;
|
|
17278
17300
|
if (shouldTryMcp && deps.mcpPool) {
|
|
17279
17301
|
try {
|
|
17302
|
+
if (context?.signal?.aborted) throw new Error("Request was cancelled");
|
|
17280
17303
|
const result = await executeViaMcpPool(
|
|
17281
17304
|
bestProvider,
|
|
17282
17305
|
agent,
|
|
@@ -17306,7 +17329,10 @@ function createRunAgentHandler(deps) {
|
|
|
17306
17329
|
}
|
|
17307
17330
|
}
|
|
17308
17331
|
try {
|
|
17309
|
-
|
|
17332
|
+
if (context?.signal?.aborted) {
|
|
17333
|
+
throw new Error("Request was cancelled");
|
|
17334
|
+
}
|
|
17335
|
+
const result = await executeViaCli(agent, task, actualProvider, no_memory, deps, shouldTryMcp, context?.signal);
|
|
17310
17336
|
logger.info("[MCP] run_agent completed (CLI spawn mode)", {
|
|
17311
17337
|
agent,
|
|
17312
17338
|
latencyMs: result.latencyMs,
|
|
@@ -18574,6 +18600,11 @@ function compressWithInfo(payload, options = {}) {
|
|
|
18574
18600
|
init_esm_shims();
|
|
18575
18601
|
init_factory();
|
|
18576
18602
|
init_logger();
|
|
18603
|
+
var NATIVE_MODULE_ERROR_PATTERNS = [
|
|
18604
|
+
"NODE_MODULE_VERSION",
|
|
18605
|
+
"was compiled against a different Node.js version",
|
|
18606
|
+
"better_sqlite3.node"
|
|
18607
|
+
];
|
|
18577
18608
|
var DEFAULT_CONFIG3 = {
|
|
18578
18609
|
dbPath: ".automatosx/tasks/tasks.db",
|
|
18579
18610
|
maxPayloadBytes: 1024 * 1024,
|
|
@@ -18701,6 +18732,28 @@ var SQL = {
|
|
|
18701
18732
|
SELECT id FROM task_store WHERE payload_hash = ? AND status = 'completed' LIMIT 1
|
|
18702
18733
|
`
|
|
18703
18734
|
};
|
|
18735
|
+
function generateTaskId() {
|
|
18736
|
+
const timestamp = Date.now().toString(36);
|
|
18737
|
+
const random = randomBytes(4).toString("hex");
|
|
18738
|
+
return `task_${timestamp}${random}`;
|
|
18739
|
+
}
|
|
18740
|
+
function hashPayload(json) {
|
|
18741
|
+
return createHash("sha256").update(json).digest("hex").substring(0, 16);
|
|
18742
|
+
}
|
|
18743
|
+
function estimateEngine(type) {
|
|
18744
|
+
switch (type) {
|
|
18745
|
+
case "web_search":
|
|
18746
|
+
return "gemini";
|
|
18747
|
+
case "code_review":
|
|
18748
|
+
case "code_generation":
|
|
18749
|
+
return "claude";
|
|
18750
|
+
case "analysis":
|
|
18751
|
+
return "claude";
|
|
18752
|
+
case "custom":
|
|
18753
|
+
default:
|
|
18754
|
+
return "auto";
|
|
18755
|
+
}
|
|
18756
|
+
}
|
|
18704
18757
|
var TaskStore = class {
|
|
18705
18758
|
db;
|
|
18706
18759
|
config;
|
|
@@ -18761,15 +18814,15 @@ var TaskStore = class {
|
|
|
18761
18814
|
isCompressed = false;
|
|
18762
18815
|
compressionRatio = 1;
|
|
18763
18816
|
}
|
|
18764
|
-
const taskId =
|
|
18765
|
-
const payloadHash =
|
|
18817
|
+
const taskId = generateTaskId();
|
|
18818
|
+
const payloadHash = hashPayload(payloadJson);
|
|
18766
18819
|
const now = Date.now();
|
|
18767
18820
|
const ttlHours = Math.min(
|
|
18768
18821
|
validated.ttlHours ?? this.config.defaultTtlHours,
|
|
18769
18822
|
this.config.maxTtlHours
|
|
18770
18823
|
);
|
|
18771
18824
|
const expiresAt = now + ttlHours * 60 * 60 * 1e3;
|
|
18772
|
-
const estimatedEngine = validated.engine === "auto" ?
|
|
18825
|
+
const estimatedEngine = validated.engine === "auto" ? estimateEngine(validated.type) : validated.engine;
|
|
18773
18826
|
try {
|
|
18774
18827
|
this.stmtInsert.run({
|
|
18775
18828
|
id: taskId,
|
|
@@ -19112,31 +19165,6 @@ var TaskStore = class {
|
|
|
19112
19165
|
throw new TaskEngineError("TaskStore is closed", "STORE_ERROR");
|
|
19113
19166
|
}
|
|
19114
19167
|
}
|
|
19115
|
-
generateTaskId() {
|
|
19116
|
-
const timestamp = Date.now().toString(36);
|
|
19117
|
-
const random = randomBytes(4).toString("hex");
|
|
19118
|
-
return `task_${timestamp}${random}`;
|
|
19119
|
-
}
|
|
19120
|
-
hashPayload(json) {
|
|
19121
|
-
return createHash("sha256").update(json).digest("hex").substring(0, 16);
|
|
19122
|
-
}
|
|
19123
|
-
estimateEngine(type) {
|
|
19124
|
-
switch (type) {
|
|
19125
|
-
case "web_search":
|
|
19126
|
-
return "gemini";
|
|
19127
|
-
// Gemini is good for web search
|
|
19128
|
-
case "code_review":
|
|
19129
|
-
case "code_generation":
|
|
19130
|
-
return "claude";
|
|
19131
|
-
// Claude is good for code
|
|
19132
|
-
case "analysis":
|
|
19133
|
-
return "claude";
|
|
19134
|
-
// Claude is good for analysis
|
|
19135
|
-
case "custom":
|
|
19136
|
-
default:
|
|
19137
|
-
return "auto";
|
|
19138
|
-
}
|
|
19139
|
-
}
|
|
19140
19168
|
rowToTask(row) {
|
|
19141
19169
|
let payload;
|
|
19142
19170
|
try {
|
|
@@ -19203,8 +19231,248 @@ var TaskStore = class {
|
|
|
19203
19231
|
};
|
|
19204
19232
|
}
|
|
19205
19233
|
};
|
|
19234
|
+
var InMemoryTaskStore = class {
|
|
19235
|
+
tasks = /* @__PURE__ */ new Map();
|
|
19236
|
+
config;
|
|
19237
|
+
closed = false;
|
|
19238
|
+
constructor(config = {}) {
|
|
19239
|
+
this.config = { ...DEFAULT_CONFIG3, ...config };
|
|
19240
|
+
logger.warn("Using in-memory task store fallback (SQLite unavailable)", {
|
|
19241
|
+
nodeVersion: process.version
|
|
19242
|
+
});
|
|
19243
|
+
}
|
|
19244
|
+
createTask(input) {
|
|
19245
|
+
this.ensureOpen();
|
|
19246
|
+
const validated = CreateTaskInputSchema.parse(input);
|
|
19247
|
+
const payloadJson = JSON.stringify(validated.payload);
|
|
19248
|
+
const payloadSize = Buffer.byteLength(payloadJson, "utf-8");
|
|
19249
|
+
if (payloadSize > this.config.maxPayloadBytes) {
|
|
19250
|
+
throw new TaskEngineError(
|
|
19251
|
+
`Payload size ${payloadSize} exceeds limit ${this.config.maxPayloadBytes}`,
|
|
19252
|
+
"PAYLOAD_TOO_LARGE",
|
|
19253
|
+
{ payloadSize, limit: this.config.maxPayloadBytes }
|
|
19254
|
+
);
|
|
19255
|
+
}
|
|
19256
|
+
const id = generateTaskId();
|
|
19257
|
+
const now = Date.now();
|
|
19258
|
+
const ttlHours = Math.min(
|
|
19259
|
+
validated.ttlHours ?? this.config.defaultTtlHours,
|
|
19260
|
+
this.config.maxTtlHours
|
|
19261
|
+
);
|
|
19262
|
+
const expiresAt = now + ttlHours * 60 * 60 * 1e3;
|
|
19263
|
+
const estimatedEngine = validated.engine === "auto" ? estimateEngine(validated.type) : validated.engine;
|
|
19264
|
+
const task = {
|
|
19265
|
+
id,
|
|
19266
|
+
type: validated.type,
|
|
19267
|
+
status: "pending",
|
|
19268
|
+
engine: validated.engine === "auto" ? null : validated.engine,
|
|
19269
|
+
priority: validated.priority ?? 5,
|
|
19270
|
+
payload: validated.payload,
|
|
19271
|
+
payloadSize,
|
|
19272
|
+
result: null,
|
|
19273
|
+
context: {
|
|
19274
|
+
originClient: validated.context?.originClient ?? "unknown",
|
|
19275
|
+
callChain: validated.context?.callChain ?? [],
|
|
19276
|
+
depth: validated.context?.depth ?? 0
|
|
19277
|
+
},
|
|
19278
|
+
createdAt: now,
|
|
19279
|
+
startedAt: null,
|
|
19280
|
+
completedAt: null,
|
|
19281
|
+
expiresAt,
|
|
19282
|
+
metrics: null,
|
|
19283
|
+
error: null,
|
|
19284
|
+
retryCount: 0,
|
|
19285
|
+
payloadHash: hashPayload(payloadJson),
|
|
19286
|
+
compressionRatio: 1
|
|
19287
|
+
};
|
|
19288
|
+
this.tasks.set(id, task);
|
|
19289
|
+
return {
|
|
19290
|
+
id,
|
|
19291
|
+
status: "pending",
|
|
19292
|
+
estimatedEngine: estimatedEngine ?? null,
|
|
19293
|
+
expiresAt,
|
|
19294
|
+
payloadSize,
|
|
19295
|
+
compressionRatio: 1
|
|
19296
|
+
};
|
|
19297
|
+
}
|
|
19298
|
+
getTask(taskId) {
|
|
19299
|
+
this.ensureOpen();
|
|
19300
|
+
const task = this.tasks.get(taskId);
|
|
19301
|
+
return task ? structuredClone(task) : null;
|
|
19302
|
+
}
|
|
19303
|
+
updateTaskStatus(taskId, status, error) {
|
|
19304
|
+
this.ensureOpen();
|
|
19305
|
+
const task = this.tasks.get(taskId);
|
|
19306
|
+
if (!task) {
|
|
19307
|
+
throw new TaskEngineError(`Task not found: ${taskId}`, "TASK_NOT_FOUND");
|
|
19308
|
+
}
|
|
19309
|
+
const now = Date.now();
|
|
19310
|
+
task.status = status;
|
|
19311
|
+
task.startedAt = status === "running" ? now : task.startedAt;
|
|
19312
|
+
if (status === "completed" || status === "failed") {
|
|
19313
|
+
task.completedAt = now;
|
|
19314
|
+
}
|
|
19315
|
+
task.error = error ?? null;
|
|
19316
|
+
}
|
|
19317
|
+
updateTaskResult(taskId, result, metrics) {
|
|
19318
|
+
this.ensureOpen();
|
|
19319
|
+
const task = this.tasks.get(taskId);
|
|
19320
|
+
if (!task) {
|
|
19321
|
+
throw new TaskEngineError(`Task not found: ${taskId}`, "TASK_NOT_FOUND");
|
|
19322
|
+
}
|
|
19323
|
+
task.status = "completed";
|
|
19324
|
+
task.result = result;
|
|
19325
|
+
task.metrics = {
|
|
19326
|
+
durationMs: metrics.durationMs ?? 0,
|
|
19327
|
+
tokensPrompt: metrics.tokensPrompt ?? null,
|
|
19328
|
+
tokensCompletion: metrics.tokensCompletion ?? null
|
|
19329
|
+
};
|
|
19330
|
+
task.completedAt = Date.now();
|
|
19331
|
+
task.error = null;
|
|
19332
|
+
}
|
|
19333
|
+
updateTaskFailed(taskId, error, durationMs) {
|
|
19334
|
+
this.ensureOpen();
|
|
19335
|
+
const task = this.tasks.get(taskId);
|
|
19336
|
+
if (!task) {
|
|
19337
|
+
throw new TaskEngineError(`Task not found: ${taskId}`, "TASK_NOT_FOUND");
|
|
19338
|
+
}
|
|
19339
|
+
task.status = "failed";
|
|
19340
|
+
task.error = error;
|
|
19341
|
+
task.metrics = task.metrics ?? {
|
|
19342
|
+
durationMs: durationMs ?? 0,
|
|
19343
|
+
tokensPrompt: null,
|
|
19344
|
+
tokensCompletion: null
|
|
19345
|
+
};
|
|
19346
|
+
task.completedAt = Date.now();
|
|
19347
|
+
}
|
|
19348
|
+
incrementRetry(taskId) {
|
|
19349
|
+
this.ensureOpen();
|
|
19350
|
+
const task = this.tasks.get(taskId);
|
|
19351
|
+
if (task) {
|
|
19352
|
+
task.retryCount += 1;
|
|
19353
|
+
}
|
|
19354
|
+
}
|
|
19355
|
+
deleteTask(taskId) {
|
|
19356
|
+
this.ensureOpen();
|
|
19357
|
+
return this.tasks.delete(taskId);
|
|
19358
|
+
}
|
|
19359
|
+
listTasks(filter = {}) {
|
|
19360
|
+
this.ensureOpen();
|
|
19361
|
+
const validated = TaskFilterSchema.parse(filter);
|
|
19362
|
+
const filtered = Array.from(this.tasks.values()).filter((task) => {
|
|
19363
|
+
if (validated.status && task.status !== validated.status) return false;
|
|
19364
|
+
if (validated.engine && task.engine !== validated.engine) return false;
|
|
19365
|
+
if (validated.type && task.type !== validated.type) return false;
|
|
19366
|
+
if (validated.originClient && task.context.originClient !== validated.originClient) return false;
|
|
19367
|
+
return true;
|
|
19368
|
+
});
|
|
19369
|
+
filtered.sort((a, b) => {
|
|
19370
|
+
if (a.priority !== b.priority) return b.priority - a.priority;
|
|
19371
|
+
return a.createdAt - b.createdAt;
|
|
19372
|
+
});
|
|
19373
|
+
const start = validated.offset ?? 0;
|
|
19374
|
+
const end = start + (validated.limit ?? 20);
|
|
19375
|
+
return filtered.slice(start, end).map((task) => structuredClone(task));
|
|
19376
|
+
}
|
|
19377
|
+
countTasks(filter = {}) {
|
|
19378
|
+
this.ensureOpen();
|
|
19379
|
+
const validated = TaskFilterSchema.parse(filter);
|
|
19380
|
+
return Array.from(this.tasks.values()).filter((task) => {
|
|
19381
|
+
if (validated.status && task.status !== validated.status) return false;
|
|
19382
|
+
if (validated.engine && task.engine !== validated.engine) return false;
|
|
19383
|
+
if (validated.type && task.type !== validated.type) return false;
|
|
19384
|
+
if (validated.originClient && task.context.originClient !== validated.originClient) return false;
|
|
19385
|
+
return true;
|
|
19386
|
+
}).length;
|
|
19387
|
+
}
|
|
19388
|
+
findByPayloadHash(payloadHash) {
|
|
19389
|
+
this.ensureOpen();
|
|
19390
|
+
for (const task of this.tasks.values()) {
|
|
19391
|
+
if (task.status === "completed" && task.payloadHash === payloadHash) {
|
|
19392
|
+
return task.id;
|
|
19393
|
+
}
|
|
19394
|
+
}
|
|
19395
|
+
return null;
|
|
19396
|
+
}
|
|
19397
|
+
cleanupExpired() {
|
|
19398
|
+
this.ensureOpen();
|
|
19399
|
+
const now = Date.now();
|
|
19400
|
+
let removed = 0;
|
|
19401
|
+
for (const [id, task] of this.tasks) {
|
|
19402
|
+
if (task.expiresAt < now && task.status !== "running") {
|
|
19403
|
+
this.tasks.delete(id);
|
|
19404
|
+
removed++;
|
|
19405
|
+
}
|
|
19406
|
+
}
|
|
19407
|
+
return removed;
|
|
19408
|
+
}
|
|
19409
|
+
cleanupZombieRunning() {
|
|
19410
|
+
this.ensureOpen();
|
|
19411
|
+
const now = Date.now();
|
|
19412
|
+
let converted = 0;
|
|
19413
|
+
for (const task of this.tasks.values()) {
|
|
19414
|
+
if (task.status === "running" && task.expiresAt < now) {
|
|
19415
|
+
task.status = "failed";
|
|
19416
|
+
task.error = {
|
|
19417
|
+
code: "ZOMBIE_TASK",
|
|
19418
|
+
message: "Task was stuck in running state past expiry"
|
|
19419
|
+
};
|
|
19420
|
+
task.completedAt = now;
|
|
19421
|
+
converted++;
|
|
19422
|
+
}
|
|
19423
|
+
}
|
|
19424
|
+
return converted;
|
|
19425
|
+
}
|
|
19426
|
+
cleanupAll() {
|
|
19427
|
+
const zombies = this.cleanupZombieRunning();
|
|
19428
|
+
const expired = this.cleanupExpired();
|
|
19429
|
+
return { expired, zombies };
|
|
19430
|
+
}
|
|
19431
|
+
getStats() {
|
|
19432
|
+
this.ensureOpen();
|
|
19433
|
+
const byStatus = {
|
|
19434
|
+
pending: 0,
|
|
19435
|
+
running: 0,
|
|
19436
|
+
completed: 0,
|
|
19437
|
+
failed: 0,
|
|
19438
|
+
expired: 0
|
|
19439
|
+
};
|
|
19440
|
+
for (const task of this.tasks.values()) {
|
|
19441
|
+
byStatus[task.status]++;
|
|
19442
|
+
}
|
|
19443
|
+
return {
|
|
19444
|
+
totalTasks: this.tasks.size,
|
|
19445
|
+
byStatus,
|
|
19446
|
+
dbSizeBytes: 0
|
|
19447
|
+
};
|
|
19448
|
+
}
|
|
19449
|
+
close() {
|
|
19450
|
+
this.closed = true;
|
|
19451
|
+
}
|
|
19452
|
+
ensureOpen() {
|
|
19453
|
+
if (this.closed) {
|
|
19454
|
+
throw new TaskEngineError("TaskStore is closed", "STORE_ERROR");
|
|
19455
|
+
}
|
|
19456
|
+
}
|
|
19457
|
+
};
|
|
19458
|
+
function isNativeModuleError(error) {
|
|
19459
|
+
if (!(error instanceof Error)) return false;
|
|
19460
|
+
const message = error.message ?? "";
|
|
19461
|
+
return NATIVE_MODULE_ERROR_PATTERNS.some((pattern) => message.includes(pattern));
|
|
19462
|
+
}
|
|
19206
19463
|
function createTaskStore(config) {
|
|
19207
|
-
|
|
19464
|
+
try {
|
|
19465
|
+
return new TaskStore(config);
|
|
19466
|
+
} catch (error) {
|
|
19467
|
+
if (isNativeModuleError(error)) {
|
|
19468
|
+
logger.warn("Falling back to in-memory task store (native SQLite unavailable)", {
|
|
19469
|
+
nodeVersion: process.version,
|
|
19470
|
+
error: error instanceof Error ? error.message : String(error)
|
|
19471
|
+
});
|
|
19472
|
+
return new InMemoryTaskStore(config);
|
|
19473
|
+
}
|
|
19474
|
+
throw error;
|
|
19475
|
+
}
|
|
19208
19476
|
}
|
|
19209
19477
|
|
|
19210
19478
|
// src/core/task-engine/engine.ts
|
|
@@ -19295,6 +19563,9 @@ var TaskEngine = class extends EventEmitter {
|
|
|
19295
19563
|
if (!task) {
|
|
19296
19564
|
throw new TaskEngineError(`Task not found: ${taskId}`, "TASK_NOT_FOUND");
|
|
19297
19565
|
}
|
|
19566
|
+
if (options.abortSignal?.aborted) {
|
|
19567
|
+
throw new TaskEngineError("Task execution aborted", "EXECUTION_TIMEOUT");
|
|
19568
|
+
}
|
|
19298
19569
|
if (task.status === "running") {
|
|
19299
19570
|
throw new TaskEngineError(
|
|
19300
19571
|
`Task is already running: ${taskId}`,
|
|
@@ -19460,6 +19731,14 @@ var TaskEngine = class extends EventEmitter {
|
|
|
19460
19731
|
async executeTask(task, targetEngine, context, options) {
|
|
19461
19732
|
const taskId = task.id;
|
|
19462
19733
|
const abortController = new AbortController();
|
|
19734
|
+
let externalCancelled = false;
|
|
19735
|
+
const externalAbort = options.abortSignal ? () => {
|
|
19736
|
+
externalCancelled = true;
|
|
19737
|
+
abortController.abort();
|
|
19738
|
+
} : null;
|
|
19739
|
+
if (options.abortSignal && externalAbort) {
|
|
19740
|
+
options.abortSignal.addEventListener("abort", externalAbort, { once: true });
|
|
19741
|
+
}
|
|
19463
19742
|
const startTime = Date.now();
|
|
19464
19743
|
this.runningTasks.set(taskId, abortController);
|
|
19465
19744
|
this.store.updateTaskStatus(taskId, "running");
|
|
@@ -19500,7 +19779,7 @@ var TaskEngine = class extends EventEmitter {
|
|
|
19500
19779
|
const durationMs = Date.now() - startTime;
|
|
19501
19780
|
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
19502
19781
|
if (abortController.signal.aborted) {
|
|
19503
|
-
const taskError2 = { code: "TIMEOUT", message: `Task timed out after ${timeoutMs}ms` };
|
|
19782
|
+
const taskError2 = externalCancelled ? { code: "CANCELLED", message: "Task was cancelled by caller" } : { code: "TIMEOUT", message: `Task timed out after ${timeoutMs}ms` };
|
|
19504
19783
|
this.store.updateTaskFailed(taskId, taskError2, durationMs);
|
|
19505
19784
|
this.stats.failed++;
|
|
19506
19785
|
this.emit("task:failed", taskId, new TaskEngineError(taskError2.message, "EXECUTION_TIMEOUT"));
|
|
@@ -19534,6 +19813,9 @@ var TaskEngine = class extends EventEmitter {
|
|
|
19534
19813
|
} finally {
|
|
19535
19814
|
clearTimeout(timeoutId);
|
|
19536
19815
|
this.runningTasks.delete(taskId);
|
|
19816
|
+
if (options.abortSignal && externalAbort) {
|
|
19817
|
+
options.abortSignal.removeEventListener("abort", externalAbort);
|
|
19818
|
+
}
|
|
19537
19819
|
}
|
|
19538
19820
|
}
|
|
19539
19821
|
async executeWithRetry(task, engine, context, signal) {
|
|
@@ -19838,8 +20120,11 @@ var createTaskSchema = {
|
|
|
19838
20120
|
init_esm_shims();
|
|
19839
20121
|
init_logger();
|
|
19840
20122
|
function createRunTaskHandler(deps) {
|
|
19841
|
-
return async (input) => {
|
|
20123
|
+
return async (input, context) => {
|
|
19842
20124
|
const startTime = Date.now();
|
|
20125
|
+
if (context?.signal?.aborted) {
|
|
20126
|
+
throw new Error("Request was cancelled");
|
|
20127
|
+
}
|
|
19843
20128
|
logger.info("[run_task] Executing task", {
|
|
19844
20129
|
taskId: input.task_id,
|
|
19845
20130
|
engineOverride: input.engine_override,
|
|
@@ -19852,7 +20137,8 @@ function createRunTaskHandler(deps) {
|
|
|
19852
20137
|
const options = {
|
|
19853
20138
|
engineOverride: input.engine_override,
|
|
19854
20139
|
timeoutMs: input.timeout_ms,
|
|
19855
|
-
skipCache: input.skip_cache
|
|
20140
|
+
skipCache: input.skip_cache,
|
|
20141
|
+
abortSignal: context?.signal
|
|
19856
20142
|
};
|
|
19857
20143
|
const result = await taskEngine.runTask(input.task_id, options);
|
|
19858
20144
|
const output = {
|
|
@@ -22178,6 +22464,10 @@ var McpServer = class _McpServer {
|
|
|
22178
22464
|
version;
|
|
22179
22465
|
ajv;
|
|
22180
22466
|
compiledValidators = /* @__PURE__ */ new Map();
|
|
22467
|
+
cancelledRequests = /* @__PURE__ */ new Set();
|
|
22468
|
+
// Track client-initiated cancellations
|
|
22469
|
+
requestControllers = /* @__PURE__ */ new Map();
|
|
22470
|
+
// Abort long-running handlers
|
|
22181
22471
|
// v10.5.0: MCP Session for Smart Routing
|
|
22182
22472
|
session = null;
|
|
22183
22473
|
// v10.6.0: MCP Client Pool for cross-provider execution
|
|
@@ -22456,6 +22746,16 @@ Use this tool first to understand what AutomatosX offers.`,
|
|
|
22456
22746
|
if (this.streamingNotifier) {
|
|
22457
22747
|
this.streamingNotifier.stop();
|
|
22458
22748
|
}
|
|
22749
|
+
if (this.router) {
|
|
22750
|
+
this.router.destroy();
|
|
22751
|
+
}
|
|
22752
|
+
this.requestControllers.clear();
|
|
22753
|
+
if (this.sessionManager) {
|
|
22754
|
+
await this.sessionManager.destroy();
|
|
22755
|
+
}
|
|
22756
|
+
if (this.contextStore) {
|
|
22757
|
+
this.contextStore.destroy();
|
|
22758
|
+
}
|
|
22459
22759
|
if (this.eventBridge) {
|
|
22460
22760
|
this.eventBridge.destroy();
|
|
22461
22761
|
}
|
|
@@ -22573,6 +22873,12 @@ Use this tool first to understand what AutomatosX offers.`,
|
|
|
22573
22873
|
return this.handleToolsList(request, responseId);
|
|
22574
22874
|
case "tools/call":
|
|
22575
22875
|
return await this.handleToolCall(request, responseId);
|
|
22876
|
+
case "resources/list":
|
|
22877
|
+
return await this.handleResourcesList(request, responseId);
|
|
22878
|
+
case "resources/read":
|
|
22879
|
+
return await this.handleResourceRead(request, responseId);
|
|
22880
|
+
case "$/cancelRequest":
|
|
22881
|
+
return this.handleCancelRequest(request, responseId);
|
|
22576
22882
|
default:
|
|
22577
22883
|
return this.createErrorResponse(responseId, -32601 /* MethodNotFound */, `Method not found: ${method}`);
|
|
22578
22884
|
}
|
|
@@ -22628,6 +22934,48 @@ Use this tool first to understand what AutomatosX offers.`,
|
|
|
22628
22934
|
const tools = _McpServer.getStaticToolSchemas();
|
|
22629
22935
|
return { jsonrpc: "2.0", id, result: { tools } };
|
|
22630
22936
|
}
|
|
22937
|
+
/**
|
|
22938
|
+
* Handle resources/list request (exposes agent profiles as MCP resources)
|
|
22939
|
+
*/
|
|
22940
|
+
async handleResourcesList(_request, id) {
|
|
22941
|
+
await this.ensureInitialized();
|
|
22942
|
+
const agents = await this.profileLoader.listProfiles();
|
|
22943
|
+
const resources = agents.map((agent) => ({
|
|
22944
|
+
uri: `agent/${agent}`,
|
|
22945
|
+
name: `Agent: ${agent}`,
|
|
22946
|
+
description: `AutomatosX agent profile for ${agent}`,
|
|
22947
|
+
mimeType: "text/markdown"
|
|
22948
|
+
}));
|
|
22949
|
+
return { jsonrpc: "2.0", id, result: { resources } };
|
|
22950
|
+
}
|
|
22951
|
+
/**
|
|
22952
|
+
* Handle resources/read request
|
|
22953
|
+
*/
|
|
22954
|
+
async handleResourceRead(request, id) {
|
|
22955
|
+
await this.ensureInitialized();
|
|
22956
|
+
const uri = request.params?.uri;
|
|
22957
|
+
if (!uri || !uri.startsWith("agent/")) {
|
|
22958
|
+
return this.createErrorResponse(id, -32602 /* InvalidParams */, "Invalid resource URI. Expected agent/{name}.");
|
|
22959
|
+
}
|
|
22960
|
+
const agentName = uri.replace("agent/", "");
|
|
22961
|
+
try {
|
|
22962
|
+
const profile = await this.profileLoader.loadProfile(agentName);
|
|
22963
|
+
const summary = [
|
|
22964
|
+
`# ${agentName}`,
|
|
22965
|
+
profile.role ? `**Role:** ${profile.role}` : "",
|
|
22966
|
+
profile.abilities?.length ? `**Abilities:** ${profile.abilities.join(", ")}` : "",
|
|
22967
|
+
"",
|
|
22968
|
+
profile.systemPrompt || "No system prompt defined."
|
|
22969
|
+
].filter(Boolean).join("\n");
|
|
22970
|
+
const contents = [
|
|
22971
|
+
{ type: "text", text: summary },
|
|
22972
|
+
{ type: "application/json", json: profile }
|
|
22973
|
+
];
|
|
22974
|
+
return { jsonrpc: "2.0", id, result: { uri, mimeType: "text/markdown", contents } };
|
|
22975
|
+
} catch (error) {
|
|
22976
|
+
return this.createErrorResponse(id, -32603 /* InternalError */, `Failed to read resource: ${error.message}`);
|
|
22977
|
+
}
|
|
22978
|
+
}
|
|
22631
22979
|
/**
|
|
22632
22980
|
* Validate tool input against its JSON schema.
|
|
22633
22981
|
* Returns null if valid, or error message string if invalid.
|
|
@@ -22639,10 +22987,34 @@ Use this tool first to understand what AutomatosX offers.`,
|
|
|
22639
22987
|
return this.ajv.errorsText(validate.errors);
|
|
22640
22988
|
}
|
|
22641
22989
|
/** Create MCP tool response wrapper */
|
|
22642
|
-
createToolResponse(id,
|
|
22643
|
-
|
|
22990
|
+
createToolResponse(id, result, isError = false) {
|
|
22991
|
+
let content;
|
|
22992
|
+
if (typeof result === "string") {
|
|
22993
|
+
content = [{ type: "text", text: result }];
|
|
22994
|
+
} else {
|
|
22995
|
+
content = [
|
|
22996
|
+
{ type: "application/json", json: result },
|
|
22997
|
+
{ type: "text", text: JSON.stringify(result, null, 2) }
|
|
22998
|
+
];
|
|
22999
|
+
}
|
|
23000
|
+
const response = { content, ...isError && { isError } };
|
|
22644
23001
|
return { jsonrpc: "2.0", id, result: response };
|
|
22645
23002
|
}
|
|
23003
|
+
/**
|
|
23004
|
+
* Handle client cancellation ($/cancelRequest)
|
|
23005
|
+
*/
|
|
23006
|
+
handleCancelRequest(request, id) {
|
|
23007
|
+
const params = request.params;
|
|
23008
|
+
const cancelId = params?.id ?? params?.requestId;
|
|
23009
|
+
if (cancelId === void 0 || cancelId === null) {
|
|
23010
|
+
return this.createErrorResponse(id, -32602 /* InvalidParams */, "cancelRequest requires an id to cancel");
|
|
23011
|
+
}
|
|
23012
|
+
this.cancelledRequests.add(cancelId);
|
|
23013
|
+
logger.info("[MCP Server] Cancellation requested", { cancelId });
|
|
23014
|
+
const controller = this.requestControllers.get(cancelId);
|
|
23015
|
+
controller?.abort();
|
|
23016
|
+
return { jsonrpc: "2.0", id, result: null };
|
|
23017
|
+
}
|
|
22646
23018
|
/**
|
|
22647
23019
|
* Ensure services are initialized (lazy initialization on first call)
|
|
22648
23020
|
* OPTIMIZATION (v10.3.1): Moves 15-20s initialization from handshake to first request
|
|
@@ -22677,6 +23049,16 @@ Use this tool first to understand what AutomatosX offers.`,
|
|
|
22677
23049
|
async handleToolCall(request, id) {
|
|
22678
23050
|
const { name, arguments: args2 } = request.params;
|
|
22679
23051
|
logger.info("[MCP Server] Tool call", { tool: name });
|
|
23052
|
+
const requestId = id ?? null;
|
|
23053
|
+
const abortController = requestId !== null ? new AbortController() : null;
|
|
23054
|
+
if (requestId !== null && abortController) {
|
|
23055
|
+
this.requestControllers.set(requestId, abortController);
|
|
23056
|
+
}
|
|
23057
|
+
if (requestId !== null && this.cancelledRequests.has(requestId)) {
|
|
23058
|
+
this.cancelledRequests.delete(requestId);
|
|
23059
|
+
this.requestControllers.delete(requestId);
|
|
23060
|
+
return this.createErrorResponse(requestId, -32800 /* RequestCancelled */, "Request was cancelled");
|
|
23061
|
+
}
|
|
22680
23062
|
await this.ensureInitialized();
|
|
22681
23063
|
const handler = this.tools.get(name);
|
|
22682
23064
|
if (!handler) {
|
|
@@ -22687,11 +23069,27 @@ Use this tool first to understand what AutomatosX offers.`,
|
|
|
22687
23069
|
return this.createErrorResponse(id, -32602 /* InvalidParams */, validationError);
|
|
22688
23070
|
}
|
|
22689
23071
|
try {
|
|
22690
|
-
const result = await handler(args2 || {});
|
|
22691
|
-
|
|
23072
|
+
const result = await handler(args2 || {}, { signal: abortController?.signal });
|
|
23073
|
+
if (requestId !== null && this.cancelledRequests.has(requestId)) {
|
|
23074
|
+
this.cancelledRequests.delete(requestId);
|
|
23075
|
+
this.requestControllers.delete(requestId);
|
|
23076
|
+
return this.createErrorResponse(requestId, -32800 /* RequestCancelled */, "Request was cancelled");
|
|
23077
|
+
}
|
|
23078
|
+
return this.createToolResponse(id, result);
|
|
22692
23079
|
} catch (error) {
|
|
23080
|
+
const err = error;
|
|
23081
|
+
const cancelled = err?.name === "AbortError" || err?.message?.toLowerCase().includes("cancel");
|
|
23082
|
+
if (cancelled) {
|
|
23083
|
+
logger.info("[MCP Server] Tool execution cancelled", { tool: name, id: requestId ?? void 0 });
|
|
23084
|
+
return this.createErrorResponse(id, -32800 /* RequestCancelled */, "Request was cancelled");
|
|
23085
|
+
}
|
|
22693
23086
|
logger.error("[MCP Server] Tool execution failed", { tool: name, error });
|
|
22694
|
-
return this.createToolResponse(id, `Error: ${error
|
|
23087
|
+
return this.createToolResponse(id, `Error: ${err?.message ?? String(error)}`, true);
|
|
23088
|
+
} finally {
|
|
23089
|
+
if (requestId !== null) {
|
|
23090
|
+
this.cancelledRequests.delete(requestId);
|
|
23091
|
+
this.requestControllers.delete(requestId);
|
|
23092
|
+
}
|
|
22695
23093
|
}
|
|
22696
23094
|
}
|
|
22697
23095
|
/**
|
|
@@ -22701,26 +23099,34 @@ Use this tool first to understand what AutomatosX offers.`,
|
|
|
22701
23099
|
return { jsonrpc: "2.0", id, error: { code, message } };
|
|
22702
23100
|
}
|
|
22703
23101
|
/**
|
|
22704
|
-
* Write MCP-compliant response
|
|
23102
|
+
* Write MCP-compliant response using newline-delimited framing
|
|
23103
|
+
*
|
|
23104
|
+
* v12.2.0: Changed from Content-Length to newline-delimited framing
|
|
23105
|
+
* per official MCP specification: https://spec.modelcontextprotocol.io/specification/basic/transports/
|
|
23106
|
+
*
|
|
23107
|
+
* Format: JSON message followed by newline character
|
|
23108
|
+
* Reference: @modelcontextprotocol/sdk serializeMessage() uses: JSON.stringify(message) + '\n'
|
|
22705
23109
|
*/
|
|
22706
23110
|
writeResponse(response) {
|
|
22707
23111
|
const json = JSON.stringify(response);
|
|
22708
|
-
|
|
22709
|
-
|
|
22710
|
-
\r
|
|
22711
|
-
${json}`;
|
|
22712
|
-
process.stdout.write(message);
|
|
22713
|
-
logger.debug("[MCP Server] Response sent", { id: response.id, contentLength });
|
|
23112
|
+
process.stdout.write(json + "\n");
|
|
23113
|
+
logger.debug("[MCP Server] Response sent", { id: response.id, length: json.length });
|
|
22714
23114
|
}
|
|
22715
23115
|
/**
|
|
22716
|
-
* Start stdio server with
|
|
23116
|
+
* Start stdio server with newline-delimited framing
|
|
23117
|
+
*
|
|
23118
|
+
* v12.2.0: Changed from Content-Length to newline-delimited framing
|
|
23119
|
+
* per official MCP specification: https://spec.modelcontextprotocol.io/specification/basic/transports/
|
|
23120
|
+
*
|
|
23121
|
+
* Format: Each JSON-RPC message is terminated by a newline character.
|
|
23122
|
+
* Messages MUST NOT contain embedded newlines.
|
|
23123
|
+
* Reference: @modelcontextprotocol/sdk ReadBuffer uses: buffer.indexOf('\n')
|
|
22717
23124
|
*
|
|
22718
23125
|
* BUG FIX (v9.0.1): Added iteration limit and buffer size checks to prevent infinite loops
|
|
22719
23126
|
*/
|
|
22720
23127
|
async start() {
|
|
22721
23128
|
logger.info("[MCP Server] Starting stdio JSON-RPC server...");
|
|
22722
23129
|
let buffer = "";
|
|
22723
|
-
let contentLength = null;
|
|
22724
23130
|
process.stdin.on("data", (chunk) => {
|
|
22725
23131
|
void this.stdinMutex.runExclusive(async () => {
|
|
22726
23132
|
buffer += chunk.toString("utf-8");
|
|
@@ -22730,49 +23136,34 @@ ${json}`;
|
|
|
22730
23136
|
maxSize: STDIO_MAX_BUFFER_SIZE
|
|
22731
23137
|
});
|
|
22732
23138
|
buffer = "";
|
|
22733
|
-
contentLength = null;
|
|
22734
23139
|
return;
|
|
22735
23140
|
}
|
|
22736
23141
|
let iterations = 0;
|
|
22737
23142
|
while (iterations < STDIO_MAX_ITERATIONS) {
|
|
22738
23143
|
iterations++;
|
|
22739
|
-
|
|
22740
|
-
|
|
22741
|
-
|
|
22742
|
-
|
|
22743
|
-
|
|
22744
|
-
|
|
22745
|
-
|
|
22746
|
-
|
|
22747
|
-
|
|
22748
|
-
|
|
22749
|
-
|
|
22750
|
-
|
|
22751
|
-
|
|
22752
|
-
|
|
22753
|
-
|
|
22754
|
-
|
|
22755
|
-
|
|
22756
|
-
|
|
22757
|
-
|
|
22758
|
-
buffer = buffer.slice(headerEndIndex + delimiter2.length);
|
|
22759
|
-
contentLength = null;
|
|
22760
|
-
continue;
|
|
22761
|
-
}
|
|
23144
|
+
const newlineIndex = buffer.indexOf("\n");
|
|
23145
|
+
if (newlineIndex === -1) break;
|
|
23146
|
+
let jsonMessage = buffer.slice(0, newlineIndex);
|
|
23147
|
+
if (jsonMessage.endsWith("\r")) {
|
|
23148
|
+
jsonMessage = jsonMessage.slice(0, -1);
|
|
23149
|
+
}
|
|
23150
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
23151
|
+
if (jsonMessage.trim() === "") continue;
|
|
23152
|
+
if (jsonMessage.length > STDIO_MAX_MESSAGE_SIZE) {
|
|
23153
|
+
logger.error("[MCP Server] Message size exceeded maximum", {
|
|
23154
|
+
messageSize: jsonMessage.length,
|
|
23155
|
+
maxSize: STDIO_MAX_MESSAGE_SIZE
|
|
23156
|
+
});
|
|
23157
|
+
this.writeResponse({
|
|
23158
|
+
jsonrpc: "2.0",
|
|
23159
|
+
id: null,
|
|
23160
|
+
error: {
|
|
23161
|
+
code: -32600 /* InvalidRequest */,
|
|
23162
|
+
message: `Message too large: ${jsonMessage.length} bytes`
|
|
22762
23163
|
}
|
|
22763
|
-
}
|
|
22764
|
-
|
|
22765
|
-
logger.error("[MCP Server] No Content-Length header found");
|
|
22766
|
-
buffer = buffer.slice(headerEndIndex + delimiter2.length);
|
|
22767
|
-
continue;
|
|
22768
|
-
}
|
|
22769
|
-
buffer = buffer.slice(headerEndIndex + delimiter2.length);
|
|
23164
|
+
});
|
|
23165
|
+
continue;
|
|
22770
23166
|
}
|
|
22771
|
-
if (Buffer.byteLength(buffer, "utf-8") < contentLength) break;
|
|
22772
|
-
const messageBuffer = Buffer.from(buffer, "utf-8");
|
|
22773
|
-
const jsonMessage = messageBuffer.slice(0, contentLength).toString("utf-8");
|
|
22774
|
-
buffer = messageBuffer.slice(contentLength).toString("utf-8");
|
|
22775
|
-
contentLength = null;
|
|
22776
23167
|
try {
|
|
22777
23168
|
const request = JSON.parse(jsonMessage);
|
|
22778
23169
|
logger.debug("[MCP Server] Request received", { method: request.method, id: request.id });
|
|
@@ -22781,7 +23172,7 @@ ${json}`;
|
|
|
22781
23172
|
this.writeResponse(response);
|
|
22782
23173
|
}
|
|
22783
23174
|
} catch (error) {
|
|
22784
|
-
logger.error("[MCP Server] Failed to parse or handle request", {
|
|
23175
|
+
logger.error("[MCP Server] Failed to parse or handle request", { error: error.message });
|
|
22785
23176
|
this.writeResponse({ jsonrpc: "2.0", id: null, error: { code: -32700 /* ParseError */, message: "Parse error: Invalid JSON" } });
|
|
22786
23177
|
}
|
|
22787
23178
|
}
|
|
@@ -22800,7 +23191,7 @@ ${json}`;
|
|
|
22800
23191
|
process.stdin.on("end", () => shutdown("Server stopped (stdin closed)"));
|
|
22801
23192
|
process.on("SIGINT", () => shutdown("Received SIGINT, shutting down..."));
|
|
22802
23193
|
process.on("SIGTERM", () => shutdown("Received SIGTERM, shutting down..."));
|
|
22803
|
-
logger.info("[MCP Server] Server started successfully (
|
|
23194
|
+
logger.info("[MCP Server] Server started successfully (newline-delimited framing)");
|
|
22804
23195
|
}
|
|
22805
23196
|
};
|
|
22806
23197
|
|