@attson/atwebpilot-mcp 0.0.78 → 0.0.79

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 (2) hide show
  1. package/dist/index.js +94 -16
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2543,7 +2543,7 @@ var SKILL_TOOL = {
2543
2543
  // package.json
2544
2544
  var package_default = {
2545
2545
  name: "@attson/atwebpilot-mcp",
2546
- version: "0.0.78",
2546
+ version: "0.0.79",
2547
2547
  license: "Apache-2.0",
2548
2548
  description: "MCP server for the atwebpilot browser extension - let Codex or Claude Code drive your browser.",
2549
2549
  homepage: "https://github.com/attson/atwebpilot#readme",
@@ -2595,39 +2595,58 @@ var MCP_VERSION = package_default.version;
2595
2595
 
2596
2596
  // src/pairing-presenter.ts
2597
2597
  import { randomUUID } from "crypto";
2598
+ function isCodexClient(server) {
2599
+ return server.getClientVersion?.()?.name.toLowerCase().includes("codex") ?? false;
2600
+ }
2598
2601
  function createPairingPresenter(server, fallbackOpenUrl) {
2599
2602
  let presentedUrl = null;
2600
2603
  const runFallback = async (url) => {
2601
- if (!fallbackOpenUrl) return;
2604
+ if (!fallbackOpenUrl) return false;
2602
2605
  try {
2603
2606
  await fallbackOpenUrl(url);
2607
+ return true;
2604
2608
  } catch (error) {
2605
- presentedUrl = null;
2606
2609
  console.error(
2607
2610
  `[atwebpilot-mcp] failed to open pairing page ${url}:`,
2608
2611
  error instanceof Error ? error.message : String(error)
2609
2612
  );
2613
+ return false;
2610
2614
  }
2611
2615
  };
2612
- return (url) => {
2613
- if (presentedUrl === url) return;
2614
- presentedUrl = url;
2615
- if (!server.getClientCapabilities()?.elicitation?.url) {
2616
- void runFallback(url);
2617
- return;
2618
- }
2616
+ const requestHostPresentation = (url, fallbackOnFailure) => {
2619
2617
  void server.elicitInput({
2620
2618
  mode: "url",
2621
2619
  message: "Open AtWebPilot in the browser to approve this pairing request.",
2622
2620
  url,
2623
2621
  elicitationId: `atwebpilot-pairing-${randomUUID()}`
2624
- }).catch((error) => {
2622
+ }).catch(async (error) => {
2625
2623
  if (!server.transport) return;
2626
2624
  console.error(
2627
- "[atwebpilot-mcp] URL elicitation failed; falling back to the system browser:",
2625
+ fallbackOnFailure ? "[atwebpilot-mcp] URL elicitation failed; falling back to the system browser:" : "[atwebpilot-mcp] URL elicitation failed:",
2628
2626
  error instanceof Error ? error.message : String(error)
2629
2627
  );
2630
- return runFallback(url);
2628
+ if (fallbackOnFailure && await runFallback(url)) return;
2629
+ presentedUrl = null;
2630
+ });
2631
+ };
2632
+ return (url) => {
2633
+ if (presentedUrl === url) return;
2634
+ presentedUrl = url;
2635
+ const supportsUrlElicitation = Boolean(server.getClientCapabilities()?.elicitation?.url);
2636
+ if (isCodexClient(server)) {
2637
+ void runFallback(url).then((opened) => {
2638
+ if (opened || !server.transport) return;
2639
+ if (supportsUrlElicitation) requestHostPresentation(url, false);
2640
+ else presentedUrl = null;
2641
+ });
2642
+ return;
2643
+ }
2644
+ if (supportsUrlElicitation) {
2645
+ requestHostPresentation(url, true);
2646
+ return;
2647
+ }
2648
+ void runFallback(url).then((opened) => {
2649
+ if (!opened) presentedUrl = null;
2631
2650
  });
2632
2651
  };
2633
2652
  }
@@ -2800,6 +2819,9 @@ function createMcpServer(deps, state = DEFAULT_STATE, options = {}) {
2800
2819
  return server;
2801
2820
  }
2802
2821
 
2822
+ // src/ensure-hub.ts
2823
+ import { readFile } from "fs/promises";
2824
+
2803
2825
  // src/loopback-ws-hub.ts
2804
2826
  import { WebSocketServer, WebSocket } from "ws";
2805
2827
  import {
@@ -3444,6 +3466,57 @@ function createHubEnsurer(d) {
3444
3466
  bound: () => bundle != null
3445
3467
  };
3446
3468
  }
3469
+ var DESKTOP_ENV_KEYS = [
3470
+ "DISPLAY",
3471
+ "WAYLAND_DISPLAY",
3472
+ "XDG_RUNTIME_DIR",
3473
+ "DBUS_SESSION_BUS_ADDRESS",
3474
+ "XAUTHORITY"
3475
+ ];
3476
+ function processId(field, status) {
3477
+ const match = new RegExp(`^${field}:\\s+(\\d+)`, "m").exec(status);
3478
+ if (!match) return null;
3479
+ const value = Number(match[1]);
3480
+ return Number.isSafeInteger(value) ? value : null;
3481
+ }
3482
+ function copyDesktopVariables(target, serialized) {
3483
+ for (const entry of serialized.split("\0")) {
3484
+ const separator = entry.indexOf("=");
3485
+ if (separator <= 0) continue;
3486
+ const key = entry.slice(0, separator);
3487
+ if (!DESKTOP_ENV_KEYS.includes(key) || target[key]) continue;
3488
+ const value = entry.slice(separator + 1);
3489
+ if (value) target[key] = value;
3490
+ }
3491
+ }
3492
+ async function resolveDesktopOpenEnvironment(options = {}) {
3493
+ const environment = { ...options.baseEnv ?? process.env };
3494
+ if ((options.platform ?? process.platform) !== "linux") return environment;
3495
+ const expectedUid = options.uid ?? process.getuid?.();
3496
+ const readTextFile = options.readTextFile ?? ((path) => readFile(path, "utf8"));
3497
+ const seen = /* @__PURE__ */ new Set();
3498
+ let pid = options.parentPid ?? process.ppid;
3499
+ const maxDepth = options.maxDepth ?? 12;
3500
+ for (let depth = 0; depth < maxDepth && pid > 1 && !seen.has(pid); depth += 1) {
3501
+ seen.add(pid);
3502
+ let status;
3503
+ try {
3504
+ status = await readTextFile(`/proc/${pid}/status`);
3505
+ } catch {
3506
+ break;
3507
+ }
3508
+ const ownerUid = processId("Uid", status);
3509
+ if (expectedUid !== void 0 && ownerUid !== expectedUid) break;
3510
+ try {
3511
+ copyDesktopVariables(environment, await readTextFile(`/proc/${pid}/environ`));
3512
+ } catch {
3513
+ }
3514
+ const parentPid = processId("PPid", status);
3515
+ if (parentPid === null || parentPid === pid) break;
3516
+ pid = parentPid;
3517
+ }
3518
+ return environment;
3519
+ }
3447
3520
  function openCommands(url) {
3448
3521
  if (process.platform === "darwin") return [{ command: "open", args: [url] }];
3449
3522
  if (process.platform === "win32") {
@@ -3457,10 +3530,14 @@ function openCommands(url) {
3457
3530
  { command: "gio", args: ["open", url] }
3458
3531
  ];
3459
3532
  }
3460
- async function runOpenCommand({ command, args }) {
3533
+ async function runOpenCommand({ command, args }, environment) {
3461
3534
  const { spawn } = await import("child_process");
3462
3535
  await new Promise((resolve, reject) => {
3463
- const child = spawn(command, args, { stdio: "ignore", detached: true });
3536
+ const child = spawn(command, args, {
3537
+ stdio: "ignore",
3538
+ detached: true,
3539
+ env: environment
3540
+ });
3464
3541
  let settled = false;
3465
3542
  const finish = (error) => {
3466
3543
  if (settled) return;
@@ -3483,9 +3560,10 @@ async function runOpenCommand({ command, args }) {
3483
3560
  }
3484
3561
  async function defaultOpenUrl(url) {
3485
3562
  const errors = [];
3563
+ const environment = await resolveDesktopOpenEnvironment();
3486
3564
  for (const candidate of openCommands(url)) {
3487
3565
  try {
3488
- await runOpenCommand(candidate);
3566
+ await runOpenCommand(candidate, environment);
3489
3567
  return;
3490
3568
  } catch (error) {
3491
3569
  errors.push(error instanceof Error ? error.message : String(error));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@attson/atwebpilot-mcp",
3
- "version": "0.0.78",
3
+ "version": "0.0.79",
4
4
  "license": "Apache-2.0",
5
5
  "description": "MCP server for the atwebpilot browser extension - let Codex or Claude Code drive your browser.",
6
6
  "homepage": "https://github.com/attson/atwebpilot#readme",