phistruct-mcp 0.1.1 → 0.1.2

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/cli.mjs +41 -19
  2. package/package.json +2 -2
package/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { spawn, execFileSync } from "node:child_process";
2
+ import { execFileSync, spawn } from "node:child_process";
3
3
  import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from "node:fs";
4
4
  import { createConnection } from "node:net";
5
5
  import { homedir } from "node:os";
@@ -71,8 +71,24 @@ function runMdfind() {
71
71
  }
72
72
  }
73
73
 
74
+ /** A visible PhiStruct window, including a different copy than `bin`. Ignores the hidden --mcp helper. */
75
+ export function isGuiCommand(command, bin) {
76
+ if (!command || isStdioMcpCommand(command)) return false;
77
+ if (bin && command.includes(bin)) return true;
78
+ return /\/MacOS\/PhiStruct(?:\s|$)/.test(command);
79
+ }
80
+
81
+ export function runningGuiBinary(listCommands = psCommands) {
82
+ for (const command of listCommands()) {
83
+ if (!isGuiCommand(command)) continue;
84
+ const match = command.match(/(\/\S+\/MacOS\/PhiStruct)(?:\s|$)/);
85
+ if (match) return match[1];
86
+ }
87
+ return null;
88
+ }
89
+
74
90
  export function guiIsRunning(bin, listCommands = psCommands) {
75
- return listCommands().some((command) => command.includes(bin) && !isStdioMcpCommand(command));
91
+ return listCommands().some((command) => isGuiCommand(command, bin));
76
92
  }
77
93
 
78
94
  function psCommands() {
@@ -193,11 +209,32 @@ export function setupConfigs({
193
209
  return written;
194
210
  }
195
211
 
212
+ export const WINDOW_CLOSED_MESSAGE = "PhiStruct 窗口没开。请先自己打开 PhiStruct。";
213
+
196
214
  function fail(message) {
197
215
  process.stderr.write(`${message}\n`);
198
216
  process.exit(1);
199
217
  }
200
218
 
219
+ /** Use the app's own helper so sandboxed UserDefaults stay inside the app container. */
220
+ export function runStdioBridge({
221
+ bin = runningGuiBinary(),
222
+ spawnProcess = spawn,
223
+ onExit = (code) => process.exit(code ?? 1),
224
+ } = {}) {
225
+ if (!bin) throw new Error(WINDOW_CLOSED_MESSAGE);
226
+ const child = spawnProcess(bin, ["--mcp"], { stdio: "inherit" });
227
+ child.once("error", (err) => {
228
+ process.stderr.write(`Could not connect to PhiStruct MCP: ${err.message}\n`);
229
+ onExit(1);
230
+ });
231
+ child.once("exit", (code, signal) => {
232
+ if (signal) process.kill(process.pid, signal);
233
+ else onExit(code);
234
+ });
235
+ return child;
236
+ }
237
+
201
238
  async function main() {
202
239
  const argv = process.argv.slice(2).filter((a) => a !== "--");
203
240
  if (argv[0] === "setup" || argv[0] === "install") {
@@ -206,24 +243,9 @@ async function main() {
206
243
  return;
207
244
  }
208
245
  if (process.platform !== "darwin") {
209
- fail("PhiStruct MCP opens PhiStruct.app and only runs on macOS.");
210
- }
211
- const bin = findApp();
212
- if (!bin) {
213
- fail("PhiStruct.app not found. Install PhiStruct, then try again.");
246
+ fail("PhiStruct MCP only runs on macOS.");
214
247
  }
215
- if (!guiIsRunning(bin)) {
216
- spawn(bin, [], { detached: true, stdio: "ignore" }).unref();
217
- }
218
- const port = await waitForLiveMcp();
219
- if (port == null) {
220
- fail("PhiStruct opened but MCP did not listen on 127.0.0.1:17321–17340.");
221
- }
222
- const child = spawn(bin, ["--mcp"], { stdio: "inherit" });
223
- child.on("exit", (code, signal) => {
224
- if (signal) process.kill(process.pid, signal);
225
- process.exit(code ?? 1);
226
- });
248
+ runStdioBridge();
227
249
  }
228
250
 
229
251
  function isDirectRun() {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "phistruct-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
- "description": "MCP stdio bridge that opens PhiStruct.app for Cursor, Claude, and other IDEs",
5
+ "description": "MCP stdio bridge for an already-open PhiStruct window. Does not launch the app.",
6
6
  "bin": {
7
7
  "phistruct-mcp": "./cli.mjs"
8
8
  },