meshy-node 0.5.6 → 0.5.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/README.md +1 -1
- package/dashboard/assets/DashboardPage-Bj9xgByf.js +134 -0
- package/dashboard/assets/{DashboardShared-DMrNrARk.js → DashboardShared-DIeAyL9S.js} +2 -2
- package/dashboard/assets/{DiffTab-CPgg5BgU.js → DiffTab-CM2AQDYU.js} +3 -3
- package/dashboard/assets/{FilesTab-Bd6A8nUE.js → FilesTab-Dz_xKH9A.js} +7 -7
- package/dashboard/assets/{PreviewTab-kljCXeWP.js → PreviewTab-C_cXp7co.js} +2 -2
- package/dashboard/assets/SharedConversationPage-CA4HWgwT.js +7 -0
- package/dashboard/assets/{file-CPaJOnu-.js → file-Bxn4xj1r.js} +1 -1
- package/dashboard/assets/{folder-DgOi0nrN.js → folder-Cze4nFZO.js} +1 -1
- package/dashboard/assets/index-BlCzIaoB.css +1 -0
- package/dashboard/assets/{index-nG4cAWuh.js → index-DX2JBoPo.js} +62 -62
- package/dashboard/assets/{play-DQGsm6yq.js → play-BR1-G2AM.js} +1 -1
- package/dashboard/index.html +2 -2
- package/main.cjs +256 -68
- package/package.json +1 -1
- package/runtime-metadata.json +5 -5
- package/dashboard/assets/DashboardPage-BSAt8kN_.js +0 -129
- package/dashboard/assets/SharedConversationPage-DmcJdyZj.js +0 -7
- package/dashboard/assets/index-DgDWjVGo.css +0 -1
package/dashboard/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Meshy Dashboard</title>
|
|
7
7
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🕸</text></svg>" />
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DX2JBoPo.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BlCzIaoB.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/main.cjs
CHANGED
|
@@ -52275,6 +52275,7 @@ function normalizeDevBoxMetadata(devbox) {
|
|
|
52275
52275
|
locationInUri: normalizeString(devbox?.locationInUri),
|
|
52276
52276
|
poolName: normalizeString(devbox?.poolName),
|
|
52277
52277
|
scope: normalizeString(devbox?.scope),
|
|
52278
|
+
alwaysOnline: devbox?.alwaysOnline === true,
|
|
52278
52279
|
lastStatus: normalizeString(devbox?.lastStatus),
|
|
52279
52280
|
checkedAt: typeof devbox?.checkedAt === "number" && Number.isFinite(devbox.checkedAt) ? devbox.checkedAt : void 0,
|
|
52280
52281
|
operationId: normalizeString(devbox?.operationId)
|
|
@@ -52356,6 +52357,7 @@ function pickDevBoxConfig(devbox) {
|
|
|
52356
52357
|
if (devbox.locationInUri) subset.locationInUri = devbox.locationInUri;
|
|
52357
52358
|
if (devbox.poolName) subset.poolName = devbox.poolName;
|
|
52358
52359
|
if (devbox.scope) subset.scope = devbox.scope;
|
|
52360
|
+
if (devbox.alwaysOnline !== void 0) subset.alwaysOnline = devbox.alwaysOnline;
|
|
52359
52361
|
return subset;
|
|
52360
52362
|
}
|
|
52361
52363
|
function persistNodeStartupTransport(storagePath, transport) {
|
|
@@ -54039,6 +54041,7 @@ function getPublicTaskUpdates(updates, updatedAt) {
|
|
|
54039
54041
|
if (updates.description !== void 0) publicUpdates.description = updates.description;
|
|
54040
54042
|
if (updates.priority !== void 0) publicUpdates.priority = updates.priority;
|
|
54041
54043
|
if (updates.status !== void 0) publicUpdates.status = updates.status;
|
|
54044
|
+
if (updates.queuedMessages !== void 0) publicUpdates.queuedMessages = updates.queuedMessages;
|
|
54042
54045
|
if (updates.assignedTo !== void 0) publicUpdates.assignedTo = updates.assignedTo;
|
|
54043
54046
|
if (updates.assignedNodeName !== void 0) publicUpdates.assignedNodeName = updates.assignedNodeName;
|
|
54044
54047
|
if (updates.result !== void 0) publicUpdates.result = updates.result;
|
|
@@ -54221,6 +54224,61 @@ var TaskEngine = class {
|
|
|
54221
54224
|
});
|
|
54222
54225
|
return true;
|
|
54223
54226
|
}
|
|
54227
|
+
enqueueTaskMessage(taskId, content) {
|
|
54228
|
+
const task = this.store.getTask(taskId);
|
|
54229
|
+
if (!task) {
|
|
54230
|
+
throw new MeshyError("TASK_NOT_FOUND", `Task ${taskId} not found`, 404);
|
|
54231
|
+
}
|
|
54232
|
+
if (task.status !== "running") {
|
|
54233
|
+
throw new MeshyError(
|
|
54234
|
+
"VALIDATION_ERROR",
|
|
54235
|
+
`Task ${taskId} is not running (status: ${task.status})`,
|
|
54236
|
+
400
|
|
54237
|
+
);
|
|
54238
|
+
}
|
|
54239
|
+
const now = Date.now();
|
|
54240
|
+
const queuedMessages = [
|
|
54241
|
+
...task.queuedMessages ?? [],
|
|
54242
|
+
{ id: (0, import_node_crypto5.randomUUID)(), content, createdAt: now }
|
|
54243
|
+
];
|
|
54244
|
+
const updated = this.store.updateTask(taskId, { queuedMessages, updatedAt: now });
|
|
54245
|
+
this.eventBus.emit("task.updated", {
|
|
54246
|
+
taskId,
|
|
54247
|
+
updates: { queuedMessages, updatedAt: now }
|
|
54248
|
+
});
|
|
54249
|
+
return updated;
|
|
54250
|
+
}
|
|
54251
|
+
dequeueTaskMessage(taskId) {
|
|
54252
|
+
const task = this.store.getTask(taskId);
|
|
54253
|
+
if (!task) {
|
|
54254
|
+
throw new MeshyError("TASK_NOT_FOUND", `Task ${taskId} not found`, 404);
|
|
54255
|
+
}
|
|
54256
|
+
const [message, ...queuedMessages] = task.queuedMessages ?? [];
|
|
54257
|
+
if (!message) return null;
|
|
54258
|
+
const now = Date.now();
|
|
54259
|
+
const updated = this.store.updateTask(taskId, { queuedMessages, updatedAt: now });
|
|
54260
|
+
this.eventBus.emit("task.updated", {
|
|
54261
|
+
taskId,
|
|
54262
|
+
updates: { queuedMessages, updatedAt: now }
|
|
54263
|
+
});
|
|
54264
|
+
return { task: updated, message };
|
|
54265
|
+
}
|
|
54266
|
+
removeQueuedTaskMessage(taskId, messageId) {
|
|
54267
|
+
const task = this.store.getTask(taskId);
|
|
54268
|
+
if (!task) {
|
|
54269
|
+
throw new MeshyError("TASK_NOT_FOUND", `Task ${taskId} not found`, 404);
|
|
54270
|
+
}
|
|
54271
|
+
const currentQueue = task.queuedMessages ?? [];
|
|
54272
|
+
const queuedMessages = currentQueue.filter((message) => message.id !== messageId);
|
|
54273
|
+
if (queuedMessages.length === currentQueue.length) return null;
|
|
54274
|
+
const now = Date.now();
|
|
54275
|
+
const updated = this.store.updateTask(taskId, { queuedMessages, updatedAt: now });
|
|
54276
|
+
this.eventBus.emit("task.updated", {
|
|
54277
|
+
taskId,
|
|
54278
|
+
updates: { queuedMessages, updatedAt: now }
|
|
54279
|
+
});
|
|
54280
|
+
return updated;
|
|
54281
|
+
}
|
|
54224
54282
|
// ── Dispatch failure ─────────────────────────────────────────────────
|
|
54225
54283
|
/**
|
|
54226
54284
|
* Handle a dispatch failure for a task that is still in `assigned` status.
|
|
@@ -58240,6 +58298,7 @@ var NodeDevBoxInfoSchema = external_exports.object({
|
|
|
58240
58298
|
locationInUri: external_exports.string().optional(),
|
|
58241
58299
|
poolName: external_exports.string().optional(),
|
|
58242
58300
|
scope: external_exports.string().optional(),
|
|
58301
|
+
alwaysOnline: external_exports.boolean().optional(),
|
|
58243
58302
|
lastStatus: external_exports.string().optional(),
|
|
58244
58303
|
checkedAt: external_exports.number().optional(),
|
|
58245
58304
|
operationId: external_exports.string().optional()
|
|
@@ -58535,6 +58594,11 @@ var TaskListResponse = external_exports.object({
|
|
|
58535
58594
|
branch: external_exports.string().nullable().optional(),
|
|
58536
58595
|
conversationKind: external_exports.enum(TASK_CONVERSATION_KIND_OPTIONS).optional(),
|
|
58537
58596
|
payload: external_exports.record(external_exports.unknown()),
|
|
58597
|
+
queuedMessages: external_exports.array(external_exports.object({
|
|
58598
|
+
id: external_exports.string(),
|
|
58599
|
+
content: external_exports.array(external_exports.record(external_exports.unknown())).min(1),
|
|
58600
|
+
createdAt: external_exports.number()
|
|
58601
|
+
})).optional(),
|
|
58538
58602
|
status: external_exports.enum(["pending", "assigned", "running", "completed", "failed", "cancelled", "archived"]),
|
|
58539
58603
|
priority: external_exports.enum(["low", "normal", "high", "critical"]),
|
|
58540
58604
|
assignedTo: external_exports.string().nullable(),
|
|
@@ -58937,6 +59001,7 @@ var import_express = __toESM(require_express2(), 1);
|
|
|
58937
59001
|
var sharedMcpControl;
|
|
58938
59002
|
var DEFAULT_START_POLL_INTERVAL_MS = 1e4;
|
|
58939
59003
|
var DEFAULT_START_TIMEOUT_MS = 15 * 6e4;
|
|
59004
|
+
var ALWAYS_ONLINE_STARTABLE_DEVBOX_STATUSES = /* @__PURE__ */ new Set(["hibernated", "stopped"]);
|
|
58940
59005
|
function getDevBoxControl(deps) {
|
|
58941
59006
|
if (deps.devBoxControl) return deps.devBoxControl;
|
|
58942
59007
|
sharedMcpControl ??= new McpDevBoxControl(deps.logger);
|
|
@@ -58952,6 +59017,7 @@ function mergeDevBoxInfo(current, next) {
|
|
|
58952
59017
|
locationInUri: merged.locationInUri,
|
|
58953
59018
|
poolName: merged.poolName,
|
|
58954
59019
|
scope: merged.scope,
|
|
59020
|
+
alwaysOnline: merged.alwaysOnline,
|
|
58955
59021
|
lastStatus: merged.lastStatus,
|
|
58956
59022
|
checkedAt: merged.checkedAt,
|
|
58957
59023
|
operationId: merged.operationId
|
|
@@ -59022,7 +59088,14 @@ async function waitForNodeDevBoxRunning(deps, nodeId, initial, options) {
|
|
|
59022
59088
|
}
|
|
59023
59089
|
}
|
|
59024
59090
|
function isRunningDevBoxStatus(status) {
|
|
59025
|
-
return status
|
|
59091
|
+
return normalizeDevBoxStatus(status) === "running";
|
|
59092
|
+
}
|
|
59093
|
+
function isAlwaysOnlineStartableDevBoxStatus(status) {
|
|
59094
|
+
const normalized = normalizeDevBoxStatus(status);
|
|
59095
|
+
return Boolean(normalized && ALWAYS_ONLINE_STARTABLE_DEVBOX_STATUSES.has(normalized));
|
|
59096
|
+
}
|
|
59097
|
+
function normalizeDevBoxStatus(status) {
|
|
59098
|
+
return status?.trim().toLowerCase().replace(/[\s_-]+/gu, "");
|
|
59026
59099
|
}
|
|
59027
59100
|
function sleep(ms) {
|
|
59028
59101
|
return new Promise((resolve14) => {
|
|
@@ -63666,29 +63739,6 @@ async function cancelRemoteTaskExecution(deps) {
|
|
|
63666
63739
|
return response.ok ? null : response;
|
|
63667
63740
|
}
|
|
63668
63741
|
|
|
63669
|
-
// ../../packages/api/src/tasks/task-follow-up.ts
|
|
63670
|
-
function startLocalTaskFollowUp(deps, task, content, assignedTo, metadata) {
|
|
63671
|
-
const engine = deps.engineRegistry.get(task.agent);
|
|
63672
|
-
if (!engine) {
|
|
63673
|
-
throw new MeshyError("VALIDATION_ERROR", `Engine not registered for agent: ${task.agent}`, 400);
|
|
63674
|
-
}
|
|
63675
|
-
deps.taskEngine.updateTask(task.id, {
|
|
63676
|
-
status: "running",
|
|
63677
|
-
assignedTo
|
|
63678
|
-
});
|
|
63679
|
-
try {
|
|
63680
|
-
engine.sendMessage(task.id, content);
|
|
63681
|
-
} catch (err) {
|
|
63682
|
-
restoreTaskState(deps.taskEngine, task);
|
|
63683
|
-
deps.logger.warn("failed to start local follow-up execution", {
|
|
63684
|
-
taskId: task.id,
|
|
63685
|
-
...metadata,
|
|
63686
|
-
error: err instanceof Error ? err.message : String(err)
|
|
63687
|
-
});
|
|
63688
|
-
throw err;
|
|
63689
|
-
}
|
|
63690
|
-
}
|
|
63691
|
-
|
|
63692
63742
|
// ../../packages/api/src/tasks/task-session-import.ts
|
|
63693
63743
|
var TASK_IMPORT_PROXY_TIMEOUT_MS = 1e4;
|
|
63694
63744
|
function buildImportedSessionTitle(agent, sessionId) {
|
|
@@ -63992,6 +64042,153 @@ async function sendTaskLogsResponse(req, res, taskId) {
|
|
|
63992
64042
|
res.json(local);
|
|
63993
64043
|
}
|
|
63994
64044
|
|
|
64045
|
+
// ../../packages/api/src/tasks/task-follow-up.ts
|
|
64046
|
+
function startLocalTaskFollowUp(deps, task, content, assignedTo, metadata) {
|
|
64047
|
+
const engine = deps.engineRegistry.get(task.agent);
|
|
64048
|
+
if (!engine) {
|
|
64049
|
+
throw new MeshyError("VALIDATION_ERROR", `Engine not registered for agent: ${task.agent}`, 400);
|
|
64050
|
+
}
|
|
64051
|
+
deps.taskEngine.updateTask(task.id, {
|
|
64052
|
+
status: "running",
|
|
64053
|
+
assignedTo
|
|
64054
|
+
});
|
|
64055
|
+
try {
|
|
64056
|
+
engine.sendMessage(task.id, content);
|
|
64057
|
+
} catch (err) {
|
|
64058
|
+
restoreTaskState(deps.taskEngine, task);
|
|
64059
|
+
deps.logger.warn("failed to start local follow-up execution", {
|
|
64060
|
+
taskId: task.id,
|
|
64061
|
+
...metadata,
|
|
64062
|
+
error: err instanceof Error ? err.message : String(err)
|
|
64063
|
+
});
|
|
64064
|
+
throw err;
|
|
64065
|
+
}
|
|
64066
|
+
}
|
|
64067
|
+
|
|
64068
|
+
// ../../packages/api/src/tasks/task-message-queue.ts
|
|
64069
|
+
var registeredDrainers = /* @__PURE__ */ new WeakSet();
|
|
64070
|
+
var drainingTaskIds = /* @__PURE__ */ new Set();
|
|
64071
|
+
var QUEUE_DRAIN_STATUSES = /* @__PURE__ */ new Set(["completed", "cancelled"]);
|
|
64072
|
+
function restoreQueuedMessage(taskEngine, taskId, message) {
|
|
64073
|
+
const current = taskEngine.getTask(taskId);
|
|
64074
|
+
if (!current) return;
|
|
64075
|
+
taskEngine.updateTask(taskId, {
|
|
64076
|
+
queuedMessages: [message, ...current.queuedMessages ?? []]
|
|
64077
|
+
});
|
|
64078
|
+
}
|
|
64079
|
+
async function sendTaskFollowUpMessage(deps, task, content, metadata) {
|
|
64080
|
+
if (!supportsFollowUpAgent(task.agent)) {
|
|
64081
|
+
throw new MeshyError("VALIDATION_ERROR", `Agent ${task.agent} does not support chat messages`, 400);
|
|
64082
|
+
}
|
|
64083
|
+
if (task.assignedTo && task.assignedTo !== deps.nodeRegistry.getSelf()?.id) {
|
|
64084
|
+
const node = deps.nodeRegistry.getNode(task.assignedTo);
|
|
64085
|
+
const log2 = deps.logger.child("tasks/message");
|
|
64086
|
+
if (!node || node.status === "offline") {
|
|
64087
|
+
log2.warn("assigned worker unavailable for follow-up", {
|
|
64088
|
+
taskId: task.id,
|
|
64089
|
+
assignedTo: task.assignedTo,
|
|
64090
|
+
nodeFound: Boolean(node),
|
|
64091
|
+
nodeStatus: node?.status,
|
|
64092
|
+
...metadata
|
|
64093
|
+
});
|
|
64094
|
+
throw new MeshyError(
|
|
64095
|
+
"NODE_OFFLINE",
|
|
64096
|
+
`Task ${task.id} is unavailable because ${task.assignedNodeName ?? task.assignedTo} is no longer reachable`,
|
|
64097
|
+
409
|
|
64098
|
+
);
|
|
64099
|
+
}
|
|
64100
|
+
deps.taskEngine.updateTask(task.id, { status: "running" });
|
|
64101
|
+
log2.info("proxying follow-up message to worker", {
|
|
64102
|
+
taskId: task.id,
|
|
64103
|
+
assignedTo: task.assignedTo,
|
|
64104
|
+
...metadata
|
|
64105
|
+
});
|
|
64106
|
+
try {
|
|
64107
|
+
const client = new NodeMessageClient({ heartbeat: deps.heartbeat, logger: deps.logger });
|
|
64108
|
+
const delivery = await client.send(node, createNodeMessage("task.message", { taskId: task.id, content }));
|
|
64109
|
+
return delivery.queued ? { queued: true } : {};
|
|
64110
|
+
} catch (err) {
|
|
64111
|
+
restoreTaskState(deps.taskEngine, task);
|
|
64112
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
64113
|
+
log2.warn("failed to proxy follow-up message to worker", {
|
|
64114
|
+
taskId: task.id,
|
|
64115
|
+
assignedTo: task.assignedTo,
|
|
64116
|
+
error: message,
|
|
64117
|
+
...metadata
|
|
64118
|
+
});
|
|
64119
|
+
throw err instanceof MeshyError ? err : new MeshyError("NODE_OFFLINE", `Failed to proxy follow-up message to worker: ${message}`, 502);
|
|
64120
|
+
}
|
|
64121
|
+
}
|
|
64122
|
+
startLocalTaskFollowUp({
|
|
64123
|
+
taskEngine: deps.taskEngine,
|
|
64124
|
+
engineRegistry: deps.engineRegistry,
|
|
64125
|
+
logger: deps.logger.child("tasks/message")
|
|
64126
|
+
}, task, content, task.assignedTo, metadata);
|
|
64127
|
+
return {};
|
|
64128
|
+
}
|
|
64129
|
+
function queueRunningTaskMessage(deps, task, content) {
|
|
64130
|
+
if (!supportsFollowUpAgent(task.agent)) {
|
|
64131
|
+
throw new MeshyError("VALIDATION_ERROR", `Agent ${task.agent} does not support chat messages`, 400);
|
|
64132
|
+
}
|
|
64133
|
+
const queued = deps.taskEngine.enqueueTaskMessage(task.id, content);
|
|
64134
|
+
deps.logger.child("tasks/message").info("queued follow-up message for running task", {
|
|
64135
|
+
taskId: task.id,
|
|
64136
|
+
queuedCount: queued.queuedMessages?.length ?? 0
|
|
64137
|
+
});
|
|
64138
|
+
return queued;
|
|
64139
|
+
}
|
|
64140
|
+
function cancelQueuedTaskMessage(deps, taskId, messageId) {
|
|
64141
|
+
const task = deps.taskEngine.removeQueuedTaskMessage(taskId, messageId);
|
|
64142
|
+
if (!task) {
|
|
64143
|
+
throw new MeshyError("TASK_NOT_FOUND", `Queued message ${messageId} not found for task ${taskId}`, 404);
|
|
64144
|
+
}
|
|
64145
|
+
deps.logger.child("tasks/message").info("cancelled queued follow-up message", {
|
|
64146
|
+
taskId,
|
|
64147
|
+
queuedMessageId: messageId,
|
|
64148
|
+
queuedCount: task.queuedMessages?.length ?? 0
|
|
64149
|
+
});
|
|
64150
|
+
return task;
|
|
64151
|
+
}
|
|
64152
|
+
function registerTaskMessageQueueDrainer(deps) {
|
|
64153
|
+
if (registeredDrainers.has(deps.eventBus)) return;
|
|
64154
|
+
registeredDrainers.add(deps.eventBus);
|
|
64155
|
+
deps.eventBus.on("task.status", (data) => {
|
|
64156
|
+
if (!QUEUE_DRAIN_STATUSES.has(data.status)) return;
|
|
64157
|
+
void drainNextQueuedTaskMessage(deps, data.taskId);
|
|
64158
|
+
});
|
|
64159
|
+
}
|
|
64160
|
+
async function drainNextQueuedTaskMessage(deps, taskId) {
|
|
64161
|
+
if (drainingTaskIds.has(taskId)) return false;
|
|
64162
|
+
const task = deps.taskEngine.getTask(taskId);
|
|
64163
|
+
if (!task || !QUEUE_DRAIN_STATUSES.has(task.status) || !task.queuedMessages?.length) {
|
|
64164
|
+
return false;
|
|
64165
|
+
}
|
|
64166
|
+
const dequeued = deps.taskEngine.dequeueTaskMessage(taskId);
|
|
64167
|
+
if (!dequeued) return false;
|
|
64168
|
+
drainingTaskIds.add(taskId);
|
|
64169
|
+
try {
|
|
64170
|
+
await sendTaskFollowUpMessage(deps, dequeued.task, dequeued.message.content, {
|
|
64171
|
+
queuedMessageId: dequeued.message.id
|
|
64172
|
+
});
|
|
64173
|
+
deps.logger.child("tasks/message").info("started queued follow-up message", {
|
|
64174
|
+
taskId,
|
|
64175
|
+
queuedMessageId: dequeued.message.id,
|
|
64176
|
+
remainingQueuedCount: dequeued.task.queuedMessages?.length ?? 0
|
|
64177
|
+
});
|
|
64178
|
+
return true;
|
|
64179
|
+
} catch (err) {
|
|
64180
|
+
restoreQueuedMessage(deps.taskEngine, taskId, dequeued.message);
|
|
64181
|
+
deps.logger.child("tasks/message").warn("failed to start queued follow-up message", {
|
|
64182
|
+
taskId,
|
|
64183
|
+
queuedMessageId: dequeued.message.id,
|
|
64184
|
+
error: err instanceof Error ? err.message : String(err)
|
|
64185
|
+
});
|
|
64186
|
+
return false;
|
|
64187
|
+
} finally {
|
|
64188
|
+
drainingTaskIds.delete(taskId);
|
|
64189
|
+
}
|
|
64190
|
+
}
|
|
64191
|
+
|
|
63995
64192
|
// ../../packages/api/src/routes/task-output.ts
|
|
63996
64193
|
var import_express8 = __toESM(require_express2(), 1);
|
|
63997
64194
|
|
|
@@ -64820,63 +65017,39 @@ function createTaskRoutes() {
|
|
|
64820
65017
|
router.get("/:id/logs", asyncHandler7(async (req, res) => {
|
|
64821
65018
|
await sendTaskLogsResponse(req, res, req.params.id);
|
|
64822
65019
|
}));
|
|
65020
|
+
router.delete("/:id/queued-messages/:messageId", asyncHandler7(async (req, res) => {
|
|
65021
|
+
const { taskEngine, logger: rootLogger } = req.app.locals.deps;
|
|
65022
|
+
const task = cancelQueuedTaskMessage(
|
|
65023
|
+
{ taskEngine, logger: rootLogger },
|
|
65024
|
+
req.params.id,
|
|
65025
|
+
req.params.messageId
|
|
65026
|
+
);
|
|
65027
|
+
res.json({ ok: true, queuedMessages: task.queuedMessages ?? [] });
|
|
65028
|
+
}));
|
|
64823
65029
|
router.post("/:id/message", asyncHandler7(async (req, res) => {
|
|
64824
65030
|
const { taskEngine, engineRegistry, nodeRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
|
|
64825
|
-
const log2 = rootLogger.child("tasks/message");
|
|
64826
65031
|
const body = SendMessageBody.parse(req.body);
|
|
64827
65032
|
const taskId = req.params.id;
|
|
64828
65033
|
const task = taskEngine.getTask(taskId);
|
|
64829
65034
|
if (!task) {
|
|
64830
65035
|
throw new MeshyError("TASK_NOT_FOUND", `Task ${taskId} not found`, 404);
|
|
64831
65036
|
}
|
|
64832
|
-
if (!supportsFollowUpAgent(task.agent)) {
|
|
64833
|
-
throw new MeshyError("VALIDATION_ERROR", `Agent ${task.agent} does not support chat messages`, 400);
|
|
64834
|
-
}
|
|
64835
65037
|
if (!["running", "completed", "cancelled"].includes(task.status)) {
|
|
64836
65038
|
throw new MeshyError("VALIDATION_ERROR", `Cannot send message to task in ${task.status} status`, 400);
|
|
64837
65039
|
}
|
|
64838
|
-
if (task.
|
|
64839
|
-
const
|
|
64840
|
-
|
|
64841
|
-
|
|
64842
|
-
taskId: task.id,
|
|
64843
|
-
assignedTo: task.assignedTo,
|
|
64844
|
-
nodeFound: Boolean(node),
|
|
64845
|
-
nodeStatus: node?.status
|
|
64846
|
-
});
|
|
64847
|
-
throw new MeshyError(
|
|
64848
|
-
"NODE_OFFLINE",
|
|
64849
|
-
`Task ${task.id} is unavailable because ${task.assignedNodeName ?? task.assignedTo} is no longer reachable`,
|
|
64850
|
-
409
|
|
64851
|
-
);
|
|
64852
|
-
}
|
|
64853
|
-
taskEngine.updateTask(task.id, { status: "running" });
|
|
64854
|
-
log2.info("proxying follow-up message to worker", {
|
|
64855
|
-
taskId: task.id,
|
|
64856
|
-
assignedTo: task.assignedTo
|
|
64857
|
-
});
|
|
64858
|
-
try {
|
|
64859
|
-
const client = new NodeMessageClient({ heartbeat, logger: rootLogger });
|
|
64860
|
-
const delivery = await client.send(node, createNodeMessage("task.message", { taskId: task.id, content: body.content }));
|
|
64861
|
-
res.json(delivery.queued ? { ok: true, queued: true } : { ok: true });
|
|
64862
|
-
return;
|
|
64863
|
-
} catch (err) {
|
|
64864
|
-
restoreTaskState(taskEngine, task);
|
|
64865
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
64866
|
-
log2.warn("failed to proxy follow-up message to worker", {
|
|
64867
|
-
taskId: task.id,
|
|
64868
|
-
assignedTo: task.assignedTo,
|
|
64869
|
-
error: message
|
|
64870
|
-
});
|
|
64871
|
-
throw err instanceof MeshyError ? err : new MeshyError("NODE_OFFLINE", `Failed to proxy follow-up message to worker: ${message}`, 502);
|
|
64872
|
-
}
|
|
65040
|
+
if (task.status === "running") {
|
|
65041
|
+
const queued = queueRunningTaskMessage({ taskEngine, logger: rootLogger }, task, body.content);
|
|
65042
|
+
res.json({ ok: true, queued: true, queuedMessages: queued.queuedMessages ?? [] });
|
|
65043
|
+
return;
|
|
64873
65044
|
}
|
|
64874
|
-
|
|
65045
|
+
const result = await sendTaskFollowUpMessage({
|
|
64875
65046
|
taskEngine,
|
|
64876
65047
|
engineRegistry,
|
|
64877
|
-
|
|
64878
|
-
|
|
64879
|
-
|
|
65048
|
+
nodeRegistry,
|
|
65049
|
+
heartbeat,
|
|
65050
|
+
logger: rootLogger
|
|
65051
|
+
}, task, body.content);
|
|
65052
|
+
res.json(result.queued ? { ok: true, queued: true } : { ok: true });
|
|
64880
65053
|
}));
|
|
64881
65054
|
router.use(createTaskOutputRoutes());
|
|
64882
65055
|
return router;
|
|
@@ -65592,6 +65765,7 @@ function resolveStaticDir(baseDir) {
|
|
|
65592
65765
|
function createServer2(deps) {
|
|
65593
65766
|
const app = (0, import_express15.default)();
|
|
65594
65767
|
app.locals.deps = deps;
|
|
65768
|
+
registerTaskMessageQueueDrainer(deps);
|
|
65595
65769
|
if (typeof deps.heartbeat.setNodeMessageHandler === "function") {
|
|
65596
65770
|
deps.heartbeat.setNodeMessageHandler((message) => handleNodeMessage(deps, message));
|
|
65597
65771
|
}
|
|
@@ -65730,11 +65904,25 @@ function createDevBoxStatusPoller(deps, options = {}) {
|
|
|
65730
65904
|
const checkedAt = node.devbox?.checkedAt;
|
|
65731
65905
|
return typeof checkedAt !== "number" || now - checkedAt >= staleAfterMs;
|
|
65732
65906
|
}
|
|
65907
|
+
function hasActiveStartOperation(nodeId) {
|
|
65908
|
+
const operationService = getNodeOperationService(deps);
|
|
65909
|
+
return operationService.list({ kind: "devbox.start", status: "queued" }).some((operation) => operation.nodeId === nodeId) || operationService.list({ kind: "devbox.start", status: "running" }).some((operation) => operation.nodeId === nodeId);
|
|
65910
|
+
}
|
|
65911
|
+
function maybeStartAlwaysOnlineDevBox(node, refreshedStatus) {
|
|
65912
|
+
if (node.status !== "offline") return;
|
|
65913
|
+
if (node.devbox?.alwaysOnline !== true) return;
|
|
65914
|
+
if (!isAlwaysOnlineStartableDevBoxStatus(refreshedStatus)) return;
|
|
65915
|
+
if (hasActiveStartOperation(node.id)) return;
|
|
65916
|
+
const operationService = getNodeOperationService(deps);
|
|
65917
|
+
const operation = operationService.create("devbox.start", node.id, { previousStatus: refreshedStatus ?? "" });
|
|
65918
|
+
operationService.runLocal(operation.id);
|
|
65919
|
+
}
|
|
65733
65920
|
async function refreshNode(node) {
|
|
65734
65921
|
if (inFlight.has(node.id)) return;
|
|
65735
65922
|
inFlight.add(node.id);
|
|
65736
65923
|
try {
|
|
65737
|
-
await refreshNodeDevBoxStatus(deps, node);
|
|
65924
|
+
const refreshed = await refreshNodeDevBoxStatus(deps, node);
|
|
65925
|
+
maybeStartAlwaysOnlineDevBox(node, refreshed.lastStatus);
|
|
65738
65926
|
} catch (err) {
|
|
65739
65927
|
logger27.debug(`refresh failed for ${node.name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
65740
65928
|
} finally {
|
package/package.json
CHANGED
package/runtime-metadata.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"packageName": "meshy-node",
|
|
3
|
-
"packageVersion": "0.5.
|
|
3
|
+
"packageVersion": "0.5.7",
|
|
4
4
|
"packages": {
|
|
5
5
|
"workspace": {
|
|
6
6
|
"name": "meshy",
|
|
7
|
-
"version": "0.5.
|
|
7
|
+
"version": "0.5.7"
|
|
8
8
|
},
|
|
9
9
|
"node": {
|
|
10
10
|
"name": "meshy-node",
|
|
11
|
-
"version": "0.5.
|
|
11
|
+
"version": "0.5.7"
|
|
12
12
|
},
|
|
13
13
|
"core": {
|
|
14
14
|
"name": "@meshy/core",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
27
27
|
"url": "https://github.com/ai-microsoft/meshy",
|
|
28
|
-
"branch": "
|
|
29
|
-
"commit": "
|
|
28
|
+
"branch": "DevBoxAlwaysOnline",
|
|
29
|
+
"commit": "9635e1a"
|
|
30
30
|
}
|
|
31
31
|
}
|