gitnexus 1.6.6-rc.146 → 1.6.6-rc.147

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.
@@ -6,10 +6,13 @@ export declare class CompatibleStdioServerTransport implements Transport {
6
6
  private readonly _stdout;
7
7
  private _readBuffer;
8
8
  private _started;
9
+ private _closed;
9
10
  private _framing;
10
11
  onmessage?: (message: JSONRPCMessage) => void;
11
12
  onerror?: (error: Error) => void;
12
13
  onclose?: () => void;
14
+ /** Stable bound reference so `on`/`off` always use the same function. */
15
+ private readonly _boundClose;
13
16
  constructor(_stdin?: NodeJS.ReadableStream, _stdout?: NodeJS.WritableStream);
14
17
  private readonly _ondata;
15
18
  private readonly _onerror;
@@ -35,10 +35,13 @@ export class CompatibleStdioServerTransport {
35
35
  _stdout;
36
36
  _readBuffer;
37
37
  _started = false;
38
+ _closed = false;
38
39
  _framing = null;
39
40
  onmessage;
40
41
  onerror;
41
42
  onclose;
43
+ /** Stable bound reference so `on`/`off` always use the same function. */
44
+ _boundClose = this.close.bind(this);
42
45
  constructor(_stdin = process.stdin, _stdout = process.stdout) {
43
46
  this._stdin = _stdin;
44
47
  this._stdout = _stdout;
@@ -59,9 +62,23 @@ export class CompatibleStdioServerTransport {
59
62
  if (this._started) {
60
63
  throw new Error('CompatibleStdioServerTransport already started!');
61
64
  }
65
+ if (this._closed) {
66
+ throw new Error('CompatibleStdioServerTransport has been permanently closed');
67
+ }
68
+ // If stdin is already closed (parent died before we registered listeners),
69
+ // the 'end'/'close' event was already emitted and will never fire again.
70
+ // Close the transport immediately to avoid orphaned processes.
71
+ if (this._stdin.readableEnded ||
72
+ this._stdin.destroyed) {
73
+ this._started = true;
74
+ await this.close();
75
+ return;
76
+ }
62
77
  this._started = true;
63
78
  this._stdin.on('data', this._ondata);
64
79
  this._stdin.on('error', this._onerror);
80
+ this._stdin.on('end', this._boundClose);
81
+ this._stdin.on('close', this._boundClose);
65
82
  }
66
83
  detectFraming() {
67
84
  if (!this._readBuffer || this._readBuffer.length === 0) {
@@ -162,8 +179,13 @@ export class CompatibleStdioServerTransport {
162
179
  }
163
180
  }
164
181
  async close() {
182
+ if (this._closed)
183
+ return;
184
+ this._closed = true;
165
185
  this._stdin.off('data', this._ondata);
166
186
  this._stdin.off('error', this._onerror);
187
+ this._stdin.off('end', this._boundClose);
188
+ this._stdin.off('close', this._boundClose);
167
189
  const remainingDataListeners = this._stdin.listenerCount('data');
168
190
  if (remainingDataListeners === 0) {
169
191
  this._stdin.pause();
@@ -287,7 +287,6 @@ export async function startMCPServer(backend) {
287
287
  },
288
288
  });
289
289
  const transport = new CompatibleStdioServerTransport(process.stdin, safeStdout);
290
- await server.connect(transport);
291
290
  // Surface the redirect counter on shutdown so users see the volume of
292
291
  // stray writes even when individual payloads were truncated/suppressed.
293
292
  process.on('exit', () => sentinel.flushSummary());
@@ -337,9 +336,18 @@ export async function startMCPServer(backend) {
337
336
  process.stderr.write(`GitNexus MCP unhandledRejection: ${reason?.stack || reason}\n`);
338
337
  });
339
338
  // Handle stdio errors — stdin close means the parent process is gone.
339
+ // Defense-in-depth: the transport also listens for stdin end/close and
340
+ // handles transport-level cleanup. These listeners handle process-level
341
+ // shutdown. Both paths are idempotent and safe to fire together.
340
342
  // Wrap so the event payload (e.g. an Error for 'error') can never reach
341
343
  // process.exit() as a non-numeric exit code, and void the returned promise.
342
344
  process.stdin.on('end', () => void shutdown(0));
345
+ process.stdin.on('close', () => void shutdown(0));
343
346
  process.stdin.on('error', () => void shutdown(0));
344
347
  process.stdout.on('error', () => void shutdown(0));
348
+ if (process.stdin.readableEnded || process.stdin.destroyed) {
349
+ await shutdown(0);
350
+ return;
351
+ }
352
+ await server.connect(transport);
345
353
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.6-rc.146",
3
+ "version": "1.6.6-rc.147",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",