meshy-node 0.3.8 → 0.3.9

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/main.cjs CHANGED
@@ -33297,6 +33297,7 @@ function createNodeMessage(kind, payload, options = {}) {
33297
33297
  }
33298
33298
 
33299
33299
  // ../../packages/core/src/messaging/node-message-client.ts
33300
+ var RETRYABLE_NODE_MESSAGE_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
33300
33301
  var NodeMessageClient = class {
33301
33302
  constructor(options = {}) {
33302
33303
  this.options = options;
@@ -33335,6 +33336,16 @@ var NodeMessageClient = class {
33335
33336
  throw error;
33336
33337
  }
33337
33338
  if (!response.ok) {
33339
+ if (RETRYABLE_NODE_MESSAGE_STATUSES.has(response.status) && this.options.heartbeat?.enqueueNodeMessage) {
33340
+ this.log?.warn("direct node message delivery returned retryable status; queued for keepalive", {
33341
+ nodeId: node.id,
33342
+ messageId: message.id,
33343
+ kind: message.kind,
33344
+ statusCode: response.status
33345
+ });
33346
+ this.options.heartbeat.enqueueNodeMessage(node.id, message);
33347
+ return { queued: true };
33348
+ }
33338
33349
  throw new Error(await formatHttpError(response));
33339
33350
  }
33340
33351
  return { queued: false };
@@ -43063,6 +43074,7 @@ var NativeSessionSummarySchema = external_exports.object({
43063
43074
  summary: external_exports.string(),
43064
43075
  updatedAt: external_exports.string().nullable()
43065
43076
  });
43077
+ var NodeOperationStatusSchema = external_exports.enum(["queued", "running", "succeeded", "failed"]);
43066
43078
  var NodeListQuery = external_exports.object({
43067
43079
  status: external_exports.enum(["online", "busy", "offline"]).optional(),
43068
43080
  capability: external_exports.string().optional()
@@ -43141,7 +43153,7 @@ var NodeNativeSessionsResponse = external_exports.object({
43141
43153
  agent: external_exports.enum(["codex", "claudecode"]),
43142
43154
  sessions: external_exports.array(NativeSessionSummarySchema)
43143
43155
  });
43144
- var NodeTerminalExecuteResponse = external_exports.object({
43156
+ var NodeTerminalExecuteResult = external_exports.object({
43145
43157
  nodeId: external_exports.string(),
43146
43158
  cwd: external_exports.string(),
43147
43159
  command: external_exports.string(),
@@ -43153,6 +43165,20 @@ var NodeTerminalExecuteResponse = external_exports.object({
43153
43165
  stdoutTruncated: external_exports.boolean(),
43154
43166
  stderrTruncated: external_exports.boolean()
43155
43167
  });
43168
+ var NodeTerminalExecuteResponse = external_exports.object({
43169
+ id: external_exports.string(),
43170
+ kind: external_exports.literal("terminal.execute"),
43171
+ nodeId: external_exports.string(),
43172
+ requestedByNodeId: external_exports.string().optional(),
43173
+ status: NodeOperationStatusSchema,
43174
+ payload: NodeTerminalExecuteBody,
43175
+ result: NodeTerminalExecuteResult.optional(),
43176
+ error: external_exports.string().optional(),
43177
+ createdAt: external_exports.number(),
43178
+ updatedAt: external_exports.number(),
43179
+ startedAt: external_exports.number().optional(),
43180
+ completedAt: external_exports.number().optional()
43181
+ });
43156
43182
  var UpdateNodeBody = external_exports.object({
43157
43183
  name: external_exports.string().min(1).optional(),
43158
43184
  capabilities: external_exports.array(external_exports.string()).optional()
@@ -44477,8 +44503,8 @@ function computeParentPath(rootPath, currentPath, useAbsolute) {
44477
44503
  }
44478
44504
 
44479
44505
  // ../../packages/api/src/node/node-operation-service.ts
44480
- var fs15 = __toESM(require("fs"), 1);
44481
- var path17 = __toESM(require("path"), 1);
44506
+ var fs16 = __toESM(require("fs"), 1);
44507
+ var path18 = __toESM(require("path"), 1);
44482
44508
  var import_node_crypto7 = require("crypto");
44483
44509
 
44484
44510
  // ../../packages/api/src/node/agent-upgrade-service.ts
@@ -44764,6 +44790,95 @@ function upgradeRuntimeAgentForDeps(deps, agent) {
44764
44790
  return result;
44765
44791
  }
44766
44792
 
44793
+ // ../../packages/api/src/node/node-terminal-service.ts
44794
+ var import_node_child_process10 = require("child_process");
44795
+ var fs15 = __toESM(require("fs"), 1);
44796
+ var path17 = __toESM(require("path"), 1);
44797
+ var DEFAULT_TIMEOUT_MS = 3e4;
44798
+ var DEFAULT_OUTPUT_LIMIT_BYTES = 64 * 1024;
44799
+ function isAbsolutePath2(value) {
44800
+ return path17.isAbsolute(value) || /^[A-Za-z]:[\/]/.test(value);
44801
+ }
44802
+ function resolveCommandCwd(nodeId, rootPath, cwd) {
44803
+ if (!rootPath) {
44804
+ throw new MeshyError("VALIDATION_ERROR", `Node ${nodeId} does not expose a working directory`, 400);
44805
+ }
44806
+ const requestedCwd = cwd?.trim() || ".";
44807
+ const resolved = isAbsolutePath2(requestedCwd) ? path17.resolve(requestedCwd) : path17.resolve(rootPath, requestedCwd);
44808
+ if (!fs15.existsSync(resolved) || !fs15.statSync(resolved).isDirectory()) {
44809
+ throw new MeshyError("VALIDATION_ERROR", `Working directory does not exist: ${resolved}`, 400);
44810
+ }
44811
+ return resolved;
44812
+ }
44813
+ function captureLimited(chunks, chunk, currentBytes, limitBytes) {
44814
+ if (currentBytes >= limitBytes) {
44815
+ return currentBytes + chunk.length;
44816
+ }
44817
+ const remaining = limitBytes - currentBytes;
44818
+ chunks.push(chunk.length <= remaining ? chunk : chunk.subarray(0, remaining));
44819
+ return currentBytes + chunk.length;
44820
+ }
44821
+ function toCapturedOutput(chunks, observedBytes, limitBytes) {
44822
+ return {
44823
+ text: Buffer.concat(chunks).toString("utf8"),
44824
+ truncated: observedBytes > limitBytes
44825
+ };
44826
+ }
44827
+ function executeLocalNodeTerminalCommand(nodeId, rootPath, command, options = {}) {
44828
+ const normalizedCommand = command.trim();
44829
+ if (!normalizedCommand) {
44830
+ throw new MeshyError("VALIDATION_ERROR", "Command must not be empty", 400);
44831
+ }
44832
+ const cwd = resolveCommandCwd(nodeId, rootPath, options.cwd);
44833
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
44834
+ const outputLimitBytes = options.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES;
44835
+ const startedAt = Date.now();
44836
+ const stdoutChunks = [];
44837
+ const stderrChunks = [];
44838
+ let stdoutBytes = 0;
44839
+ let stderrBytes = 0;
44840
+ let timedOut = false;
44841
+ return new Promise((resolve15, reject) => {
44842
+ const child = (0, import_node_child_process10.spawn)(normalizedCommand, {
44843
+ cwd,
44844
+ shell: true,
44845
+ windowsHide: true,
44846
+ stdio: ["ignore", "pipe", "pipe"]
44847
+ });
44848
+ const timeout = setTimeout(() => {
44849
+ timedOut = true;
44850
+ child.kill("SIGTERM");
44851
+ }, timeoutMs);
44852
+ child.stdout?.on("data", (chunk) => {
44853
+ stdoutBytes = captureLimited(stdoutChunks, chunk, stdoutBytes, outputLimitBytes);
44854
+ });
44855
+ child.stderr?.on("data", (chunk) => {
44856
+ stderrBytes = captureLimited(stderrChunks, chunk, stderrBytes, outputLimitBytes);
44857
+ });
44858
+ child.on("error", (err) => {
44859
+ clearTimeout(timeout);
44860
+ reject(new MeshyError("VALIDATION_ERROR", err.message, 400));
44861
+ });
44862
+ child.on("close", (code) => {
44863
+ clearTimeout(timeout);
44864
+ const stdout = toCapturedOutput(stdoutChunks, stdoutBytes, outputLimitBytes);
44865
+ const stderr = toCapturedOutput(stderrChunks, stderrBytes, outputLimitBytes);
44866
+ resolve15({
44867
+ nodeId,
44868
+ cwd,
44869
+ command: normalizedCommand,
44870
+ exitCode: code,
44871
+ stdout: stdout.text,
44872
+ stderr: stderr.text,
44873
+ durationMs: Date.now() - startedAt,
44874
+ timedOut,
44875
+ stdoutTruncated: stdout.truncated,
44876
+ stderrTruncated: stderr.truncated
44877
+ });
44878
+ });
44879
+ });
44880
+ }
44881
+
44767
44882
  // ../../packages/api/src/node/node-operation-service.ts
44768
44883
  var NodeOperationFailure = class extends Error {
44769
44884
  constructor(message, result) {
@@ -44827,8 +44942,8 @@ var FileNodeOperationStore = class {
44827
44942
  load() {
44828
44943
  if (this.loaded) return;
44829
44944
  this.loaded = true;
44830
- if (!fs15.existsSync(this.filePath)) return;
44831
- const raw = JSON.parse(fs15.readFileSync(this.filePath, "utf-8"));
44945
+ if (!fs16.existsSync(this.filePath)) return;
44946
+ const raw = JSON.parse(fs16.readFileSync(this.filePath, "utf-8"));
44832
44947
  const entries = Array.isArray(raw) ? raw : Object.values(raw);
44833
44948
  for (const entry of entries) {
44834
44949
  if (isNodeOperation(entry)) {
@@ -44837,14 +44952,14 @@ var FileNodeOperationStore = class {
44837
44952
  }
44838
44953
  }
44839
44954
  persist() {
44840
- fs15.mkdirSync(this.storagePath, { recursive: true });
44955
+ fs16.mkdirSync(this.storagePath, { recursive: true });
44841
44956
  const body = JSON.stringify(Object.fromEntries(this.operations), null, 2);
44842
44957
  const tmpPath = `${this.filePath}.tmp`;
44843
- fs15.writeFileSync(tmpPath, body, "utf-8");
44844
- fs15.renameSync(tmpPath, this.filePath);
44958
+ fs16.writeFileSync(tmpPath, body, "utf-8");
44959
+ fs16.renameSync(tmpPath, this.filePath);
44845
44960
  }
44846
44961
  get filePath() {
44847
- return path17.join(this.storagePath, "node-operations.json");
44962
+ return path18.join(this.storagePath, "node-operations.json");
44848
44963
  }
44849
44964
  };
44850
44965
  var NodeOperationService = class {
@@ -44852,6 +44967,7 @@ var NodeOperationService = class {
44852
44967
  this.deps = deps;
44853
44968
  this.store = store;
44854
44969
  this.registerHandler("agent.upgrade", runAgentUpgradeOperation);
44970
+ this.registerHandler("terminal.execute", runTerminalExecuteOperation);
44855
44971
  this.registerHandler("workdir.branch-create", runWorkDirBranchCreateOperation);
44856
44972
  }
44857
44973
  handlers = /* @__PURE__ */ new Map();
@@ -44997,6 +45113,15 @@ function runAgentUpgradeOperation(operation, deps) {
44997
45113
  }
44998
45114
  return result;
44999
45115
  }
45116
+ async function runTerminalExecuteOperation(operation, deps) {
45117
+ const self2 = deps.nodeRegistry.getSelf();
45118
+ return executeLocalNodeTerminalCommand(
45119
+ self2.id,
45120
+ self2.workDir ?? deps.workDir,
45121
+ readPayloadString(operation, "command"),
45122
+ { cwd: readPayloadString(operation, "cwd") || void 0 }
45123
+ );
45124
+ }
45000
45125
  function runWorkDirBranchCreateOperation(operation, deps) {
45001
45126
  const self2 = deps.nodeRegistry.getSelf();
45002
45127
  return createLocalNodeWorkDirBranch(
@@ -45154,7 +45279,7 @@ async function sendNodeWorkDirBranchCreateOperation(req, res, nodeId) {
45154
45279
  }
45155
45280
 
45156
45281
  // ../../packages/api/src/tasks/task-route-utils.ts
45157
- var fs16 = __toESM(require("fs"), 1);
45282
+ var fs17 = __toESM(require("fs"), 1);
45158
45283
  var import_node_stream2 = require("stream");
45159
45284
  var import_promises5 = require("stream/promises");
45160
45285
 
@@ -45209,10 +45334,10 @@ function readLocalTaskLogs(engineRegistry, taskId, after, agent) {
45209
45334
  throw new MeshyError("VALIDATION_ERROR", `Engine not registered for agent: ${agent}`, 400);
45210
45335
  }
45211
45336
  const logPath = engine.getLogPath(taskId);
45212
- if (!fs16.existsSync(logPath)) {
45337
+ if (!fs17.existsSync(logPath)) {
45213
45338
  return { logs: [], total: 0 };
45214
45339
  }
45215
- const content = fs16.readFileSync(logPath, "utf-8");
45340
+ const content = fs17.readFileSync(logPath, "utf-8");
45216
45341
  const allLines = content.trim().split("\n").filter(Boolean);
45217
45342
  const logs = [];
45218
45343
  for (let i = after; i < allLines.length; i++) {
@@ -45442,95 +45567,6 @@ async function maybeProxyReadToLeader(req, res, options = {}) {
45442
45567
  }
45443
45568
  }
45444
45569
 
45445
- // ../../packages/api/src/node/node-terminal-service.ts
45446
- var import_node_child_process10 = require("child_process");
45447
- var fs17 = __toESM(require("fs"), 1);
45448
- var path18 = __toESM(require("path"), 1);
45449
- var DEFAULT_TIMEOUT_MS = 3e4;
45450
- var DEFAULT_OUTPUT_LIMIT_BYTES = 64 * 1024;
45451
- function isAbsolutePath2(value) {
45452
- return path18.isAbsolute(value) || /^[A-Za-z]:[\/]/.test(value);
45453
- }
45454
- function resolveCommandCwd(nodeId, rootPath, cwd) {
45455
- if (!rootPath) {
45456
- throw new MeshyError("VALIDATION_ERROR", `Node ${nodeId} does not expose a working directory`, 400);
45457
- }
45458
- const requestedCwd = cwd?.trim() || ".";
45459
- const resolved = isAbsolutePath2(requestedCwd) ? path18.resolve(requestedCwd) : path18.resolve(rootPath, requestedCwd);
45460
- if (!fs17.existsSync(resolved) || !fs17.statSync(resolved).isDirectory()) {
45461
- throw new MeshyError("VALIDATION_ERROR", `Working directory does not exist: ${resolved}`, 400);
45462
- }
45463
- return resolved;
45464
- }
45465
- function captureLimited(chunks, chunk, currentBytes, limitBytes) {
45466
- if (currentBytes >= limitBytes) {
45467
- return currentBytes + chunk.length;
45468
- }
45469
- const remaining = limitBytes - currentBytes;
45470
- chunks.push(chunk.length <= remaining ? chunk : chunk.subarray(0, remaining));
45471
- return currentBytes + chunk.length;
45472
- }
45473
- function toCapturedOutput(chunks, observedBytes, limitBytes) {
45474
- return {
45475
- text: Buffer.concat(chunks).toString("utf8"),
45476
- truncated: observedBytes > limitBytes
45477
- };
45478
- }
45479
- function executeLocalNodeTerminalCommand(nodeId, rootPath, command, options = {}) {
45480
- const normalizedCommand = command.trim();
45481
- if (!normalizedCommand) {
45482
- throw new MeshyError("VALIDATION_ERROR", "Command must not be empty", 400);
45483
- }
45484
- const cwd = resolveCommandCwd(nodeId, rootPath, options.cwd);
45485
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
45486
- const outputLimitBytes = options.outputLimitBytes ?? DEFAULT_OUTPUT_LIMIT_BYTES;
45487
- const startedAt = Date.now();
45488
- const stdoutChunks = [];
45489
- const stderrChunks = [];
45490
- let stdoutBytes = 0;
45491
- let stderrBytes = 0;
45492
- let timedOut = false;
45493
- return new Promise((resolve15, reject) => {
45494
- const child = (0, import_node_child_process10.spawn)(normalizedCommand, {
45495
- cwd,
45496
- shell: true,
45497
- windowsHide: true,
45498
- stdio: ["ignore", "pipe", "pipe"]
45499
- });
45500
- const timeout = setTimeout(() => {
45501
- timedOut = true;
45502
- child.kill("SIGTERM");
45503
- }, timeoutMs);
45504
- child.stdout?.on("data", (chunk) => {
45505
- stdoutBytes = captureLimited(stdoutChunks, chunk, stdoutBytes, outputLimitBytes);
45506
- });
45507
- child.stderr?.on("data", (chunk) => {
45508
- stderrBytes = captureLimited(stderrChunks, chunk, stderrBytes, outputLimitBytes);
45509
- });
45510
- child.on("error", (err) => {
45511
- clearTimeout(timeout);
45512
- reject(new MeshyError("VALIDATION_ERROR", err.message, 400));
45513
- });
45514
- child.on("close", (code) => {
45515
- clearTimeout(timeout);
45516
- const stdout = toCapturedOutput(stdoutChunks, stdoutBytes, outputLimitBytes);
45517
- const stderr = toCapturedOutput(stderrChunks, stderrBytes, outputLimitBytes);
45518
- resolve15({
45519
- nodeId,
45520
- cwd,
45521
- command: normalizedCommand,
45522
- exitCode: code,
45523
- stdout: stdout.text,
45524
- stderr: stderr.text,
45525
- durationMs: Date.now() - startedAt,
45526
- timedOut,
45527
- stdoutTruncated: stdout.truncated,
45528
- stderrTruncated: stderr.truncated
45529
- });
45530
- });
45531
- });
45532
- }
45533
-
45534
45570
  // ../../packages/api/src/node/node-native-session-service.ts
45535
45571
  function getLocalNodeNativeSessions(nodeId, agent, limit) {
45536
45572
  return {
@@ -46954,142 +46990,35 @@ async function sendNodeAgentUpgrade(req, res, nodeId, agentParam) {
46954
46990
  }
46955
46991
 
46956
46992
  // ../../packages/api/src/routes/node-terminal.ts
46957
- var NODE_TERMINAL_PROXY_TIMEOUT_MS = 35e3;
46958
- function describeProxyError2(error) {
46959
- if (error instanceof Error) {
46960
- const errorCategory = error.name === "AbortError" || /aborted/i.test(error.message) ? "abort" : /timeout/i.test(error.message) ? "timeout" : "network";
46961
- return {
46962
- errorName: error.name,
46963
- errorMessage: error.message,
46964
- errorCategory
46965
- };
46966
- }
46967
- return {
46968
- errorName: "UnknownError",
46969
- errorMessage: String(error),
46970
- errorCategory: "unknown"
46971
- };
46972
- }
46973
- function createNodeTerminalProxyTrace(log2, nodeId, proxyPath) {
46974
- return {
46975
- onAttempt: ({ attempt, endpoint, timeoutMs, totalEndpoints }) => {
46976
- log2.debug("node terminal proxy attempt", {
46977
- nodeId,
46978
- proxyPath,
46979
- endpoint,
46980
- attempt,
46981
- totalEndpoints,
46982
- timeoutMs
46983
- });
46984
- },
46985
- onResponse: ({ attempt, endpoint, response, timeoutMs, totalEndpoints }) => {
46986
- log2.info("node terminal proxy response", {
46987
- nodeId,
46988
- proxyPath,
46989
- endpoint,
46990
- attempt,
46991
- totalEndpoints,
46992
- timeoutMs,
46993
- ok: response.ok,
46994
- statusCode: response.status
46995
- });
46996
- },
46997
- onError: ({ attempt, endpoint, error, timeoutMs, totalEndpoints }) => {
46998
- log2.warn("node terminal proxy attempt failed", {
46999
- nodeId,
47000
- proxyPath,
47001
- endpoint,
47002
- attempt,
47003
- totalEndpoints,
47004
- timeoutMs,
47005
- ...describeProxyError2(error)
47006
- });
47007
- }
47008
- };
47009
- }
47010
- async function maybeHandleRemoteNodeTerminalExecuteRequest(req, res, nodeId) {
46993
+ async function sendNodeTerminalExecuteOperation(req, res, nodeId) {
47011
46994
  const body = NodeTerminalExecuteBody.parse(req.body);
47012
- const { nodeRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
46995
+ const deps = req.app.locals.deps;
46996
+ const { nodeRegistry } = deps;
47013
46997
  const selfId = nodeRegistry.getSelf().id;
47014
- if (nodeId === selfId) {
47015
- return false;
47016
- }
47017
- const node = nodeRegistry.getNode(nodeId);
47018
- if (!node) {
47019
- throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
47020
- }
47021
- const log2 = rootLogger.child("nodes/terminal");
47022
- const proxyPath = req.originalUrl ?? `/api/nodes/${nodeId}/terminal/execute`;
47023
- const fallbackRequest = createNodeMessage("node.terminal.execute", {
46998
+ const node = nodeId === selfId ? nodeRegistry.getSelf() : nodeRegistry.getNode(nodeId);
46999
+ if (!node) throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
47000
+ const operations = getNodeOperationService(deps);
47001
+ const operation = operations.create("terminal.execute", nodeId, {
47024
47002
  command: body.command,
47025
47003
  cwd: body.cwd
47026
- }, { expectsResponse: true });
47027
- const canPushToNode = heartbeat?.canPushToNode?.(nodeId) ?? true;
47028
- if (!canPushToNode && canRequestNodeMessage(heartbeat)) {
47029
- log2.warn("node terminal request falling back to keepalive control", { nodeId, proxyPath });
47030
- const controlResponse = await requestFallbackNodeMessage(heartbeat, nodeId, fallbackRequest);
47031
- sendWorkerControlResponse(res, controlResponse);
47032
- return true;
47033
- }
47034
- try {
47035
- const { endpoint, response } = await fetchNodeWithFallback(
47036
- node,
47037
- proxyPath,
47038
- {
47039
- method: "POST",
47040
- headers: { "Content-Type": "application/json" },
47041
- body: JSON.stringify(body)
47042
- },
47043
- NODE_TERMINAL_PROXY_TIMEOUT_MS,
47044
- createNodeTerminalProxyTrace(log2, nodeId, proxyPath),
47045
- { preferPublicEndpoint: true }
47046
- );
47047
- log2.debug("proxying node terminal request", { nodeId, endpoint, proxyPath });
47048
- await sendProxyResponse(res, response);
47049
- return true;
47050
- } catch (err) {
47051
- const errorDetails = describeProxyError2(err);
47052
- log2.warn("node terminal proxy error", {
47053
- nodeId,
47054
- proxyPath,
47055
- timeoutMs: NODE_TERMINAL_PROXY_TIMEOUT_MS,
47056
- ...errorDetails
47057
- });
47058
- if (canRequestNodeMessage(heartbeat)) {
47059
- log2.warn("node terminal proxy failed, falling back to keepalive control", {
47060
- nodeId,
47061
- proxyPath,
47062
- timeoutMs: NODE_TERMINAL_PROXY_TIMEOUT_MS,
47063
- ...errorDetails
47064
- });
47065
- const controlResponse = await requestFallbackNodeMessage(heartbeat, nodeId, fallbackRequest);
47066
- sendWorkerControlResponse(res, controlResponse);
47067
- return true;
47004
+ });
47005
+ if (nodeId === selfId) {
47006
+ operations.runLocal(operation.id);
47007
+ } else {
47008
+ try {
47009
+ await dispatchNodeOperation(deps, operation, node);
47010
+ } catch (err) {
47011
+ operations.markFailed(operation.id, err instanceof Error ? err.message : String(err));
47068
47012
  }
47069
- throw new MeshyError("NODE_OFFLINE", `Cannot reach node ${nodeId} to execute a terminal command`, 502);
47070
- }
47071
- }
47072
- async function sendLocalNodeTerminalExecute(req, res, nodeId) {
47073
- const body = NodeTerminalExecuteBody.parse(req.body);
47074
- const { nodeRegistry, workDir } = req.app.locals.deps;
47075
- const self2 = nodeRegistry.getSelf();
47076
- if (nodeId !== self2.id) {
47077
- throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
47078
47013
  }
47079
- const result = await executeLocalNodeTerminalCommand(
47080
- self2.id,
47081
- self2.workDir ?? workDir,
47082
- body.command,
47083
- { cwd: body.cwd }
47084
- );
47085
- res.json(result);
47014
+ res.status(202).json(operation);
47086
47015
  }
47087
47016
 
47088
47017
  // ../../packages/api/src/routes/nodes.ts
47089
47018
  var NODE_WORKDIR_PROXY_TIMEOUT_MS = 1e4;
47090
47019
  var NODE_WORKDIR_BRANCH_PROXY_TIMEOUT_MS = 25e3;
47091
47020
  var NODE_NATIVE_SESSIONS_PROXY_TIMEOUT_MS = 1e4;
47092
- function describeProxyError3(error) {
47021
+ function describeProxyError2(error) {
47093
47022
  if (error instanceof Error) {
47094
47023
  const errorCategory = error.name === "AbortError" || /aborted/i.test(error.message) ? "abort" : /timeout/i.test(error.message) ? "timeout" : "network";
47095
47024
  return {
@@ -47136,7 +47065,7 @@ function createNodeWorkdirProxyTrace(log2, nodeId, proxyPath) {
47136
47065
  attempt,
47137
47066
  totalEndpoints,
47138
47067
  timeoutMs,
47139
- ...describeProxyError3(error)
47068
+ ...describeProxyError2(error)
47140
47069
  });
47141
47070
  }
47142
47071
  };
@@ -47191,7 +47120,7 @@ async function maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId) {
47191
47120
  await sendProxyResponse(res, response);
47192
47121
  return true;
47193
47122
  } catch (err) {
47194
- const errorDetails = describeProxyError3(err);
47123
+ const errorDetails = describeProxyError2(err);
47195
47124
  log2.warn("node workdir proxy error", {
47196
47125
  nodeId,
47197
47126
  proxyPath,
@@ -47258,7 +47187,7 @@ async function maybeHandleRemoteNodeWorkDirBranchInfoRequest(req, res, nodeId) {
47258
47187
  await sendProxyResponse(res, response);
47259
47188
  return true;
47260
47189
  } catch (err) {
47261
- const errorDetails = describeProxyError3(err);
47190
+ const errorDetails = describeProxyError2(err);
47262
47191
  log2.warn("node workdir branch proxy error", {
47263
47192
  nodeId,
47264
47193
  proxyPath,
@@ -47323,7 +47252,7 @@ async function maybeHandleRemoteNodeNativeSessionsRequest(req, res, nodeId) {
47323
47252
  await sendProxyResponse(res, response);
47324
47253
  return true;
47325
47254
  } catch (err) {
47326
- const errorDetails = describeProxyError3(err);
47255
+ const errorDetails = describeProxyError2(err);
47327
47256
  log2.warn("node native sessions proxy error", {
47328
47257
  nodeId,
47329
47258
  proxyPath,
@@ -47412,11 +47341,7 @@ function createNodeRoutes() {
47412
47341
  }));
47413
47342
  router.post("/:id/terminal/execute", asyncHandler3(async (req, res) => {
47414
47343
  const nodeId = req.params.id;
47415
- const handled = await maybeHandleRemoteNodeTerminalExecuteRequest(req, res, nodeId);
47416
- if (handled) {
47417
- return;
47418
- }
47419
- await sendLocalNodeTerminalExecute(req, res, nodeId);
47344
+ await sendNodeTerminalExecuteOperation(req, res, nodeId);
47420
47345
  }));
47421
47346
  router.post("/:id/workdir/branch", asyncHandler3(async (req, res) => {
47422
47347
  const nodeId = req.params.id;
@@ -47837,7 +47762,7 @@ function getTaskLogsProxyRequestMetadata(req) {
47837
47762
  const sourceNodeId = req.get(TASK_LOG_PROXY_SOURCE_HEADER) ?? void 0;
47838
47763
  return { isProxy: purpose === TASK_LOG_PROXY_PURPOSE, sourceNodeId, task: decodeTaskSnapshot(req.get(TASK_LOG_PROXY_TASK_HEADER)) };
47839
47764
  }
47840
- function describeProxyError4(error) {
47765
+ function describeProxyError3(error) {
47841
47766
  if (error instanceof Error) {
47842
47767
  const errorCategory = error.name === "AbortError" || /aborted/i.test(error.message) ? "abort" : /timeout/i.test(error.message) ? "timeout" : "network";
47843
47768
  return {
@@ -47879,7 +47804,7 @@ function createTaskLogsProxyTrace(log2, taskId, nodeId, proxyPath) {
47879
47804
  attempt,
47880
47805
  totalEndpoints,
47881
47806
  timeoutMs,
47882
- ...describeProxyError4(error)
47807
+ ...describeProxyError3(error)
47883
47808
  });
47884
47809
  }
47885
47810
  };
@@ -47957,7 +47882,7 @@ async function sendTaskLogsResponse(req, res, taskId) {
47957
47882
  log2.warn("failed to seed task snapshot before task logs proxy", {
47958
47883
  taskId,
47959
47884
  assignedTo,
47960
- ...describeProxyError4(err)
47885
+ ...describeProxyError3(err)
47961
47886
  });
47962
47887
  return [];
47963
47888
  });
@@ -47990,7 +47915,7 @@ async function sendTaskLogsResponse(req, res, taskId) {
47990
47915
  taskId,
47991
47916
  assignedTo,
47992
47917
  timeoutMs: TASK_LOG_PROXY_TIMEOUT_MS,
47993
- ...describeProxyError4(err)
47918
+ ...describeProxyError3(err)
47994
47919
  });
47995
47920
  const fallback = await requestTaskLogsOverKeepalive(heartbeat, assignedTo, task, after);
47996
47921
  if (fallback) {
@@ -48067,7 +47992,7 @@ function resolveRequestOrigin(req) {
48067
47992
 
48068
47993
  // ../../packages/api/src/routes/task-output.ts
48069
47994
  var TASK_OUTPUT_PROXY_TIMEOUT_MS = 1e4;
48070
- function describeProxyError5(error) {
47995
+ function describeProxyError4(error) {
48071
47996
  if (error instanceof Error) {
48072
47997
  const errorCategory = error.name === "AbortError" || /aborted/i.test(error.message) ? "abort" : /timeout/i.test(error.message) ? "timeout" : "network";
48073
47998
  return {
@@ -48120,7 +48045,7 @@ function createTaskOutputProxyTrace(log2, taskId, assignedTo, kind, proxyPath) {
48120
48045
  attempt,
48121
48046
  totalEndpoints,
48122
48047
  timeoutMs,
48123
- ...describeProxyError5(error)
48048
+ ...describeProxyError4(error)
48124
48049
  });
48125
48050
  }
48126
48051
  };
@@ -48238,7 +48163,7 @@ async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, ini
48238
48163
  assignedTo: assignedNodeId,
48239
48164
  kind: hydratedFallbackRequest.kind,
48240
48165
  timeoutMs: TASK_OUTPUT_PROXY_TIMEOUT_MS,
48241
- ...describeProxyError5(err)
48166
+ ...describeProxyError4(err)
48242
48167
  });
48243
48168
  const controlResponse = await requestFallbackNodeMessage(heartbeat, assignedNodeId, hydratedFallbackRequest);
48244
48169
  if (hydratedFallbackRequest.kind === "task.preview.create" && controlResponse.bodyEncoding === "json" && isPreviewSessionPayload(controlResponse.body)) {
@@ -48255,7 +48180,7 @@ async function maybeHandleRemoteTaskOutputRequest(req, res, taskId, subPath, ini
48255
48180
  assignedTo: assignedNodeId,
48256
48181
  kind: messageKind,
48257
48182
  timeoutMs: TASK_OUTPUT_PROXY_TIMEOUT_MS,
48258
- ...describeProxyError5(err)
48183
+ ...describeProxyError4(err)
48259
48184
  });
48260
48185
  throw new MeshyError("NODE_OFFLINE", "Cannot reach worker for task output", 502);
48261
48186
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meshy-node",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
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.3.8",
3
+ "packageVersion": "0.3.9",
4
4
  "packages": {
5
5
  "workspace": {
6
6
  "name": "meshy",
7
- "version": "0.3.8"
7
+ "version": "0.3.9"
8
8
  },
9
9
  "node": {
10
10
  "name": "meshy-node",
11
- "version": "0.3.8"
11
+ "version": "0.3.9"
12
12
  },
13
13
  "core": {
14
14
  "name": "@meshy/core",
@@ -26,6 +26,6 @@
26
26
  "repository": {
27
27
  "url": "https://github.com/ai-microsoft/meshy",
28
28
  "branch": "supportTerminal",
29
- "commit": "373ec48"
29
+ "commit": "0c23d39"
30
30
  }
31
31
  }