meshy-node 0.4.4 → 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.
- package/README.md +1 -1
- package/dashboard/assets/DashboardPage-D90kD6BP.js +124 -0
- package/dashboard/assets/{DashboardShared-CJtOr7QZ.js → DashboardShared-C3JGW4Hk.js} +2 -2
- package/dashboard/assets/{DiffTab-Bi7Lu7wa.js → DiffTab-Dwqf5Gav.js} +2 -2
- package/dashboard/assets/{FilesTab-CwM0TYJk.js → FilesTab-DGtXQ9rR.js} +1 -1
- package/dashboard/assets/PreviewTab-BcdMUFw3.js +16 -0
- package/dashboard/assets/{SharedConversationPage-CUG9tnp-.js → SharedConversationPage-CYx3AV6M.js} +3 -3
- package/dashboard/assets/{file-BTuUAaOs.js → file-BeUioHu4.js} +1 -1
- package/dashboard/assets/{folder-BbOC2arM.js → folder-Dl50jm8B.js} +1 -1
- package/dashboard/assets/index-BOC8nP24.css +1 -0
- package/dashboard/assets/index-D2UnB_kx.js +301 -0
- package/dashboard/assets/play-B08sSxiw.js +6 -0
- package/dashboard/index.html +2 -2
- package/main.cjs +735 -96
- package/package.json +1 -1
- package/runtime-metadata.json +5 -5
- package/dashboard/assets/DashboardPage-mQpgVZSz.js +0 -124
- package/dashboard/assets/PreviewTab-ti-mR-KD.js +0 -21
- package/dashboard/assets/index-BzzXPy7Y.css +0 -1
- package/dashboard/assets/index-Cba_59ol.js +0 -291
- package/dashboard/assets/input-DXbjJpeh.js +0 -6
package/main.cjs
CHANGED
|
@@ -6629,8 +6629,8 @@ var require_node2 = __commonJS({
|
|
|
6629
6629
|
}
|
|
6630
6630
|
break;
|
|
6631
6631
|
case "FILE":
|
|
6632
|
-
var
|
|
6633
|
-
stream2 = new
|
|
6632
|
+
var fs23 = require("fs");
|
|
6633
|
+
stream2 = new fs23.SyncWriteStream(fd2, { autoClose: false });
|
|
6634
6634
|
stream2._type = "fs";
|
|
6635
6635
|
break;
|
|
6636
6636
|
case "PIPE":
|
|
@@ -23749,8 +23749,8 @@ var require_view = __commonJS({
|
|
|
23749
23749
|
"use strict";
|
|
23750
23750
|
var debug = require_src2()("express:view");
|
|
23751
23751
|
var path23 = require("path");
|
|
23752
|
-
var
|
|
23753
|
-
var
|
|
23752
|
+
var fs23 = require("fs");
|
|
23753
|
+
var dirname8 = path23.dirname;
|
|
23754
23754
|
var basename5 = path23.basename;
|
|
23755
23755
|
var extname3 = path23.extname;
|
|
23756
23756
|
var join17 = path23.join;
|
|
@@ -23789,7 +23789,7 @@ var require_view = __commonJS({
|
|
|
23789
23789
|
for (var i = 0; i < roots.length && !path24; i++) {
|
|
23790
23790
|
var root = roots[i];
|
|
23791
23791
|
var loc = resolve15(root, name2);
|
|
23792
|
-
var dir =
|
|
23792
|
+
var dir = dirname8(loc);
|
|
23793
23793
|
var file = basename5(loc);
|
|
23794
23794
|
path24 = this.resolve(dir, file);
|
|
23795
23795
|
}
|
|
@@ -23815,7 +23815,7 @@ var require_view = __commonJS({
|
|
|
23815
23815
|
function tryStat(path24) {
|
|
23816
23816
|
debug('stat "%s"', path24);
|
|
23817
23817
|
try {
|
|
23818
|
-
return
|
|
23818
|
+
return fs23.statSync(path24);
|
|
23819
23819
|
} catch (e) {
|
|
23820
23820
|
return void 0;
|
|
23821
23821
|
}
|
|
@@ -24113,7 +24113,7 @@ var require_mime = __commonJS({
|
|
|
24113
24113
|
"../../node_modules/.pnpm/mime@1.6.0/node_modules/mime/mime.js"(exports2, module2) {
|
|
24114
24114
|
"use strict";
|
|
24115
24115
|
var path23 = require("path");
|
|
24116
|
-
var
|
|
24116
|
+
var fs23 = require("fs");
|
|
24117
24117
|
function Mime() {
|
|
24118
24118
|
this.types = /* @__PURE__ */ Object.create(null);
|
|
24119
24119
|
this.extensions = /* @__PURE__ */ Object.create(null);
|
|
@@ -24134,7 +24134,7 @@ var require_mime = __commonJS({
|
|
|
24134
24134
|
};
|
|
24135
24135
|
Mime.prototype.load = function(file) {
|
|
24136
24136
|
this._loading = file;
|
|
24137
|
-
var map = {}, content =
|
|
24137
|
+
var map = {}, content = fs23.readFileSync(file, "ascii"), lines = content.split(/[\r\n]+/);
|
|
24138
24138
|
lines.forEach(function(line) {
|
|
24139
24139
|
var fields = line.replace(/\s*#.*|^\s*|\s*$/g, "").split(/\s+/);
|
|
24140
24140
|
map[fields.shift()] = fields;
|
|
@@ -24256,7 +24256,7 @@ var require_send = __commonJS({
|
|
|
24256
24256
|
var escapeHtml2 = require_escape_html();
|
|
24257
24257
|
var etag = require_etag();
|
|
24258
24258
|
var fresh = require_fresh();
|
|
24259
|
-
var
|
|
24259
|
+
var fs23 = require("fs");
|
|
24260
24260
|
var mime = require_mime();
|
|
24261
24261
|
var ms = require_ms();
|
|
24262
24262
|
var onFinished = require_on_finished();
|
|
@@ -24589,7 +24589,7 @@ var require_send = __commonJS({
|
|
|
24589
24589
|
var i = 0;
|
|
24590
24590
|
var self2 = this;
|
|
24591
24591
|
debug('stat "%s"', path24);
|
|
24592
|
-
|
|
24592
|
+
fs23.stat(path24, function onstat(err, stat) {
|
|
24593
24593
|
if (err && err.code === "ENOENT" && !extname3(path24) && path24[path24.length - 1] !== sep4) {
|
|
24594
24594
|
return next(err);
|
|
24595
24595
|
}
|
|
@@ -24604,7 +24604,7 @@ var require_send = __commonJS({
|
|
|
24604
24604
|
}
|
|
24605
24605
|
var p = path24 + "." + self2._extensions[i++];
|
|
24606
24606
|
debug('stat "%s"', p);
|
|
24607
|
-
|
|
24607
|
+
fs23.stat(p, function(err2, stat) {
|
|
24608
24608
|
if (err2) return next(err2);
|
|
24609
24609
|
if (stat.isDirectory()) return next();
|
|
24610
24610
|
self2.emit("file", p, stat);
|
|
@@ -24622,7 +24622,7 @@ var require_send = __commonJS({
|
|
|
24622
24622
|
}
|
|
24623
24623
|
var p = join17(path24, self2._index[i]);
|
|
24624
24624
|
debug('stat "%s"', p);
|
|
24625
|
-
|
|
24625
|
+
fs23.stat(p, function(err2, stat) {
|
|
24626
24626
|
if (err2) return next(err2);
|
|
24627
24627
|
if (stat.isDirectory()) return next();
|
|
24628
24628
|
self2.emit("file", p, stat);
|
|
@@ -24634,7 +24634,7 @@ var require_send = __commonJS({
|
|
|
24634
24634
|
SendStream.prototype.stream = function stream(path24, options) {
|
|
24635
24635
|
var self2 = this;
|
|
24636
24636
|
var res = this.res;
|
|
24637
|
-
var stream2 =
|
|
24637
|
+
var stream2 = fs23.createReadStream(path24, options);
|
|
24638
24638
|
this.emit("stream", stream2);
|
|
24639
24639
|
stream2.pipe(res);
|
|
24640
24640
|
function cleanup() {
|
|
@@ -31894,11 +31894,11 @@ var processUtils = {
|
|
|
31894
31894
|
// ../../node_modules/.pnpm/@azure+identity@4.13.1/node_modules/@azure/identity/dist/esm/credentials/azurePowerShellCredential.js
|
|
31895
31895
|
var logger18 = credentialLogger("AzurePowerShellCredential");
|
|
31896
31896
|
var isWindows = process.platform === "win32";
|
|
31897
|
-
function formatCommand(
|
|
31897
|
+
function formatCommand(commandName2) {
|
|
31898
31898
|
if (isWindows) {
|
|
31899
|
-
return `${
|
|
31899
|
+
return `${commandName2}.exe`;
|
|
31900
31900
|
} else {
|
|
31901
|
-
return
|
|
31901
|
+
return commandName2;
|
|
31902
31902
|
}
|
|
31903
31903
|
}
|
|
31904
31904
|
async function runCommands(commands, timeout) {
|
|
@@ -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
|
|
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
|
|
36164
|
-
const existing = taskEngine.getTask(
|
|
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:
|
|
36212
|
+
taskId: incomingTask.id,
|
|
36168
36213
|
status: existing.status,
|
|
36169
|
-
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) {
|
|
@@ -37934,7 +37992,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
37934
37992
|
this.election.stop();
|
|
37935
37993
|
try {
|
|
37936
37994
|
const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
|
|
37937
|
-
if (leaderEndpoint) {
|
|
37995
|
+
if (leaderEndpoint && !this.nodeRegistry.isLeader()) {
|
|
37938
37996
|
this.logger.info("sending shutdown cluster leave request", {
|
|
37939
37997
|
leaderEndpoint,
|
|
37940
37998
|
nodeId: this.selfInfo.id
|
|
@@ -38835,7 +38893,7 @@ function isDirectRunPath(entryPath) {
|
|
|
38835
38893
|
}
|
|
38836
38894
|
|
|
38837
38895
|
// src/bootstrap/start-node.ts
|
|
38838
|
-
var
|
|
38896
|
+
var nodePath3 = __toESM(require("path"), 1);
|
|
38839
38897
|
|
|
38840
38898
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
38841
38899
|
var external_exports = {};
|
|
@@ -42951,6 +43009,15 @@ var SystemAgentInfoSchema = external_exports.object({
|
|
|
42951
43009
|
detail: external_exports.string().nullable().optional()
|
|
42952
43010
|
}).optional()
|
|
42953
43011
|
});
|
|
43012
|
+
var SystemRuntimeUpdateInfoSchema = external_exports.object({
|
|
43013
|
+
packageName: external_exports.string(),
|
|
43014
|
+
currentVersion: external_exports.string().nullable(),
|
|
43015
|
+
latestVersion: external_exports.string().nullable(),
|
|
43016
|
+
updateAvailable: external_exports.boolean(),
|
|
43017
|
+
checkedAt: external_exports.string(),
|
|
43018
|
+
restartMode: external_exports.enum(["package", "development"]),
|
|
43019
|
+
detail: external_exports.string().nullable().optional()
|
|
43020
|
+
});
|
|
42954
43021
|
var NodeSettingsSnapshotSchema = external_exports.object({
|
|
42955
43022
|
collectedAt: external_exports.number(),
|
|
42956
43023
|
version: external_exports.string(),
|
|
@@ -42959,6 +43026,7 @@ var NodeSettingsSnapshotSchema = external_exports.object({
|
|
|
42959
43026
|
auth: SystemAuthInfoSchema.optional(),
|
|
42960
43027
|
os: SystemOsInfoSchema.optional(),
|
|
42961
43028
|
runtime: SystemRuntimeInfoSchema.optional(),
|
|
43029
|
+
runtimeUpdate: SystemRuntimeUpdateInfoSchema.optional(),
|
|
42962
43030
|
agents: external_exports.array(SystemAgentInfoSchema).optional(),
|
|
42963
43031
|
startupRequirements: external_exports.object({
|
|
42964
43032
|
lastCheckedAt: external_exports.string().optional(),
|
|
@@ -43020,6 +43088,7 @@ var JoinTaskSchema = external_exports.object({
|
|
|
43020
43088
|
agent: external_exports.string(),
|
|
43021
43089
|
project: external_exports.string().nullable(),
|
|
43022
43090
|
effectiveProjectPath: external_exports.string().nullable(),
|
|
43091
|
+
branch: external_exports.string().nullable().optional(),
|
|
43023
43092
|
conversationKind: external_exports.enum(["meshyChat", "nativeSession"]).optional(),
|
|
43024
43093
|
payload: external_exports.record(external_exports.unknown()),
|
|
43025
43094
|
status: external_exports.enum(["pending", "assigned", "running", "completed", "failed", "cancelled", "archived"]),
|
|
@@ -43806,10 +43875,19 @@ function createClusterRoutes() {
|
|
|
43806
43875
|
});
|
|
43807
43876
|
}));
|
|
43808
43877
|
router.post("/leave", asyncHandler(async (req, res) => {
|
|
43809
|
-
const { nodeRegistry, logger: rootLogger } = req.app.locals.deps;
|
|
43878
|
+
const { nodeRegistry, election, leaveCurrentCluster, logger: rootLogger } = req.app.locals.deps;
|
|
43810
43879
|
const log2 = rootLogger.child("cluster/leave");
|
|
43811
43880
|
const { nodeId } = req.body;
|
|
43812
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
|
+
}
|
|
43813
43891
|
nodeRegistry.removeNode(nodeId);
|
|
43814
43892
|
res.json({ ok: true });
|
|
43815
43893
|
}));
|
|
@@ -44755,6 +44833,7 @@ function buildNodeSettingsSnapshot(options) {
|
|
|
44755
44833
|
storagePath: options.storagePath ?? null,
|
|
44756
44834
|
localDashboardOrigin: options.localDashboardOrigin ?? null
|
|
44757
44835
|
},
|
|
44836
|
+
runtimeUpdate: options.runtimeUpdate,
|
|
44758
44837
|
agents,
|
|
44759
44838
|
startupRequirements: {
|
|
44760
44839
|
lastCheckedAt: runtimeMetadata?.startupRequirementsLastCheckedAt,
|
|
@@ -44838,8 +44917,61 @@ function upgradeRuntimeAgentForDeps(deps, agent) {
|
|
|
44838
44917
|
return result;
|
|
44839
44918
|
}
|
|
44840
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
|
+
|
|
44841
44972
|
// ../../packages/api/src/node/node-operation-service.ts
|
|
44842
44973
|
var LEADER_REPORT_RETRY_MS = 5e3;
|
|
44974
|
+
var OPERATION_COMMIT_EFFECT = /* @__PURE__ */ Symbol("operationCommitEffect");
|
|
44843
44975
|
var NodeOperationFailure = class extends Error {
|
|
44844
44976
|
constructor(message, result) {
|
|
44845
44977
|
super(message);
|
|
@@ -44873,6 +45005,7 @@ var NodeOperationService = class {
|
|
|
44873
45005
|
this.deps = deps;
|
|
44874
45006
|
this.store = store;
|
|
44875
45007
|
this.registerHandler("agent.upgrade", runAgentUpgradeOperation);
|
|
45008
|
+
this.registerHandler("runtime.restart", runRuntimeRestartOperation);
|
|
44876
45009
|
this.registerHandler("workdir.branch-create", runWorkDirBranchCreateOperation);
|
|
44877
45010
|
}
|
|
44878
45011
|
handlers = /* @__PURE__ */ new Map();
|
|
@@ -44943,8 +45076,14 @@ var NodeOperationService = class {
|
|
|
44943
45076
|
try {
|
|
44944
45077
|
const handler = this.handlers.get(running.kind);
|
|
44945
45078
|
if (!handler) throw new Error(`No node operation handler registered for kind: ${running.kind}`);
|
|
44946
|
-
const
|
|
44947
|
-
this.update(id, { status: "succeeded", result, completedAt: Date.now() }
|
|
45079
|
+
const handled = readOperationCommitEffect(await handler(running, this.deps));
|
|
45080
|
+
const saved = this.update(id, { status: "succeeded", result: handled.result, completedAt: Date.now() }, {
|
|
45081
|
+
reportToLeader: handled.afterCommit ? false : true
|
|
45082
|
+
});
|
|
45083
|
+
if (handled.afterCommit) {
|
|
45084
|
+
if (saved) await this.reportToLeader(saved);
|
|
45085
|
+
await handled.afterCommit();
|
|
45086
|
+
}
|
|
44948
45087
|
} catch (err) {
|
|
44949
45088
|
this.update(id, {
|
|
44950
45089
|
status: "failed",
|
|
@@ -44954,12 +45093,12 @@ var NodeOperationService = class {
|
|
|
44954
45093
|
});
|
|
44955
45094
|
}
|
|
44956
45095
|
}
|
|
44957
|
-
update(id, updates) {
|
|
45096
|
+
update(id, updates, options = {}) {
|
|
44958
45097
|
const saved = this.store.update(id, { ...updates, updatedAt: Date.now() });
|
|
44959
45098
|
if (!saved) return null;
|
|
44960
45099
|
this.applyOperationSideEffects(saved);
|
|
44961
45100
|
this.deps.eventBus.emit("node.operation.updated", { operation: saved });
|
|
44962
|
-
void this.reportToLeader(saved);
|
|
45101
|
+
if (options.reportToLeader !== false) void this.reportToLeader(saved);
|
|
44963
45102
|
return saved;
|
|
44964
45103
|
}
|
|
44965
45104
|
applyOperationSideEffects(operation) {
|
|
@@ -45040,6 +45179,24 @@ function runAgentUpgradeOperation(operation, deps) {
|
|
|
45040
45179
|
}
|
|
45041
45180
|
return result;
|
|
45042
45181
|
}
|
|
45182
|
+
function runRuntimeRestartOperation(operation, deps) {
|
|
45183
|
+
if (!deps.restartRuntime) throw new Error("Runtime restart is not available for this node");
|
|
45184
|
+
const reason = readPayloadString(operation, "reason") === "update" ? "update" : "restart";
|
|
45185
|
+
const startArgs = readPayloadStartArgs(operation);
|
|
45186
|
+
return deps.restartRuntime({ reason, ...startArgs && { startArgs }, deferShutdown: true }).then(
|
|
45187
|
+
({ completeShutdown, ...result }) => operationCommitEffect(result, completeShutdown)
|
|
45188
|
+
);
|
|
45189
|
+
}
|
|
45190
|
+
function operationCommitEffect(result, afterCommit) {
|
|
45191
|
+
return { [OPERATION_COMMIT_EFFECT]: true, result, afterCommit };
|
|
45192
|
+
}
|
|
45193
|
+
function readOperationCommitEffect(value) {
|
|
45194
|
+
if (value && typeof value === "object" && value[OPERATION_COMMIT_EFFECT]) {
|
|
45195
|
+
const effect = value;
|
|
45196
|
+
return { result: effect.result, afterCommit: effect.afterCommit };
|
|
45197
|
+
}
|
|
45198
|
+
return { result: value };
|
|
45199
|
+
}
|
|
45043
45200
|
function runWorkDirBranchCreateOperation(operation, deps) {
|
|
45044
45201
|
const self2 = deps.nodeRegistry.getSelf();
|
|
45045
45202
|
return createLocalNodeWorkDirBranch(
|
|
@@ -45073,6 +45230,11 @@ function readPayloadBoolean(operation, key, fallback) {
|
|
|
45073
45230
|
const value = payload[key];
|
|
45074
45231
|
return typeof value === "boolean" ? value : fallback;
|
|
45075
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
|
+
}
|
|
45076
45238
|
function readSettingsSnapshot(value) {
|
|
45077
45239
|
if (!value || typeof value !== "object") return void 0;
|
|
45078
45240
|
const snapshot = value.settingsSnapshot;
|
|
@@ -45240,7 +45402,7 @@ function toLegacyWorkerControl2(message) {
|
|
|
45240
45402
|
}
|
|
45241
45403
|
|
|
45242
45404
|
// ../../packages/api/src/tasks/task-route-utils.ts
|
|
45243
|
-
function
|
|
45405
|
+
function isRecord5(value) {
|
|
45244
45406
|
return typeof value === "object" && value !== null;
|
|
45245
45407
|
}
|
|
45246
45408
|
function restoreTaskState(taskEngine, task) {
|
|
@@ -45307,7 +45469,7 @@ function normalizeStructuredValue(value) {
|
|
|
45307
45469
|
if (Array.isArray(value)) {
|
|
45308
45470
|
return value.map((entry) => normalizeStructuredValue(entry));
|
|
45309
45471
|
}
|
|
45310
|
-
if (!
|
|
45472
|
+
if (!isRecord5(value)) {
|
|
45311
45473
|
return value;
|
|
45312
45474
|
}
|
|
45313
45475
|
return Object.fromEntries(
|
|
@@ -45316,20 +45478,20 @@ function normalizeStructuredValue(value) {
|
|
|
45316
45478
|
}
|
|
45317
45479
|
function getTranscriptEventSignature(event) {
|
|
45318
45480
|
if (event.type === "user") {
|
|
45319
|
-
const signature = getTaskUserMessageSignature(
|
|
45481
|
+
const signature = getTaskUserMessageSignature(isRecord5(event.message) ? event.message.content : event.message) ?? getTaskUserMessageSignature(event.content);
|
|
45320
45482
|
return signature ? `user:${signature}` : null;
|
|
45321
45483
|
}
|
|
45322
45484
|
if (event.type === "assistant") {
|
|
45323
45485
|
if (typeof event.message === "string") {
|
|
45324
45486
|
return `assistant:${JSON.stringify(event.message)}`;
|
|
45325
45487
|
}
|
|
45326
|
-
if (
|
|
45488
|
+
if (isRecord5(event.message) && "content" in event.message) {
|
|
45327
45489
|
return `assistant:${JSON.stringify(normalizeStructuredValue(event.message.content))}`;
|
|
45328
45490
|
}
|
|
45329
45491
|
if (Array.isArray(event.content)) {
|
|
45330
45492
|
return `assistant:${JSON.stringify(normalizeStructuredValue(event.content))}`;
|
|
45331
45493
|
}
|
|
45332
|
-
if (
|
|
45494
|
+
if (isRecord5(event.message)) {
|
|
45333
45495
|
return `assistant:${JSON.stringify(normalizeStructuredValue(event.message))}`;
|
|
45334
45496
|
}
|
|
45335
45497
|
}
|
|
@@ -47125,6 +47287,34 @@ async function sendNodeAgentUpgrade(req, res, nodeId, agentParam) {
|
|
|
47125
47287
|
res.status(202).json(operation);
|
|
47126
47288
|
}
|
|
47127
47289
|
|
|
47290
|
+
// ../../packages/api/src/routes/node-runtime.ts
|
|
47291
|
+
async function sendNodeRuntimeRestart(req, res, nodeId) {
|
|
47292
|
+
const deps = req.app.locals.deps;
|
|
47293
|
+
const self2 = deps.nodeRegistry.getSelf();
|
|
47294
|
+
const isSelf = nodeId === self2.id;
|
|
47295
|
+
if (!isSelf && !deps.election.isLeader()) {
|
|
47296
|
+
throw new MeshyError("NOT_LEADER", "Only the leader can restart other nodes", 403);
|
|
47297
|
+
}
|
|
47298
|
+
const node = isSelf ? self2 : deps.nodeRegistry.getNode(nodeId);
|
|
47299
|
+
if (!node) {
|
|
47300
|
+
throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
|
|
47301
|
+
}
|
|
47302
|
+
const restartRequest = parseRuntimeRestartRequest(req.body);
|
|
47303
|
+
const operations = getNodeOperationService(deps);
|
|
47304
|
+
const operation = operations.create("runtime.restart", nodeId, { ...restartRequest });
|
|
47305
|
+
if (isSelf) {
|
|
47306
|
+
operations.runLocal(operation.id);
|
|
47307
|
+
} else {
|
|
47308
|
+
try {
|
|
47309
|
+
await dispatchNodeOperation(deps, operation, node);
|
|
47310
|
+
} catch (err) {
|
|
47311
|
+
operations.markFailed(operation.id, err instanceof Error ? err.message : String(err));
|
|
47312
|
+
throw new MeshyError("NODE_OFFLINE", `Cannot reach node ${nodeId} to restart runtime`, 502);
|
|
47313
|
+
}
|
|
47314
|
+
}
|
|
47315
|
+
res.status(202).json(operation);
|
|
47316
|
+
}
|
|
47317
|
+
|
|
47128
47318
|
// ../../packages/api/src/routes/node-terminal.ts
|
|
47129
47319
|
var TERMINAL_SESSION_PROXY_TIMEOUT_MS = 1e4;
|
|
47130
47320
|
function getTerminalSessionService2(deps) {
|
|
@@ -47548,6 +47738,9 @@ function createNodeRoutes() {
|
|
|
47548
47738
|
router.post("/:id/agents/:agent/upgrade", asyncHandler3(async (req, res) => {
|
|
47549
47739
|
await sendNodeAgentUpgrade(req, res, req.params.id, req.params.agent);
|
|
47550
47740
|
}));
|
|
47741
|
+
router.post("/:id/runtime/restart", asyncHandler3(async (req, res) => {
|
|
47742
|
+
await sendNodeRuntimeRestart(req, res, req.params.id);
|
|
47743
|
+
}));
|
|
47551
47744
|
router.patch("/:id", asyncHandler3(async (req, res) => {
|
|
47552
47745
|
const { nodeRegistry, persistNodeNamePreference } = req.app.locals.deps;
|
|
47553
47746
|
const updates = UpdateNodeBody.parse(req.body);
|
|
@@ -48029,8 +48222,10 @@ async function sendTaskLogsResponse(req, res, taskId) {
|
|
|
48029
48222
|
if (!task && !proxyRequest.isProxy && await maybeProxyReadToLeader(req, res)) return;
|
|
48030
48223
|
const selfId = nodeRegistry.getSelf()?.id;
|
|
48031
48224
|
const isLeader = nodeRegistry.isLeader();
|
|
48225
|
+
const snapshotOwnerId = task ? getJoinTaskSnapshotOwnerId(task) : null;
|
|
48226
|
+
const proxyNodeId = task?.assignedTo ?? snapshotOwnerId;
|
|
48032
48227
|
const isFollowerRemoteTask = !isLeader && !!(task?.assignedTo && task.assignedTo !== selfId);
|
|
48033
|
-
const needsProxy = isLeader && !!(
|
|
48228
|
+
const needsProxy = isLeader && !!(proxyNodeId && proxyNodeId !== selfId);
|
|
48034
48229
|
if (proxyRequest.isProxy) {
|
|
48035
48230
|
log2.info("received proxied task logs request", {
|
|
48036
48231
|
taskId,
|
|
@@ -48048,6 +48243,7 @@ async function sendTaskLogsResponse(req, res, taskId) {
|
|
|
48048
48243
|
log2.debug("log request", {
|
|
48049
48244
|
taskId,
|
|
48050
48245
|
assignedTo: task?.assignedTo,
|
|
48246
|
+
snapshotOwnerId,
|
|
48051
48247
|
selfId,
|
|
48052
48248
|
isLeader,
|
|
48053
48249
|
needsProxy
|
|
@@ -48071,20 +48267,21 @@ async function sendTaskLogsResponse(req, res, taskId) {
|
|
|
48071
48267
|
selfId
|
|
48072
48268
|
});
|
|
48073
48269
|
}
|
|
48074
|
-
|
|
48075
|
-
|
|
48076
|
-
const node = nodeRegistry.getNode(assignedTo);
|
|
48270
|
+
if (needsProxy && proxyNodeId) {
|
|
48271
|
+
const node = nodeRegistry.getNode(proxyNodeId);
|
|
48077
48272
|
log2.debug("proxy target", { nodeId: node?.id, endpoint: node?.endpoint, devtunnel: node?.devtunnelEndpoint, status: node?.status });
|
|
48078
48273
|
if (node) {
|
|
48079
|
-
|
|
48080
|
-
|
|
48081
|
-
|
|
48082
|
-
|
|
48083
|
-
|
|
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 [];
|
|
48084
48282
|
});
|
|
48085
|
-
|
|
48086
|
-
}
|
|
48087
|
-
if (seededLogs.length > 0) recordLocalTaskLogs(engineRegistry, task, seededLogs);
|
|
48283
|
+
if (seededLogs.length > 0) recordLocalTaskLogs(engineRegistry, task, seededLogs);
|
|
48284
|
+
}
|
|
48088
48285
|
const proxyPath = `/api/tasks/${taskId}/logs?after=${after}`;
|
|
48089
48286
|
try {
|
|
48090
48287
|
const { endpoint, response: proxyRes } = await fetchNodeWithFallback(
|
|
@@ -48098,7 +48295,7 @@ async function sendTaskLogsResponse(req, res, taskId) {
|
|
|
48098
48295
|
const proxyUrl = `${endpoint}${proxyPath}`;
|
|
48099
48296
|
log2.info("proxying task logs request", {
|
|
48100
48297
|
taskId,
|
|
48101
|
-
assignedTo,
|
|
48298
|
+
assignedTo: proxyNodeId,
|
|
48102
48299
|
endpoint,
|
|
48103
48300
|
proxyPath,
|
|
48104
48301
|
url: proxyUrl
|
|
@@ -48111,11 +48308,11 @@ async function sendTaskLogsResponse(req, res, taskId) {
|
|
|
48111
48308
|
} catch (err) {
|
|
48112
48309
|
log2.warn("task logs proxy failed; falling back to keepalive control", {
|
|
48113
48310
|
taskId,
|
|
48114
|
-
assignedTo,
|
|
48311
|
+
assignedTo: proxyNodeId,
|
|
48115
48312
|
timeoutMs: TASK_LOG_PROXY_TIMEOUT_MS,
|
|
48116
48313
|
...describeProxyError3(err)
|
|
48117
48314
|
});
|
|
48118
|
-
const fallback = await requestTaskLogsOverKeepalive(heartbeat,
|
|
48315
|
+
const fallback = await requestTaskLogsOverKeepalive(heartbeat, proxyNodeId, task, after);
|
|
48119
48316
|
if (fallback) {
|
|
48120
48317
|
sendWorkerControlResponse(res, fallback);
|
|
48121
48318
|
return;
|
|
@@ -48506,6 +48703,8 @@ var TERMINAL_STATUSES3 = /* @__PURE__ */ new Set(["completed", "failed", "cancel
|
|
|
48506
48703
|
var ARCHIVABLE_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "archived"]);
|
|
48507
48704
|
var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "assigned", "running"]);
|
|
48508
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";
|
|
48509
48708
|
function shouldGenerateTitle(task) {
|
|
48510
48709
|
return task.payload.titleSource === "derived";
|
|
48511
48710
|
}
|
|
@@ -48616,6 +48815,62 @@ function withShareMetadata(task, taskEngine, shareOrigin) {
|
|
|
48616
48815
|
function toTaskResponse(task, nodeRegistry, taskEngine, shareOrigin) {
|
|
48617
48816
|
return withShareMetadata(withAssignedNodeMetadata(task, nodeRegistry), taskEngine, shareOrigin);
|
|
48618
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
|
+
}
|
|
48619
48874
|
function buildShareUrl(origin, shareId) {
|
|
48620
48875
|
return `${origin.replace(/\/+$/, "")}/shared/tasks/${encodeURIComponent(shareId)}`;
|
|
48621
48876
|
}
|
|
@@ -48739,14 +48994,15 @@ function createTaskRoutes() {
|
|
|
48739
48994
|
res.json({ results });
|
|
48740
48995
|
}));
|
|
48741
48996
|
router.get("/:id", asyncHandler6(async (req, res) => {
|
|
48742
|
-
const { taskEngine, nodeRegistry, shareOrigin } = req.app.locals.deps;
|
|
48997
|
+
const { taskEngine, nodeRegistry, shareOrigin, logger: logger27 } = req.app.locals.deps;
|
|
48743
48998
|
const taskId = req.params.id;
|
|
48744
48999
|
const task = taskEngine.getTask(taskId);
|
|
48745
49000
|
if (!task) {
|
|
48746
49001
|
if (await maybeProxyReadToLeader(req, res)) return;
|
|
48747
49002
|
throw new MeshyError("TASK_NOT_FOUND", `Task ${taskId} not found`, 404);
|
|
48748
49003
|
}
|
|
48749
|
-
|
|
49004
|
+
const fullTask = await proxyJoinSnapshotTaskDetail({ task, req, logger: logger27, nodeRegistry });
|
|
49005
|
+
res.json(toTaskResponse(fullTask ?? task, nodeRegistry, taskEngine, shareOrigin));
|
|
48750
49006
|
}));
|
|
48751
49007
|
router.post("/:id/share", asyncHandler6(async (req, res) => {
|
|
48752
49008
|
const { taskEngine, ensureShareTunnel } = req.app.locals.deps;
|
|
@@ -49378,7 +49634,8 @@ function createSystemRoutes() {
|
|
|
49378
49634
|
localDashboardOrigin,
|
|
49379
49635
|
storagePath,
|
|
49380
49636
|
inspectRuntimeTools: inspectTools,
|
|
49381
|
-
runtimeMetadata
|
|
49637
|
+
runtimeMetadata,
|
|
49638
|
+
runtimeUpdate
|
|
49382
49639
|
} = req.app.locals.deps;
|
|
49383
49640
|
const self2 = nodeRegistry.getSelf();
|
|
49384
49641
|
const auth = config.authMetadata ?? {
|
|
@@ -49391,6 +49648,7 @@ function createSystemRoutes() {
|
|
|
49391
49648
|
inspectRuntimeTools: inspectTools,
|
|
49392
49649
|
localDashboardOrigin,
|
|
49393
49650
|
runtimeMetadata,
|
|
49651
|
+
runtimeUpdate,
|
|
49394
49652
|
storagePath,
|
|
49395
49653
|
workDir: self2.workDir
|
|
49396
49654
|
});
|
|
@@ -49406,6 +49664,7 @@ function createSystemRoutes() {
|
|
|
49406
49664
|
auth: settingsSnapshot.auth,
|
|
49407
49665
|
os: settingsSnapshot.os,
|
|
49408
49666
|
runtime: settingsSnapshot.runtime,
|
|
49667
|
+
runtimeUpdate: settingsSnapshot.runtimeUpdate,
|
|
49409
49668
|
agents: settingsSnapshot.agents,
|
|
49410
49669
|
startupRequirements: settingsSnapshot.startupRequirements,
|
|
49411
49670
|
components: settingsSnapshot.components,
|
|
@@ -49413,6 +49672,23 @@ function createSystemRoutes() {
|
|
|
49413
49672
|
packages: settingsSnapshot.packages
|
|
49414
49673
|
});
|
|
49415
49674
|
}));
|
|
49675
|
+
router.post("/runtime/restart", asyncHandler9(async (req, res) => {
|
|
49676
|
+
const { restartRuntime } = req.app.locals.deps;
|
|
49677
|
+
if (!restartRuntime) {
|
|
49678
|
+
throw new MeshyError("VALIDATION_ERROR", "Runtime restart is not available for this node", 501);
|
|
49679
|
+
}
|
|
49680
|
+
const restartRequest = parseRuntimeRestartRequest(req.body);
|
|
49681
|
+
const result = await restartRuntime(restartRequest);
|
|
49682
|
+
res.status(202).json(result);
|
|
49683
|
+
}));
|
|
49684
|
+
router.post("/runtime/stop", asyncHandler9(async (req, res) => {
|
|
49685
|
+
const { stopRuntime } = req.app.locals.deps;
|
|
49686
|
+
if (!stopRuntime) {
|
|
49687
|
+
throw new MeshyError("VALIDATION_ERROR", "Runtime stop is not available for this node", 501);
|
|
49688
|
+
}
|
|
49689
|
+
const result = await stopRuntime();
|
|
49690
|
+
res.status(202).json(result);
|
|
49691
|
+
}));
|
|
49416
49692
|
router.post("/transport", asyncHandler9(async (req, res) => {
|
|
49417
49693
|
const { switchTransport } = req.app.locals.deps;
|
|
49418
49694
|
if (!switchTransport) {
|
|
@@ -49581,6 +49857,9 @@ function createNodeOperationRoutes() {
|
|
|
49581
49857
|
var JSON_BODY_LIMIT = "1mb";
|
|
49582
49858
|
var JSON_BODY_LIMIT_LARGE = "25mb";
|
|
49583
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
|
+
}
|
|
49584
49863
|
function normalizeHost2(value) {
|
|
49585
49864
|
const trimmed = value?.trim().toLowerCase();
|
|
49586
49865
|
return trimmed ? trimmed.replace(/:\d+$/, "") : void 0;
|
|
@@ -49707,7 +49986,12 @@ function createServer2(deps) {
|
|
|
49707
49986
|
staticMiddleware(req, res, next);
|
|
49708
49987
|
});
|
|
49709
49988
|
}
|
|
49710
|
-
|
|
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
|
+
});
|
|
49711
49995
|
app.use(createAuthMiddleware(authConfig));
|
|
49712
49996
|
app.use((req, res, next) => {
|
|
49713
49997
|
void (async () => {
|
|
@@ -49733,14 +50017,13 @@ function createServer2(deps) {
|
|
|
49733
50017
|
taskEngine: deps.taskEngine,
|
|
49734
50018
|
logger: deps.logger
|
|
49735
50019
|
}));
|
|
49736
|
-
const largeBodyParser = import_express14.default.json({ limit: JSON_BODY_LIMIT_LARGE });
|
|
49737
50020
|
app.use("/api/cluster", createClusterRoutes());
|
|
49738
50021
|
app.use("/api/cluster-control", createClusterControlRoutes());
|
|
49739
|
-
app.use("/api/node",
|
|
50022
|
+
app.use("/api/node", createNodeMessageRoutes());
|
|
49740
50023
|
app.use("/api/nodes", createNodeRoutes());
|
|
49741
|
-
app.use("/api/tasks",
|
|
50024
|
+
app.use("/api/tasks", createTaskRoutes());
|
|
49742
50025
|
app.use("/api/shared", createSharedRoutes());
|
|
49743
|
-
app.use("/api/worker",
|
|
50026
|
+
app.use("/api/worker", createWorkerRoutes());
|
|
49744
50027
|
app.use("/api/system", createSystemRoutes());
|
|
49745
50028
|
app.use("/api/node-operations", createNodeOperationRoutes());
|
|
49746
50029
|
app.use("/api/events", createEventRoutes());
|
|
@@ -50780,6 +51063,346 @@ function buildRuntimeMetadata(storagePath) {
|
|
|
50780
51063
|
};
|
|
50781
51064
|
}
|
|
50782
51065
|
|
|
51066
|
+
// src/bootstrap/runtime-restart.ts
|
|
51067
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
51068
|
+
var nodePath2 = __toESM(require("path"), 1);
|
|
51069
|
+
var import_node_child_process14 = require("child_process");
|
|
51070
|
+
function resolveRuntimeRestartStartArgs(hydratedArgs, restartArgs) {
|
|
51071
|
+
return restartArgs ? { ...restartArgs } : hydratedArgs;
|
|
51072
|
+
}
|
|
51073
|
+
var runtimeUpdateCache = /* @__PURE__ */ new Map();
|
|
51074
|
+
var RESTARTER_SOURCE = String.raw`
|
|
51075
|
+
const { spawn } = require('node:child_process');
|
|
51076
|
+
const http = require('node:http');
|
|
51077
|
+
|
|
51078
|
+
const plan = JSON.parse(process.env.MESHY_RESTART_PLAN || '{}');
|
|
51079
|
+
const parentPid = Number(process.env.MESHY_RESTART_PARENT_PID || '0');
|
|
51080
|
+
|
|
51081
|
+
function log(message) {
|
|
51082
|
+
process.stdout.write('[' + new Date().toISOString() + '] ' + message + '\n');
|
|
51083
|
+
}
|
|
51084
|
+
|
|
51085
|
+
function sleep(ms) {
|
|
51086
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
51087
|
+
}
|
|
51088
|
+
|
|
51089
|
+
function isProcessAlive(pid) {
|
|
51090
|
+
if (!pid) return false;
|
|
51091
|
+
try {
|
|
51092
|
+
process.kill(pid, 0);
|
|
51093
|
+
return true;
|
|
51094
|
+
} catch {
|
|
51095
|
+
return false;
|
|
51096
|
+
}
|
|
51097
|
+
}
|
|
51098
|
+
|
|
51099
|
+
function requestHealth(url) {
|
|
51100
|
+
return new Promise(resolve => {
|
|
51101
|
+
const req = http.get(url, res => {
|
|
51102
|
+
res.resume();
|
|
51103
|
+
res.on('end', () => resolve(res.statusCode >= 200 && res.statusCode < 500));
|
|
51104
|
+
});
|
|
51105
|
+
req.setTimeout(1000, () => {
|
|
51106
|
+
req.destroy();
|
|
51107
|
+
resolve(false);
|
|
51108
|
+
});
|
|
51109
|
+
req.on('error', () => resolve(false));
|
|
51110
|
+
});
|
|
51111
|
+
}
|
|
51112
|
+
|
|
51113
|
+
async function waitForParentExit() {
|
|
51114
|
+
const deadline = Date.now() + 30000;
|
|
51115
|
+
while (isProcessAlive(parentPid) && Date.now() < deadline) {
|
|
51116
|
+
await sleep(250);
|
|
51117
|
+
}
|
|
51118
|
+
}
|
|
51119
|
+
|
|
51120
|
+
async function waitForEndpointDown() {
|
|
51121
|
+
if (!plan.healthUrl) return;
|
|
51122
|
+
const deadline = Date.now() + 30000;
|
|
51123
|
+
while (Date.now() < deadline) {
|
|
51124
|
+
if (!await requestHealth(plan.healthUrl)) return;
|
|
51125
|
+
await sleep(250);
|
|
51126
|
+
}
|
|
51127
|
+
}
|
|
51128
|
+
|
|
51129
|
+
(async () => {
|
|
51130
|
+
log('waiting to restart ' + (plan.displayCommand || plan.command));
|
|
51131
|
+
await waitForParentExit();
|
|
51132
|
+
await waitForEndpointDown();
|
|
51133
|
+
log('starting ' + (plan.displayCommand || plan.command));
|
|
51134
|
+
const child = spawn(plan.command, plan.args || [], {
|
|
51135
|
+
cwd: plan.cwd,
|
|
51136
|
+
env: { ...process.env, ...(plan.env || {}), MESHY_RESTART_CHILD: '1' },
|
|
51137
|
+
detached: true,
|
|
51138
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
51139
|
+
windowsHide: true,
|
|
51140
|
+
});
|
|
51141
|
+
child.on('error', error => {
|
|
51142
|
+
log('failed to launch restart command: ' + (error && error.message ? error.message : String(error)));
|
|
51143
|
+
process.exitCode = 1;
|
|
51144
|
+
});
|
|
51145
|
+
child.unref();
|
|
51146
|
+
await sleep(500);
|
|
51147
|
+
})().catch(error => {
|
|
51148
|
+
log('restart helper failed: ' + (error && error.message ? error.message : String(error)));
|
|
51149
|
+
process.exit(1);
|
|
51150
|
+
});
|
|
51151
|
+
`;
|
|
51152
|
+
function formatLocalDate3(date) {
|
|
51153
|
+
const year = date.getFullYear();
|
|
51154
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
51155
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
51156
|
+
return `${year}-${month}-${day}`;
|
|
51157
|
+
}
|
|
51158
|
+
function normalizeOutput2(output) {
|
|
51159
|
+
if (!output) return null;
|
|
51160
|
+
const firstLine = output.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
|
|
51161
|
+
return firstLine ?? null;
|
|
51162
|
+
}
|
|
51163
|
+
function normalizePackageVersion2(output) {
|
|
51164
|
+
const normalized = normalizeOutput2(output);
|
|
51165
|
+
if (!normalized) return null;
|
|
51166
|
+
try {
|
|
51167
|
+
const parsed = JSON.parse(normalized);
|
|
51168
|
+
return typeof parsed === "string" ? parsed.trim() || null : normalized;
|
|
51169
|
+
} catch {
|
|
51170
|
+
return normalized;
|
|
51171
|
+
}
|
|
51172
|
+
}
|
|
51173
|
+
function compareSemver2(left, right) {
|
|
51174
|
+
const leftParts = left.split(/[.-]/).map((part) => Number.parseInt(part, 10));
|
|
51175
|
+
const rightParts = right.split(/[.-]/).map((part) => Number.parseInt(part, 10));
|
|
51176
|
+
for (let index = 0; index < 3; index += 1) {
|
|
51177
|
+
const delta = (leftParts[index] || 0) - (rightParts[index] || 0);
|
|
51178
|
+
if (delta !== 0) return delta;
|
|
51179
|
+
}
|
|
51180
|
+
return 0;
|
|
51181
|
+
}
|
|
51182
|
+
function runRuntimePackageCommand(command, args) {
|
|
51183
|
+
const result = (0, import_node_child_process14.spawnSync)(command, args, {
|
|
51184
|
+
encoding: "utf-8",
|
|
51185
|
+
windowsHide: true,
|
|
51186
|
+
timeout: 2500
|
|
51187
|
+
});
|
|
51188
|
+
return {
|
|
51189
|
+
status: result.status,
|
|
51190
|
+
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
51191
|
+
stderr: typeof result.stderr === "string" ? result.stderr : "",
|
|
51192
|
+
error: result.error?.message ?? null
|
|
51193
|
+
};
|
|
51194
|
+
}
|
|
51195
|
+
function commandName(base, platform2) {
|
|
51196
|
+
return platform2 === "win32" ? `${base}.cmd` : base;
|
|
51197
|
+
}
|
|
51198
|
+
function pathForPlatform(platform2) {
|
|
51199
|
+
return platform2 === "win32" ? nodePath2.win32 : nodePath2;
|
|
51200
|
+
}
|
|
51201
|
+
function resolveDevelopmentRepoRoot(cwd, env, platform2) {
|
|
51202
|
+
if (env.MESHY_STORAGE_BASE_DIR) return env.MESHY_STORAGE_BASE_DIR;
|
|
51203
|
+
const pathApi = pathForPlatform(platform2);
|
|
51204
|
+
const packageDir = pathApi.basename(cwd);
|
|
51205
|
+
const packageParent = pathApi.basename(pathApi.dirname(cwd));
|
|
51206
|
+
return packageDir === "node" && packageParent === "apps" ? pathApi.dirname(pathApi.dirname(cwd)) : cwd;
|
|
51207
|
+
}
|
|
51208
|
+
function windowsShellQuote(value) {
|
|
51209
|
+
return /[\s&()^|<>"]/.test(value) ? `"${value.replace(/"/g, '\\"')}"` : value;
|
|
51210
|
+
}
|
|
51211
|
+
function createSpawnableCommand(command, args, platform2) {
|
|
51212
|
+
const displayCommand = [command, ...args].map(shellQuote).join(" ");
|
|
51213
|
+
if (platform2 !== "win32") return { command, args, displayCommand };
|
|
51214
|
+
return {
|
|
51215
|
+
command: "cmd.exe",
|
|
51216
|
+
args: ["/d", "/s", "/c", [command, ...args].map(windowsShellQuote).join(" ")],
|
|
51217
|
+
displayCommand
|
|
51218
|
+
};
|
|
51219
|
+
}
|
|
51220
|
+
function readProcessCommand(pid, platform2) {
|
|
51221
|
+
if (platform2 === "win32") return null;
|
|
51222
|
+
const result = (0, import_node_child_process14.spawnSync)("ps", ["-p", String(pid), "-o", "args="], {
|
|
51223
|
+
encoding: "utf-8",
|
|
51224
|
+
windowsHide: true,
|
|
51225
|
+
timeout: 1e3
|
|
51226
|
+
});
|
|
51227
|
+
return result.status === 0 && typeof result.stdout === "string" ? result.stdout.trim() || null : null;
|
|
51228
|
+
}
|
|
51229
|
+
function isNodeWatchCommand(command) {
|
|
51230
|
+
return /(?:^|[/\\])node(?:\.exe)?(?:\s|$)/.test(command) && /(?:^|\s)--watch(?:=|\s|$)/.test(command);
|
|
51231
|
+
}
|
|
51232
|
+
function terminateRuntimeWatchParent(options) {
|
|
51233
|
+
if (options.mode !== "development") return { terminated: false, reason: "not-development" };
|
|
51234
|
+
const parentPid = options.parentPid ?? process.ppid;
|
|
51235
|
+
if (!Number.isInteger(parentPid) || parentPid <= 1 || parentPid === process.pid) {
|
|
51236
|
+
return { terminated: false, reason: "invalid-parent" };
|
|
51237
|
+
}
|
|
51238
|
+
const commandReader = options.commandReader ?? ((pid) => readProcessCommand(pid, options.platform ?? process.platform));
|
|
51239
|
+
const parentCommand = commandReader(parentPid);
|
|
51240
|
+
const parentIsWatch = parentCommand !== null ? isNodeWatchCommand(parentCommand) : options.env?.WATCH_REPORT_DEPENDENCIES === "1";
|
|
51241
|
+
if (!parentIsWatch) return { terminated: false, reason: "parent-not-watch" };
|
|
51242
|
+
try {
|
|
51243
|
+
const kill = options.kill ?? process.kill;
|
|
51244
|
+
kill(parentPid, "SIGINT");
|
|
51245
|
+
return { terminated: true, pid: parentPid };
|
|
51246
|
+
} catch {
|
|
51247
|
+
return { terminated: false, reason: "kill-failed" };
|
|
51248
|
+
}
|
|
51249
|
+
}
|
|
51250
|
+
function compactEnv(env) {
|
|
51251
|
+
const result = {};
|
|
51252
|
+
for (const [key, value] of Object.entries(env)) {
|
|
51253
|
+
if (typeof value === "string") result[key] = value;
|
|
51254
|
+
}
|
|
51255
|
+
return result;
|
|
51256
|
+
}
|
|
51257
|
+
function shellQuote(value) {
|
|
51258
|
+
return /\s/.test(value) ? JSON.stringify(value) : value;
|
|
51259
|
+
}
|
|
51260
|
+
function formatStartArgs(args) {
|
|
51261
|
+
const result = ["start"];
|
|
51262
|
+
if (args.port !== void 0) result.push("--port", String(args.port));
|
|
51263
|
+
if (args.name) result.push("--name", args.name);
|
|
51264
|
+
if (args.join) result.push("--join", args.join);
|
|
51265
|
+
if (args.transport) result.push("--transport", args.transport);
|
|
51266
|
+
if (args.workDir) result.push("--work-dir", args.workDir);
|
|
51267
|
+
if (args.config) result.push("--config", args.config);
|
|
51268
|
+
if (args.disableAuth) result.push("--disable-auth");
|
|
51269
|
+
return result;
|
|
51270
|
+
}
|
|
51271
|
+
function detectRuntimeRestartMode(env = process.env, entryPath = process.argv[1]) {
|
|
51272
|
+
if (env.MESHY_RESTART_MODE === "package" || env.MESHY_RESTART_MODE === "development") {
|
|
51273
|
+
return env.MESHY_RESTART_MODE;
|
|
51274
|
+
}
|
|
51275
|
+
if (env.MESHY_STORAGE_MODE === "cwd" && env.MESHY_STORAGE_BASE_DIR) {
|
|
51276
|
+
return "development";
|
|
51277
|
+
}
|
|
51278
|
+
return typeof entryPath === "string" && /src[/\\]main\.ts$/.test(entryPath) ? "development" : "package";
|
|
51279
|
+
}
|
|
51280
|
+
function createRuntimeRestartLaunchPlan(options) {
|
|
51281
|
+
const platform2 = options.platform ?? process.platform;
|
|
51282
|
+
const startArgs = formatStartArgs(options.startArgs);
|
|
51283
|
+
const env = compactEnv(options.env);
|
|
51284
|
+
const logPath = pathForPlatform(platform2).join(options.storagePath, "logs", "restart.log");
|
|
51285
|
+
const healthUrl = new URL("/api/system/health", options.localDashboardOrigin).toString();
|
|
51286
|
+
if (options.mode === "development") {
|
|
51287
|
+
const repoRoot2 = resolveDevelopmentRepoRoot(options.cwd, options.env, platform2);
|
|
51288
|
+
const launch2 = createSpawnableCommand(commandName("pnpm", platform2), ["dev:node", "--", ...startArgs], platform2);
|
|
51289
|
+
return {
|
|
51290
|
+
mode: "development",
|
|
51291
|
+
command: launch2.command,
|
|
51292
|
+
args: launch2.args,
|
|
51293
|
+
cwd: repoRoot2,
|
|
51294
|
+
env,
|
|
51295
|
+
displayCommand: launch2.displayCommand,
|
|
51296
|
+
logPath,
|
|
51297
|
+
healthUrl
|
|
51298
|
+
};
|
|
51299
|
+
}
|
|
51300
|
+
const launch = createSpawnableCommand(commandName("npx", platform2), ["-y", "meshy-node@latest", ...startArgs], platform2);
|
|
51301
|
+
return {
|
|
51302
|
+
mode: "package",
|
|
51303
|
+
command: launch.command,
|
|
51304
|
+
args: launch.args,
|
|
51305
|
+
cwd: options.cwd,
|
|
51306
|
+
env,
|
|
51307
|
+
displayCommand: launch.displayCommand,
|
|
51308
|
+
logPath,
|
|
51309
|
+
healthUrl
|
|
51310
|
+
};
|
|
51311
|
+
}
|
|
51312
|
+
function scheduleRuntimeRestart(plan, options = {}) {
|
|
51313
|
+
fs22.mkdirSync(nodePath2.dirname(plan.logPath), { recursive: true });
|
|
51314
|
+
const logFd = fs22.openSync(plan.logPath, "a");
|
|
51315
|
+
const spawnImpl = options.spawnImpl ?? import_node_child_process14.spawn;
|
|
51316
|
+
const env = {
|
|
51317
|
+
...process.env,
|
|
51318
|
+
MESHY_RESTART_PARENT_PID: String(options.parentPid ?? process.pid),
|
|
51319
|
+
MESHY_RESTART_PLAN: JSON.stringify(plan)
|
|
51320
|
+
};
|
|
51321
|
+
const child = spawnImpl(process.execPath, ["-e", RESTARTER_SOURCE], {
|
|
51322
|
+
detached: true,
|
|
51323
|
+
env,
|
|
51324
|
+
stdio: ["ignore", logFd, logFd],
|
|
51325
|
+
windowsHide: true
|
|
51326
|
+
});
|
|
51327
|
+
child.unref();
|
|
51328
|
+
}
|
|
51329
|
+
function createRuntimeUpdateSnapshot(options) {
|
|
51330
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
51331
|
+
const checkedAt = now.toISOString();
|
|
51332
|
+
const currentVersion = options.runtimeMetadata?.packageVersion ?? null;
|
|
51333
|
+
const packageName = "meshy-node";
|
|
51334
|
+
if (options.mode === "development") {
|
|
51335
|
+
return {
|
|
51336
|
+
packageName,
|
|
51337
|
+
currentVersion,
|
|
51338
|
+
latestVersion: null,
|
|
51339
|
+
updateAvailable: false,
|
|
51340
|
+
checkedAt,
|
|
51341
|
+
restartMode: "development",
|
|
51342
|
+
detail: "Development runtime restarts from the local workspace."
|
|
51343
|
+
};
|
|
51344
|
+
}
|
|
51345
|
+
const cache = options.updateCache ?? runtimeUpdateCache;
|
|
51346
|
+
const checkedOn = formatLocalDate3(now);
|
|
51347
|
+
const cached = cache.get(packageName);
|
|
51348
|
+
let latestVersion = cached?.latestVersion ?? null;
|
|
51349
|
+
let detail = cached?.detail ?? null;
|
|
51350
|
+
let updateCheckedAt = cached?.checkedAt ?? checkedAt;
|
|
51351
|
+
if (cached?.checkedOn !== checkedOn) {
|
|
51352
|
+
const runner = options.commandRunner ?? runRuntimePackageCommand;
|
|
51353
|
+
const result = runner("npm", ["view", `${packageName}@latest`, "version", "--json"]);
|
|
51354
|
+
latestVersion = result.status === 0 ? normalizePackageVersion2(result.stdout) : null;
|
|
51355
|
+
detail = result.status === 0 ? null : normalizeOutput2(result.stderr) ?? result.error ?? "Runtime update check failed";
|
|
51356
|
+
updateCheckedAt = checkedAt;
|
|
51357
|
+
cache.set(packageName, { checkedOn, checkedAt, latestVersion, detail });
|
|
51358
|
+
}
|
|
51359
|
+
return {
|
|
51360
|
+
packageName,
|
|
51361
|
+
currentVersion,
|
|
51362
|
+
latestVersion,
|
|
51363
|
+
updateAvailable: Boolean(currentVersion && latestVersion && compareSemver2(latestVersion, currentVersion) > 0),
|
|
51364
|
+
checkedAt: updateCheckedAt,
|
|
51365
|
+
restartMode: "package",
|
|
51366
|
+
detail
|
|
51367
|
+
};
|
|
51368
|
+
}
|
|
51369
|
+
|
|
51370
|
+
// src/bootstrap/settings-snapshot.ts
|
|
51371
|
+
function createSettingsSnapshotProvider(options) {
|
|
51372
|
+
let cachedSnapshot = null;
|
|
51373
|
+
let cachedSnapshotAt = 0;
|
|
51374
|
+
function buildSnapshot() {
|
|
51375
|
+
cachedSnapshot = buildNodeSettingsSnapshot({
|
|
51376
|
+
auth: options.authMetadata,
|
|
51377
|
+
localDashboardOrigin: options.localDashboardOrigin,
|
|
51378
|
+
runtimeMetadata: options.runtimeMetadata,
|
|
51379
|
+
runtimeUpdate: createRuntimeUpdateSnapshot({
|
|
51380
|
+
mode: options.runtimeRestartMode,
|
|
51381
|
+
runtimeMetadata: options.runtimeMetadata
|
|
51382
|
+
}),
|
|
51383
|
+
storagePath: options.storagePath,
|
|
51384
|
+
workDir: options.workDir
|
|
51385
|
+
});
|
|
51386
|
+
cachedSnapshotAt = Date.now();
|
|
51387
|
+
return structuredClone(cachedSnapshot);
|
|
51388
|
+
}
|
|
51389
|
+
function getSettingsSnapshot() {
|
|
51390
|
+
const now = Date.now();
|
|
51391
|
+
if (cachedSnapshot && now - cachedSnapshotAt < 3e4) {
|
|
51392
|
+
return structuredClone(cachedSnapshot);
|
|
51393
|
+
}
|
|
51394
|
+
return buildSnapshot();
|
|
51395
|
+
}
|
|
51396
|
+
return {
|
|
51397
|
+
getSettingsSnapshot,
|
|
51398
|
+
refreshSettingsSnapshot: () => {
|
|
51399
|
+
cachedSnapshot = null;
|
|
51400
|
+
cachedSnapshotAt = 0;
|
|
51401
|
+
return buildSnapshot();
|
|
51402
|
+
}
|
|
51403
|
+
};
|
|
51404
|
+
}
|
|
51405
|
+
|
|
50783
51406
|
// src/bootstrap/tunnel-health.ts
|
|
50784
51407
|
var DEFAULT_TUNNEL_REACHABILITY_INTERVAL_MS = 6e4;
|
|
50785
51408
|
var DEFAULT_TUNNEL_REACHABILITY_TIMEOUT_MS = 5e3;
|
|
@@ -50857,36 +51480,6 @@ async function fetchWithTimeout2(fetchImpl, url, timeoutMs) {
|
|
|
50857
51480
|
}
|
|
50858
51481
|
|
|
50859
51482
|
// src/bootstrap/start-node.ts
|
|
50860
|
-
function createSettingsSnapshotProvider(options) {
|
|
50861
|
-
let cachedSnapshot = null;
|
|
50862
|
-
let cachedSnapshotAt = 0;
|
|
50863
|
-
function buildSnapshot() {
|
|
50864
|
-
cachedSnapshot = buildNodeSettingsSnapshot({
|
|
50865
|
-
auth: options.authMetadata,
|
|
50866
|
-
localDashboardOrigin: options.localDashboardOrigin,
|
|
50867
|
-
runtimeMetadata: options.runtimeMetadata,
|
|
50868
|
-
storagePath: options.storagePath,
|
|
50869
|
-
workDir: options.workDir
|
|
50870
|
-
});
|
|
50871
|
-
cachedSnapshotAt = Date.now();
|
|
50872
|
-
return structuredClone(cachedSnapshot);
|
|
50873
|
-
}
|
|
50874
|
-
function getSettingsSnapshot() {
|
|
50875
|
-
const now = Date.now();
|
|
50876
|
-
if (cachedSnapshot && now - cachedSnapshotAt < 3e4) {
|
|
50877
|
-
return structuredClone(cachedSnapshot);
|
|
50878
|
-
}
|
|
50879
|
-
return buildSnapshot();
|
|
50880
|
-
}
|
|
50881
|
-
return {
|
|
50882
|
-
getSettingsSnapshot,
|
|
50883
|
-
refreshSettingsSnapshot: () => {
|
|
50884
|
-
cachedSnapshot = null;
|
|
50885
|
-
cachedSnapshotAt = 0;
|
|
50886
|
-
return buildSnapshot();
|
|
50887
|
-
}
|
|
50888
|
-
};
|
|
50889
|
-
}
|
|
50890
51483
|
async function resolveStartConfig(args) {
|
|
50891
51484
|
const configPath = args.config ?? "./config.json";
|
|
50892
51485
|
const fileConfig = loadConfigFile(configPath);
|
|
@@ -50916,7 +51509,7 @@ async function resolveStartConfig(args) {
|
|
|
50916
51509
|
ignorePersistedName: args.reset === true
|
|
50917
51510
|
});
|
|
50918
51511
|
const config = mergeConfig(defaults, scopedFileConfig, resolvedArgs);
|
|
50919
|
-
setStartupFatalLogPath(
|
|
51512
|
+
setStartupFatalLogPath(nodePath3.join(config.storage.path, "logs", "startup-fatal.log"));
|
|
50920
51513
|
persistDefaultNodeName(storageRoot, config.node.name);
|
|
50921
51514
|
persistDefaultNodeName(config.storage.path, config.node.name);
|
|
50922
51515
|
persistNodeStartupMetadata(config.storage.path, {
|
|
@@ -51271,15 +51864,20 @@ function createTunnelManager(options) {
|
|
|
51271
51864
|
}
|
|
51272
51865
|
function registerShutdownHandlers(options) {
|
|
51273
51866
|
let shuttingDown = false;
|
|
51274
|
-
|
|
51867
|
+
function stopDevelopmentWatchParent(runtimeMode) {
|
|
51868
|
+
if (runtimeMode) terminateRuntimeWatchParent({ mode: runtimeMode, env: process.env });
|
|
51869
|
+
}
|
|
51870
|
+
async function shutdown(reason = "shutdown", runtimeMode) {
|
|
51275
51871
|
if (shuttingDown) {
|
|
51276
51872
|
terminalWriter.line("Force exit.");
|
|
51873
|
+
stopDevelopmentWatchParent(runtimeMode);
|
|
51277
51874
|
process.exit(130);
|
|
51278
51875
|
}
|
|
51279
51876
|
shuttingDown = true;
|
|
51280
|
-
terminalWriter.line("\nShutting down...");
|
|
51877
|
+
terminalWriter.line(reason === "restart" ? "\nRestarting..." : "\nShutting down...");
|
|
51281
51878
|
const forceExitTimer = setTimeout(() => {
|
|
51282
51879
|
terminalWriter.line("Force exit.");
|
|
51880
|
+
stopDevelopmentWatchParent(runtimeMode);
|
|
51283
51881
|
process.exit(0);
|
|
51284
51882
|
}, 1e4);
|
|
51285
51883
|
forceExitTimer.unref?.();
|
|
@@ -51289,15 +51887,21 @@ function registerShutdownHandlers(options) {
|
|
|
51289
51887
|
await options.tunnelManager.stop();
|
|
51290
51888
|
await options.meshyNode.stop();
|
|
51291
51889
|
clearTimeout(forceExitTimer);
|
|
51292
|
-
terminalWriter.line("Goodbye!");
|
|
51890
|
+
terminalWriter.line(reason === "restart" ? "Restart handoff complete." : "Goodbye!");
|
|
51891
|
+
stopDevelopmentWatchParent(runtimeMode);
|
|
51293
51892
|
process.exit(0);
|
|
51294
51893
|
} catch (err) {
|
|
51295
51894
|
terminalWriter.error("Error during shutdown:", err);
|
|
51296
51895
|
process.exit(1);
|
|
51297
51896
|
}
|
|
51298
51897
|
}
|
|
51299
|
-
process.on("SIGINT", shutdown);
|
|
51300
|
-
process.on("SIGTERM", shutdown);
|
|
51898
|
+
process.on("SIGINT", () => void shutdown("shutdown"));
|
|
51899
|
+
process.on("SIGTERM", () => void shutdown("shutdown"));
|
|
51900
|
+
return {
|
|
51901
|
+
requestShutdown: (reason = "shutdown", runtimeMode) => {
|
|
51902
|
+
void shutdown(reason, runtimeMode);
|
|
51903
|
+
}
|
|
51904
|
+
};
|
|
51301
51905
|
}
|
|
51302
51906
|
async function startNode(args) {
|
|
51303
51907
|
const { authMetadata, config, hydratedArgs, runtimeMetadata, storageRoot } = await resolveStartConfig(args);
|
|
@@ -51309,7 +51913,7 @@ async function startNode(args) {
|
|
|
51309
51913
|
const localDashboardOrigin = `http://localhost:${config.node.port}`;
|
|
51310
51914
|
const logger27 = createLogger({
|
|
51311
51915
|
component: "node",
|
|
51312
|
-
logDir:
|
|
51916
|
+
logDir: nodePath3.join(config.storage.path, "logs"),
|
|
51313
51917
|
console: true
|
|
51314
51918
|
});
|
|
51315
51919
|
const nodeAuth = new AzureCliNodeAuth(config.storage.path, {
|
|
@@ -51331,8 +51935,9 @@ async function startNode(args) {
|
|
|
51331
51935
|
authMetadata,
|
|
51332
51936
|
localDashboardOrigin,
|
|
51333
51937
|
runtimeMetadata,
|
|
51938
|
+
runtimeRestartMode: detectRuntimeRestartMode(),
|
|
51334
51939
|
storagePath: config.storage.path,
|
|
51335
|
-
workDir:
|
|
51940
|
+
workDir: nodePath3.resolve(config.node.workDir ?? process.cwd())
|
|
51336
51941
|
});
|
|
51337
51942
|
const { getSettingsSnapshot, refreshSettingsSnapshot } = settingsSnapshotProvider;
|
|
51338
51943
|
const meshyNode = new MeshyNode(config, {
|
|
@@ -51348,6 +51953,7 @@ async function startNode(args) {
|
|
|
51348
51953
|
const previewSessionManager = new PreviewSessionManager();
|
|
51349
51954
|
const previewProxyManager = new PreviewProxyManager();
|
|
51350
51955
|
let deps;
|
|
51956
|
+
let requestShutdownForRestart;
|
|
51351
51957
|
const tunnelManager = createTunnelManager({
|
|
51352
51958
|
authMetadata,
|
|
51353
51959
|
config,
|
|
@@ -51424,7 +52030,39 @@ async function startNode(args) {
|
|
|
51424
52030
|
isDevTunnelEnabled: () => meshyNode.isDevTunnelEnabled(),
|
|
51425
52031
|
localDashboardOrigin,
|
|
51426
52032
|
upgradeRuntimeAgent,
|
|
52033
|
+
restartRuntime: async (request) => {
|
|
52034
|
+
const mode = detectRuntimeRestartMode();
|
|
52035
|
+
const plan = createRuntimeRestartLaunchPlan({
|
|
52036
|
+
mode,
|
|
52037
|
+
cwd: process.cwd(),
|
|
52038
|
+
env: process.env,
|
|
52039
|
+
localDashboardOrigin,
|
|
52040
|
+
startArgs: resolveRuntimeRestartStartArgs(hydratedArgs.args, request.startArgs),
|
|
52041
|
+
storagePath: config.storage.path
|
|
52042
|
+
});
|
|
52043
|
+
scheduleRuntimeRestart(plan, { parentPid: process.pid });
|
|
52044
|
+
const completeShutdown = () => setTimeout(() => requestShutdownForRestart?.("restart", mode), 250).unref?.();
|
|
52045
|
+
if (!request.deferShutdown) completeShutdown();
|
|
52046
|
+
return {
|
|
52047
|
+
ok: true,
|
|
52048
|
+
mode: plan.mode,
|
|
52049
|
+
command: plan.displayCommand,
|
|
52050
|
+
logPath: plan.logPath,
|
|
52051
|
+
pid: process.pid,
|
|
52052
|
+
completeShutdown
|
|
52053
|
+
};
|
|
52054
|
+
},
|
|
52055
|
+
stopRuntime: async () => {
|
|
52056
|
+
const pid = process.pid;
|
|
52057
|
+
const mode = detectRuntimeRestartMode();
|
|
52058
|
+
setTimeout(() => requestShutdownForRestart?.("shutdown", mode), 250).unref?.();
|
|
52059
|
+
return { ok: true, pid };
|
|
52060
|
+
},
|
|
51427
52061
|
refreshSettingsSnapshot,
|
|
52062
|
+
runtimeUpdate: createRuntimeUpdateSnapshot({
|
|
52063
|
+
mode: detectRuntimeRestartMode(),
|
|
52064
|
+
runtimeMetadata
|
|
52065
|
+
}),
|
|
51428
52066
|
dashboardOrigin: tunnelManager.getDashboardOrigin(),
|
|
51429
52067
|
shareOrigin: tunnelManager.getShareOrigin(),
|
|
51430
52068
|
ensureShareTunnel: () => tunnelManager.ensureShareTunnel(),
|
|
@@ -51456,11 +52094,12 @@ async function startNode(args) {
|
|
|
51456
52094
|
terminalWriter.line(banner);
|
|
51457
52095
|
terminalWriter.line("");
|
|
51458
52096
|
});
|
|
51459
|
-
registerShutdownHandlers({
|
|
52097
|
+
const shutdownHandle = registerShutdownHandlers({
|
|
51460
52098
|
server,
|
|
51461
52099
|
meshyNode,
|
|
51462
52100
|
tunnelManager
|
|
51463
52101
|
});
|
|
52102
|
+
requestShutdownForRestart = shutdownHandle.requestShutdown;
|
|
51464
52103
|
}
|
|
51465
52104
|
|
|
51466
52105
|
// src/main.ts
|