meshy-node 0.4.4 → 0.4.5

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
@@ -6629,8 +6629,8 @@ var require_node2 = __commonJS({
6629
6629
  }
6630
6630
  break;
6631
6631
  case "FILE":
6632
- var fs22 = require("fs");
6633
- stream2 = new fs22.SyncWriteStream(fd2, { autoClose: false });
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 fs22 = require("fs");
23753
- var dirname7 = path23.dirname;
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 = dirname7(loc);
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 fs22.statSync(path24);
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 fs22 = require("fs");
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 = fs22.readFileSync(file, "ascii"), lines = content.split(/[\r\n]+/);
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 fs22 = require("fs");
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
- fs22.stat(path24, function onstat(err, stat) {
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
- fs22.stat(p, function(err2, stat) {
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
- fs22.stat(p, function(err2, stat) {
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 = fs22.createReadStream(path24, options);
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(commandName) {
31897
+ function formatCommand(commandName2) {
31898
31898
  if (isWindows) {
31899
- return `${commandName}.exe`;
31899
+ return `${commandName2}.exe`;
31900
31900
  } else {
31901
- return commandName;
31901
+ return commandName2;
31902
31902
  }
31903
31903
  }
31904
31904
  async function runCommands(commands, timeout) {
@@ -37934,7 +37934,7 @@ ${joinErrors.map((e) => ` - ${e}`).join("\n")}`
37934
37934
  this.election.stop();
37935
37935
  try {
37936
37936
  const leaderEndpoint = this.nodeRegistry.getLeaderEndpoint();
37937
- if (leaderEndpoint) {
37937
+ if (leaderEndpoint && !this.nodeRegistry.isLeader()) {
37938
37938
  this.logger.info("sending shutdown cluster leave request", {
37939
37939
  leaderEndpoint,
37940
37940
  nodeId: this.selfInfo.id
@@ -38835,7 +38835,7 @@ function isDirectRunPath(entryPath) {
38835
38835
  }
38836
38836
 
38837
38837
  // src/bootstrap/start-node.ts
38838
- var nodePath2 = __toESM(require("path"), 1);
38838
+ var nodePath3 = __toESM(require("path"), 1);
38839
38839
 
38840
38840
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
38841
38841
  var external_exports = {};
@@ -42951,6 +42951,15 @@ var SystemAgentInfoSchema = external_exports.object({
42951
42951
  detail: external_exports.string().nullable().optional()
42952
42952
  }).optional()
42953
42953
  });
42954
+ var SystemRuntimeUpdateInfoSchema = external_exports.object({
42955
+ packageName: external_exports.string(),
42956
+ currentVersion: external_exports.string().nullable(),
42957
+ latestVersion: external_exports.string().nullable(),
42958
+ updateAvailable: external_exports.boolean(),
42959
+ checkedAt: external_exports.string(),
42960
+ restartMode: external_exports.enum(["package", "development"]),
42961
+ detail: external_exports.string().nullable().optional()
42962
+ });
42954
42963
  var NodeSettingsSnapshotSchema = external_exports.object({
42955
42964
  collectedAt: external_exports.number(),
42956
42965
  version: external_exports.string(),
@@ -42959,6 +42968,7 @@ var NodeSettingsSnapshotSchema = external_exports.object({
42959
42968
  auth: SystemAuthInfoSchema.optional(),
42960
42969
  os: SystemOsInfoSchema.optional(),
42961
42970
  runtime: SystemRuntimeInfoSchema.optional(),
42971
+ runtimeUpdate: SystemRuntimeUpdateInfoSchema.optional(),
42962
42972
  agents: external_exports.array(SystemAgentInfoSchema).optional(),
42963
42973
  startupRequirements: external_exports.object({
42964
42974
  lastCheckedAt: external_exports.string().optional(),
@@ -44755,6 +44765,7 @@ function buildNodeSettingsSnapshot(options) {
44755
44765
  storagePath: options.storagePath ?? null,
44756
44766
  localDashboardOrigin: options.localDashboardOrigin ?? null
44757
44767
  },
44768
+ runtimeUpdate: options.runtimeUpdate,
44758
44769
  agents,
44759
44770
  startupRequirements: {
44760
44771
  lastCheckedAt: runtimeMetadata?.startupRequirementsLastCheckedAt,
@@ -44840,6 +44851,7 @@ function upgradeRuntimeAgentForDeps(deps, agent) {
44840
44851
 
44841
44852
  // ../../packages/api/src/node/node-operation-service.ts
44842
44853
  var LEADER_REPORT_RETRY_MS = 5e3;
44854
+ var OPERATION_COMMIT_EFFECT = /* @__PURE__ */ Symbol("operationCommitEffect");
44843
44855
  var NodeOperationFailure = class extends Error {
44844
44856
  constructor(message, result) {
44845
44857
  super(message);
@@ -44873,6 +44885,7 @@ var NodeOperationService = class {
44873
44885
  this.deps = deps;
44874
44886
  this.store = store;
44875
44887
  this.registerHandler("agent.upgrade", runAgentUpgradeOperation);
44888
+ this.registerHandler("runtime.restart", runRuntimeRestartOperation);
44876
44889
  this.registerHandler("workdir.branch-create", runWorkDirBranchCreateOperation);
44877
44890
  }
44878
44891
  handlers = /* @__PURE__ */ new Map();
@@ -44943,8 +44956,14 @@ var NodeOperationService = class {
44943
44956
  try {
44944
44957
  const handler = this.handlers.get(running.kind);
44945
44958
  if (!handler) throw new Error(`No node operation handler registered for kind: ${running.kind}`);
44946
- const result = await handler(running, this.deps);
44947
- this.update(id, { status: "succeeded", result, completedAt: Date.now() });
44959
+ const handled = readOperationCommitEffect(await handler(running, this.deps));
44960
+ const saved = this.update(id, { status: "succeeded", result: handled.result, completedAt: Date.now() }, {
44961
+ reportToLeader: handled.afterCommit ? false : true
44962
+ });
44963
+ if (handled.afterCommit) {
44964
+ if (saved) await this.reportToLeader(saved);
44965
+ await handled.afterCommit();
44966
+ }
44948
44967
  } catch (err) {
44949
44968
  this.update(id, {
44950
44969
  status: "failed",
@@ -44954,12 +44973,12 @@ var NodeOperationService = class {
44954
44973
  });
44955
44974
  }
44956
44975
  }
44957
- update(id, updates) {
44976
+ update(id, updates, options = {}) {
44958
44977
  const saved = this.store.update(id, { ...updates, updatedAt: Date.now() });
44959
44978
  if (!saved) return null;
44960
44979
  this.applyOperationSideEffects(saved);
44961
44980
  this.deps.eventBus.emit("node.operation.updated", { operation: saved });
44962
- void this.reportToLeader(saved);
44981
+ if (options.reportToLeader !== false) void this.reportToLeader(saved);
44963
44982
  return saved;
44964
44983
  }
44965
44984
  applyOperationSideEffects(operation) {
@@ -45040,6 +45059,23 @@ function runAgentUpgradeOperation(operation, deps) {
45040
45059
  }
45041
45060
  return result;
45042
45061
  }
45062
+ function runRuntimeRestartOperation(operation, deps) {
45063
+ if (!deps.restartRuntime) throw new Error("Runtime restart is not available for this node");
45064
+ const reason = readPayloadString(operation, "reason") === "update" ? "update" : "restart";
45065
+ return deps.restartRuntime({ reason, deferShutdown: true }).then(
45066
+ ({ completeShutdown, ...result }) => operationCommitEffect(result, completeShutdown)
45067
+ );
45068
+ }
45069
+ function operationCommitEffect(result, afterCommit) {
45070
+ return { [OPERATION_COMMIT_EFFECT]: true, result, afterCommit };
45071
+ }
45072
+ function readOperationCommitEffect(value) {
45073
+ if (value && typeof value === "object" && value[OPERATION_COMMIT_EFFECT]) {
45074
+ const effect = value;
45075
+ return { result: effect.result, afterCommit: effect.afterCommit };
45076
+ }
45077
+ return { result: value };
45078
+ }
45043
45079
  function runWorkDirBranchCreateOperation(operation, deps) {
45044
45080
  const self2 = deps.nodeRegistry.getSelf();
45045
45081
  return createLocalNodeWorkDirBranch(
@@ -47125,6 +47161,37 @@ async function sendNodeAgentUpgrade(req, res, nodeId, agentParam) {
47125
47161
  res.status(202).json(operation);
47126
47162
  }
47127
47163
 
47164
+ // ../../packages/api/src/routes/node-runtime.ts
47165
+ function parseRestartReason(value) {
47166
+ return value === "update" ? "update" : "restart";
47167
+ }
47168
+ async function sendNodeRuntimeRestart(req, res, nodeId) {
47169
+ const deps = req.app.locals.deps;
47170
+ const self2 = deps.nodeRegistry.getSelf();
47171
+ const isSelf = nodeId === self2.id;
47172
+ if (!isSelf && !deps.election.isLeader()) {
47173
+ throw new MeshyError("NOT_LEADER", "Only the leader can restart other nodes", 403);
47174
+ }
47175
+ const node = isSelf ? self2 : deps.nodeRegistry.getNode(nodeId);
47176
+ if (!node) {
47177
+ throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
47178
+ }
47179
+ const reason = parseRestartReason(req.body?.reason);
47180
+ const operations = getNodeOperationService(deps);
47181
+ const operation = operations.create("runtime.restart", nodeId, { reason });
47182
+ if (isSelf) {
47183
+ operations.runLocal(operation.id);
47184
+ } else {
47185
+ try {
47186
+ await dispatchNodeOperation(deps, operation, node);
47187
+ } catch (err) {
47188
+ operations.markFailed(operation.id, err instanceof Error ? err.message : String(err));
47189
+ throw new MeshyError("NODE_OFFLINE", `Cannot reach node ${nodeId} to restart runtime`, 502);
47190
+ }
47191
+ }
47192
+ res.status(202).json(operation);
47193
+ }
47194
+
47128
47195
  // ../../packages/api/src/routes/node-terminal.ts
47129
47196
  var TERMINAL_SESSION_PROXY_TIMEOUT_MS = 1e4;
47130
47197
  function getTerminalSessionService2(deps) {
@@ -47548,6 +47615,9 @@ function createNodeRoutes() {
47548
47615
  router.post("/:id/agents/:agent/upgrade", asyncHandler3(async (req, res) => {
47549
47616
  await sendNodeAgentUpgrade(req, res, req.params.id, req.params.agent);
47550
47617
  }));
47618
+ router.post("/:id/runtime/restart", asyncHandler3(async (req, res) => {
47619
+ await sendNodeRuntimeRestart(req, res, req.params.id);
47620
+ }));
47551
47621
  router.patch("/:id", asyncHandler3(async (req, res) => {
47552
47622
  const { nodeRegistry, persistNodeNamePreference } = req.app.locals.deps;
47553
47623
  const updates = UpdateNodeBody.parse(req.body);
@@ -49378,7 +49448,8 @@ function createSystemRoutes() {
49378
49448
  localDashboardOrigin,
49379
49449
  storagePath,
49380
49450
  inspectRuntimeTools: inspectTools,
49381
- runtimeMetadata
49451
+ runtimeMetadata,
49452
+ runtimeUpdate
49382
49453
  } = req.app.locals.deps;
49383
49454
  const self2 = nodeRegistry.getSelf();
49384
49455
  const auth = config.authMetadata ?? {
@@ -49391,6 +49462,7 @@ function createSystemRoutes() {
49391
49462
  inspectRuntimeTools: inspectTools,
49392
49463
  localDashboardOrigin,
49393
49464
  runtimeMetadata,
49465
+ runtimeUpdate,
49394
49466
  storagePath,
49395
49467
  workDir: self2.workDir
49396
49468
  });
@@ -49406,6 +49478,7 @@ function createSystemRoutes() {
49406
49478
  auth: settingsSnapshot.auth,
49407
49479
  os: settingsSnapshot.os,
49408
49480
  runtime: settingsSnapshot.runtime,
49481
+ runtimeUpdate: settingsSnapshot.runtimeUpdate,
49409
49482
  agents: settingsSnapshot.agents,
49410
49483
  startupRequirements: settingsSnapshot.startupRequirements,
49411
49484
  components: settingsSnapshot.components,
@@ -49413,6 +49486,24 @@ function createSystemRoutes() {
49413
49486
  packages: settingsSnapshot.packages
49414
49487
  });
49415
49488
  }));
49489
+ router.post("/runtime/restart", asyncHandler9(async (req, res) => {
49490
+ const { restartRuntime } = req.app.locals.deps;
49491
+ if (!restartRuntime) {
49492
+ throw new MeshyError("VALIDATION_ERROR", "Runtime restart is not available for this node", 501);
49493
+ }
49494
+ const body = req.body;
49495
+ const reason = body.reason === "update" ? "update" : "restart";
49496
+ const result = await restartRuntime({ reason });
49497
+ res.status(202).json(result);
49498
+ }));
49499
+ router.post("/runtime/stop", asyncHandler9(async (req, res) => {
49500
+ const { stopRuntime } = req.app.locals.deps;
49501
+ if (!stopRuntime) {
49502
+ throw new MeshyError("VALIDATION_ERROR", "Runtime stop is not available for this node", 501);
49503
+ }
49504
+ const result = await stopRuntime();
49505
+ res.status(202).json(result);
49506
+ }));
49416
49507
  router.post("/transport", asyncHandler9(async (req, res) => {
49417
49508
  const { switchTransport } = req.app.locals.deps;
49418
49509
  if (!switchTransport) {
@@ -50780,6 +50871,343 @@ function buildRuntimeMetadata(storagePath) {
50780
50871
  };
50781
50872
  }
50782
50873
 
50874
+ // src/bootstrap/runtime-restart.ts
50875
+ var fs22 = __toESM(require("fs"), 1);
50876
+ var nodePath2 = __toESM(require("path"), 1);
50877
+ var import_node_child_process14 = require("child_process");
50878
+ var runtimeUpdateCache = /* @__PURE__ */ new Map();
50879
+ var RESTARTER_SOURCE = String.raw`
50880
+ const { spawn } = require('node:child_process');
50881
+ const http = require('node:http');
50882
+
50883
+ const plan = JSON.parse(process.env.MESHY_RESTART_PLAN || '{}');
50884
+ const parentPid = Number(process.env.MESHY_RESTART_PARENT_PID || '0');
50885
+
50886
+ function log(message) {
50887
+ process.stdout.write('[' + new Date().toISOString() + '] ' + message + '\n');
50888
+ }
50889
+
50890
+ function sleep(ms) {
50891
+ return new Promise(resolve => setTimeout(resolve, ms));
50892
+ }
50893
+
50894
+ function isProcessAlive(pid) {
50895
+ if (!pid) return false;
50896
+ try {
50897
+ process.kill(pid, 0);
50898
+ return true;
50899
+ } catch {
50900
+ return false;
50901
+ }
50902
+ }
50903
+
50904
+ function requestHealth(url) {
50905
+ return new Promise(resolve => {
50906
+ const req = http.get(url, res => {
50907
+ res.resume();
50908
+ res.on('end', () => resolve(res.statusCode >= 200 && res.statusCode < 500));
50909
+ });
50910
+ req.setTimeout(1000, () => {
50911
+ req.destroy();
50912
+ resolve(false);
50913
+ });
50914
+ req.on('error', () => resolve(false));
50915
+ });
50916
+ }
50917
+
50918
+ async function waitForParentExit() {
50919
+ const deadline = Date.now() + 30000;
50920
+ while (isProcessAlive(parentPid) && Date.now() < deadline) {
50921
+ await sleep(250);
50922
+ }
50923
+ }
50924
+
50925
+ async function waitForEndpointDown() {
50926
+ if (!plan.healthUrl) return;
50927
+ const deadline = Date.now() + 30000;
50928
+ while (Date.now() < deadline) {
50929
+ if (!await requestHealth(plan.healthUrl)) return;
50930
+ await sleep(250);
50931
+ }
50932
+ }
50933
+
50934
+ (async () => {
50935
+ log('waiting to restart ' + (plan.displayCommand || plan.command));
50936
+ await waitForParentExit();
50937
+ await waitForEndpointDown();
50938
+ log('starting ' + (plan.displayCommand || plan.command));
50939
+ const child = spawn(plan.command, plan.args || [], {
50940
+ cwd: plan.cwd,
50941
+ env: { ...process.env, ...(plan.env || {}), MESHY_RESTART_CHILD: '1' },
50942
+ detached: true,
50943
+ stdio: ['ignore', 'inherit', 'inherit'],
50944
+ windowsHide: true,
50945
+ });
50946
+ child.on('error', error => {
50947
+ log('failed to launch restart command: ' + (error && error.message ? error.message : String(error)));
50948
+ process.exitCode = 1;
50949
+ });
50950
+ child.unref();
50951
+ await sleep(500);
50952
+ })().catch(error => {
50953
+ log('restart helper failed: ' + (error && error.message ? error.message : String(error)));
50954
+ process.exit(1);
50955
+ });
50956
+ `;
50957
+ function formatLocalDate3(date) {
50958
+ const year = date.getFullYear();
50959
+ const month = String(date.getMonth() + 1).padStart(2, "0");
50960
+ const day = String(date.getDate()).padStart(2, "0");
50961
+ return `${year}-${month}-${day}`;
50962
+ }
50963
+ function normalizeOutput2(output) {
50964
+ if (!output) return null;
50965
+ const firstLine = output.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
50966
+ return firstLine ?? null;
50967
+ }
50968
+ function normalizePackageVersion2(output) {
50969
+ const normalized = normalizeOutput2(output);
50970
+ if (!normalized) return null;
50971
+ try {
50972
+ const parsed = JSON.parse(normalized);
50973
+ return typeof parsed === "string" ? parsed.trim() || null : normalized;
50974
+ } catch {
50975
+ return normalized;
50976
+ }
50977
+ }
50978
+ function compareSemver2(left, right) {
50979
+ const leftParts = left.split(/[.-]/).map((part) => Number.parseInt(part, 10));
50980
+ const rightParts = right.split(/[.-]/).map((part) => Number.parseInt(part, 10));
50981
+ for (let index = 0; index < 3; index += 1) {
50982
+ const delta = (leftParts[index] || 0) - (rightParts[index] || 0);
50983
+ if (delta !== 0) return delta;
50984
+ }
50985
+ return 0;
50986
+ }
50987
+ function runRuntimePackageCommand(command, args) {
50988
+ const result = (0, import_node_child_process14.spawnSync)(command, args, {
50989
+ encoding: "utf-8",
50990
+ windowsHide: true,
50991
+ timeout: 2500
50992
+ });
50993
+ return {
50994
+ status: result.status,
50995
+ stdout: typeof result.stdout === "string" ? result.stdout : "",
50996
+ stderr: typeof result.stderr === "string" ? result.stderr : "",
50997
+ error: result.error?.message ?? null
50998
+ };
50999
+ }
51000
+ function commandName(base, platform2) {
51001
+ return platform2 === "win32" ? `${base}.cmd` : base;
51002
+ }
51003
+ function pathForPlatform(platform2) {
51004
+ return platform2 === "win32" ? nodePath2.win32 : nodePath2;
51005
+ }
51006
+ function resolveDevelopmentRepoRoot(cwd, env, platform2) {
51007
+ if (env.MESHY_STORAGE_BASE_DIR) return env.MESHY_STORAGE_BASE_DIR;
51008
+ const pathApi = pathForPlatform(platform2);
51009
+ const packageDir = pathApi.basename(cwd);
51010
+ const packageParent = pathApi.basename(pathApi.dirname(cwd));
51011
+ return packageDir === "node" && packageParent === "apps" ? pathApi.dirname(pathApi.dirname(cwd)) : cwd;
51012
+ }
51013
+ function windowsShellQuote(value) {
51014
+ return /[\s&()^|<>"]/.test(value) ? `"${value.replace(/"/g, '\\"')}"` : value;
51015
+ }
51016
+ function createSpawnableCommand(command, args, platform2) {
51017
+ const displayCommand = [command, ...args].map(shellQuote).join(" ");
51018
+ if (platform2 !== "win32") return { command, args, displayCommand };
51019
+ return {
51020
+ command: "cmd.exe",
51021
+ args: ["/d", "/s", "/c", [command, ...args].map(windowsShellQuote).join(" ")],
51022
+ displayCommand
51023
+ };
51024
+ }
51025
+ function readProcessCommand(pid, platform2) {
51026
+ if (platform2 === "win32") return null;
51027
+ const result = (0, import_node_child_process14.spawnSync)("ps", ["-p", String(pid), "-o", "args="], {
51028
+ encoding: "utf-8",
51029
+ windowsHide: true,
51030
+ timeout: 1e3
51031
+ });
51032
+ return result.status === 0 && typeof result.stdout === "string" ? result.stdout.trim() || null : null;
51033
+ }
51034
+ function isNodeWatchCommand(command) {
51035
+ return /(?:^|[/\\])node(?:\.exe)?(?:\s|$)/.test(command) && /(?:^|\s)--watch(?:=|\s|$)/.test(command);
51036
+ }
51037
+ function terminateRuntimeWatchParent(options) {
51038
+ if (options.mode !== "development") return { terminated: false, reason: "not-development" };
51039
+ const parentPid = options.parentPid ?? process.ppid;
51040
+ if (!Number.isInteger(parentPid) || parentPid <= 1 || parentPid === process.pid) {
51041
+ return { terminated: false, reason: "invalid-parent" };
51042
+ }
51043
+ const commandReader = options.commandReader ?? ((pid) => readProcessCommand(pid, options.platform ?? process.platform));
51044
+ const parentCommand = commandReader(parentPid);
51045
+ const parentIsWatch = parentCommand !== null ? isNodeWatchCommand(parentCommand) : options.env?.WATCH_REPORT_DEPENDENCIES === "1";
51046
+ if (!parentIsWatch) return { terminated: false, reason: "parent-not-watch" };
51047
+ try {
51048
+ const kill = options.kill ?? process.kill;
51049
+ kill(parentPid, "SIGINT");
51050
+ return { terminated: true, pid: parentPid };
51051
+ } catch {
51052
+ return { terminated: false, reason: "kill-failed" };
51053
+ }
51054
+ }
51055
+ function compactEnv(env) {
51056
+ const result = {};
51057
+ for (const [key, value] of Object.entries(env)) {
51058
+ if (typeof value === "string") result[key] = value;
51059
+ }
51060
+ return result;
51061
+ }
51062
+ function shellQuote(value) {
51063
+ return /\s/.test(value) ? JSON.stringify(value) : value;
51064
+ }
51065
+ function formatStartArgs(args) {
51066
+ const result = ["start"];
51067
+ if (args.port !== void 0) result.push("--port", String(args.port));
51068
+ if (args.name) result.push("--name", args.name);
51069
+ if (args.join) result.push("--join", args.join);
51070
+ if (args.transport) result.push("--transport", args.transport);
51071
+ if (args.workDir) result.push("--work-dir", args.workDir);
51072
+ if (args.config) result.push("--config", args.config);
51073
+ if (args.disableAuth) result.push("--disable-auth");
51074
+ return result;
51075
+ }
51076
+ function detectRuntimeRestartMode(env = process.env, entryPath = process.argv[1]) {
51077
+ if (env.MESHY_RESTART_MODE === "package" || env.MESHY_RESTART_MODE === "development") {
51078
+ return env.MESHY_RESTART_MODE;
51079
+ }
51080
+ if (env.MESHY_STORAGE_MODE === "cwd" && env.MESHY_STORAGE_BASE_DIR) {
51081
+ return "development";
51082
+ }
51083
+ return typeof entryPath === "string" && /src[/\\]main\.ts$/.test(entryPath) ? "development" : "package";
51084
+ }
51085
+ function createRuntimeRestartLaunchPlan(options) {
51086
+ const platform2 = options.platform ?? process.platform;
51087
+ const startArgs = formatStartArgs(options.startArgs);
51088
+ const env = compactEnv(options.env);
51089
+ const logPath = pathForPlatform(platform2).join(options.storagePath, "logs", "restart.log");
51090
+ const healthUrl = new URL("/api/system/health", options.localDashboardOrigin).toString();
51091
+ if (options.mode === "development") {
51092
+ const repoRoot2 = resolveDevelopmentRepoRoot(options.cwd, options.env, platform2);
51093
+ const launch2 = createSpawnableCommand(commandName("pnpm", platform2), ["dev:node", "--", ...startArgs], platform2);
51094
+ return {
51095
+ mode: "development",
51096
+ command: launch2.command,
51097
+ args: launch2.args,
51098
+ cwd: repoRoot2,
51099
+ env,
51100
+ displayCommand: launch2.displayCommand,
51101
+ logPath,
51102
+ healthUrl
51103
+ };
51104
+ }
51105
+ const launch = createSpawnableCommand(commandName("npx", platform2), ["-y", "meshy-node@latest", ...startArgs], platform2);
51106
+ return {
51107
+ mode: "package",
51108
+ command: launch.command,
51109
+ args: launch.args,
51110
+ cwd: options.cwd,
51111
+ env,
51112
+ displayCommand: launch.displayCommand,
51113
+ logPath,
51114
+ healthUrl
51115
+ };
51116
+ }
51117
+ function scheduleRuntimeRestart(plan, options = {}) {
51118
+ fs22.mkdirSync(nodePath2.dirname(plan.logPath), { recursive: true });
51119
+ const logFd = fs22.openSync(plan.logPath, "a");
51120
+ const spawnImpl = options.spawnImpl ?? import_node_child_process14.spawn;
51121
+ const env = {
51122
+ ...process.env,
51123
+ MESHY_RESTART_PARENT_PID: String(options.parentPid ?? process.pid),
51124
+ MESHY_RESTART_PLAN: JSON.stringify(plan)
51125
+ };
51126
+ const child = spawnImpl(process.execPath, ["-e", RESTARTER_SOURCE], {
51127
+ detached: true,
51128
+ env,
51129
+ stdio: ["ignore", logFd, logFd],
51130
+ windowsHide: true
51131
+ });
51132
+ child.unref();
51133
+ }
51134
+ function createRuntimeUpdateSnapshot(options) {
51135
+ const now = options.now ?? /* @__PURE__ */ new Date();
51136
+ const checkedAt = now.toISOString();
51137
+ const currentVersion = options.runtimeMetadata?.packageVersion ?? null;
51138
+ const packageName = "meshy-node";
51139
+ if (options.mode === "development") {
51140
+ return {
51141
+ packageName,
51142
+ currentVersion,
51143
+ latestVersion: null,
51144
+ updateAvailable: false,
51145
+ checkedAt,
51146
+ restartMode: "development",
51147
+ detail: "Development runtime restarts from the local workspace."
51148
+ };
51149
+ }
51150
+ const cache = options.updateCache ?? runtimeUpdateCache;
51151
+ const checkedOn = formatLocalDate3(now);
51152
+ const cached = cache.get(packageName);
51153
+ let latestVersion = cached?.latestVersion ?? null;
51154
+ let detail = cached?.detail ?? null;
51155
+ let updateCheckedAt = cached?.checkedAt ?? checkedAt;
51156
+ if (cached?.checkedOn !== checkedOn) {
51157
+ const runner = options.commandRunner ?? runRuntimePackageCommand;
51158
+ const result = runner("npm", ["view", `${packageName}@latest`, "version", "--json"]);
51159
+ latestVersion = result.status === 0 ? normalizePackageVersion2(result.stdout) : null;
51160
+ detail = result.status === 0 ? null : normalizeOutput2(result.stderr) ?? result.error ?? "Runtime update check failed";
51161
+ updateCheckedAt = checkedAt;
51162
+ cache.set(packageName, { checkedOn, checkedAt, latestVersion, detail });
51163
+ }
51164
+ return {
51165
+ packageName,
51166
+ currentVersion,
51167
+ latestVersion,
51168
+ updateAvailable: Boolean(currentVersion && latestVersion && compareSemver2(latestVersion, currentVersion) > 0),
51169
+ checkedAt: updateCheckedAt,
51170
+ restartMode: "package",
51171
+ detail
51172
+ };
51173
+ }
51174
+
51175
+ // src/bootstrap/settings-snapshot.ts
51176
+ function createSettingsSnapshotProvider(options) {
51177
+ let cachedSnapshot = null;
51178
+ let cachedSnapshotAt = 0;
51179
+ function buildSnapshot() {
51180
+ cachedSnapshot = buildNodeSettingsSnapshot({
51181
+ auth: options.authMetadata,
51182
+ localDashboardOrigin: options.localDashboardOrigin,
51183
+ runtimeMetadata: options.runtimeMetadata,
51184
+ runtimeUpdate: createRuntimeUpdateSnapshot({
51185
+ mode: options.runtimeRestartMode,
51186
+ runtimeMetadata: options.runtimeMetadata
51187
+ }),
51188
+ storagePath: options.storagePath,
51189
+ workDir: options.workDir
51190
+ });
51191
+ cachedSnapshotAt = Date.now();
51192
+ return structuredClone(cachedSnapshot);
51193
+ }
51194
+ function getSettingsSnapshot() {
51195
+ const now = Date.now();
51196
+ if (cachedSnapshot && now - cachedSnapshotAt < 3e4) {
51197
+ return structuredClone(cachedSnapshot);
51198
+ }
51199
+ return buildSnapshot();
51200
+ }
51201
+ return {
51202
+ getSettingsSnapshot,
51203
+ refreshSettingsSnapshot: () => {
51204
+ cachedSnapshot = null;
51205
+ cachedSnapshotAt = 0;
51206
+ return buildSnapshot();
51207
+ }
51208
+ };
51209
+ }
51210
+
50783
51211
  // src/bootstrap/tunnel-health.ts
50784
51212
  var DEFAULT_TUNNEL_REACHABILITY_INTERVAL_MS = 6e4;
50785
51213
  var DEFAULT_TUNNEL_REACHABILITY_TIMEOUT_MS = 5e3;
@@ -50857,36 +51285,6 @@ async function fetchWithTimeout2(fetchImpl, url, timeoutMs) {
50857
51285
  }
50858
51286
 
50859
51287
  // 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
51288
  async function resolveStartConfig(args) {
50891
51289
  const configPath = args.config ?? "./config.json";
50892
51290
  const fileConfig = loadConfigFile(configPath);
@@ -50916,7 +51314,7 @@ async function resolveStartConfig(args) {
50916
51314
  ignorePersistedName: args.reset === true
50917
51315
  });
50918
51316
  const config = mergeConfig(defaults, scopedFileConfig, resolvedArgs);
50919
- setStartupFatalLogPath(nodePath2.join(config.storage.path, "logs", "startup-fatal.log"));
51317
+ setStartupFatalLogPath(nodePath3.join(config.storage.path, "logs", "startup-fatal.log"));
50920
51318
  persistDefaultNodeName(storageRoot, config.node.name);
50921
51319
  persistDefaultNodeName(config.storage.path, config.node.name);
50922
51320
  persistNodeStartupMetadata(config.storage.path, {
@@ -51271,15 +51669,20 @@ function createTunnelManager(options) {
51271
51669
  }
51272
51670
  function registerShutdownHandlers(options) {
51273
51671
  let shuttingDown = false;
51274
- async function shutdown() {
51672
+ function stopDevelopmentWatchParent(runtimeMode) {
51673
+ if (runtimeMode) terminateRuntimeWatchParent({ mode: runtimeMode, env: process.env });
51674
+ }
51675
+ async function shutdown(reason = "shutdown", runtimeMode) {
51275
51676
  if (shuttingDown) {
51276
51677
  terminalWriter.line("Force exit.");
51678
+ stopDevelopmentWatchParent(runtimeMode);
51277
51679
  process.exit(130);
51278
51680
  }
51279
51681
  shuttingDown = true;
51280
- terminalWriter.line("\nShutting down...");
51682
+ terminalWriter.line(reason === "restart" ? "\nRestarting..." : "\nShutting down...");
51281
51683
  const forceExitTimer = setTimeout(() => {
51282
51684
  terminalWriter.line("Force exit.");
51685
+ stopDevelopmentWatchParent(runtimeMode);
51283
51686
  process.exit(0);
51284
51687
  }, 1e4);
51285
51688
  forceExitTimer.unref?.();
@@ -51289,15 +51692,21 @@ function registerShutdownHandlers(options) {
51289
51692
  await options.tunnelManager.stop();
51290
51693
  await options.meshyNode.stop();
51291
51694
  clearTimeout(forceExitTimer);
51292
- terminalWriter.line("Goodbye!");
51695
+ terminalWriter.line(reason === "restart" ? "Restart handoff complete." : "Goodbye!");
51696
+ stopDevelopmentWatchParent(runtimeMode);
51293
51697
  process.exit(0);
51294
51698
  } catch (err) {
51295
51699
  terminalWriter.error("Error during shutdown:", err);
51296
51700
  process.exit(1);
51297
51701
  }
51298
51702
  }
51299
- process.on("SIGINT", shutdown);
51300
- process.on("SIGTERM", shutdown);
51703
+ process.on("SIGINT", () => void shutdown("shutdown"));
51704
+ process.on("SIGTERM", () => void shutdown("shutdown"));
51705
+ return {
51706
+ requestShutdown: (reason = "shutdown", runtimeMode) => {
51707
+ void shutdown(reason, runtimeMode);
51708
+ }
51709
+ };
51301
51710
  }
51302
51711
  async function startNode(args) {
51303
51712
  const { authMetadata, config, hydratedArgs, runtimeMetadata, storageRoot } = await resolveStartConfig(args);
@@ -51309,7 +51718,7 @@ async function startNode(args) {
51309
51718
  const localDashboardOrigin = `http://localhost:${config.node.port}`;
51310
51719
  const logger27 = createLogger({
51311
51720
  component: "node",
51312
- logDir: nodePath2.join(config.storage.path, "logs"),
51721
+ logDir: nodePath3.join(config.storage.path, "logs"),
51313
51722
  console: true
51314
51723
  });
51315
51724
  const nodeAuth = new AzureCliNodeAuth(config.storage.path, {
@@ -51331,8 +51740,9 @@ async function startNode(args) {
51331
51740
  authMetadata,
51332
51741
  localDashboardOrigin,
51333
51742
  runtimeMetadata,
51743
+ runtimeRestartMode: detectRuntimeRestartMode(),
51334
51744
  storagePath: config.storage.path,
51335
- workDir: nodePath2.resolve(config.node.workDir ?? process.cwd())
51745
+ workDir: nodePath3.resolve(config.node.workDir ?? process.cwd())
51336
51746
  });
51337
51747
  const { getSettingsSnapshot, refreshSettingsSnapshot } = settingsSnapshotProvider;
51338
51748
  const meshyNode = new MeshyNode(config, {
@@ -51348,6 +51758,7 @@ async function startNode(args) {
51348
51758
  const previewSessionManager = new PreviewSessionManager();
51349
51759
  const previewProxyManager = new PreviewProxyManager();
51350
51760
  let deps;
51761
+ let requestShutdownForRestart;
51351
51762
  const tunnelManager = createTunnelManager({
51352
51763
  authMetadata,
51353
51764
  config,
@@ -51424,7 +51835,39 @@ async function startNode(args) {
51424
51835
  isDevTunnelEnabled: () => meshyNode.isDevTunnelEnabled(),
51425
51836
  localDashboardOrigin,
51426
51837
  upgradeRuntimeAgent,
51838
+ restartRuntime: async (request) => {
51839
+ const mode = detectRuntimeRestartMode();
51840
+ const plan = createRuntimeRestartLaunchPlan({
51841
+ mode,
51842
+ cwd: process.cwd(),
51843
+ env: process.env,
51844
+ localDashboardOrigin,
51845
+ startArgs: hydratedArgs.args,
51846
+ storagePath: config.storage.path
51847
+ });
51848
+ scheduleRuntimeRestart(plan, { parentPid: process.pid });
51849
+ const completeShutdown = () => setTimeout(() => requestShutdownForRestart?.("restart", mode), 250).unref?.();
51850
+ if (!request.deferShutdown) completeShutdown();
51851
+ return {
51852
+ ok: true,
51853
+ mode: plan.mode,
51854
+ command: plan.displayCommand,
51855
+ logPath: plan.logPath,
51856
+ pid: process.pid,
51857
+ completeShutdown
51858
+ };
51859
+ },
51860
+ stopRuntime: async () => {
51861
+ const pid = process.pid;
51862
+ const mode = detectRuntimeRestartMode();
51863
+ setTimeout(() => requestShutdownForRestart?.("shutdown", mode), 250).unref?.();
51864
+ return { ok: true, pid };
51865
+ },
51427
51866
  refreshSettingsSnapshot,
51867
+ runtimeUpdate: createRuntimeUpdateSnapshot({
51868
+ mode: detectRuntimeRestartMode(),
51869
+ runtimeMetadata
51870
+ }),
51428
51871
  dashboardOrigin: tunnelManager.getDashboardOrigin(),
51429
51872
  shareOrigin: tunnelManager.getShareOrigin(),
51430
51873
  ensureShareTunnel: () => tunnelManager.ensureShareTunnel(),
@@ -51456,11 +51899,12 @@ async function startNode(args) {
51456
51899
  terminalWriter.line(banner);
51457
51900
  terminalWriter.line("");
51458
51901
  });
51459
- registerShutdownHandlers({
51902
+ const shutdownHandle = registerShutdownHandlers({
51460
51903
  server,
51461
51904
  meshyNode,
51462
51905
  tunnelManager
51463
51906
  });
51907
+ requestShutdownForRestart = shutdownHandle.requestShutdown;
51464
51908
  }
51465
51909
 
51466
51910
  // src/main.ts