@imenam/mcp-documentor 1.0.63 → 1.0.64

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/dist/src/index.js CHANGED
@@ -81,6 +81,9 @@ storageEngine.setHistoryStore(historyStore);
81
81
  const syncEngine = new SyncEngine(storageEngine);
82
82
  const server = new Server({ name: "mcp-documentor", version: APP_VERSION }, { capabilities: { tools: {} } });
83
83
  let guiLauncher;
84
+ let guiStatus = "disabled";
85
+ let guiUrl = null;
86
+ let guiStartWaiter = null;
84
87
  const sseControllers = new Set();
85
88
  function broadcastToGUI(message) {
86
89
  const child = guiLauncher.getProcess();
@@ -95,9 +98,15 @@ function broadcastToGUI(message) {
95
98
  }
96
99
  function handleIPCMessage(msg) {
97
100
  if (msg.type === "ALREADY_RUNNING") {
101
+ guiStatus = "already_running";
102
+ guiUrl = msg.data?.url ?? guiUrl;
103
+ guiStartWaiter?.({ outcome: "already_running", url: msg.data?.url });
98
104
  logger.info(`GUI is already running at: ${msg.data?.url || "unknown URL"}.`);
99
105
  }
100
106
  else if (msg.type === "READY") {
107
+ guiStatus = "ready";
108
+ guiUrl = msg.data?.url ?? null;
109
+ guiStartWaiter?.({ outcome: "ready", url: msg.data?.url });
101
110
  logger.info(`GUI is ready! Access it at: ${msg.data.url}`);
102
111
  }
103
112
  else if (msg.type === "GET_INITIAL_STATE") {
@@ -641,13 +650,70 @@ guiLauncher = new GuiLauncher({
641
650
  handleIPCMessage(msg);
642
651
  },
643
652
  });
653
+ function startGuiWorker() {
654
+ guiStatus = "starting";
655
+ const child = guiLauncher.start();
656
+ child.on("exit", () => {
657
+ // Un start() ultérieur remplace le process courant : seul l'exit du process
658
+ // actif change l'état. ALREADY_RUNNING = la GUI vit dans une autre instance,
659
+ // l'exit du worker est alors attendu.
660
+ if (guiLauncher.getProcess() === child && guiStatus !== "already_running") {
661
+ guiStatus = "stopped";
662
+ }
663
+ });
664
+ return child;
665
+ }
644
666
  function launchGUI() {
645
667
  if (!process.env.PROXY_URL) {
646
668
  logger.info('[MASTER] PROXY_URL non défini — GUI désactivée.');
669
+ guiStatus = "disabled";
647
670
  return;
648
671
  }
649
672
  logger.info("Launching GUI worker...");
650
- guiLauncher.start();
673
+ startGuiWorker();
674
+ }
675
+ async function reconnectGui(args) {
676
+ getConfig(); // relit le .env au cas où PROXY_URL aurait été ajouté après le démarrage
677
+ if (!process.env.PROXY_URL) {
678
+ return {
679
+ content: [{ type: "text", text: "Error: PROXY_URL is not set — the GUI is disabled. Add PROXY_URL to the .env file, then call reconnect_gui again." }],
680
+ isError: true,
681
+ };
682
+ }
683
+ const child = guiLauncher.getProcess();
684
+ const alive = !!child && child.exitCode === null && !child.killed;
685
+ const force = args?.force === true;
686
+ if (alive && !force) {
687
+ if (guiStatus === "starting") {
688
+ return { content: [{ type: "text", text: "GUI worker is already starting (proxy registration in progress). Wait a few seconds, then call reconnect_gui again if needed." }] };
689
+ }
690
+ return { content: [{ type: "text", text: `GUI is already registered with the proxy${guiUrl ? ` at ${guiUrl}` : ""}. Nothing to do (use force=true to restart it anyway).` }] };
691
+ }
692
+ logger.info(`[MASTER] reconnect_gui: ${alive ? "restarting (force)" : "relaunching"} GUI worker...`);
693
+ const result = await new Promise((resolve) => {
694
+ const newChild = startGuiWorker();
695
+ const onExit = (code) => { cleanup(); resolve({ outcome: "exited", code }); };
696
+ const timer = setTimeout(() => { cleanup(); resolve({ outcome: "timeout" }); }, 15000);
697
+ const cleanup = () => { clearTimeout(timer); newChild.off("exit", onExit); guiStartWaiter = null; };
698
+ guiStartWaiter = (r) => { cleanup(); resolve(r); };
699
+ newChild.on("exit", onExit);
700
+ });
701
+ if (result.outcome === "ready") {
702
+ return { content: [{ type: "text", text: `GUI reconnected and registered with the proxy. URL: ${result.url}` }] };
703
+ }
704
+ if (result.outcome === "already_running") {
705
+ return { content: [{ type: "text", text: `GUI is already registered by another MCP instance. URL: ${result.url ?? "unknown"}` }] };
706
+ }
707
+ if (result.outcome === "exited") {
708
+ return {
709
+ content: [{ type: "text", text: `GUI worker exited before completing registration (code=${result.code}). The proxy server is probably still unreachable at ${process.env.PROXY_URL}. Start the proxy server, then call reconnect_gui again.` }],
710
+ isError: true,
711
+ };
712
+ }
713
+ return {
714
+ content: [{ type: "text", text: "GUI worker started but did not confirm proxy registration within 15s. Check the logs (.docs-data/logs), then retry." }],
715
+ isError: true,
716
+ };
651
717
  }
652
718
  server.setRequestHandler(ListToolsRequestSchema, async () => {
653
719
  const tools = [
@@ -1083,6 +1149,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
1083
1149
  required: ["strategy"],
1084
1150
  },
1085
1151
  },
1152
+ {
1153
+ name: "reconnect_gui",
1154
+ description: "Relaunch the GUI worker and re-register it with the proxy server. Use this when the proxy server was not running when the MCP server started (so the GUI registration failed), to redeploy the GUI without restarting the MCP server. Does nothing if the GUI is already registered, unless force=true.",
1155
+ inputSchema: {
1156
+ type: "object",
1157
+ properties: {
1158
+ force: { type: "boolean", description: "Restart the GUI worker even if it is already running and registered (default: false)" },
1159
+ },
1160
+ },
1161
+ },
1086
1162
  ];
1087
1163
  return {
1088
1164
  tools: isReadOnly() ? tools.filter((t) => !WRITE_TOOLS.has(t.name)) : tools,
@@ -1174,6 +1250,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1174
1250
  return await syncDocs(syncEngine, storageEngine, embeddingEngine, embeddingStore, args);
1175
1251
  case "resolve_sync_conflict":
1176
1252
  return await resolveSyncConflict(syncEngine, args);
1253
+ case "reconnect_gui":
1254
+ return await reconnectGui(args);
1177
1255
  default:
1178
1256
  throw new Error(`Tool not found: ${name}`);
1179
1257
  }
@@ -1 +1 @@
1
- export declare const APP_VERSION = "1.0.63";
1
+ export declare const APP_VERSION = "1.0.64";
@@ -1,2 +1,2 @@
1
1
  // Auto-generated version file - do not edit manually
2
- export const APP_VERSION = '1.0.63';
2
+ export const APP_VERSION = '1.0.64';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imenam/mcp-documentor",
3
- "version": "1.0.63",
3
+ "version": "1.0.64",
4
4
  "main": "dist/src/index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",