meshy-node 0.4.5 → 0.4.6

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.
@@ -0,0 +1,6 @@
1
+ import{c as a}from"./index-D2UnB_kx.js";/**
2
+ * @license lucide-react v1.7.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const o=[["path",{d:"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",key:"10ikf1"}]],e=a("play",o);export{e as P};
@@ -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'>&#x1F578;</text></svg>" />
8
- <script type="module" crossorigin src="/assets/index-BgSOSh2K.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-BzzXPy7Y.css">
8
+ <script type="module" crossorigin src="/assets/index-D2UnB_kx.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-BOC8nP24.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
package/main.cjs CHANGED
@@ -33863,6 +33863,49 @@ var LeaderElection = class {
33863
33863
  var import_node_crypto5 = require("crypto");
33864
33864
  var fs4 = __toESM(require("fs"), 1);
33865
33865
  var path4 = __toESM(require("path"), 1);
33866
+
33867
+ // ../../packages/core/src/tasks/task-join-snapshot.ts
33868
+ var JOIN_TASK_SNAPSHOT_PAYLOAD_KEY = "__meshyJoinSnapshot";
33869
+ var MAX_JOIN_TASK_ERROR_LENGTH = 2e3;
33870
+ function truncate(value, maxLength) {
33871
+ if (value === null || value.length <= maxLength) {
33872
+ return value;
33873
+ }
33874
+ return `${value.slice(0, maxLength)}...`;
33875
+ }
33876
+ function shouldIncludeTaskInJoinSnapshot(task, selfId) {
33877
+ return task.assignedTo === null || task.assignedTo === selfId;
33878
+ }
33879
+ function createJoinTaskSnapshot(task, ownerNodeId) {
33880
+ return {
33881
+ ...task,
33882
+ description: "",
33883
+ payload: {
33884
+ [JOIN_TASK_SNAPSHOT_PAYLOAD_KEY]: {
33885
+ ownerNodeId,
33886
+ version: 1
33887
+ }
33888
+ },
33889
+ result: null,
33890
+ error: truncate(task.error, MAX_JOIN_TASK_ERROR_LENGTH)
33891
+ };
33892
+ }
33893
+ function buildJoinTaskSnapshots(tasks, ownerNodeId) {
33894
+ return tasks.filter((task) => shouldIncludeTaskInJoinSnapshot(task, ownerNodeId)).map((task) => createJoinTaskSnapshot(task, ownerNodeId));
33895
+ }
33896
+ function getJoinTaskSnapshotOwnerId(task) {
33897
+ const metadata = task.payload[JOIN_TASK_SNAPSHOT_PAYLOAD_KEY];
33898
+ if (typeof metadata !== "object" || metadata === null) {
33899
+ return null;
33900
+ }
33901
+ const ownerNodeId = metadata.ownerNodeId;
33902
+ return typeof ownerNodeId === "string" && ownerNodeId.length > 0 ? ownerNodeId : null;
33903
+ }
33904
+ function isJoinTaskSnapshot(task) {
33905
+ return getJoinTaskSnapshotOwnerId(task) !== null;
33906
+ }
33907
+
33908
+ // ../../packages/core/src/tasks/task-engine.ts
33866
33909
  function nodeSupportsAgent(node, agent) {
33867
33910
  return !node.supportedAgents || node.supportedAgents.length === 0 || node.supportedAgents.includes(agent);
33868
33911
  }
@@ -34148,7 +34191,9 @@ var TaskEngine = class {
34148
34191
  if (now - task.updatedAt < backoff) continue;
34149
34192
  }
34150
34193
  const previousNodeId = this.previousAssignments.get(task.id);
34151
- const capableNodes = availableNodes.filter((node) => nodeSupportsAgent(node, task.agent));
34194
+ const snapshotOwnerId = getJoinTaskSnapshotOwnerId(task);
34195
+ const candidateNodes = snapshotOwnerId ? availableNodes.filter((node) => node.id === snapshotOwnerId) : availableNodes;
34196
+ const capableNodes = candidateNodes.filter((node) => nodeSupportsAgent(node, task.agent));
34152
34197
  if (capableNodes.length === 0) continue;
34153
34198
  const targetNode = this.pickLeastBusyNode(capableNodes, nodeLoad, previousNodeId);
34154
34199
  if (!targetNode) continue;
@@ -36160,16 +36205,17 @@ var RestLeaderTaskReporter = class {
36160
36205
  var import_node_child_process2 = require("child_process");
36161
36206
  async function startWorkerTaskExecution(options) {
36162
36207
  const { taskEngine, engineRegistry, nodeRegistry, eventBus, logger: logger27, workDir, leaderReporter } = options;
36163
- const task = { ...options.task };
36164
- const existing = taskEngine.getTask(task.id);
36208
+ const incomingTask = { ...options.task };
36209
+ const existing = taskEngine.getTask(incomingTask.id);
36165
36210
  if (existing && hasExecutionAlreadyStarted(existing.status)) {
36166
36211
  logger27.warn("skipping duplicate task.execute for already-started task", {
36167
- taskId: task.id,
36212
+ taskId: incomingTask.id,
36168
36213
  status: existing.status,
36169
- agent: task.agent
36214
+ agent: incomingTask.agent
36170
36215
  });
36171
36216
  return existing;
36172
36217
  }
36218
+ const task = getExecutionTask(incomingTask, existing);
36173
36219
  task.effectiveProjectPath = resolveTaskWorkDir(task.project, workDir);
36174
36220
  task.branch = getCurrentGitBranch(task.effectiveProjectPath) ?? task.branch ?? null;
36175
36221
  await taskEngine.executeTask(task);
@@ -36219,6 +36265,17 @@ async function startWorkerTaskExecution(options) {
36219
36265
  }
36220
36266
  return task;
36221
36267
  }
36268
+ function getExecutionTask(incomingTask, existing) {
36269
+ if (!existing || !isJoinTaskSnapshot(incomingTask) || isJoinTaskSnapshot(existing)) {
36270
+ return incomingTask;
36271
+ }
36272
+ return {
36273
+ ...existing,
36274
+ status: incomingTask.status,
36275
+ assignedTo: incomingTask.assignedTo,
36276
+ assignedNodeName: incomingTask.assignedNodeName
36277
+ };
36278
+ }
36222
36279
  function hasExecutionAlreadyStarted(status) {
36223
36280
  return status === "running" || status === "completed" || status === "failed" || status === "cancelled" || status === "archived";
36224
36281
  }
@@ -37780,8 +37837,8 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
37780
37837
  devtunnelEndpoint
37781
37838
  });
37782
37839
  }
37783
- const tasks = this.taskEngine.listTasks().tasks;
37784
37840
  const self2 = this.nodeRegistry.getSelf();
37841
+ const tasks = buildJoinTaskSnapshots(this.taskEngine.listTasks().tasks, self2.id);
37785
37842
  const joinBody = {
37786
37843
  id: self2.id,
37787
37844
  endpoint: self2.endpoint,
@@ -37872,6 +37929,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
37872
37929
  leaderEndpoint,
37873
37930
  selfId: self2.id
37874
37931
  });
37932
+ persistNodeStartupJoin(this.config.storage.path, void 0);
37875
37933
  return;
37876
37934
  }
37877
37935
  if (leader && leaderEndpoint) {
@@ -43030,6 +43088,7 @@ var JoinTaskSchema = external_exports.object({
43030
43088
  agent: external_exports.string(),
43031
43089
  project: external_exports.string().nullable(),
43032
43090
  effectiveProjectPath: external_exports.string().nullable(),
43091
+ branch: external_exports.string().nullable().optional(),
43033
43092
  conversationKind: external_exports.enum(["meshyChat", "nativeSession"]).optional(),
43034
43093
  payload: external_exports.record(external_exports.unknown()),
43035
43094
  status: external_exports.enum(["pending", "assigned", "running", "completed", "failed", "cancelled", "archived"]),
@@ -43816,10 +43875,19 @@ function createClusterRoutes() {
43816
43875
  });
43817
43876
  }));
43818
43877
  router.post("/leave", asyncHandler(async (req, res) => {
43819
- const { nodeRegistry, logger: rootLogger } = req.app.locals.deps;
43878
+ const { nodeRegistry, election, leaveCurrentCluster, logger: rootLogger } = req.app.locals.deps;
43820
43879
  const log2 = rootLogger.child("cluster/leave");
43821
43880
  const { nodeId } = req.body;
43822
43881
  log2.info("received cluster leave request", { nodeId });
43882
+ if (!election.isLeader()) {
43883
+ if (!leaveCurrentCluster) {
43884
+ throw new MeshyError("VALIDATION_ERROR", "Leave flow is not available on this node", 501);
43885
+ }
43886
+ log2.info("handling cluster leave request as local follower detach", { requestedNodeId: nodeId });
43887
+ await leaveCurrentCluster();
43888
+ res.json({ ok: true });
43889
+ return;
43890
+ }
43823
43891
  nodeRegistry.removeNode(nodeId);
43824
43892
  res.json({ ok: true });
43825
43893
  }));
@@ -44849,6 +44917,58 @@ function upgradeRuntimeAgentForDeps(deps, agent) {
44849
44917
  return result;
44850
44918
  }
44851
44919
 
44920
+ // ../../packages/api/src/node/runtime-restart-request.ts
44921
+ function parseRuntimeRestartRequest(value) {
44922
+ const body = isRecord4(value) ? value : {};
44923
+ const startArgs = parseRuntimeRestartStartArgs(body.startArgs);
44924
+ return {
44925
+ reason: body.reason === "update" ? "update" : "restart",
44926
+ ...startArgs && { startArgs }
44927
+ };
44928
+ }
44929
+ function parseRuntimeRestartStartArgs(value) {
44930
+ if (value === void 0) return void 0;
44931
+ if (!isRecord4(value)) {
44932
+ throw new MeshyError("VALIDATION_ERROR", "Runtime restart startArgs must be an object", 400);
44933
+ }
44934
+ const startArgs = {};
44935
+ if (value.port !== void 0) {
44936
+ const port = value.port;
44937
+ if (typeof port !== "number" || !Number.isInteger(port) || port <= 0) {
44938
+ throw new MeshyError("VALIDATION_ERROR", "Runtime restart port must be a positive integer", 400);
44939
+ }
44940
+ startArgs.port = port;
44941
+ }
44942
+ for (const key of ["name", "join", "workDir", "config"]) {
44943
+ const parsed = parseOptionalString(value[key], key);
44944
+ if (parsed !== void 0) startArgs[key] = parsed;
44945
+ }
44946
+ if (value.transport !== void 0) {
44947
+ if (value.transport !== "direct" && value.transport !== "devtunnel" && value.transport !== "tailscale") {
44948
+ throw new MeshyError("VALIDATION_ERROR", "Runtime restart transport must be direct, devtunnel, or tailscale", 400);
44949
+ }
44950
+ startArgs.transport = value.transport;
44951
+ }
44952
+ if (value.disableAuth !== void 0) {
44953
+ if (typeof value.disableAuth !== "boolean") {
44954
+ throw new MeshyError("VALIDATION_ERROR", "Runtime restart disableAuth must be a boolean", 400);
44955
+ }
44956
+ startArgs.disableAuth = value.disableAuth;
44957
+ }
44958
+ return Object.keys(startArgs).length > 0 ? startArgs : void 0;
44959
+ }
44960
+ function parseOptionalString(value, key) {
44961
+ if (value === void 0) return void 0;
44962
+ if (typeof value !== "string") {
44963
+ throw new MeshyError("VALIDATION_ERROR", `Runtime restart ${key} must be a string`, 400);
44964
+ }
44965
+ const trimmed = value.trim();
44966
+ return trimmed || void 0;
44967
+ }
44968
+ function isRecord4(value) {
44969
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
44970
+ }
44971
+
44852
44972
  // ../../packages/api/src/node/node-operation-service.ts
44853
44973
  var LEADER_REPORT_RETRY_MS = 5e3;
44854
44974
  var OPERATION_COMMIT_EFFECT = /* @__PURE__ */ Symbol("operationCommitEffect");
