@mcpcloud/cli 0.29.0 → 0.30.0

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +294 -195
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7972,6 +7972,8 @@ function registerServerGetCommand(servers) {
7972
7972
  "upstream keys": s.upstreamApiKeyMode ?? "shared",
7973
7973
  "client identity": s.forwardClientIdentity ? "forwarded" : "off",
7974
7974
  "connections hub offer": s.offerConnectionsHub === false ? "off" : "shown",
7975
+ world: s.closedWorld ? "closed (openWorldHint: false)" : "open",
7976
+ "client refresh": s.refreshClientsOnToolChange ? "on tool change" : "off",
7975
7977
  upstream: "mcp deployments get latest --server <server>",
7976
7978
  "end-user access": s.endUserAccess ?? "disabled",
7977
7979
  ...s.endUserAccess === "enabled" && s.connectPageUrl ? { "connect page": s.connectPageUrl } : {},
@@ -9126,7 +9128,7 @@ function driftLine(change) {
9126
9128
 
9127
9129
  // src/commands/servers-update.ts
9128
9130
  function registerServerUpdateCommand(servers) {
9129
- servers.command("update <server>").description("Update a server (name, description, tool surface, upstream key mode, runtime token TTL, client identity forwarding, connections hub offer, spec source URL)").option("--org <organizationId>", "Organization ID").option("--name <name>", "New display name").option("--description <text>", "New description").option("--discovery-mode <all|wrapper>", 'Tool surface: "all" registers every operation; "wrapper" registers searchTools/getToolDefinition/useTool INSTEAD (operations are called through useTool).').option("--code-mode <off|opt-in|default>", "Code Mode: expose codemode_execute so an agent can script several calls in one sandboxed run. Served by the edge, so it takes effect on the next deploy.").option("--upstream-api-key-mode <shared|perMember>", "Whose upstream credential the server uses: one shared key, or each member their own (Pro and above). perMember needs a protected access mode (privateOrg or unlisted) — refused while the active deployment is public.").option("--runtime-token-ttl <seconds|default>", 'Runtime token lifetime in seconds (60-86400; the default AND cap for minted tokens). Pass "default" to restore the 300s platform default.').option("--forward-client-identity <on|off>", 'Tell your upstream API which agent is calling: "on" adds X-MCP-Client-Name (e.g. "Claude Code") and the MCP client info headers to every upstream request, so your app can show the agent by name. The values are the client’s own claims — for display, never for authentication. Takes effect on the next deploy.').option("--connections-hub-offer <on|off>", "Whether your connect page shows one quiet line after a successful connect, pointing customers who use several MCPCloud apps to the connections hub (see and disconnect them all with a verified email). On by default; applies right away, no redeploy. It never asks customers to create an account.").option("--source-url <url>", "Read this server’s spec from a different URL from now on. The URL is fetched and parsed as the server’s source type first, and the report shows what a regenerate from it would change. Tools are not touched until you regenerate.").option("--dry-run", "With --source-url: fetch, parse and report without storing anything").addHelpText("after", [
9131
+ servers.command("update <server>").description("Update a server (name, description, tool surface, upstream key mode, runtime token TTL, client identity forwarding, connections hub offer, spec source URL)").option("--org <organizationId>", "Organization ID").option("--name <name>", "New display name").option("--description <text>", "New description").option("--discovery-mode <all|wrapper>", 'Tool surface: "all" registers every operation; "wrapper" registers searchTools/getToolDefinition/useTool INSTEAD (operations are called through useTool).').option("--code-mode <off|opt-in|default>", "Code Mode: expose codemode_execute so an agent can script several calls in one sandboxed run. Served by the edge, so it takes effect on the next deploy.").option("--upstream-api-key-mode <shared|perMember>", "Whose upstream credential the server uses: one shared key, or each member their own (Pro and above). perMember needs a protected access mode (privateOrg or unlisted) — refused while the active deployment is public.").option("--runtime-token-ttl <seconds|default>", 'Runtime token lifetime in seconds (60-86400; the default AND cap for minted tokens). Pass "default" to restore the 300s platform default.').option("--forward-client-identity <on|off>", 'Tell your upstream API which agent is calling: "on" adds X-MCP-Client-Name (e.g. "Claude Code") and the MCP client info headers to every upstream request, so your app can show the agent by name. The values are the client’s own claims — for display, never for authentication. Takes effect on the next deploy.').option("--connections-hub-offer <on|off>", "Whether your connect page shows one quiet line after a successful connect, pointing customers who use several MCPCloud apps to the connections hub (see and disconnect them all with a verified email). On by default; applies right away, no redeploy. It never asks customers to create an account.").option("--closed-world <on|off>", 'Whether your tools act only inside the signed-in user’s own account. "on" tells clients openWorldHint: false, so they can skip the "this reaches the outside world" caution; leave it off for tools that email, post or otherwise reach people or systems outside the account. A tool’s own setting (`mcp tools edit`, or x-mcp-annotations in the spec) still wins. Takes effect on the next regenerate + deploy.').option("--refresh-clients <on|off>", "After a deploy that changes your tools, make agents already connected load the new list: each connection gets a session tied to the current tools, and the old one ends when they change. Some agents report the ended session as one failed call instead of reconnecting by themselves. Off by default; takes effect on the next deploy.").option("--source-url <url>", "Read this server’s spec from a different URL from now on. The URL is fetched and parsed as the server’s source type first, and the report shows what a regenerate from it would change. Tools are not touched until you regenerate.").option("--dry-run", "With --source-url: fetch, parse and report without storing anything").addHelpText("after", [
9130
9132
  "",
9131
9133
  "Notes:",
9132
9134
  " The OAuth provider is `mcp servers oauth set`; how customers sign in is",
@@ -9161,7 +9163,7 @@ async function runUpdate(serverRef, opts) {
9161
9163
  throw new Error("--dry-run only previews --source-url. Run the other changes without --dry-run.");
9162
9164
  }
9163
9165
  if (!hasSettings && opts.sourceUrl === undefined) {
9164
- throw new Error("Provide at least one of --name, --description, --discovery-mode, --code-mode, --upstream-api-key-mode, --runtime-token-ttl, --forward-client-identity, --connections-hub-offer, or --source-url.");
9166
+ throw new Error("Provide at least one of --name, --description, --discovery-mode, --code-mode, --upstream-api-key-mode, --runtime-token-ttl, --forward-client-identity, --connections-hub-offer, --closed-world, --refresh-clients, or --source-url.");
9165
9167
  }
9166
9168
  const orgId = await resolveOrgId(opts.org);
9167
9169
  const serverId = await resolveServerId(serverRef, orgId);
@@ -9246,6 +9248,12 @@ function buildSettingsPatch(opts) {
9246
9248
  "off"
9247
9249
  ]) === "on";
9248
9250
  }
9251
+ if (opts.refreshClients !== undefined) {
9252
+ body["refreshClientsOnToolChange"] = validateChoice("refresh-clients", opts.refreshClients, ["on", "off"]) === "on";
9253
+ }
9254
+ if (opts.closedWorld !== undefined) {
9255
+ body["closedWorld"] = validateChoice("closed-world", opts.closedWorld, ["on", "off"]) === "on";
9256
+ }
9249
9257
  if (opts.forwardClientIdentity !== undefined) {
9250
9258
  body["forwardClientIdentity"] = validateChoice("forward-client-identity", opts.forwardClientIdentity, [
9251
9259
  "on",
@@ -11270,8 +11278,8 @@ function renderBool(value) {
11270
11278
  }
11271
11279
 
11272
11280
  // src/commands/tools-edit.ts
11273
- import { existsSync as existsSync14 } from "node:fs";
11274
- import { join as join11, relative as relative3 } from "node:path";
11281
+ import { existsSync as existsSync15 } from "node:fs";
11282
+ import { join as join12, relative as relative3 } from "node:path";
11275
11283
 
11276
11284
  // src/lib/editor-shell.ts
11277
11285
  import { spawn as spawn2 } from "node:child_process";
@@ -11365,15 +11373,106 @@ async function runEditor(args) {
11365
11373
  return { ok: true, contents, command };
11366
11374
  }
11367
11375
 
11376
+ // src/commands/tools-edit-declared.ts
11377
+ import { existsSync as existsSync14 } from "node:fs";
11378
+ import { join as join11 } from "node:path";
11379
+ var HINT_FLAGS = [
11380
+ { flag: "destructive", option: "--destructive", key: "destructiveHint" },
11381
+ { flag: "openWorld", option: "--open-world", key: "openWorldHint" },
11382
+ { flag: "idempotent", option: "--idempotent", key: "idempotentHint" }
11383
+ ];
11384
+ function hasDeclaredEditFlags(flags) {
11385
+ return flags.title !== undefined || HINT_FLAGS.some(({ flag }) => flags[flag] !== undefined);
11386
+ }
11387
+ function parseHintChoice(option, raw) {
11388
+ const value = raw.trim().toLowerCase();
11389
+ if (value === "on" || value === "true")
11390
+ return true;
11391
+ if (value === "off" || value === "false")
11392
+ return false;
11393
+ if (value === "default")
11394
+ return null;
11395
+ throw new Error(`${option} must be on, off, or default (got "${raw}").`);
11396
+ }
11397
+ function buildDeclaredPatch(flags) {
11398
+ const body = {};
11399
+ if (flags.title !== undefined) {
11400
+ const title = flags.title.replace(/\s+/g, " ").trim();
11401
+ body.title = title === "" || title.toLowerCase() === "default" ? null : title;
11402
+ }
11403
+ for (const { flag, option, key } of HINT_FLAGS) {
11404
+ const raw = flags[flag];
11405
+ if (raw === undefined)
11406
+ continue;
11407
+ body.annotationOverrides = {
11408
+ ...body.annotationOverrides,
11409
+ [key]: parseHintChoice(option, raw)
11410
+ };
11411
+ }
11412
+ return body;
11413
+ }
11414
+ async function runDeclaredToolEdit(args) {
11415
+ const patch = buildDeclaredPatch(args.flags);
11416
+ const tools = await fetchAllPages("/api/v1/project/tools", { organizationId: args.ctx.organizationId, projectId: args.ctx.projectId }, "tools");
11417
+ const tool = tools.find((candidate) => candidate.serverId === args.ctx.serverId && candidate.name === args.toolName);
11418
+ if (!tool) {
11419
+ printError(`No tool named ${args.toolName} on this server.`);
11420
+ throw new CliExitError(1);
11421
+ }
11422
+ const result = await api.patch("/api/v1/server/tool", {
11423
+ organizationId: args.ctx.organizationId,
11424
+ projectId: args.ctx.projectId,
11425
+ serverId: args.ctx.serverId,
11426
+ toolId: tool.id,
11427
+ expectedUpdatedAt: tool.updatedAt,
11428
+ ...patch
11429
+ });
11430
+ if (isJsonMode()) {
11431
+ printJson({
11432
+ ok: true,
11433
+ updatedAt: result.tool.updatedAt,
11434
+ changedFields: result.patchedFields,
11435
+ title: result.tool.title ?? null,
11436
+ annotationOverrides: result.tool.annotationOverrides ?? null
11437
+ });
11438
+ return;
11439
+ }
11440
+ printSuccess(`Saved ${c.bold(args.toolName)} ${c.dim(`(${result.patchedFields.join(", ")})`)}`);
11441
+ printInfo(c.dim(" → titles and hints are baked into the tool definitions: run `mcp servers regenerate` and deploy for clients to see them."));
11442
+ if (patch.annotationOverrides?.destructiveHint === true) {
11443
+ printInfo(c.dim(" → a destructive tool is called directly; Code Mode will not run it inside a script."));
11444
+ }
11445
+ const localFile = join11(serverToolsDir(devRoot(process.cwd()), args.ctx.serverId), `${args.toolName}.md`);
11446
+ if (existsSync14(localFile)) {
11447
+ printInfo(c.dim(` → run \`mcp tools pull ${args.toolName}\` before editing its .md again, so the next push is not refused as a conflict.`));
11448
+ }
11449
+ }
11450
+
11368
11451
  // src/commands/tools-edit.ts
11369
11452
  function registerToolsEditCommand(tools) {
11370
- tools.command("edit <name>").description("Open a tool's local .md in $EDITOR; pushes your changes to the cloud on save. Requires `mcp dev` to have materialized tools (run `mcp tools pull` first if needed).").option("--org <organizationId>", "Organization ID (defaults to .mcpcloud/state.json)").option("--server <server>", "Server (id, name, or slug; defaults to .mcpcloud/state.json)").option("--editor <command>", "Editor binary to use (defaults to $VISUAL, then $EDITOR, then vi)").addHelpText("after", [
11453
+ tools.command("edit <name>").description("Open a tool's local .md in $EDITOR; pushes your changes to the cloud on save. Requires `mcp dev` to have materialized tools (run `mcp tools pull` first if needed). With --title / --destructive / --open-world / --idempotent, sets those directly instead — no editor, no local file needed.").option("--org <organizationId>", "Organization ID (defaults to .mcpcloud/state.json)").option("--server <server>", "Server (id, name, or slug; defaults to .mcpcloud/state.json)").option("--editor <command>", "Editor binary to use (defaults to $VISUAL, then $EDITOR, then vi)").option("--title <title|default>", `Human title clients show for the tool (max 80 characters), e.g. "Create a page". "default" hands it back to the spec's x-mcp-title, else the operation summary.`).option("--destructive <on|off|default>", 'Declare the tool destructive (destructiveHint) — for an overwrite or move the method alone under-describes. "on" makes clients confirm it and keeps it out of Code Mode scripts; "off" never relabels a DELETE as safe.').option("--open-world <on|off|default>", "Whether the tool reaches people or systems outside the user's own account (openWorldHint). Overrides the server's --closed-world setting for this tool.").option("--idempotent <on|off|default>", "Whether repeating the call with the same arguments has no further effect (idempotentHint).").addHelpText("after", [
11371
11454
  "",
11372
11455
  "Examples:",
11373
11456
  " $ mcp tools edit get_user # opens .mcpcloud/tools/<server>/get_user.md",
11374
- " $ mcp tools edit get_user --editor nano"
11457
+ " $ mcp tools edit get_user --editor nano",
11458
+ ' $ mcp tools edit createpage --title "Create a page"',
11459
+ " $ mcp tools edit replacepagemarkdown --destructive on --open-world off",
11460
+ "",
11461
+ "Titles and hints are baked into the generated tool definitions: regenerate",
11462
+ "and deploy for clients to see them. A spec can declare the same per",
11463
+ "operation with x-mcp-title and x-mcp-annotations; values set here win."
11375
11464
  ].join(`
11376
11465
  `)).action(runAction(async (name, opts) => {
11466
+ if (hasDeclaredEditFlags(opts)) {
11467
+ const ctx = await resolveToolsContext({
11468
+ orgOverride: opts.org,
11469
+ serverOverride: opts.server
11470
+ });
11471
+ if (!ctx)
11472
+ return;
11473
+ await runDeclaredToolEdit({ ctx, toolName: name, flags: opts });
11474
+ return;
11475
+ }
11377
11476
  await runToolsEdit({
11378
11477
  toolName: name,
11379
11478
  orgOverride: opts.org,
@@ -11394,8 +11493,8 @@ async function runToolsEdit(args) {
11394
11493
  if (!ctx)
11395
11494
  return;
11396
11495
  const cwd = process.cwd();
11397
- const filePath = join11(serverToolsDir(devRoot(cwd), ctx.serverId), `${args.toolName}.md`);
11398
- if (!existsSync14(filePath)) {
11496
+ const filePath = join12(serverToolsDir(devRoot(cwd), ctx.serverId), `${args.toolName}.md`);
11497
+ if (!existsSync15(filePath)) {
11399
11498
  printError(`Tool file not found: ${relative3(cwd, filePath)}`);
11400
11499
  printInfo(` ${c.dim("Run")} ${c.bold(`mcp tools pull ${args.toolName}`)} ${c.dim("first to materialize it, or check the name is spelled correctly.")}`);
11401
11500
  throw new CliExitError(1);
@@ -12161,11 +12260,11 @@ async function runPullHandler(args) {
12161
12260
  }
12162
12261
 
12163
12262
  // src/commands/tools-rename.ts
12164
- import { existsSync as existsSync16 } from "node:fs";
12263
+ import { existsSync as existsSync17 } from "node:fs";
12165
12264
  import { relative as relative6 } from "node:path";
12166
12265
 
12167
12266
  // src/commands/tools-rename-input.ts
12168
- import { existsSync as existsSync15, readFileSync as readFileSync18 } from "node:fs";
12267
+ import { existsSync as existsSync16, readFileSync as readFileSync18 } from "node:fs";
12169
12268
  import { isAbsolute as isAbsolute3, resolve as resolve7 } from "node:path";
12170
12269
  var MODES_HINT = "Pass exactly one of: <old> <new>, --from-operation-ids, or --map @renames.json.";
12171
12270
  function resolveRenameSelection(args) {
@@ -12196,7 +12295,7 @@ function readRenameMap(ref, cwd) {
12196
12295
  if (!raw)
12197
12296
  throw new CliExitError(1, "--map needs a file path, e.g. --map @renames.json.");
12198
12297
  const path = isAbsolute3(raw) ? raw : resolve7(cwd, raw);
12199
- if (!existsSync15(path))
12298
+ if (!existsSync16(path))
12200
12299
  throw new CliExitError(1, `--map file not found: ${path}`);
12201
12300
  let parsed;
12202
12301
  try {
@@ -12392,7 +12491,7 @@ async function runToolsRename(oldName, newName, opts) {
12392
12491
  printRenameReport(res, {
12393
12492
  serverId: ctx.serverId,
12394
12493
  fromOperationIds: "fromOperationIds" in selection,
12395
- localToolsDir: existsSync16(localDir) ? relative6(cwd, localDir) || "." : null
12494
+ localToolsDir: existsSync17(localDir) ? relative6(cwd, localDir) || "." : null
12396
12495
  });
12397
12496
  }
12398
12497
  function selectionBody(selection) {
@@ -12548,7 +12647,7 @@ async function runResetHandler(args) {
12548
12647
  }
12549
12648
 
12550
12649
  // src/commands/tools-show.ts
12551
- import { existsSync as existsSync17 } from "node:fs";
12650
+ import { existsSync as existsSync18 } from "node:fs";
12552
12651
  function registerToolsShowCommand(tools) {
12553
12652
  tools.command("show <name>").description("Show a tool's full applied metadata (and any pending AI suggestion).").option("--org <organizationId>", "Organization ID (defaults to .mcpcloud/state.json)").option("--server <server>", "Server (id, name, or slug; defaults to .mcpcloud/state.json)").action(runAction(async (name, opts) => {
12554
12653
  await runToolsShow({
@@ -12576,7 +12675,7 @@ async function runToolsShow(args) {
12576
12675
  throw new CliExitError(1);
12577
12676
  }
12578
12677
  const devRootDir = devRoot(process.cwd());
12579
- const inDevTree = existsSync17(devRootDir);
12678
+ const inDevTree = existsSync18(devRootDir);
12580
12679
  const [detailed, handlerResult] = await Promise.all([
12581
12680
  fetchEnrichedToolDetail({
12582
12681
  organizationId: ctx.organizationId,
@@ -13812,7 +13911,7 @@ function registerSkillInstallCommand(skills) {
13812
13911
 
13813
13912
  // src/commands/skills-pull.ts
13814
13913
  import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "node:fs";
13815
- import { dirname as dirname6, isAbsolute as isAbsolute4, join as join12, resolve as resolve8 } from "node:path";
13914
+ import { dirname as dirname6, isAbsolute as isAbsolute4, join as join13, resolve as resolve8 } from "node:path";
13816
13915
  function formatBytes2(bytes) {
13817
13916
  if (bytes < 1024)
13818
13917
  return `${bytes} B`;
@@ -13843,7 +13942,7 @@ function registerSkillPullCommand(skills) {
13843
13942
  const dir = resolve8(opts.output ?? `./${result.skill.slug}`);
13844
13943
  for (const file of result.files) {
13845
13944
  assertSafeRelativePath2(file.path);
13846
- const full = join12(dir, file.path);
13945
+ const full = join13(dir, file.path);
13847
13946
  mkdirSync8(dirname6(full), { recursive: true });
13848
13947
  writeFileSync7(full, file.content);
13849
13948
  }
@@ -13861,12 +13960,12 @@ function registerSkillPullCommand(skills) {
13861
13960
  const missing = result.dependencies.filter((entry) => !entry.installed);
13862
13961
  if (result.dependencies.length === 0) {
13863
13962
  printKeyValue({
13864
- Next: `Copy ${join12(dir, "SKILL.md")} into the skills directory your agent reads.`
13963
+ Next: `Copy ${join13(dir, "SKILL.md")} into the skills directory your agent reads.`
13865
13964
  });
13866
13965
  return;
13867
13966
  }
13868
13967
  printKeyValue({
13869
- Next: `Copy ${join12(dir, "SKILL.md")} into the skills directory your agent reads.`,
13968
+ Next: `Copy ${join13(dir, "SKILL.md")} into the skills directory your agent reads.`,
13870
13969
  Servers: result.dependencies.map((entry) => `${entry.name}${entry.installed ? "" : " (not installed)"}`).join(", ")
13871
13970
  });
13872
13971
  if (missing.length > 0) {
@@ -14298,18 +14397,18 @@ function registerSkillCommands(program) {
14298
14397
  }
14299
14398
 
14300
14399
  // src/lib/dev/prepare.ts
14301
- import { existsSync as existsSync24, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "node:fs";
14302
- import { join as join19, relative as relative8, resolve as resolve9 } from "node:path";
14400
+ import { existsSync as existsSync25, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "node:fs";
14401
+ import { join as join20, relative as relative8, resolve as resolve9 } from "node:path";
14303
14402
 
14304
14403
  // src/lib/dev/bundle-sync.ts
14305
14404
  import {
14306
- existsSync as existsSync18,
14405
+ existsSync as existsSync19,
14307
14406
  mkdirSync as mkdirSync9,
14308
14407
  readFileSync as readFileSync21,
14309
14408
  rmSync as rmSync2,
14310
14409
  writeFileSync as writeFileSync8
14311
14410
  } from "node:fs";
14312
- import { dirname as dirname7, join as join13 } from "node:path";
14411
+ import { dirname as dirname7, join as join14 } from "node:path";
14313
14412
  async function resolveServerProject(args) {
14314
14413
  const data = await api.get("/api/v1/server", {
14315
14414
  organizationId: args.organizationId,
@@ -14370,7 +14469,7 @@ async function fetchBundle(args) {
14370
14469
  return parsed;
14371
14470
  }
14372
14471
  function materializeBundle(destDir, bundle, options = {}) {
14373
- if (!existsSync18(destDir)) {
14472
+ if (!existsSync19(destDir)) {
14374
14473
  mkdirSync9(destDir, { recursive: true });
14375
14474
  }
14376
14475
  const preserve = options.preservePaths;
@@ -14386,7 +14485,7 @@ function materializeBundle(destDir, bundle, options = {}) {
14386
14485
  preservedCount += 1;
14387
14486
  continue;
14388
14487
  }
14389
- const target = join13(destDir, safePath);
14488
+ const target = join14(destDir, safePath);
14390
14489
  mkdirSync9(dirname7(target), { recursive: true });
14391
14490
  writeFileSync8(target, file.content, "utf-8");
14392
14491
  writtenCount += 1;
@@ -14416,7 +14515,7 @@ function pruneStaleFiles(rootDir, currentDir, kept) {
14416
14515
  const { relative } = __require("node:path");
14417
14516
  let removed = 0;
14418
14517
  for (const entry of readdirSync(currentDir)) {
14419
- const abs = join13(currentDir, entry);
14518
+ const abs = join14(currentDir, entry);
14420
14519
  const stat = statSync(abs);
14421
14520
  if (stat.isDirectory()) {
14422
14521
  removed += pruneStaleFiles(rootDir, abs, kept);
@@ -14440,12 +14539,12 @@ function pruneStaleFiles(rootDir, currentDir, kept) {
14440
14539
  // src/lib/dev/git-clone.ts
14441
14540
  import { spawnSync } from "node:child_process";
14442
14541
  import {
14443
- existsSync as existsSync19,
14542
+ existsSync as existsSync20,
14444
14543
  mkdirSync as mkdirSync10,
14445
14544
  readFileSync as readFileSync22,
14446
14545
  writeFileSync as writeFileSync9
14447
14546
  } from "node:fs";
14448
- import { dirname as dirname8, join as join14 } from "node:path";
14547
+ import { dirname as dirname8, join as join15 } from "node:path";
14449
14548
 
14450
14549
  class GitNotAvailableError extends Error {
14451
14550
  constructor() {
@@ -14536,12 +14635,12 @@ function isGitAvailable() {
14536
14635
  }
14537
14636
  }
14538
14637
  function applyLocalExcludes(repoDir) {
14539
- const excludePath = join14(repoDir, ".git", "info", "exclude");
14540
- const existing = existsSync19(excludePath) ? readFileSync22(excludePath, "utf-8") : "";
14638
+ const excludePath = join15(repoDir, ".git", "info", "exclude");
14639
+ const existing = existsSync20(excludePath) ? readFileSync22(excludePath, "utf-8") : "";
14541
14640
  const next = mergeLocalExcludes(existing);
14542
14641
  if (next === null)
14543
14642
  return;
14544
- if (!existsSync19(dirname8(excludePath))) {
14643
+ if (!existsSync20(dirname8(excludePath))) {
14545
14644
  mkdirSync10(dirname8(excludePath), { recursive: true });
14546
14645
  }
14547
14646
  writeFileSync9(excludePath, next, "utf-8");
@@ -14550,7 +14649,7 @@ function ensureClone(opts) {
14550
14649
  if (!isGitAvailable()) {
14551
14650
  throw new GitNotAvailableError;
14552
14651
  }
14553
- if (existsSync19(join14(opts.repoDir, ".git"))) {
14652
+ if (existsSync20(join15(opts.repoDir, ".git"))) {
14554
14653
  opts.onStep?.("Refreshing existing clone (git fetch)…");
14555
14654
  runGit(gitFetchArgs(opts.branch), opts.repoDir);
14556
14655
  applyLocalExcludes(opts.repoDir);
@@ -14566,12 +14665,12 @@ function ensureClone(opts) {
14566
14665
  }
14567
14666
 
14568
14667
  // src/lib/dev/host-runtime.ts
14569
- import { existsSync as existsSync21, mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
14570
- import { dirname as dirname9, join as join16 } from "node:path";
14668
+ import { existsSync as existsSync22, mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
14669
+ import { dirname as dirname9, join as join17 } from "node:path";
14571
14670
 
14572
14671
  // src/lib/dev/inspector-module.ts
14573
- import { existsSync as existsSync20, mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "node:fs";
14574
- import { join as join15 } from "node:path";
14672
+ import { existsSync as existsSync21, mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "node:fs";
14673
+ import { join as join16 } from "node:path";
14575
14674
 
14576
14675
  // src/lib/dev/inspector-assets.ts
14577
14676
  var INSPECTOR_HTML = `<!doctype html>
@@ -29719,9 +29818,9 @@ function buildInspectorModule() {
29719
29818
  `);
29720
29819
  }
29721
29820
  function writeInspectorModule(serverDir) {
29722
- if (!existsSync20(serverDir))
29821
+ if (!existsSync21(serverDir))
29723
29822
  mkdirSync11(serverDir, { recursive: true });
29724
- const target = join15(serverDir, INSPECTOR_FILE_NAME);
29823
+ const target = join16(serverDir, INSPECTOR_FILE_NAME);
29725
29824
  writeFileSync10(target, buildInspectorModule(), "utf-8");
29726
29825
  return target;
29727
29826
  }
@@ -29907,9 +30006,9 @@ function buildHostScript(options) {
29907
30006
  `);
29908
30007
  }
29909
30008
  function writeHostScript(serverDir, options) {
29910
- if (!existsSync21(serverDir))
30009
+ if (!existsSync22(serverDir))
29911
30010
  mkdirSync12(serverDir, { recursive: true });
29912
- const target = join16(serverDir, HOST_FILE_NAME);
30011
+ const target = join17(serverDir, HOST_FILE_NAME);
29913
30012
  mkdirSync12(dirname9(target), { recursive: true });
29914
30013
  writeFileSync11(target, buildHostScript(options), "utf-8");
29915
30014
  if (options.inspector) {
@@ -29921,38 +30020,38 @@ function writeHostScript(serverDir, options) {
29921
30020
  // src/lib/dev/inspector-store.ts
29922
30021
  import {
29923
30022
  appendFileSync as appendFileSync2,
29924
- existsSync as existsSync22,
30023
+ existsSync as existsSync23,
29925
30024
  mkdirSync as mkdirSync13,
29926
30025
  readFileSync as readFileSync23,
29927
30026
  readdirSync as readdirSync2,
29928
30027
  renameSync,
29929
30028
  statSync as statSync2
29930
30029
  } from "node:fs";
29931
- import { join as join17 } from "node:path";
30030
+ import { join as join18 } from "node:path";
29932
30031
  var INSPECTOR_DIRNAME = "inspector";
29933
30032
  var ACTIVE_FILE = "calls.ndjson";
29934
30033
  var ROTATED_PREFIX = "calls.";
29935
30034
  var ROTATED_SUFFIX = ".ndjson";
29936
30035
  var ROTATION_LIMIT_BYTES = 50 * 1024 * 1024;
29937
30036
  function inspectorDir(cwd) {
29938
- return join17(devRoot(cwd), INSPECTOR_DIRNAME);
30037
+ return join18(devRoot(cwd), INSPECTOR_DIRNAME);
29939
30038
  }
29940
30039
  function ensureInspectorDir(dir) {
29941
- if (!existsSync22(dir))
30040
+ if (!existsSync23(dir))
29942
30041
  mkdirSync13(dir, { recursive: true });
29943
30042
  }
29944
30043
  function activeFilePath(dir) {
29945
- return join17(dir, ACTIVE_FILE);
30044
+ return join18(dir, ACTIVE_FILE);
29946
30045
  }
29947
30046
  function isRotatedName(name) {
29948
30047
  return name !== ACTIVE_FILE && name.startsWith(ROTATED_PREFIX) && name.endsWith(ROTATED_SUFFIX);
29949
30048
  }
29950
30049
  function listRotatedFiles(dir) {
29951
- if (!existsSync22(dir))
30050
+ if (!existsSync23(dir))
29952
30051
  return [];
29953
30052
  const rotated = readdirSync2(dir).filter(isRotatedName);
29954
30053
  rotated.sort();
29955
- return rotated.map((n) => join17(dir, n));
30054
+ return rotated.map((n) => join18(dir, n));
29956
30055
  }
29957
30056
  function parseLines(text) {
29958
30057
  if (!text)
@@ -29969,11 +30068,11 @@ function parseLines(text) {
29969
30068
  return out;
29970
30069
  }
29971
30070
  function readAll(dir) {
29972
- if (!existsSync22(dir))
30071
+ if (!existsSync23(dir))
29973
30072
  return [];
29974
30073
  const out = [];
29975
30074
  for (const path of [...listRotatedFiles(dir), activeFilePath(dir)]) {
29976
- if (!existsSync22(path))
30075
+ if (!existsSync23(path))
29977
30076
  continue;
29978
30077
  out.push(...parseLines(readFileSync23(path, "utf-8")));
29979
30078
  }
@@ -30025,8 +30124,8 @@ function parseDuration(input) {
30025
30124
 
30026
30125
  // src/lib/dev/local-runtime.ts
30027
30126
  import { spawn as spawn4 } from "node:child_process";
30028
- import { existsSync as existsSync23 } from "node:fs";
30029
- import { join as join18 } from "node:path";
30127
+ import { existsSync as existsSync24 } from "node:fs";
30128
+ import { join as join19 } from "node:path";
30030
30129
  function detectRuntime(preferred = "auto") {
30031
30130
  if (preferred === "bun" || preferred === "node")
30032
30131
  return preferred;
@@ -30037,7 +30136,7 @@ function detectRuntime(preferred = "auto") {
30037
30136
  return "node";
30038
30137
  }
30039
30138
  function startRuntime(options) {
30040
- if (!existsSync23(options.hostScriptPath)) {
30139
+ if (!existsSync24(options.hostScriptPath)) {
30041
30140
  throw new Error(`Host script not found: ${options.hostScriptPath}`);
30042
30141
  }
30043
30142
  const runtime = detectRuntime(options.runtime);
@@ -30078,11 +30177,11 @@ function startRuntime(options) {
30078
30177
  };
30079
30178
  }
30080
30179
  async function installDependencies(options) {
30081
- const pkgPath = join18(options.serverDir, "package.json");
30082
- if (!existsSync23(pkgPath))
30180
+ const pkgPath = join19(options.serverDir, "package.json");
30181
+ if (!existsSync24(pkgPath))
30083
30182
  return { ran: false, exitCode: null };
30084
- const nodeModules = join18(options.serverDir, "node_modules");
30085
- if (options.skipIfPresent !== false && existsSync23(nodeModules)) {
30183
+ const nodeModules = join19(options.serverDir, "node_modules");
30184
+ if (options.skipIfPresent !== false && existsSync24(nodeModules)) {
30086
30185
  return { ran: false, exitCode: 0 };
30087
30186
  }
30088
30187
  options.onStep?.("Installing dependencies (bun install)…");
@@ -30121,14 +30220,14 @@ function missingEnvBindingNames(envExample, envJson) {
30121
30220
  return names;
30122
30221
  }
30123
30222
  function printEnvBindingHint(dest, envPath, cwd) {
30124
- const examplePath = join19(dest, ".env.example");
30125
- if (!existsSync24(examplePath))
30223
+ const examplePath = join20(dest, ".env.example");
30224
+ if (!existsSync25(examplePath))
30126
30225
  return;
30127
30226
  let example = "";
30128
30227
  let envJson = "{}";
30129
30228
  try {
30130
30229
  example = readFileSync24(examplePath, "utf-8");
30131
- if (existsSync24(envPath))
30230
+ if (existsSync25(envPath))
30132
30231
  envJson = readFileSync24(envPath, "utf-8");
30133
30232
  } catch {
30134
30233
  return;
@@ -30165,7 +30264,7 @@ async function prepareDev(opts) {
30165
30264
  const registered = readConfig().gitRepoDirs?.[opts.serverId];
30166
30265
  const chosen = opts.repoDirOverride ? resolve9(cwd, opts.repoDirOverride) : registered;
30167
30266
  repoDir = chosen ?? gitCloneDir(cwd, gitLink.owner, gitLink.name);
30168
- if (chosen && existsSync24(join19(repoDir, ".git"))) {
30267
+ if (chosen && existsSync25(join20(repoDir, ".git"))) {
30169
30268
  const origin = getOriginUrl(repoDir);
30170
30269
  if (!origin || !originMatchesRepo(origin, gitLink.owner, gitLink.name)) {
30171
30270
  printError(`${repoDir} is a checkout of ${origin ?? "an unknown remote"}, not ${gitLink.owner}/${gitLink.name}. Pass a checkout of the linked repo, or drop --repo to use the default clone.`);
@@ -30175,7 +30274,7 @@ async function prepareDev(opts) {
30175
30274
  if (registered && !opts.repoDirOverride) {
30176
30275
  printInfo(` → using registered checkout ${repoDir}`);
30177
30276
  }
30178
- dest = gitLink.pathPrefix ? join19(repoDir, gitLink.pathPrefix) : repoDir;
30277
+ dest = gitLink.pathPrefix ? join20(repoDir, gitLink.pathPrefix) : repoDir;
30179
30278
  printStep(`Git-linked server — cloning ${gitLink.owner}/${gitLink.name}@${gitLink.branch}…`);
30180
30279
  try {
30181
30280
  const result = ensureClone({
@@ -30200,7 +30299,7 @@ async function prepareDev(opts) {
30200
30299
  }
30201
30300
  process.exit(1);
30202
30301
  }
30203
- if (!existsSync24(env)) {
30302
+ if (!existsSync25(env)) {
30204
30303
  writeFileSync12(env, `{}
30205
30304
  `, "utf-8");
30206
30305
  printInfo(` → seeded ${relative8(cwd, env)} (empty; fill secrets here)`);
@@ -30226,7 +30325,7 @@ async function prepareDev(opts) {
30226
30325
  });
30227
30326
  const result = materializeBundle(dest, bundle, { prune: true });
30228
30327
  printInfo(` → wrote ${result.filesWritten} files (pruned ${result.filesRemoved})`);
30229
- if (!existsSync24(env)) {
30328
+ if (!existsSync25(env)) {
30230
30329
  writeFileSync12(env, `{}
30231
30330
  `, "utf-8");
30232
30331
  printInfo(` → seeded ${relative8(cwd, env)} (empty; fill secrets here)`);
@@ -30245,7 +30344,7 @@ async function prepareDev(opts) {
30245
30344
  });
30246
30345
  printInfo(` → wrote ${toolsResult.filesWritten} editable tool file${toolsResult.filesWritten === 1 ? "" : "s"}${toolsResult.filesRemoved > 0 ? ` (pruned ${toolsResult.filesRemoved})` : ""}`);
30247
30346
  } else {
30248
- if (!existsSync24(dest)) {
30347
+ if (!existsSync25(dest)) {
30249
30348
  printError("No cached bundle found. Run once without --offline first.");
30250
30349
  process.exit(1);
30251
30350
  }
@@ -30254,7 +30353,7 @@ async function prepareDev(opts) {
30254
30353
  process.exit(1);
30255
30354
  }
30256
30355
  }
30257
- const entryRel = ENTRY_CANDIDATES.find((c2) => existsSync24(join19(dest, c2)));
30356
+ const entryRel = ENTRY_CANDIDATES.find((c2) => existsSync25(join20(dest, c2)));
30258
30357
  if (!entryRel) {
30259
30358
  printError("Could not locate an entry file (expected src/worker.ts).");
30260
30359
  process.exit(1);
@@ -30302,8 +30401,8 @@ async function prepareDev(opts) {
30302
30401
 
30303
30402
  // src/lib/dev/tree-sync.ts
30304
30403
  import { createHash as createHash4 } from "node:crypto";
30305
- import { existsSync as existsSync25, mkdirSync as mkdirSync14, readdirSync as readdirSync3, readFileSync as readFileSync25, writeFileSync as writeFileSync13 } from "node:fs";
30306
- import { join as join20 } from "node:path";
30404
+ import { existsSync as existsSync26, mkdirSync as mkdirSync14, readdirSync as readdirSync3, readFileSync as readFileSync25, writeFileSync as writeFileSync13 } from "node:fs";
30405
+ import { join as join21 } from "node:path";
30307
30406
  var AUTHORING_GUIDE_FILE = "AGENTS.md";
30308
30407
  var STRUCTURAL_FRONTMATTER_KEYS = [
30309
30408
  "inputSchema",
@@ -30318,12 +30417,12 @@ function isEmptyPlan(plan) {
30318
30417
  }
30319
30418
  function listToolFiles(devRootDir, serverId) {
30320
30419
  const dir = serverToolsDir(devRootDir, serverId);
30321
- if (!existsSync25(dir))
30420
+ if (!existsSync26(dir))
30322
30421
  return [];
30323
30422
  return readdirSync3(dir).filter((entry) => entry.endsWith(".md")).filter((entry) => entry !== AUTHORING_GUIDE_FILE).map((entry) => entry.slice(0, -3)).sort();
30324
30423
  }
30325
30424
  function readToolFile(devRootDir, serverId, toolName) {
30326
- const file = join20(serverToolsDir(devRootDir, serverId), `${toolName}.md`);
30425
+ const file = join21(serverToolsDir(devRootDir, serverId), `${toolName}.md`);
30327
30426
  const raw = readFileSync25(file, "utf-8");
30328
30427
  try {
30329
30428
  return { raw, view: parseToolMarkdown(raw) };
@@ -30350,7 +30449,7 @@ async function writeAuthoringGuide(args) {
30350
30449
  return null;
30351
30450
  const dir = serverToolsDir(args.devRootDir, args.serverId);
30352
30451
  mkdirSync14(dir, { recursive: true });
30353
- const guidePath = join20(dir, AUTHORING_GUIDE_FILE);
30452
+ const guidePath = join21(dir, AUTHORING_GUIDE_FILE);
30354
30453
  writeFileSync13(guidePath, markdown, "utf8");
30355
30454
  return guidePath;
30356
30455
  } catch {
@@ -30441,18 +30540,18 @@ function changedFieldNames(view, storedHash) {
30441
30540
  }
30442
30541
  var HANDLER_MANIFEST_FILE = ".handlers-state.json";
30443
30542
  function handlerManifestPath(devRootDir, serverId) {
30444
- return join20(serverToolsDir(devRootDir, serverId), HANDLER_MANIFEST_FILE);
30543
+ return join21(serverToolsDir(devRootDir, serverId), HANDLER_MANIFEST_FILE);
30445
30544
  }
30446
30545
  function hashSource2(source) {
30447
30546
  return createHash4("sha256").update(source).digest("hex");
30448
30547
  }
30449
30548
  function listHandlerFiles(devRootDir) {
30450
30549
  const dir = serverBundleHandlersDir(devRootDir);
30451
- if (!existsSync25(dir))
30550
+ if (!existsSync26(dir))
30452
30551
  return [];
30453
30552
  return readdirSync3(dir).filter((entry) => entry.endsWith(".ts") && !entry.endsWith(".definition.ts")).sort().map((entry) => ({
30454
30553
  slug: entry.slice(0, -3),
30455
- source: readFileSync25(join20(dir, entry), "utf-8")
30554
+ source: readFileSync25(join21(dir, entry), "utf-8")
30456
30555
  }));
30457
30556
  }
30458
30557
  function writeHandlerManifest(args) {
@@ -30461,7 +30560,7 @@ function writeHandlerManifest(args) {
30461
30560
  handlers[file.slug] = hashSource2(file.source);
30462
30561
  }
30463
30562
  const dir = serverToolsDir(args.devRootDir, args.serverId);
30464
- if (!existsSync25(dir))
30563
+ if (!existsSync26(dir))
30465
30564
  mkdirSync14(dir, { recursive: true });
30466
30565
  const manifest = {
30467
30566
  handlers,
@@ -30472,8 +30571,8 @@ function writeHandlerManifest(args) {
30472
30571
  return Object.keys(handlers).length;
30473
30572
  }
30474
30573
  function recordHandlerPushed(args) {
30475
- const file = join20(serverBundleHandlersDir(args.devRootDir), `${args.slug}.ts`);
30476
- if (!existsSync25(file))
30574
+ const file = join21(serverBundleHandlersDir(args.devRootDir), `${args.slug}.ts`);
30575
+ if (!existsSync26(file))
30477
30576
  return;
30478
30577
  const manifest = readHandlerManifest(args.devRootDir, args.serverId) ?? {
30479
30578
  handlers: {},
@@ -30485,7 +30584,7 @@ function recordHandlerPushed(args) {
30485
30584
  }
30486
30585
  function readHandlerManifest(devRootDir, serverId) {
30487
30586
  const file = handlerManifestPath(devRootDir, serverId);
30488
- if (!existsSync25(file))
30587
+ if (!existsSync26(file))
30489
30588
  return null;
30490
30589
  try {
30491
30590
  const parsed = JSON.parse(readFileSync25(file, "utf-8"));
@@ -31258,9 +31357,9 @@ function registerDomainCommands(program) {
31258
31357
 
31259
31358
  // src/commands/config.ts
31260
31359
  import { homedir as homedir2 } from "node:os";
31261
- import { join as join21 } from "node:path";
31360
+ import { join as join22 } from "node:path";
31262
31361
  function configFilePath() {
31263
- return join21(homedir2(), ".mcpcloud", "config.json");
31362
+ return join22(homedir2(), ".mcpcloud", "config.json");
31264
31363
  }
31265
31364
  function previewKey2(key) {
31266
31365
  if (!key)
@@ -31505,12 +31604,12 @@ function registerConfigCommands(program) {
31505
31604
  }
31506
31605
 
31507
31606
  // src/commands/dev.ts
31508
- import { existsSync as existsSync38 } from "node:fs";
31607
+ import { existsSync as existsSync39 } from "node:fs";
31509
31608
  import { isAbsolute as isAbsolute5, relative as relative9, resolve as resolve11 } from "node:path";
31510
31609
 
31511
31610
  // src/lib/dev/sessions.ts
31512
31611
  import {
31513
- existsSync as existsSync26,
31612
+ existsSync as existsSync27,
31514
31613
  mkdirSync as mkdirSync15,
31515
31614
  readFileSync as readFileSync26,
31516
31615
  readdirSync as readdirSync4,
@@ -31518,17 +31617,17 @@ import {
31518
31617
  writeFileSync as writeFileSync14
31519
31618
  } from "node:fs";
31520
31619
  import { homedir as homedir3 } from "node:os";
31521
- import { join as join22 } from "node:path";
31620
+ import { join as join23 } from "node:path";
31522
31621
  var SESSIONS_DIR_NAME = "dev-sessions";
31523
31622
  function sessionsDir() {
31524
- return join22(homedir3(), ".mcpcloud", SESSIONS_DIR_NAME);
31623
+ return join23(homedir3(), ".mcpcloud", SESSIONS_DIR_NAME);
31525
31624
  }
31526
31625
  function sessionFile(pid) {
31527
- return join22(sessionsDir(), `${pid}.json`);
31626
+ return join23(sessionsDir(), `${pid}.json`);
31528
31627
  }
31529
31628
  function ensureDir() {
31530
31629
  const dir = sessionsDir();
31531
- if (!existsSync26(dir))
31630
+ if (!existsSync27(dir))
31532
31631
  mkdirSync15(dir, { recursive: true, mode: 448 });
31533
31632
  }
31534
31633
  function recordSession(record) {
@@ -31540,7 +31639,7 @@ function recordSession(record) {
31540
31639
  }
31541
31640
  function removeSession(pid) {
31542
31641
  const path = sessionFile(pid);
31543
- if (existsSync26(path)) {
31642
+ if (existsSync27(path)) {
31544
31643
  try {
31545
31644
  unlinkSync(path);
31546
31645
  } catch {}
@@ -31548,13 +31647,13 @@ function removeSession(pid) {
31548
31647
  }
31549
31648
  function listSessions() {
31550
31649
  const dir = sessionsDir();
31551
- if (!existsSync26(dir))
31650
+ if (!existsSync27(dir))
31552
31651
  return [];
31553
31652
  const live = [];
31554
31653
  for (const entry of readdirSync4(dir)) {
31555
31654
  if (!entry.endsWith(".json"))
31556
31655
  continue;
31557
- const path = join22(dir, entry);
31656
+ const path = join23(dir, entry);
31558
31657
  try {
31559
31658
  const parsed = JSON.parse(readFileSync26(path, "utf-8"));
31560
31659
  if (typeof parsed.pid !== "number") {
@@ -31893,13 +31992,13 @@ function formatSummary(record) {
31893
31992
 
31894
31993
  // src/commands/dev-tail.ts
31895
31994
  import {
31896
- existsSync as existsSync27,
31995
+ existsSync as existsSync28,
31897
31996
  openSync,
31898
31997
  readSync,
31899
31998
  closeSync,
31900
31999
  statSync as statSync3
31901
32000
  } from "node:fs";
31902
- import { join as join23 } from "node:path";
32001
+ import { join as join24 } from "node:path";
31903
32002
  var DEFAULT_INTERVAL_MS = 250;
31904
32003
  var MAX_READ_CHUNK = 64 * 1024;
31905
32004
  function registerDevTailCommand(dev) {
@@ -31908,14 +32007,14 @@ function registerDevTailCommand(dev) {
31908
32007
  async function runDevTail(opts) {
31909
32008
  const cwd = process.cwd();
31910
32009
  const dir = inspectorDir(cwd);
31911
- const activePath = join23(dir, ACTIVE_FILE);
32010
+ const activePath = join24(dir, ACTIVE_FILE);
31912
32011
  const intervalMs = parseInterval(opts.intervalMs);
31913
- if (!existsSync27(dir)) {
32012
+ if (!existsSync28(dir)) {
31914
32013
  printInfo(`No inspector history yet at ${dir}. Run \`mcp dev\` to start capturing.`);
31915
32014
  throw new CliExitError(0);
31916
32015
  }
31917
32016
  let cursor = 0;
31918
- if (existsSync27(activePath)) {
32017
+ if (existsSync28(activePath)) {
31919
32018
  try {
31920
32019
  cursor = opts.fromStart ? 0 : statSync3(activePath).size;
31921
32020
  } catch {
@@ -31931,7 +32030,7 @@ async function runDevTail(opts) {
31931
32030
  process.on("SIGTERM", stop);
31932
32031
  while (!stopped) {
31933
32032
  let size = 0;
31934
- if (existsSync27(activePath)) {
32033
+ if (existsSync28(activePath)) {
31935
32034
  try {
31936
32035
  size = statSync3(activePath).size;
31937
32036
  } catch {
@@ -32176,8 +32275,8 @@ function startGitPullPoll(args) {
32176
32275
 
32177
32276
  // src/lib/dev/editor.ts
32178
32277
  import { spawn as spawn5 } from "node:child_process";
32179
- import { existsSync as existsSync28, statSync as statSync4 } from "node:fs";
32180
- import { delimiter as delimiter2, join as join24 } from "node:path";
32278
+ import { existsSync as existsSync29, statSync as statSync4 } from "node:fs";
32279
+ import { delimiter as delimiter2, join as join25 } from "node:path";
32181
32280
  import { platform as platform3 } from "node:os";
32182
32281
  var TARGET_LABEL = {
32183
32282
  tools: "tool metadata",
@@ -32213,8 +32312,8 @@ function findOnPath2(command) {
32213
32312
  if (!dir)
32214
32313
  continue;
32215
32314
  for (const ext of exts) {
32216
- const candidate = join24(dir, command + ext);
32217
- if (existsSync28(candidate) && isExecutable(candidate))
32315
+ const candidate = join25(dir, command + ext);
32316
+ if (existsSync29(candidate) && isExecutable(candidate))
32218
32317
  return candidate;
32219
32318
  }
32220
32319
  }
@@ -32503,11 +32602,11 @@ function parseOpenChoice(raw) {
32503
32602
  }
32504
32603
 
32505
32604
  // src/lib/dev/file-watcher.ts
32506
- import { existsSync as existsSync29, statSync as statSync5, watch as fsWatch2 } from "node:fs";
32507
- import { join as join25 } from "node:path";
32605
+ import { existsSync as existsSync30, statSync as statSync5, watch as fsWatch2 } from "node:fs";
32606
+ import { join as join26 } from "node:path";
32508
32607
  var DEFAULT_IGNORE = ["node_modules", ".git", "_mcpsh_host.mjs"];
32509
32608
  function watchDir(options) {
32510
- if (!existsSync29(options.rootDir)) {
32609
+ if (!existsSync30(options.rootDir)) {
32511
32610
  throw new Error(`watchDir: directory does not exist: ${options.rootDir}`);
32512
32611
  }
32513
32612
  const ignore = new Set([...DEFAULT_IGNORE, ...options.ignore ?? []]);
@@ -32543,7 +32642,7 @@ function watchDir(options) {
32543
32642
  for (const entry of readdirSync(options.rootDir)) {
32544
32643
  if (ignore.has(entry))
32545
32644
  continue;
32546
- const sub = join25(options.rootDir, entry);
32645
+ const sub = join26(options.rootDir, entry);
32547
32646
  try {
32548
32647
  const stat = statSync5(sub);
32549
32648
  if (!stat.isDirectory())
@@ -32591,10 +32690,10 @@ function isToolHandlerPath(rel) {
32591
32690
  }
32592
32691
 
32593
32692
  // src/lib/dev/tools-watcher.ts
32594
- import { existsSync as existsSync30 } from "node:fs";
32693
+ import { existsSync as existsSync31 } from "node:fs";
32595
32694
  function startToolsWatcher(args) {
32596
32695
  const rootDir = serverToolsDir(devRoot(args.cwd), args.serverId);
32597
- if (!existsSync30(rootDir))
32696
+ if (!existsSync31(rootDir))
32598
32697
  return null;
32599
32698
  let inflight = false;
32600
32699
  let pendingNames = new Set;
@@ -32713,10 +32812,10 @@ async function maybeHotReload(args) {
32713
32812
  }
32714
32813
 
32715
32814
  // src/lib/dev/handlers-watcher.ts
32716
- import { existsSync as existsSync31 } from "node:fs";
32815
+ import { existsSync as existsSync32 } from "node:fs";
32717
32816
  function startHandlersWatcher(args) {
32718
32817
  const rootDir = serverBundleHandlersDir(devRoot(args.cwd));
32719
- if (!existsSync31(rootDir))
32818
+ if (!existsSync32(rootDir))
32720
32819
  return null;
32721
32820
  let inflight = false;
32722
32821
  let pendingSlugs = new Set;
@@ -32923,15 +33022,15 @@ function createBurstGuard() {
32923
33022
  }
32924
33023
 
32925
33024
  // src/lib/dev/agent-connectors/claude-code.ts
32926
- import { existsSync as existsSync33, unlinkSync as unlinkSync2, writeFileSync as writeFileSync16 } from "node:fs";
33025
+ import { existsSync as existsSync34, unlinkSync as unlinkSync2, writeFileSync as writeFileSync16 } from "node:fs";
32927
33026
  import { homedir as homedir4 } from "node:os";
32928
- import { join as join27 } from "node:path";
33027
+ import { join as join28 } from "node:path";
32929
33028
 
32930
33029
  // src/lib/dev/agent-connectors/json-config-utils.ts
32931
- import { existsSync as existsSync32, mkdirSync as mkdirSync16, readFileSync as readFileSync27, writeFileSync as writeFileSync15 } from "node:fs";
32932
- import { dirname as dirname10, join as join26, basename } from "node:path";
33030
+ import { existsSync as existsSync33, mkdirSync as mkdirSync16, readFileSync as readFileSync27, writeFileSync as writeFileSync15 } from "node:fs";
33031
+ import { dirname as dirname10, join as join27, basename } from "node:path";
32933
33032
  function readJsonFile(path) {
32934
- if (!existsSync32(path))
33033
+ if (!existsSync33(path))
32935
33034
  return { ok: true, value: {} };
32936
33035
  try {
32937
33036
  const raw = readFileSync27(path, "utf-8");
@@ -32955,13 +33054,13 @@ function atomicWriteJson(path, value) {
32955
33054
  renameSync(tmp, path);
32956
33055
  }
32957
33056
  function backupConfig(args) {
32958
- if (!existsSync32(args.configPath)) {
33057
+ if (!existsSync33(args.configPath)) {
32959
33058
  return { backupPath: null, existed: false };
32960
33059
  }
32961
33060
  mkdirSync16(args.backupsDir, { recursive: true });
32962
33061
  const filename = `${args.agentId}__${basename(args.configPath)}.bak`;
32963
- const backupPath = join26(args.backupsDir, filename);
32964
- if (!existsSync32(backupPath)) {
33062
+ const backupPath = join27(args.backupsDir, filename);
33063
+ if (!existsSync33(backupPath)) {
32965
33064
  const raw = readFileSync27(args.configPath, "utf-8");
32966
33065
  writeFileSync15(backupPath, raw, "utf-8");
32967
33066
  }
@@ -32969,8 +33068,8 @@ function backupConfig(args) {
32969
33068
  }
32970
33069
  function restoreFromBackup(args) {
32971
33070
  const filename = `${args.agentId}__${basename(args.configPath)}.bak`;
32972
- const backupPath = join26(args.backupsDir, filename);
32973
- if (!existsSync32(backupPath)) {
33071
+ const backupPath = join27(args.backupsDir, filename);
33072
+ if (!existsSync33(backupPath)) {
32974
33073
  return { restored: false };
32975
33074
  }
32976
33075
  const raw = readFileSync27(backupPath, "utf-8");
@@ -32981,15 +33080,15 @@ function restoreFromBackup(args) {
32981
33080
 
32982
33081
  // src/lib/dev/agent-connectors/claude-code.ts
32983
33082
  function configPath() {
32984
- return join27(homedir4(), ".claude.json");
33083
+ return join28(homedir4(), ".claude.json");
32985
33084
  }
32986
33085
  function legacyConfigPath() {
32987
- return join27(homedir4(), ".claude", "mcp.json");
33086
+ return join28(homedir4(), ".claude", "mcp.json");
32988
33087
  }
32989
33088
  function resolveConfigPath() {
32990
- if (existsSync33(configPath()))
33089
+ if (existsSync34(configPath()))
32991
33090
  return configPath();
32992
- if (existsSync33(legacyConfigPath()))
33091
+ if (existsSync34(legacyConfigPath()))
32993
33092
  return legacyConfigPath();
32994
33093
  return configPath();
32995
33094
  }
@@ -32999,8 +33098,8 @@ var claudeCodeConnector = {
32999
33098
  hotkey: "c",
33000
33099
  describeLocation: () => resolveConfigPath(),
33001
33100
  async detect() {
33002
- const claudeDir = join27(homedir4(), ".claude");
33003
- if (existsSync33(configPath()) || existsSync33(legacyConfigPath()) || existsSync33(claudeDir)) {
33101
+ const claudeDir = join28(homedir4(), ".claude");
33102
+ if (existsSync34(configPath()) || existsSync34(legacyConfigPath()) || existsSync34(claudeDir)) {
33004
33103
  return { installed: true, note: "Found Claude Code config" };
33005
33104
  }
33006
33105
  return { installed: false };
@@ -33038,7 +33137,7 @@ var claudeCodeConnector = {
33038
33137
  backupsDir: args.backupsDir,
33039
33138
  agentId: this.id
33040
33139
  });
33041
- if (!restored.restored && existsSync33(path)) {
33140
+ if (!restored.restored && existsSync34(path)) {
33042
33141
  const after = readJsonFile(path);
33043
33142
  if (after.ok && after.value && typeof after.value === "object") {
33044
33143
  const root = after.value;
@@ -33060,16 +33159,16 @@ var claudeCodeConnector = {
33060
33159
 
33061
33160
  // src/lib/dev/agent-connectors/codex.ts
33062
33161
  import {
33063
- existsSync as existsSync34,
33162
+ existsSync as existsSync35,
33064
33163
  mkdirSync as mkdirSync17,
33065
33164
  readFileSync as readFileSync28,
33066
33165
  unlinkSync as unlinkSync3,
33067
33166
  writeFileSync as writeFileSync17
33068
33167
  } from "node:fs";
33069
33168
  import { homedir as homedir5 } from "node:os";
33070
- import { dirname as dirname11, join as join28 } from "node:path";
33169
+ import { dirname as dirname11, join as join29 } from "node:path";
33071
33170
  function configPath2() {
33072
- return join28(homedir5(), ".codex", "config.toml");
33171
+ return join29(homedir5(), ".codex", "config.toml");
33073
33172
  }
33074
33173
  var SECTION_PREFIX = "mcp_servers.";
33075
33174
  function buildSection(name, url) {
@@ -33107,7 +33206,7 @@ var codexConnector = {
33107
33206
  hotkey: "x",
33108
33207
  describeLocation: () => configPath2(),
33109
33208
  async detect() {
33110
- if (existsSync34(join28(homedir5(), ".codex")) || existsSync34(configPath2())) {
33209
+ if (existsSync35(join29(homedir5(), ".codex")) || existsSync35(configPath2())) {
33111
33210
  return { installed: true, note: "Found ~/.codex/" };
33112
33211
  }
33113
33212
  return { installed: false };
@@ -33120,7 +33219,7 @@ var codexConnector = {
33120
33219
  agentId: this.id
33121
33220
  });
33122
33221
  let existing = "";
33123
- if (existsSync34(path)) {
33222
+ if (existsSync35(path)) {
33124
33223
  existing = readFileSync28(path, "utf-8");
33125
33224
  }
33126
33225
  const conflict = findSectionRange(existing, args.name) !== null;
@@ -33142,7 +33241,7 @@ var codexConnector = {
33142
33241
  },
33143
33242
  async remove(args) {
33144
33243
  const path = configPath2();
33145
- if (existsSync34(path)) {
33244
+ if (existsSync35(path)) {
33146
33245
  const existing = readFileSync28(path, "utf-8");
33147
33246
  const range = findSectionRange(existing, args.name);
33148
33247
  if (range) {
@@ -33155,7 +33254,7 @@ var codexConnector = {
33155
33254
  backupsDir: args.backupsDir,
33156
33255
  agentId: this.id
33157
33256
  });
33158
- if (!restored.restored && existsSync34(path)) {
33257
+ if (!restored.restored && existsSync35(path)) {
33159
33258
  const after = readFileSync28(path, "utf-8");
33160
33259
  if (!after.trim()) {
33161
33260
  try {
@@ -33168,11 +33267,11 @@ var codexConnector = {
33168
33267
  };
33169
33268
 
33170
33269
  // src/lib/dev/agent-connectors/continue.ts
33171
- import { existsSync as existsSync35, unlinkSync as unlinkSync4, writeFileSync as writeFileSync18 } from "node:fs";
33270
+ import { existsSync as existsSync36, unlinkSync as unlinkSync4, writeFileSync as writeFileSync18 } from "node:fs";
33172
33271
  import { homedir as homedir6 } from "node:os";
33173
- import { join as join29 } from "node:path";
33272
+ import { join as join30 } from "node:path";
33174
33273
  function configPath3() {
33175
- return join29(homedir6(), ".continue", "config.json");
33274
+ return join30(homedir6(), ".continue", "config.json");
33176
33275
  }
33177
33276
  function isContinueServerEntry(value) {
33178
33277
  return Boolean(value && typeof value === "object" && typeof value.name === "string");
@@ -33183,8 +33282,8 @@ var continueConnector = {
33183
33282
  hotkey: "n",
33184
33283
  describeLocation: () => configPath3(),
33185
33284
  async detect() {
33186
- const dir = join29(homedir6(), ".continue");
33187
- if (existsSync35(dir) || existsSync35(configPath3())) {
33285
+ const dir = join30(homedir6(), ".continue");
33286
+ if (existsSync36(dir) || existsSync36(configPath3())) {
33188
33287
  return { installed: true, note: "Found ~/.continue/" };
33189
33288
  }
33190
33289
  return { installed: false };
@@ -33222,7 +33321,7 @@ var continueConnector = {
33222
33321
  backupsDir: args.backupsDir,
33223
33322
  agentId: this.id
33224
33323
  });
33225
- if (!restored.restored && existsSync35(path)) {
33324
+ if (!restored.restored && existsSync36(path)) {
33226
33325
  const after = readJsonFile(path);
33227
33326
  if (after.ok && after.value && typeof after.value === "object") {
33228
33327
  const root = after.value;
@@ -33243,11 +33342,11 @@ var continueConnector = {
33243
33342
  };
33244
33343
 
33245
33344
  // src/lib/dev/agent-connectors/cursor.ts
33246
- import { existsSync as existsSync36, unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "node:fs";
33345
+ import { existsSync as existsSync37, unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "node:fs";
33247
33346
  import { homedir as homedir7 } from "node:os";
33248
- import { join as join30 } from "node:path";
33347
+ import { join as join31 } from "node:path";
33249
33348
  function globalConfigPath() {
33250
- return join30(homedir7(), ".cursor", "mcp.json");
33349
+ return join31(homedir7(), ".cursor", "mcp.json");
33251
33350
  }
33252
33351
  var cursorConnector = {
33253
33352
  id: "cursor",
@@ -33255,9 +33354,9 @@ var cursorConnector = {
33255
33354
  hotkey: "u",
33256
33355
  describeLocation: () => globalConfigPath(),
33257
33356
  async detect() {
33258
- const cursorDir = join30(homedir7(), ".cursor");
33259
- const macAppSupport = join30(homedir7(), "Library", "Application Support", "Cursor");
33260
- if (existsSync36(cursorDir) || existsSync36(macAppSupport)) {
33357
+ const cursorDir = join31(homedir7(), ".cursor");
33358
+ const macAppSupport = join31(homedir7(), "Library", "Application Support", "Cursor");
33359
+ if (existsSync37(cursorDir) || existsSync37(macAppSupport)) {
33261
33360
  return { installed: true, note: "Found Cursor config dir" };
33262
33361
  }
33263
33362
  return { installed: false };
@@ -33295,7 +33394,7 @@ var cursorConnector = {
33295
33394
  backupsDir: args.backupsDir,
33296
33395
  agentId: this.id
33297
33396
  });
33298
- if (!restored.restored && existsSync36(path)) {
33397
+ if (!restored.restored && existsSync37(path)) {
33299
33398
  const after = readJsonFile(path);
33300
33399
  if (after.ok && after.value && typeof after.value === "object") {
33301
33400
  const root = after.value;
@@ -33316,30 +33415,30 @@ var cursorConnector = {
33316
33415
  };
33317
33416
 
33318
33417
  // src/lib/dev/agent-connectors/vscode-copilot.ts
33319
- import { existsSync as existsSync37, unlinkSync as unlinkSync6, writeFileSync as writeFileSync20 } from "node:fs";
33418
+ import { existsSync as existsSync38, unlinkSync as unlinkSync6, writeFileSync as writeFileSync20 } from "node:fs";
33320
33419
  import { homedir as homedir8, platform as platform4 } from "node:os";
33321
- import { join as join31, resolve as resolve10 } from "node:path";
33420
+ import { join as join32, resolve as resolve10 } from "node:path";
33322
33421
  function userLevelConfigPath() {
33323
33422
  const home = homedir8();
33324
33423
  const p = platform4();
33325
33424
  if (p === "darwin")
33326
- return join31(home, "Library", "Application Support", "Code", "User", "mcp.json");
33425
+ return join32(home, "Library", "Application Support", "Code", "User", "mcp.json");
33327
33426
  if (p === "win32") {
33328
- const appData = process.env["APPDATA"] ?? join31(home, "AppData", "Roaming");
33329
- return join31(appData, "Code", "User", "mcp.json");
33427
+ const appData = process.env["APPDATA"] ?? join32(home, "AppData", "Roaming");
33428
+ return join32(appData, "Code", "User", "mcp.json");
33330
33429
  }
33331
- const xdg = process.env["XDG_CONFIG_HOME"] ?? join31(home, ".config");
33332
- return join31(xdg, "Code", "User", "mcp.json");
33430
+ const xdg = process.env["XDG_CONFIG_HOME"] ?? join32(home, ".config");
33431
+ return join32(xdg, "Code", "User", "mcp.json");
33333
33432
  }
33334
33433
  function isHomeDir(cwd) {
33335
33434
  return resolve10(cwd) === resolve10(homedir8());
33336
33435
  }
33337
33436
  function hasWorkspaceVscode(cwd) {
33338
- return existsSync37(join31(cwd, ".vscode"));
33437
+ return existsSync38(join32(cwd, ".vscode"));
33339
33438
  }
33340
33439
  function configPath4(cwd) {
33341
33440
  if (!isHomeDir(cwd) && hasWorkspaceVscode(cwd)) {
33342
- return join31(cwd, ".vscode", "mcp.json");
33441
+ return join32(cwd, ".vscode", "mcp.json");
33343
33442
  }
33344
33443
  return userLevelConfigPath();
33345
33444
  }
@@ -33353,7 +33452,7 @@ var vscodeCopilotConnector = {
33353
33452
  if (!isHomeDir(here) && hasWorkspaceVscode(here)) {
33354
33453
  return { installed: true, note: "Found .vscode/ in current dir" };
33355
33454
  }
33356
- if (existsSync37(userLevelConfigPath().replace(/mcp\.json$/, ""))) {
33455
+ if (existsSync38(userLevelConfigPath().replace(/mcp\.json$/, ""))) {
33357
33456
  return { installed: true, note: "Found VS Code user profile" };
33358
33457
  }
33359
33458
  return { installed: false };
@@ -33391,7 +33490,7 @@ var vscodeCopilotConnector = {
33391
33490
  backupsDir: args.backupsDir,
33392
33491
  agentId: this.id
33393
33492
  });
33394
- if (!restored.restored && existsSync37(path)) {
33493
+ if (!restored.restored && existsSync38(path)) {
33395
33494
  const after = readJsonFile(path);
33396
33495
  if (after.ok && after.value && typeof after.value === "object") {
33397
33496
  const root = after.value;
@@ -33709,7 +33808,7 @@ async function runDev(opts) {
33709
33808
  let specPath = null;
33710
33809
  if (opts.spec) {
33711
33810
  const resolved = resolveSpecPath(cwd, opts.spec);
33712
- if (!existsSync38(resolved)) {
33811
+ if (!existsSync39(resolved)) {
33713
33812
  printError(`Spec file not found: ${resolved}`);
33714
33813
  process.exit(1);
33715
33814
  }
@@ -34639,13 +34738,13 @@ async function confirmRollback(deploymentId) {
34639
34738
  }
34640
34739
 
34641
34740
  // src/commands/doctor.ts
34642
- import { existsSync as existsSync40, statSync as statSync6, readFileSync as readFileSync30 } from "node:fs";
34741
+ import { existsSync as existsSync41, statSync as statSync6, readFileSync as readFileSync30 } from "node:fs";
34643
34742
  import { homedir as homedir9, platform as platform6 } from "node:os";
34644
- import { join as join33, delimiter as delimiter3 } from "node:path";
34743
+ import { join as join34, delimiter as delimiter3 } from "node:path";
34645
34744
 
34646
34745
  // src/lib/version-check.ts
34647
- import { existsSync as existsSync39, mkdirSync as mkdirSync18, readFileSync as readFileSync29, writeFileSync as writeFileSync21 } from "node:fs";
34648
- import { join as join32 } from "node:path";
34746
+ import { existsSync as existsSync40, mkdirSync as mkdirSync18, readFileSync as readFileSync29, writeFileSync as writeFileSync21 } from "node:fs";
34747
+ import { join as join33 } from "node:path";
34649
34748
  var CACHE_TTL_MS = 24 * 60 * 60 * 1000;
34650
34749
  var FETCH_TIMEOUT_MS2 = 2000;
34651
34750
  var REGISTRY_URL = "https://registry.npmjs.org/@mcpcloud/cli/latest";
@@ -34653,10 +34752,10 @@ function cacheDir() {
34653
34752
  return configDir();
34654
34753
  }
34655
34754
  function cacheFile() {
34656
- return join32(cacheDir(), "version-check.json");
34755
+ return join33(cacheDir(), "version-check.json");
34657
34756
  }
34658
34757
  function readCache() {
34659
- if (!existsSync39(cacheFile()))
34758
+ if (!existsSync40(cacheFile()))
34660
34759
  return null;
34661
34760
  try {
34662
34761
  const raw = JSON.parse(readFileSync29(cacheFile(), "utf-8"));
@@ -34669,7 +34768,7 @@ function readCache() {
34669
34768
  }
34670
34769
  function writeCache(entry) {
34671
34770
  try {
34672
- if (!existsSync39(cacheDir()))
34771
+ if (!existsSync40(cacheDir()))
34673
34772
  mkdirSync18(cacheDir(), { recursive: true, mode: 448 });
34674
34773
  writeFileSync21(cacheFile(), JSON.stringify(entry, null, 2), { mode: 384 });
34675
34774
  } catch {}
@@ -34782,8 +34881,8 @@ function checkNode() {
34782
34881
  }
34783
34882
  function checkConfigFile() {
34784
34883
  const t0 = Date.now();
34785
- const path = join33(homedir9(), ".mcpcloud", "config.json");
34786
- if (!existsSync40(path)) {
34884
+ const path = join34(homedir9(), ".mcpcloud", "config.json");
34885
+ if (!existsSync41(path)) {
34787
34886
  return {
34788
34887
  name: "Config file",
34789
34888
  status: "warn",
@@ -34936,8 +35035,8 @@ function checkClaudeCli() {
34936
35035
  for (const dir of PATH.split(delimiter3)) {
34937
35036
  if (!dir)
34938
35037
  continue;
34939
- const candidate = join33(dir, exe);
34940
- if (existsSync40(candidate)) {
35038
+ const candidate = join34(dir, exe);
35039
+ if (existsSync41(candidate)) {
34941
35040
  return {
34942
35041
  name: "claude CLI",
34943
35042
  status: "pass",
@@ -35688,8 +35787,8 @@ function registerInstallationCommands(program) {
35688
35787
  }
35689
35788
 
35690
35789
  // src/commands/invoke.ts
35691
- import { existsSync as existsSync41, readFileSync as readFileSync31 } from "node:fs";
35692
- import { join as join34 } from "node:path";
35790
+ import { existsSync as existsSync42, readFileSync as readFileSync31 } from "node:fs";
35791
+ import { join as join35 } from "node:path";
35693
35792
 
35694
35793
  // src/lib/dev/local-invoke.ts
35695
35794
  var READY_TIMEOUT_MS = 30000;
@@ -36072,7 +36171,7 @@ async function runLocalInvoke(args) {
36072
36171
  const prepared = await prepareDev({
36073
36172
  cwd,
36074
36173
  inspector: false,
36075
- offline: existsSync41(join34(devRoot(cwd), "server")),
36174
+ offline: existsSync42(join35(devRoot(cwd), "server")),
36076
36175
  organizationId: target.organizationId,
36077
36176
  port,
36078
36177
  serverId: target.serverId,
@@ -37054,26 +37153,26 @@ function registerConnectionsCommands(program) {
37054
37153
  // src/lib/plugins.ts
37055
37154
  import { spawn as spawn7 } from "node:child_process";
37056
37155
  import {
37057
- existsSync as existsSync42,
37156
+ existsSync as existsSync43,
37058
37157
  mkdirSync as mkdirSync19,
37059
37158
  readdirSync as readdirSync5,
37060
37159
  readFileSync as readFileSync32,
37061
37160
  rmSync as rmSync3,
37062
37161
  statSync as statSync7
37063
37162
  } from "node:fs";
37064
- import { join as join35 } from "node:path";
37163
+ import { join as join36 } from "node:path";
37065
37164
  import { pathToFileURL } from "node:url";
37066
37165
  function pluginsDir() {
37067
- return join35(configDir(), "plugins");
37166
+ return join36(configDir(), "plugins");
37068
37167
  }
37069
37168
  function ensureDir2() {
37070
37169
  const dir = pluginsDir();
37071
- if (!existsSync42(dir))
37170
+ if (!existsSync43(dir))
37072
37171
  mkdirSync19(dir, { recursive: true, mode: 448 });
37073
37172
  }
37074
37173
  function readManifestFromPackageDir(packageDir) {
37075
- const pkgPath = join35(packageDir, "package.json");
37076
- if (!existsSync42(pkgPath))
37174
+ const pkgPath = join36(packageDir, "package.json");
37175
+ if (!existsSync43(pkgPath))
37077
37176
  return null;
37078
37177
  let pkg;
37079
37178
  try {
@@ -37084,8 +37183,8 @@ function readManifestFromPackageDir(packageDir) {
37084
37183
  if (!pkg.name)
37085
37184
  return null;
37086
37185
  const relEntry = pkg.mcpsh?.register ?? pkg.mcp?.register ?? pkg.main ?? "index.js";
37087
- const entry = join35(packageDir, relEntry);
37088
- if (!existsSync42(entry))
37186
+ const entry = join36(packageDir, relEntry);
37187
+ if (!existsSync43(entry))
37089
37188
  return null;
37090
37189
  return {
37091
37190
  name: pkg.name,
@@ -37096,11 +37195,11 @@ function readManifestFromPackageDir(packageDir) {
37096
37195
  }
37097
37196
  function listInstalledPlugins() {
37098
37197
  const dir = pluginsDir();
37099
- if (!existsSync42(dir))
37198
+ if (!existsSync43(dir))
37100
37199
  return [];
37101
37200
  const out = [];
37102
37201
  for (const entry of readdirSync5(dir)) {
37103
- const full = join35(dir, entry);
37202
+ const full = join36(dir, entry);
37104
37203
  let s;
37105
37204
  try {
37106
37205
  s = statSync7(full);
@@ -37111,7 +37210,7 @@ function listInstalledPlugins() {
37111
37210
  continue;
37112
37211
  if (entry.startsWith("@")) {
37113
37212
  for (const child of readdirSync5(full)) {
37114
- const m = readManifestFromPackageDir(join35(full, child));
37213
+ const m = readManifestFromPackageDir(join36(full, child));
37115
37214
  if (m)
37116
37215
  out.push(m);
37117
37216
  }
@@ -37175,12 +37274,12 @@ async function installPlugin(packageSpec) {
37175
37274
  if (code !== 0) {
37176
37275
  throw new Error(`npm install ${packageSpec} exited with code ${code}.`);
37177
37276
  }
37178
- const nm = join35(dir, "node_modules");
37179
- if (!existsSync42(nm)) {
37277
+ const nm = join36(dir, "node_modules");
37278
+ if (!existsSync43(nm)) {
37180
37279
  throw new Error(`npm install ran but produced no node_modules under ${dir}.`);
37181
37280
  }
37182
37281
  const baseName = packageSpec.replace(/@[^@/]+$/, "");
37183
- const candidatePath = baseName.startsWith("@") ? join35(nm, baseName.split("/")[0], baseName.split("/")[1] ?? "") : join35(nm, baseName);
37282
+ const candidatePath = baseName.startsWith("@") ? join36(nm, baseName.split("/")[0], baseName.split("/")[1] ?? "") : join36(nm, baseName);
37184
37283
  const manifest = readManifestFromPackageDir(candidatePath);
37185
37284
  if (!manifest) {
37186
37285
  throw new Error(`Installed but could not read plugin manifest at ${candidatePath}.`);
@@ -37188,26 +37287,26 @@ async function installPlugin(packageSpec) {
37188
37287
  return { name: manifest.name, entry: manifest.entry };
37189
37288
  }
37190
37289
  function removePlugin(name) {
37191
- const nm = join35(pluginsDir(), "node_modules");
37192
- if (!existsSync42(nm))
37290
+ const nm = join36(pluginsDir(), "node_modules");
37291
+ if (!existsSync43(nm))
37193
37292
  return false;
37194
- const target = name.startsWith("@") ? join35(nm, name.split("/")[0], name.split("/")[1] ?? "") : join35(nm, name);
37195
- if (!existsSync42(target))
37293
+ const target = name.startsWith("@") ? join36(nm, name.split("/")[0], name.split("/")[1] ?? "") : join36(nm, name);
37294
+ if (!existsSync43(target))
37196
37295
  return false;
37197
37296
  rmSync3(target, { recursive: true, force: true });
37198
37297
  return true;
37199
37298
  }
37200
37299
  function listInstalledPluginsCombined() {
37201
37300
  const direct = listInstalledPlugins();
37202
- const nm = join35(pluginsDir(), "node_modules");
37203
- if (!existsSync42(nm))
37301
+ const nm = join36(pluginsDir(), "node_modules");
37302
+ if (!existsSync43(nm))
37204
37303
  return direct;
37205
37304
  const seen = new Set(direct.map((p) => p.name));
37206
37305
  const out = [...direct];
37207
37306
  for (const entry of readdirSync5(nm)) {
37208
37307
  if (entry === ".bin" || entry === ".package-lock.json")
37209
37308
  continue;
37210
- const full = join35(nm, entry);
37309
+ const full = join36(nm, entry);
37211
37310
  let s;
37212
37311
  try {
37213
37312
  s = statSync7(full);
@@ -37218,7 +37317,7 @@ function listInstalledPluginsCombined() {
37218
37317
  continue;
37219
37318
  if (entry.startsWith("@")) {
37220
37319
  for (const child of readdirSync5(full)) {
37221
- const m = readManifestFromPackageDir(join35(full, child));
37320
+ const m = readManifestFromPackageDir(join36(full, child));
37222
37321
  if (m && !seen.has(m.name)) {
37223
37322
  seen.add(m.name);
37224
37323
  out.push(m);
@@ -38828,12 +38927,12 @@ function displayValueFor(field, value) {
38828
38927
 
38829
38928
  // src/lib/tui/state-store.ts
38830
38929
  import {
38831
- existsSync as existsSync43,
38930
+ existsSync as existsSync44,
38832
38931
  mkdirSync as mkdirSync20,
38833
38932
  readFileSync as readFileSync33,
38834
38933
  writeFileSync as writeFileSync22
38835
38934
  } from "node:fs";
38836
- import { join as join36 } from "node:path";
38935
+ import { join as join37 } from "node:path";
38837
38936
  var ALL_TABS = [
38838
38937
  "servers",
38839
38938
  "projects",
@@ -38843,7 +38942,7 @@ var ALL_TABS = [
38843
38942
  "devSessions"
38844
38943
  ];
38845
38944
  function tuiStateFile() {
38846
- return join36(configDir(), "tui-state.json");
38945
+ return join37(configDir(), "tui-state.json");
38847
38946
  }
38848
38947
  function isTab(v) {
38849
38948
  return typeof v === "string" && ALL_TABS.includes(v);
@@ -38908,7 +39007,7 @@ function sanitizeTuiState(input) {
38908
39007
  }
38909
39008
  function readTuiState() {
38910
39009
  const path = tuiStateFile();
38911
- if (!existsSync43(path))
39010
+ if (!existsSync44(path))
38912
39011
  return {};
38913
39012
  let parsed;
38914
39013
  try {
@@ -38920,7 +39019,7 @@ function readTuiState() {
38920
39019
  }
38921
39020
  function writeTuiState(state) {
38922
39021
  try {
38923
- if (!existsSync43(configDir())) {
39022
+ if (!existsSync44(configDir())) {
38924
39023
  mkdirSync20(configDir(), { recursive: true, mode: 448 });
38925
39024
  }
38926
39025
  writeFileSync22(tuiStateFile(), JSON.stringify(state, null, 2), {