meshy-node 0.5.6 → 0.5.8
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-DZvoRYz2.js +134 -0
- package/dashboard/assets/{DashboardShared-DMrNrARk.js → DashboardShared-EIrXwlKQ.js} +2 -2
- package/dashboard/assets/{DiffTab-CPgg5BgU.js → DiffTab-RR71B7Td.js} +3 -3
- package/dashboard/assets/{FilesTab-Bd6A8nUE.js → FilesTab-BzAuq2V1.js} +7 -7
- package/dashboard/assets/{PreviewTab-kljCXeWP.js → PreviewTab-Dul4hiGt.js} +2 -2
- package/dashboard/assets/SharedConversationPage-DmimAj_x.js +7 -0
- package/dashboard/assets/{file-CPaJOnu-.js → file-CL1x0Gq_.js} +1 -1
- package/dashboard/assets/{folder-DgOi0nrN.js → folder-B7_msHnX.js} +1 -1
- package/dashboard/assets/index-BlCzIaoB.css +1 -0
- package/dashboard/assets/index-C8QVuMfU.js +301 -0
- package/dashboard/assets/{play-DQGsm6yq.js → play-IZPebZI4.js} +1 -1
- package/dashboard/index.html +2 -2
- package/main.cjs +267 -82
- 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/assets/index-nG4cAWuh.js +0 -301
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-C8QVuMfU.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;
|
|
@@ -65283,7 +65456,7 @@ function createSystemRoutes() {
|
|
|
65283
65456
|
path: req.originalUrl || req.url,
|
|
65284
65457
|
remoteAddress: req.ip || req.socket.remoteAddress
|
|
65285
65458
|
});
|
|
65286
|
-
res.json({ status: "ok", timestamp: Date.now() });
|
|
65459
|
+
res.json({ status: "ok", timestamp: Date.now(), pid: process.pid });
|
|
65287
65460
|
}));
|
|
65288
65461
|
router.get("/info", asyncHandler10(async (req, res) => {
|
|
65289
65462
|
const {
|
|
@@ -65295,6 +65468,7 @@ function createSystemRoutes() {
|
|
|
65295
65468
|
storagePath,
|
|
65296
65469
|
inspectRuntimeTools: inspectTools,
|
|
65297
65470
|
runtimeMetadata,
|
|
65471
|
+
getRuntimeUpdate,
|
|
65298
65472
|
runtimeUpdate
|
|
65299
65473
|
} = req.app.locals.deps;
|
|
65300
65474
|
const self2 = nodeRegistry.getSelf();
|
|
@@ -65308,7 +65482,7 @@ function createSystemRoutes() {
|
|
|
65308
65482
|
inspectRuntimeTools: inspectTools,
|
|
65309
65483
|
localDashboardOrigin,
|
|
65310
65484
|
runtimeMetadata,
|
|
65311
|
-
runtimeUpdate,
|
|
65485
|
+
runtimeUpdate: getRuntimeUpdate?.() ?? runtimeUpdate,
|
|
65312
65486
|
storagePath,
|
|
65313
65487
|
workDir: self2.workDir
|
|
65314
65488
|
});
|
|
@@ -65592,6 +65766,7 @@ function resolveStaticDir(baseDir) {
|
|
|
65592
65766
|
function createServer2(deps) {
|
|
65593
65767
|
const app = (0, import_express15.default)();
|
|
65594
65768
|
app.locals.deps = deps;
|
|
65769
|
+
registerTaskMessageQueueDrainer(deps);
|
|
65595
65770
|
if (typeof deps.heartbeat.setNodeMessageHandler === "function") {
|
|
65596
65771
|
deps.heartbeat.setNodeMessageHandler((message) => handleNodeMessage(deps, message));
|
|
65597
65772
|
}
|
|
@@ -65730,11 +65905,25 @@ function createDevBoxStatusPoller(deps, options = {}) {
|
|
|
65730
65905
|
const checkedAt = node.devbox?.checkedAt;
|
|
65731
65906
|
return typeof checkedAt !== "number" || now - checkedAt >= staleAfterMs;
|
|
65732
65907
|
}
|
|
65908
|
+
function hasActiveStartOperation(nodeId) {
|
|
65909
|
+
const operationService = getNodeOperationService(deps);
|
|
65910
|
+
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);
|
|
65911
|
+
}
|
|
65912
|
+
function maybeStartAlwaysOnlineDevBox(node, refreshedStatus) {
|
|
65913
|
+
if (node.status !== "offline") return;
|
|
65914
|
+
if (node.devbox?.alwaysOnline !== true) return;
|
|
65915
|
+
if (!isAlwaysOnlineStartableDevBoxStatus(refreshedStatus)) return;
|
|
65916
|
+
if (hasActiveStartOperation(node.id)) return;
|
|
65917
|
+
const operationService = getNodeOperationService(deps);
|
|
65918
|
+
const operation = operationService.create("devbox.start", node.id, { previousStatus: refreshedStatus ?? "" });
|
|
65919
|
+
operationService.runLocal(operation.id);
|
|
65920
|
+
}
|
|
65733
65921
|
async function refreshNode(node) {
|
|
65734
65922
|
if (inFlight.has(node.id)) return;
|
|
65735
65923
|
inFlight.add(node.id);
|
|
65736
65924
|
try {
|
|
65737
|
-
await refreshNodeDevBoxStatus(deps, node);
|
|
65925
|
+
const refreshed = await refreshNodeDevBoxStatus(deps, node);
|
|
65926
|
+
maybeStartAlwaysOnlineDevBox(node, refreshed.lastStatus);
|
|
65738
65927
|
} catch (err) {
|
|
65739
65928
|
logger27.debug(`refresh failed for ${node.name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
65740
65929
|
} finally {
|
|
@@ -66804,6 +66993,7 @@ function buildRuntimeMetadata(storagePath) {
|
|
|
66804
66993
|
var fs22 = __toESM(require("fs"), 1);
|
|
66805
66994
|
var nodePath2 = __toESM(require("path"), 1);
|
|
66806
66995
|
var import_node_child_process13 = require("child_process");
|
|
66996
|
+
var RUNTIME_UPDATE_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1e3;
|
|
66807
66997
|
function resolveRuntimeRestartStartArgs(hydratedArgs, restartArgs) {
|
|
66808
66998
|
return restartArgs ? { ...restartArgs } : hydratedArgs;
|
|
66809
66999
|
}
|
|
@@ -66886,12 +67076,6 @@ async function waitForEndpointDown() {
|
|
|
66886
67076
|
process.exit(1);
|
|
66887
67077
|
});
|
|
66888
67078
|
`;
|
|
66889
|
-
function formatLocalDate3(date3) {
|
|
66890
|
-
const year = date3.getFullYear();
|
|
66891
|
-
const month = String(date3.getMonth() + 1).padStart(2, "0");
|
|
66892
|
-
const day = String(date3.getDate()).padStart(2, "0");
|
|
66893
|
-
return `${year}-${month}-${day}`;
|
|
66894
|
-
}
|
|
66895
67079
|
function normalizeOutput2(output) {
|
|
66896
67080
|
if (!output) return null;
|
|
66897
67081
|
const firstLine = output.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
|
|
@@ -67080,18 +67264,18 @@ function createRuntimeUpdateSnapshot(options) {
|
|
|
67080
67264
|
};
|
|
67081
67265
|
}
|
|
67082
67266
|
const cache = options.updateCache ?? runtimeUpdateCache;
|
|
67083
|
-
const
|
|
67267
|
+
const nowMs = now.getTime();
|
|
67084
67268
|
const cached2 = cache.get(packageName);
|
|
67085
67269
|
let latestVersion = cached2?.latestVersion ?? null;
|
|
67086
67270
|
let detail = cached2?.detail ?? null;
|
|
67087
67271
|
let updateCheckedAt = cached2?.checkedAt ?? checkedAt;
|
|
67088
|
-
if (cached2
|
|
67272
|
+
if (!cached2 || nowMs - cached2.checkedAtMs >= RUNTIME_UPDATE_CHECK_INTERVAL_MS) {
|
|
67089
67273
|
const runner = options.commandRunner ?? runRuntimePackageCommand;
|
|
67090
67274
|
const result = runner("npm", ["view", `${packageName}@latest`, "version", "--json"]);
|
|
67091
67275
|
latestVersion = result.status === 0 ? normalizePackageVersion2(result.stdout) : null;
|
|
67092
67276
|
detail = result.status === 0 ? null : normalizeOutput2(result.stderr) ?? result.error ?? "Runtime update check failed";
|
|
67093
67277
|
updateCheckedAt = checkedAt;
|
|
67094
|
-
cache.set(packageName, {
|
|
67278
|
+
cache.set(packageName, { checkedAt, checkedAtMs: nowMs, latestVersion, detail });
|
|
67095
67279
|
}
|
|
67096
67280
|
return {
|
|
67097
67281
|
packageName,
|
|
@@ -67669,11 +67853,12 @@ async function startNode(args) {
|
|
|
67669
67853
|
} else {
|
|
67670
67854
|
setRequestAuthHeadersProvider(null);
|
|
67671
67855
|
}
|
|
67856
|
+
const runtimeRestartMode = detectRuntimeRestartMode();
|
|
67672
67857
|
const settingsSnapshotProvider = createSettingsSnapshotProvider({
|
|
67673
67858
|
authMetadata,
|
|
67674
67859
|
localDashboardOrigin,
|
|
67675
67860
|
runtimeMetadata,
|
|
67676
|
-
runtimeRestartMode
|
|
67861
|
+
runtimeRestartMode,
|
|
67677
67862
|
storagePath: config2.storage.path,
|
|
67678
67863
|
workDir: nodePath3.resolve(config2.node.workDir ?? process.cwd())
|
|
67679
67864
|
});
|
|
@@ -67797,8 +67982,8 @@ async function startNode(args) {
|
|
|
67797
67982
|
return { ok: true, pid };
|
|
67798
67983
|
},
|
|
67799
67984
|
refreshSettingsSnapshot,
|
|
67800
|
-
|
|
67801
|
-
mode:
|
|
67985
|
+
getRuntimeUpdate: () => createRuntimeUpdateSnapshot({
|
|
67986
|
+
mode: runtimeRestartMode,
|
|
67802
67987
|
runtimeMetadata
|
|
67803
67988
|
}),
|
|
67804
67989
|
dashboardOrigin: tunnelManager.getDashboardOrigin(),
|
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.8",
|
|
4
4
|
"packages": {
|
|
5
5
|
"workspace": {
|
|
6
6
|
"name": "meshy",
|
|
7
|
-
"version": "0.5.
|
|
7
|
+
"version": "0.5.8"
|
|
8
8
|
},
|
|
9
9
|
"node": {
|
|
10
10
|
"name": "meshy-node",
|
|
11
|
-
"version": "0.5.
|
|
11
|
+
"version": "0.5.8"
|
|
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": "RestartOpt",
|
|
29
|
+
"commit": "160a1d3"
|
|
30
30
|
}
|
|
31
31
|
}
|