@@ -45062,7 +45182,8 @@ function runAgentUpgradeOperation(operation, deps) {
45062
45182
  function runRuntimeRestartOperation(operation, deps) {
45063
45183
  if (!deps.restartRuntime) throw new Error("Runtime restart is not available for this node");
45064
45184
  const reason = readPayloadString(operation, "reason") === "update" ? "update" : "restart";
45065
- return deps.restartRuntime({ reason, deferShutdown: true }).then(
45185
+ const startArgs = readPayloadStartArgs(operation);
45186
+ return deps.restartRuntime({ reason, ...startArgs && { startArgs }, deferShutdown: true }).then(
45066
45187
  ({ completeShutdown, ...result }) => operationCommitEffect(result, completeShutdown)
45067
45188
  );
45068
45189
  }
@@ -45109,6 +45230,11 @@ function readPayloadBoolean(operation, key, fallback) {
45109
45230
  const value = payload[key];
45110
45231
  return typeof value === "boolean" ? value : fallback;
45111
45232
  }
45233
+ function readPayloadStartArgs(operation) {
45234
+ const payload = operation.payload;
45235
+ if (!payload || typeof payload !== "object") return void 0;
45236
+ return parseRuntimeRestartStartArgs(payload.startArgs);
45237
+ }
45112
45238
  function readSettingsSnapshot(value) {
45113
45239
  if (!value || typeof value !== "object") return void 0;
45114
45240
  const snapshot = value.settingsSnapshot;
@@ -45276,7 +45402,7 @@ function toLegacyWorkerControl2(message) {
45276
45402
  }
45277
45403
 
45278
45404
  // ../../packages/api/src/tasks/task-route-utils.ts
45279
- function isRecord4(value) {
45405
+ function isRecord5(value) {
45280
45406
  return typeof value === "object" && value !== null;
45281
45407
  }
45282
45408
  function restoreTaskState(taskEngine, task) {
@@ -45343,7 +45469,7 @@ function normalizeStructuredValue(value) {
45343
45469
  if (Array.isArray(value)) {
45344
45470
  return value.map((entry) => normalizeStructuredValue(entry));
45345
45471
  }
45346
- if (!isRecord4(value)) {
45472
+ if (!isRecord5(value)) {
45347
45473
  return value;
45348
45474
  }
45349
45475
  return Object.fromEntries(
@@ -45352,20 +45478,20 @@ function normalizeStructuredValue(value) {
45352
45478
  }
45353
45479
  function getTranscriptEventSignature(event) {
45354
45480
  if (event.type === "user") {
45355
- const signature = getTaskUserMessageSignature(isRecord4(event.message) ? event.message.content : event.message) ?? getTaskUserMessageSignature(event.content);
45481
+ const signature = getTaskUserMessageSignature(isRecord5(event.message) ? event.message.content : event.message) ?? getTaskUserMessageSignature(event.content);
45356
45482
  return signature ? `user:${signature}` : null;
45357
45483
  }
45358
45484
  if (event.type === "assistant") {
45359
45485
  if (typeof event.message === "string") {
45360
45486
  return `assistant:${JSON.stringify(event.message)}`;
45361
45487
  }
45362
- if (isRecord4(event.message) && "content" in event.message) {
45488
+ if (isRecord5(event.message) && "content" in event.message) {
45363
45489
  return `assistant:${JSON.stringify(normalizeStructuredValue(event.message.content))}`;
45364
45490
  }
45365
45491
  if (Array.isArray(event.content)) {
45366
45492
  return `assistant:${JSON.stringify(normalizeStructuredValue(event.content))}`;
45367
45493
  }
45368
- if (isRecord4(event.message)) {
45494
+ if (isRecord5(event.message)) {
45369
45495
  return `assistant:${JSON.stringify(normalizeStructuredValue(event.message))}`;
45370
45496
  }
45371
45497
  }
@@ -47162,9 +47288,6 @@ async function sendNodeAgentUpgrade(req, res, nodeId, agentParam) {
47162
47288
  }
47163
47289
 
47164
47290
  // ../../packages/api/src/routes/node-runtime.ts
47165
- function parseRestartReason(value) {
47166
- return value === "update" ? "update" : "restart";
47167
- }
47168
47291
  async function sendNodeRuntimeRestart(req, res, nodeId) {
47169
47292
  const deps = req.app.locals.deps;
47170
47293
  const self2 = deps.nodeRegistry.getSelf();
@@ -47176,9 +47299,9 @@ async function sendNodeRuntimeRestart(req, res, nodeId) {
47176
47299
  if (!node) {
47177
47300
  throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
47178
47301
  }
47179
- const reason = parseRestartReason(req.body?.reason);
47302
+ const restartRequest = parseRuntimeRestartRequest(req.body);
47180
47303
  const operations = getNodeOperationService(deps);
47181
- const operation = operations.create("runtime.restart", nodeId, { reason });
47304
+ const operation = operations.create("runtime.restart", nodeId, { ...restartRequest });
47182
47305
  if (isSelf) {
47183
47306
  operations.runLocal(operation.id);
47184
47307
  } else {
@@ -48099,8 +48222,10 @@ async function sendTaskLogsResponse(req, res, taskId) {
48099
48222
  if (!task && !proxyRequest.isProxy && await maybeProxyReadToLeader(req, res)) return;
48100
48223
  const selfId = nodeRegistry.getSelf()?.id;
48101
48224
  const isLeader = nodeRegistry.isLeader();
48225
+ const snapshotOwnerId = task ? getJoinTaskSnapshotOwnerId(task) : null;
48226
+ const proxyNodeId = task?.assignedTo ?? snapshotOwnerId;
48102
48227
  const isFollowerRemoteTask = !isLeader && !!(task?.assignedTo && task.assignedTo !== selfId);
48103
- const needsProxy = isLeader && !!(task?.assignedTo && task.assignedTo !== selfId);
48228
+ const needsProxy = isLeader && !!(proxyNodeId && proxyNodeId !== selfId);
48104
48229
  if (proxyRequest.isProxy) {
48105
48230
  log2.info("received proxied task logs request", {
48106
48231
  taskId,
@@ -48118,6 +48243,7 @@ async function sendTaskLogsResponse(req, res, taskId) {
48118
48243
  log2.debug("log request", {
48119
48244
  taskId,
48120
48245
  assignedTo: task?.assignedTo,
48246
+ snapshotOwnerId,
48121
48247
  selfId,
48122
48248
  isLeader,
48123
48249
  needsProxy
@@ -48141,20 +48267,21 @@ async function sendTaskLogsResponse(req, res, taskId) {
48141
48267
  selfId
48142
48268
  });
48143
48269
  }
48144
- const assignedTo = task.assignedTo;
48145
- if (needsProxy && assignedTo) {
48146
- const node = nodeRegistry.getNode(assignedTo);
48270
+ if (needsProxy && proxyNodeId) {
48271
+ const node = nodeRegistry.getNode(proxyNodeId);
48147
48272
  log2.debug("proxy target", { nodeId: node?.id, endpoint: node?.endpoint, devtunnel: node?.devtunnelEndpoint, status: node?.status });
48148
48273
  if (node) {
48149
- const seededLogs = await seedTaskSnapshotOnWorker(task, [], node, log2).catch((err) => {
48150
- log2.warn("failed to seed task snapshot before task logs proxy", {
48151
- taskId,
48152
- assignedTo,
48153
- ...describeProxyError3(err)
48274
+ if (task.assignedTo === proxyNodeId && !snapshotOwnerId) {
48275
+ const seededLogs = await seedTaskSnapshotOnWorker(task, [], node, log2).catch((err) => {
48276
+ log2.warn("failed to seed task snapshot before task logs proxy", {
48277
+ taskId,
48278
+ assignedTo: proxyNodeId,
48279
+ ...describeProxyError3(err)
48280
+ });
48281
+ return [];
48154
48282
  });
48155
- return [];
48156
- });
48157
- if (seededLogs.length > 0) recordLocalTaskLogs(engineRegistry, task, seededLogs);
48283
+ if (seededLogs.length > 0) recordLocalTaskLogs(engineRegistry, task, seededLogs);
48284
+ }
48158
48285
  const proxyPath = `/api/tasks/${taskId}/logs?after=${after}`;
48159
48286
  try {
48160
48287
  const { endpoint, response: proxyRes } = await fetchNodeWithFallback(
@@ -48168,7 +48295,7 @@ async function sendTaskLogsResponse(req, res, taskId) {
48168
48295
  const proxyUrl = `${endpoint}${proxyPath}`;
48169
48296
  log2.info("proxying task logs request", {
48170
48297
  taskId,
48171
- assignedTo,
48298
+ assignedTo: proxyNodeId,
48172
48299
  endpoint,
48173
48300
  proxyPath,
48174
48301
  url: proxyUrl
@@ -48181,11 +48308,11 @@ async function sendTaskLogsResponse(req, res, taskId) {
48181
48308
  } catch (err) {
48182
48309
  log2.warn("task logs proxy failed; falling back to keepalive control", {
48183
48310
  taskId,
48184
- assignedTo,
48311
+ assignedTo: proxyNodeId,
48185
48312
  timeoutMs: TASK_LOG_PROXY_TIMEOUT_MS,
48186
48313
  ...describeProxyError3(err)
48187
48314
  });
48188
- const fallback = await requestTaskLogsOverKeepalive(heartbeat, assignedTo, task, after);
48315
+ const fallback = await requestTaskLogsOverKeepalive(heartbeat, proxyNodeId, task, after);
48189
48316
  if (fallback) {
48190
48317
  sendWorkerControlResponse(res, fallback);
48191
48318
  return;
@@ -48576,6 +48703,8 @@ var TERMINAL_STATUSES3 = /* @__PURE__ */ new Set(["completed", "failed", "cancel
48576
48703
  var ARCHIVABLE_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "archived"]);
48577
48704
  var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "assigned", "running"]);
48578
48705
  var TASK_DELETE_NOTIFY_TIMEOUT_MS = 1500;
48706
+ var TASK_DETAIL_PROXY_TIMEOUT_MS = 1e4;
48707
+ var TASK_DETAIL_PROXY_HEADER = "x-meshy-task-detail-proxy";
48579
48708
  function shouldGenerateTitle(task) {
48580
48709
  return task.payload.titleSource === "derived";
48581
48710
  }
@@ -48686,6 +48815,62 @@ function withShareMetadata(task, taskEngine, shareOrigin) {
48686
48815
  function toTaskResponse(task, nodeRegistry, taskEngine, shareOrigin) {
48687
48816
  return withShareMetadata(withAssignedNodeMetadata(task, nodeRegistry), taskEngine, shareOrigin);
48688
48817
  }
48818
+ async function proxyJoinSnapshotTaskDetail(deps) {
48819
+ if (deps.req.get(TASK_DETAIL_PROXY_HEADER) === "1") {
48820
+ return null;
48821
+ }
48822
+ const ownerNodeId = getJoinTaskSnapshotOwnerId(deps.task);
48823
+ const selfId = deps.nodeRegistry.getSelf()?.id;
48824
+ if (!ownerNodeId || ownerNodeId === selfId) {
48825
+ return null;
48826
+ }
48827
+ const owner = deps.nodeRegistry.getNode(ownerNodeId);
48828
+ const log2 = deps.logger.child("tasks/detail");
48829
+ if (!owner) {
48830
+ log2.warn("join snapshot owner is unavailable for task detail proxy", {
48831
+ taskId: deps.task.id,
48832
+ ownerNodeId
48833
+ });
48834
+ return null;
48835
+ }
48836
+ const proxyPath = `/api/tasks/${encodeURIComponent(deps.task.id)}`;
48837
+ try {
48838
+ const { endpoint, response } = await fetchNodeWithFallback(
48839
+ owner,
48840
+ proxyPath,
48841
+ { method: "GET", headers: { [TASK_DETAIL_PROXY_HEADER]: "1" } },
48842
+ TASK_DETAIL_PROXY_TIMEOUT_MS,
48843
+ void 0,
48844
+ { preferPublicEndpoint: true }
48845
+ );
48846
+ if (!response.ok) {
48847
+ log2.warn("join snapshot task detail proxy returned non-ok response", {
48848
+ taskId: deps.task.id,
48849
+ ownerNodeId,
48850
+ endpoint,
48851
+ statusCode: response.status
48852
+ });
48853
+ return null;
48854
+ }
48855
+ const fullTask = await response.json();
48856
+ if (fullTask.id !== deps.task.id) {
48857
+ log2.warn("join snapshot task detail proxy returned a different task id", {
48858
+ taskId: deps.task.id,
48859
+ ownerNodeId,
48860
+ returnedTaskId: fullTask.id
48861
+ });
48862
+ return null;
48863
+ }
48864
+ return fullTask;
48865
+ } catch (err) {
48866
+ log2.warn("join snapshot task detail proxy failed", {
48867
+ taskId: deps.task.id,
48868
+ ownerNodeId,
48869
+ error: err instanceof Error ? err.message : String(err)
48870
+ });
48871
+ return null;
48872
+ }
48873
+ }
48689
48874
  function buildShareUrl(origin, shareId) {
48690
48875
  return `${origin.replace(/\/+$/, "")}/shared/tasks/${encodeURIComponent(shareId)}`;
48691
48876
  }
@@ -48809,14 +48994,15 @@ function createTaskRoutes() {
48809
48994
  res.json({ results });
48810
48995
  }));
48811
48996
  router.get("/:id", asyncHandler6(async (req, res) => {
48812
- const { taskEngine, nodeRegistry, shareOrigin } = req.app.locals.deps;
48997
+ const { taskEngine, nodeRegistry, shareOrigin, logger: logger27 } = req.app.locals.deps;
48813
48998
  const taskId = req.params.id;
48814
48999
  const task = taskEngine.getTask(taskId);
48815
49000
  if (!task) {
48816
49001
  if (await maybeProxyReadToLeader(req, res)) return;
48817
49002
  throw new MeshyError("TASK_NOT_FOUND", `Task ${taskId} not found`, 404);
48818
49003
  }
48819
- res.json(toTaskResponse(task, nodeRegistry, taskEngine, shareOrigin));
49004
+ const fullTask = await proxyJoinSnapshotTaskDetail({ task, req, logger: logger27, nodeRegistry });
49005
+ res.json(toTaskResponse(fullTask ?? task, nodeRegistry, taskEngine, shareOrigin));
48820
49006
  }));
48821
49007
  router.post("/:id/share", asyncHandler6(async (req, res) => {
48822
49008
  const { taskEngine, ensureShareTunnel } = req.app.locals.deps;
@@ -49491,9 +49677,8 @@ function createSystemRoutes() {
49491
49677
  if (!restartRuntime) {
49492
49678
  throw new MeshyError("VALIDATION_ERROR", "Runtime restart is not available for this node", 501);
49493
49679
  }
49494
- const body = req.body;
49495
- const reason = body.reason === "update" ? "update" : "restart";
49496
- const result = await restartRuntime({ reason });
49680
+ const restartRequest = parseRuntimeRestartRequest(req.body);
49681
+ const result = await restartRuntime(restartRequest);
49497
49682
  res.status(202).json(result);
49498
49683
  }));
49499
49684
  router.post("/runtime/stop", asyncHandler9(async (req, res) => {
@@ -49672,6 +49857,9 @@ function createNodeOperationRoutes() {
49672
49857
  var JSON_BODY_LIMIT = "1mb";
49673
49858
  var JSON_BODY_LIMIT_LARGE = "25mb";
49674
49859
  var TRUSTED_LOCAL_HOSTS2 = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
49860
+ function usesLargeJsonBodyLimit(pathname) {
49861
+ return pathname === "/api/cluster/join" || pathname === "/api/node" || pathname.startsWith("/api/node/") || pathname === "/api/tasks" || pathname.startsWith("/api/tasks/") || pathname === "/api/worker" || pathname.startsWith("/api/worker/");
49862
+ }
49675
49863
  function normalizeHost2(value) {
49676
49864
  const trimmed = value?.trim().toLowerCase();
49677
49865
  return trimmed ? trimmed.replace(/:\d+$/, "") : void 0;
@@ -49798,7 +49986,12 @@ function createServer2(deps) {
49798
49986
  staticMiddleware(req, res, next);
49799
49987
  });
49800
49988
  }
49801
- app.use(import_express14.default.json({ limit: JSON_BODY_LIMIT }));
49989
+ const defaultJsonParser = import_express14.default.json({ limit: JSON_BODY_LIMIT });
49990
+ const largeJsonParser = import_express14.default.json({ limit: JSON_BODY_LIMIT_LARGE });
49991
+ app.use((req, res, next) => {
49992
+ const parser = usesLargeJsonBodyLimit(req.path) ? largeJsonParser : defaultJsonParser;
49993
+ parser(req, res, next);
49994
+ });
49802
49995
  app.use(createAuthMiddleware(authConfig));
49803
49996
  app.use((req, res, next) => {
49804
49997
  void (async () => {
@@ -49824,14 +50017,13 @@ function createServer2(deps) {
49824
50017
  taskEngine: deps.taskEngine,
49825
50018
  logger: deps.logger
49826
50019
  }));
49827
- const largeBodyParser = import_express14.default.json({ limit: JSON_BODY_LIMIT_LARGE });
49828
50020
  app.use("/api/cluster", createClusterRoutes());
49829
50021
  app.use("/api/cluster-control", createClusterControlRoutes());
49830
- app.use("/api/node", largeBodyParser, createNodeMessageRoutes());
50022
+ app.use("/api/node", createNodeMessageRoutes());
49831
50023
  app.use("/api/nodes", createNodeRoutes());
49832
- app.use("/api/tasks", largeBodyParser, createTaskRoutes());
50024
+ app.use("/api/tasks", createTaskRoutes());
49833
50025
  app.use("/api/shared", createSharedRoutes());
49834
- app.use("/api/worker", largeBodyParser, createWorkerRoutes());
50026
+ app.use("/api/worker", createWorkerRoutes());
49835
50027
  app.use("/api/system", createSystemRoutes());
49836
50028
  app.use("/api/node-operations", createNodeOperationRoutes());
49837
50029
  app.use("/api/events", createEventRoutes());
@@ -50875,6 +51067,9 @@ function buildRuntimeMetadata(storagePath) {
50875
51067
  var fs22 = __toESM(require("fs"), 1);
50876
51068
  var nodePath2 = __toESM(require("path"), 1);
50877
51069
  var import_node_child_process14 = require("child_process");
51070
+ function resolveRuntimeRestartStartArgs(hydratedArgs, restartArgs) {
51071
+ return restartArgs ? { ...restartArgs } : hydratedArgs;
51072
+ }
50878
51073
  var runtimeUpdateCache = /* @__PURE__ */ new Map();
50879
51074
  var RESTARTER_SOURCE = String.raw`
50880
51075
  const { spawn } = require('node:child_process');
@@ -51842,7 +52037,7 @@ async function startNode(args) {
51842
52037
  cwd: process.cwd(),
51843
52038
  env: process.env,
51844
52039
  localDashboardOrigin,
51845
- startArgs: hydratedArgs.args,
52040
+ startArgs: resolveRuntimeRestartStartArgs(hydratedArgs.args, request.startArgs),
51846
52041
  storagePath: config.storage.path
51847
52042
  });
51848
52043
  scheduleRuntimeRestart(plan, { parentPid: process.pid });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meshy-node",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "private": false,
5
5
  "description": "Standalone Meshy node package with bundled runtime and dashboard assets.",
6
6
  "type": "commonjs",
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "packageName": "meshy-node",
3
- "packageVersion": "0.4.5",
3
+ "packageVersion": "0.4.6",
4
4
  "packages": {
5
5
  "workspace": {
6
6
  "name": "meshy",
7
- "version": "0.4.5"
7
+ "version": "0.4.6"
8
8
  },
9
9
  "node": {
10
10
  "name": "meshy-node",
11
- "version": "0.4.5"
11
+ "version": "0.4.6"
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": "NodeRelaunch",
29
- "commit": "9e6493f"
28
+ "branch": "fixNodeJoin",
29
+ "commit": "ea67bf5"
30
30
  }
31
31
  }