jjhub 0.1.5 → 0.1.7

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/cli/jjhub.mjs +385 -49
  2. package/package.json +1 -1
@@ -26536,6 +26536,155 @@ var init_dist = __esm({
26536
26536
  }
26537
26537
  });
26538
26538
 
26539
+ // node_modules/@modelcontextprotocol/sdk/node_modules/content-type/index.js
26540
+ var require_content_type = __commonJS({
26541
+ "node_modules/@modelcontextprotocol/sdk/node_modules/content-type/index.js"(exports) {
26542
+ "use strict";
26543
+ var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g;
26544
+ var TEXT_REGEXP = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/;
26545
+ var TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
26546
+ var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g;
26547
+ var QUOTE_REGEXP = /([\\"])/g;
26548
+ var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
26549
+ exports.format = format;
26550
+ exports.parse = parse3;
26551
+ function format(obj) {
26552
+ if (!obj || typeof obj !== "object") {
26553
+ throw new TypeError("argument obj is required");
26554
+ }
26555
+ var parameters = obj.parameters;
26556
+ var type = obj.type;
26557
+ if (!type || !TYPE_REGEXP.test(type)) {
26558
+ throw new TypeError("invalid type");
26559
+ }
26560
+ var string4 = type;
26561
+ if (parameters && typeof parameters === "object") {
26562
+ var param;
26563
+ var params = Object.keys(parameters).sort();
26564
+ for (var i2 = 0; i2 < params.length; i2++) {
26565
+ param = params[i2];
26566
+ if (!TOKEN_REGEXP.test(param)) {
26567
+ throw new TypeError("invalid parameter name");
26568
+ }
26569
+ string4 += "; " + param + "=" + qstring(parameters[param]);
26570
+ }
26571
+ }
26572
+ return string4;
26573
+ }
26574
+ function parse3(string4) {
26575
+ if (!string4) {
26576
+ throw new TypeError("argument string is required");
26577
+ }
26578
+ var header = typeof string4 === "object" ? getcontenttype(string4) : string4;
26579
+ if (typeof header !== "string") {
26580
+ throw new TypeError("argument string is required to be a string");
26581
+ }
26582
+ var index4 = header.indexOf(";");
26583
+ var type = index4 !== -1 ? header.slice(0, index4).trim() : header.trim();
26584
+ if (!TYPE_REGEXP.test(type)) {
26585
+ throw new TypeError("invalid media type");
26586
+ }
26587
+ var obj = new ContentType(type.toLowerCase());
26588
+ if (index4 !== -1) {
26589
+ var key;
26590
+ var match;
26591
+ var value;
26592
+ PARAM_REGEXP.lastIndex = index4;
26593
+ while (match = PARAM_REGEXP.exec(header)) {
26594
+ if (match.index !== index4) {
26595
+ throw new TypeError("invalid parameter format");
26596
+ }
26597
+ index4 += match[0].length;
26598
+ key = match[1].toLowerCase();
26599
+ value = match[2];
26600
+ if (value.charCodeAt(0) === 34) {
26601
+ value = value.slice(1, -1);
26602
+ if (value.indexOf("\\") !== -1) {
26603
+ value = value.replace(QESC_REGEXP, "$1");
26604
+ }
26605
+ }
26606
+ obj.parameters[key] = value;
26607
+ }
26608
+ if (index4 !== header.length) {
26609
+ throw new TypeError("invalid parameter format");
26610
+ }
26611
+ }
26612
+ return obj;
26613
+ }
26614
+ function getcontenttype(obj) {
26615
+ var header;
26616
+ if (typeof obj.getHeader === "function") {
26617
+ header = obj.getHeader("content-type");
26618
+ } else if (typeof obj.headers === "object") {
26619
+ header = obj.headers && obj.headers["content-type"];
26620
+ }
26621
+ if (typeof header !== "string") {
26622
+ throw new TypeError("content-type header is missing from object");
26623
+ }
26624
+ return header;
26625
+ }
26626
+ function qstring(val) {
26627
+ var str = String(val);
26628
+ if (TOKEN_REGEXP.test(str)) {
26629
+ return str;
26630
+ }
26631
+ if (str.length > 0 && !TEXT_REGEXP.test(str)) {
26632
+ throw new TypeError("invalid parameter value");
26633
+ }
26634
+ return '"' + str.replace(QUOTE_REGEXP, "\\$1") + '"';
26635
+ }
26636
+ function ContentType(type) {
26637
+ this.parameters = /* @__PURE__ */ Object.create(null);
26638
+ this.type = type;
26639
+ }
26640
+ }
26641
+ });
26642
+
26643
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js
26644
+ function mediaTypeEssence(header) {
26645
+ if (!header) {
26646
+ return void 0;
26647
+ }
26648
+ try {
26649
+ return import_content_type.default.parse(header).type;
26650
+ } catch {
26651
+ const essence = (header.split(";", 1)[0] ?? "").trim().toLowerCase();
26652
+ if (essence === "" || header.slice(essence.length).includes(",")) {
26653
+ return void 0;
26654
+ }
26655
+ return essence;
26656
+ }
26657
+ }
26658
+ function isJsonContentType(header) {
26659
+ if (header === "application/json") {
26660
+ return true;
26661
+ }
26662
+ return mediaTypeEssence(header) === "application/json";
26663
+ }
26664
+ var import_content_type;
26665
+ var init_mediaType = __esm({
26666
+ "node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js"() {
26667
+ import_content_type = __toESM(require_content_type(), 1);
26668
+ }
26669
+ });
26670
+
26671
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.js
26672
+ function armSseKeepAlive(intervalMs, onTick) {
26673
+ if (!Number.isFinite(intervalMs) || intervalMs < 1) {
26674
+ return void 0;
26675
+ }
26676
+ const timer = setInterval(onTick, Math.min(intervalMs, MAX_TIMER_DELAY_MS));
26677
+ timer.unref?.();
26678
+ return timer;
26679
+ }
26680
+ var DEFAULT_SSE_KEEP_ALIVE_MS, MAX_TIMER_DELAY_MS;
26681
+ var init_sseKeepAlive = __esm({
26682
+ "node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.js"() {
26683
+ DEFAULT_SSE_KEEP_ALIVE_MS = 15e3;
26684
+ MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
26685
+ }
26686
+ });
26687
+
26539
26688
  // node_modules/zod/v4/core/core.js
26540
26689
  // @__NO_SIDE_EFFECTS__
26541
26690
  function $constructor(name, initializer3, params) {
@@ -43166,6 +43315,8 @@ var init_types = __esm({
43166
43315
  var WebStandardStreamableHTTPServerTransport;
43167
43316
  var init_webStandardStreamableHttp = __esm({
43168
43317
  "node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js"() {
43318
+ init_mediaType();
43319
+ init_sseKeepAlive();
43169
43320
  init_types();
43170
43321
  WebStandardStreamableHTTPServerTransport = class {
43171
43322
  constructor(options = {}) {
@@ -43173,10 +43324,12 @@ var init_webStandardStreamableHttp = __esm({
43173
43324
  this._hasHandledRequest = false;
43174
43325
  this._streamMapping = /* @__PURE__ */ new Map();
43175
43326
  this._requestToStreamMapping = /* @__PURE__ */ new Map();
43327
+ this._resumableStreams = /* @__PURE__ */ new Set();
43176
43328
  this._requestResponseMap = /* @__PURE__ */ new Map();
43177
43329
  this._initialized = false;
43178
43330
  this._enableJsonResponse = false;
43179
43331
  this._standaloneSseStreamId = "_GET_stream";
43332
+ this._closed = false;
43180
43333
  this.sessionIdGenerator = options.sessionIdGenerator;
43181
43334
  this._enableJsonResponse = options.enableJsonResponse ?? false;
43182
43335
  this._eventStore = options.eventStore;
@@ -43186,6 +43339,27 @@ var init_webStandardStreamableHttp = __esm({
43186
43339
  this._allowedOrigins = options.allowedOrigins;
43187
43340
  this._enableDnsRebindingProtection = options.enableDnsRebindingProtection ?? false;
43188
43341
  this._retryInterval = options.retryInterval;
43342
+ this._keepAliveMs = options.keepAliveMs ?? DEFAULT_SSE_KEEP_ALIVE_MS;
43343
+ }
43344
+ /**
43345
+ * Arms a keep-alive interval for an SSE stream that periodically writes an SSE
43346
+ * comment frame so intermediaries and idle timeouts don't kill the connection.
43347
+ * The returned timer is owned by the stream it was armed for: the stream's
43348
+ * cancel/cleanup callbacks must clear it. The interval clears itself if a
43349
+ * write fails (stream already closed/cancelled).
43350
+ */
43351
+ startKeepAlive(controller, encoder) {
43352
+ if (this._closed)
43353
+ return void 0;
43354
+ const timer = armSseKeepAlive(this._keepAliveMs, () => {
43355
+ try {
43356
+ controller.enqueue(encoder.encode(": keepalive\n\n"));
43357
+ } catch {
43358
+ if (timer !== void 0)
43359
+ clearInterval(timer);
43360
+ }
43361
+ });
43362
+ return timer;
43189
43363
  }
43190
43364
  /**
43191
43365
  * Starts the transport. This is required by the Transport interface but is a no-op
@@ -43248,6 +43422,9 @@ var init_webStandardStreamableHttp = __esm({
43248
43422
  * Returns a Response object (Web Standard)
43249
43423
  */
43250
43424
  async handleRequest(req, options) {
43425
+ if (this._closed) {
43426
+ return this.createJsonErrorResponse(404, -32001, "Session not found");
43427
+ }
43251
43428
  if (!this.sessionIdGenerator && this._hasHandledRequest) {
43252
43429
  throw new Error("Stateless transport cannot be reused across requests. Create a new transport per request.");
43253
43430
  }
@@ -43292,6 +43469,7 @@ data:
43292
43469
  `;
43293
43470
  }
43294
43471
  controller.enqueue(encoder.encode(primingEvent));
43472
+ this._resumableStreams.add(streamId);
43295
43473
  }
43296
43474
  /**
43297
43475
  * Handles GET requests for SSE stream
@@ -43322,18 +43500,25 @@ data:
43322
43500
  }
43323
43501
  const encoder = new TextEncoder();
43324
43502
  let streamController;
43503
+ let keepAliveTimer = void 0;
43325
43504
  const readable = new ReadableStream({
43326
43505
  start: (controller) => {
43327
43506
  streamController = controller;
43328
43507
  },
43329
43508
  cancel: () => {
43330
- this._streamMapping.delete(this._standaloneSseStreamId);
43509
+ if (keepAliveTimer !== void 0) {
43510
+ clearInterval(keepAliveTimer);
43511
+ }
43512
+ if (this._streamMapping.get(this._standaloneSseStreamId)?.controller === streamController) {
43513
+ this._streamMapping.delete(this._standaloneSseStreamId);
43514
+ }
43331
43515
  }
43332
43516
  });
43333
43517
  const headers = {
43334
43518
  "Content-Type": "text/event-stream",
43335
43519
  "Cache-Control": "no-cache, no-transform",
43336
- Connection: "keep-alive"
43520
+ Connection: "keep-alive",
43521
+ "X-Accel-Buffering": "no"
43337
43522
  };
43338
43523
  if (this.sessionId !== void 0) {
43339
43524
  headers["mcp-session-id"] = this.sessionId;
@@ -43342,6 +43527,9 @@ data:
43342
43527
  controller: streamController,
43343
43528
  encoder,
43344
43529
  cleanup: () => {
43530
+ if (keepAliveTimer !== void 0) {
43531
+ clearInterval(keepAliveTimer);
43532
+ }
43345
43533
  this._streamMapping.delete(this._standaloneSseStreamId);
43346
43534
  try {
43347
43535
  streamController.close();
@@ -43349,6 +43537,7 @@ data:
43349
43537
  }
43350
43538
  }
43351
43539
  });
43540
+ keepAliveTimer = this.startKeepAlive(streamController, encoder);
43352
43541
  return new Response(readable, { headers });
43353
43542
  }
43354
43543
  /**
@@ -43376,21 +43565,33 @@ data:
43376
43565
  const headers = {
43377
43566
  "Content-Type": "text/event-stream",
43378
43567
  "Cache-Control": "no-cache, no-transform",
43379
- Connection: "keep-alive"
43568
+ Connection: "keep-alive",
43569
+ "X-Accel-Buffering": "no"
43380
43570
  };
43381
43571
  if (this.sessionId !== void 0) {
43382
43572
  headers["mcp-session-id"] = this.sessionId;
43383
43573
  }
43384
43574
  const encoder = new TextEncoder();
43385
43575
  let streamController;
43576
+ let keepAliveTimer = void 0;
43577
+ let replayedStreamId = void 0;
43578
+ let cancelled = false;
43386
43579
  const readable = new ReadableStream({
43387
43580
  start: (controller) => {
43388
43581
  streamController = controller;
43389
43582
  },
43390
43583
  cancel: () => {
43584
+ cancelled = true;
43585
+ if (keepAliveTimer !== void 0) {
43586
+ clearInterval(keepAliveTimer);
43587
+ }
43588
+ if (replayedStreamId !== void 0 && this._streamMapping.get(replayedStreamId)?.controller === streamController) {
43589
+ this._streamMapping.delete(replayedStreamId);
43590
+ }
43391
43591
  }
43392
43592
  });
43393
- const replayedStreamId = await this._eventStore.replayEventsAfter(lastEventId, {
43593
+ const replayedEventIds = /* @__PURE__ */ new Set();
43594
+ replayedStreamId = await this._eventStore.replayEventsAfter(lastEventId, {
43394
43595
  send: async (eventId, message) => {
43395
43596
  const success2 = this.writeSSEEvent(streamController, encoder, message, eventId);
43396
43597
  if (!success2) {
@@ -43399,13 +43600,27 @@ data:
43399
43600
  streamController.close();
43400
43601
  } catch {
43401
43602
  }
43603
+ } else {
43604
+ replayedEventIds.add(eventId);
43402
43605
  }
43403
43606
  }
43404
43607
  });
43608
+ if (this._closed || cancelled) {
43609
+ try {
43610
+ streamController.close();
43611
+ } catch {
43612
+ }
43613
+ return this.createJsonErrorResponse(404, -32001, "Session not found");
43614
+ }
43615
+ this._streamMapping.get(replayedStreamId)?.cleanup();
43405
43616
  this._streamMapping.set(replayedStreamId, {
43406
43617
  controller: streamController,
43407
43618
  encoder,
43619
+ replayedEventIds,
43408
43620
  cleanup: () => {
43621
+ if (keepAliveTimer !== void 0) {
43622
+ clearInterval(keepAliveTimer);
43623
+ }
43409
43624
  this._streamMapping.delete(replayedStreamId);
43410
43625
  try {
43411
43626
  streamController.close();
@@ -43413,6 +43628,8 @@ data:
43413
43628
  }
43414
43629
  }
43415
43630
  });
43631
+ this._resumableStreams.add(replayedStreamId);
43632
+ keepAliveTimer = this.startKeepAlive(streamController, encoder);
43416
43633
  return new Response(readable, { headers });
43417
43634
  } catch (error51) {
43418
43635
  this.onerror?.(error51);
@@ -43471,7 +43688,7 @@ data:
43471
43688
  return this.createJsonErrorResponse(406, -32e3, "Not Acceptable: Client must accept both application/json and text/event-stream");
43472
43689
  }
43473
43690
  const ct = req.headers.get("content-type");
43474
- if (!ct || !ct.includes("application/json")) {
43691
+ if (!isJsonContentType(ct)) {
43475
43692
  this.onerror?.(new Error("Unsupported Media Type: Content-Type must be application/json"));
43476
43693
  return this.createJsonErrorResponse(415, -32e3, "Unsupported Media Type: Content-Type must be application/json");
43477
43694
  }
@@ -43501,6 +43718,9 @@ data:
43501
43718
  this.onerror?.(new Error("Parse error: Invalid JSON-RPC message"));
43502
43719
  return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON-RPC message");
43503
43720
  }
43721
+ if (this._closed) {
43722
+ return this.createJsonErrorResponse(404, -32001, "Session not found");
43723
+ }
43504
43724
  const isInitializationRequest = messages.some(isInitializeRequest);
43505
43725
  if (isInitializationRequest) {
43506
43726
  if (this._initialized && this.sessionId !== void 0) {
@@ -43527,6 +43747,9 @@ data:
43527
43747
  return protocolError;
43528
43748
  }
43529
43749
  }
43750
+ if (this._closed) {
43751
+ return this.createJsonErrorResponse(404, -32001, "Session not found");
43752
+ }
43530
43753
  const hasRequests = messages.some(isJSONRPCRequest);
43531
43754
  if (!hasRequests) {
43532
43755
  for (const message of messages) {
@@ -43557,18 +43780,25 @@ data:
43557
43780
  }
43558
43781
  const encoder = new TextEncoder();
43559
43782
  let streamController;
43783
+ let keepAliveTimer = void 0;
43560
43784
  const readable = new ReadableStream({
43561
43785
  start: (controller) => {
43562
43786
  streamController = controller;
43563
43787
  },
43564
43788
  cancel: () => {
43565
- this._streamMapping.delete(streamId);
43789
+ if (keepAliveTimer !== void 0) {
43790
+ clearInterval(keepAliveTimer);
43791
+ }
43792
+ if (this._streamMapping.get(streamId)?.controller === streamController) {
43793
+ this._streamMapping.delete(streamId);
43794
+ }
43566
43795
  }
43567
43796
  });
43568
43797
  const headers = {
43569
43798
  "Content-Type": "text/event-stream",
43570
- "Cache-Control": "no-cache",
43571
- Connection: "keep-alive"
43799
+ "Cache-Control": "no-cache, no-transform",
43800
+ Connection: "keep-alive",
43801
+ "X-Accel-Buffering": "no"
43572
43802
  };
43573
43803
  if (this.sessionId !== void 0) {
43574
43804
  headers["mcp-session-id"] = this.sessionId;
@@ -43579,6 +43809,9 @@ data:
43579
43809
  controller: streamController,
43580
43810
  encoder,
43581
43811
  cleanup: () => {
43812
+ if (keepAliveTimer !== void 0) {
43813
+ clearInterval(keepAliveTimer);
43814
+ }
43582
43815
  this._streamMapping.delete(streamId);
43583
43816
  try {
43584
43817
  streamController.close();
@@ -43589,19 +43822,33 @@ data:
43589
43822
  this._requestToStreamMapping.set(message.id, streamId);
43590
43823
  }
43591
43824
  }
43592
- await this.writePrimingEvent(streamController, encoder, streamId, clientProtocolVersion);
43593
- for (const message of messages) {
43594
- let closeSSEStream;
43595
- let closeStandaloneSSEStream;
43596
- if (isJSONRPCRequest(message) && this._eventStore && clientProtocolVersion >= "2025-11-25") {
43597
- closeSSEStream = () => {
43598
- this.closeSSEStream(message.id);
43599
- };
43600
- closeStandaloneSSEStream = () => {
43601
- this.closeStandaloneSSEStream();
43602
- };
43825
+ try {
43826
+ await this.writePrimingEvent(streamController, encoder, streamId, clientProtocolVersion);
43827
+ for (const message of messages) {
43828
+ let closeSSEStream;
43829
+ let closeStandaloneSSEStream;
43830
+ if (isJSONRPCRequest(message) && this._eventStore && clientProtocolVersion >= "2025-11-25") {
43831
+ closeSSEStream = () => {
43832
+ this.closeSSEStream(message.id);
43833
+ };
43834
+ closeStandaloneSSEStream = () => {
43835
+ this.closeStandaloneSSEStream();
43836
+ };
43837
+ }
43838
+ this.onmessage?.(message, { authInfo: options?.authInfo, requestInfo, closeSSEStream, closeStandaloneSSEStream });
43839
+ }
43840
+ } catch (error51) {
43841
+ this._streamMapping.get(streamId)?.cleanup();
43842
+ this._resumableStreams.delete(streamId);
43843
+ for (const message of messages) {
43844
+ if (isJSONRPCRequest(message)) {
43845
+ this._requestToStreamMapping.delete(message.id);
43846
+ }
43603
43847
  }
43604
- this.onmessage?.(message, { authInfo: options?.authInfo, requestInfo, closeSSEStream, closeStandaloneSSEStream });
43848
+ throw error51;
43849
+ }
43850
+ if (this._streamMapping.get(streamId)?.controller === streamController) {
43851
+ keepAliveTimer = this.startKeepAlive(streamController, encoder);
43605
43852
  }
43606
43853
  return new Response(readable, { status: 200, headers });
43607
43854
  } catch (error51) {
@@ -43621,9 +43868,12 @@ data:
43621
43868
  if (protocolError) {
43622
43869
  return protocolError;
43623
43870
  }
43624
- await Promise.resolve(this._onsessionclosed?.(this.sessionId));
43625
- await this.close();
43626
- return new Response(null, { status: 200 });
43871
+ try {
43872
+ await Promise.resolve(this._onsessionclosed?.(this.sessionId));
43873
+ return new Response(null, { status: 200 });
43874
+ } finally {
43875
+ await this.close();
43876
+ }
43627
43877
  }
43628
43878
  /**
43629
43879
  * Validates session ID for non-initialization requests.
@@ -43670,11 +43920,16 @@ data:
43670
43920
  return void 0;
43671
43921
  }
43672
43922
  async close() {
43923
+ if (this._closed) {
43924
+ return;
43925
+ }
43926
+ this._closed = true;
43673
43927
  this._streamMapping.forEach(({ cleanup: cleanup2 }) => {
43674
43928
  cleanup2();
43675
43929
  });
43676
43930
  this._streamMapping.clear();
43677
43931
  this._requestResponseMap.clear();
43932
+ this._resumableStreams.clear();
43678
43933
  this.onclose?.();
43679
43934
  }
43680
43935
  /**
@@ -43718,7 +43973,7 @@ data:
43718
43973
  if (standaloneSse === void 0) {
43719
43974
  return;
43720
43975
  }
43721
- if (standaloneSse.controller && standaloneSse.encoder) {
43976
+ if (standaloneSse.controller && standaloneSse.encoder && (eventId === void 0 || !standaloneSse.replayedEventIds?.has(eventId))) {
43722
43977
  this.writeSSEEvent(standaloneSse.controller, standaloneSse.encoder, message, eventId);
43723
43978
  }
43724
43979
  return;
@@ -43727,13 +43982,19 @@ data:
43727
43982
  if (!streamId) {
43728
43983
  throw new Error(`No connection established for request ID: ${String(requestId)}`);
43729
43984
  }
43730
- const stream = this._streamMapping.get(streamId);
43731
- if (!this._enableJsonResponse && stream?.controller && stream?.encoder) {
43985
+ let stream = this._streamMapping.get(streamId);
43986
+ if (!this._enableJsonResponse) {
43732
43987
  let eventId;
43733
43988
  if (this._eventStore) {
43734
43989
  eventId = await this._eventStore.storeEvent(streamId, message);
43990
+ stream = this._streamMapping.get(streamId);
43991
+ }
43992
+ if (stream?.controller && stream?.encoder && (eventId === void 0 || !stream.replayedEventIds?.has(eventId))) {
43993
+ const written = this.writeSSEEvent(stream.controller, stream.encoder, message, eventId);
43994
+ if (written && eventId !== void 0) {
43995
+ this._resumableStreams.add(streamId);
43996
+ }
43735
43997
  }
43736
- this.writeSSEEvent(stream.controller, stream.encoder, message, eventId);
43737
43998
  }
43738
43999
  if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {
43739
44000
  this._requestResponseMap.set(requestId, message);
@@ -43741,6 +44002,25 @@ data:
43741
44002
  const allResponsesReady = relatedIds.every((id) => this._requestResponseMap.has(id));
43742
44003
  if (allResponsesReady) {
43743
44004
  if (!stream) {
44005
+ if (this._closed) {
44006
+ for (const id of relatedIds) {
44007
+ this._requestResponseMap.delete(id);
44008
+ this._requestToStreamMapping.delete(id);
44009
+ }
44010
+ return;
44011
+ }
44012
+ if (!this._enableJsonResponse && this._eventStore && this._resumableStreams.has(streamId)) {
44013
+ for (const id of relatedIds) {
44014
+ this._requestResponseMap.delete(id);
44015
+ this._requestToStreamMapping.delete(id);
44016
+ }
44017
+ this._resumableStreams.delete(streamId);
44018
+ return;
44019
+ }
44020
+ for (const id of relatedIds) {
44021
+ this._requestResponseMap.delete(id);
44022
+ this._requestToStreamMapping.delete(id);
44023
+ }
43744
44024
  throw new Error(`No connection established for request ID: ${String(requestId)}`);
43745
44025
  }
43746
44026
  if (this._enableJsonResponse && stream.resolveJson) {
@@ -43763,6 +44043,7 @@ data:
43763
44043
  this._requestResponseMap.delete(id);
43764
44044
  this._requestToStreamMapping.delete(id);
43765
44045
  }
44046
+ this._resumableStreams.delete(streamId);
43766
44047
  }
43767
44048
  }
43768
44049
  }
@@ -48032,17 +48313,33 @@ function normalizeObjectSchema(schema) {
48032
48313
  }
48033
48314
  return void 0;
48034
48315
  }
48316
+ function getDotPath(path3) {
48317
+ if (path3.length === 0) {
48318
+ return "object root";
48319
+ }
48320
+ return path3.reduce((acc, seg, index4) => {
48321
+ if (index4 === 0) {
48322
+ return String(seg);
48323
+ }
48324
+ if (typeof seg === "number") {
48325
+ return `${acc}[${seg}]`;
48326
+ }
48327
+ return `${acc}.${seg}`;
48328
+ }, "");
48329
+ }
48035
48330
  function getParseErrorMessage(error51) {
48036
48331
  if (error51 && typeof error51 === "object") {
48332
+ if ("issues" in error51 && Array.isArray(error51.issues) && error51.issues.length > 0) {
48333
+ return error51.issues.map((i2) => {
48334
+ if (!i2.path?.length) {
48335
+ return i2.message;
48336
+ }
48337
+ return `${i2.message} at ${getDotPath(i2.path)}`;
48338
+ }).join("\n");
48339
+ }
48037
48340
  if ("message" in error51 && typeof error51.message === "string") {
48038
48341
  return error51.message;
48039
48342
  }
48040
- if ("issues" in error51 && Array.isArray(error51.issues) && error51.issues.length > 0) {
48041
- const firstIssue = error51.issues[0];
48042
- if (firstIssue && typeof firstIssue === "object" && "message" in firstIssue) {
48043
- return String(firstIssue.message);
48044
- }
48045
- }
48046
48343
  try {
48047
48344
  return JSON.stringify(error51);
48048
48345
  } catch {
@@ -54303,7 +54600,12 @@ var require_fast_uri = __commonJS({
54303
54600
  }
54304
54601
  function resolve(baseURI, relativeURI, options) {
54305
54602
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
54306
- const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
54603
+ const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
54604
+ const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
54605
+ if (baseMalformed || relativeMalformed) {
54606
+ throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
54607
+ }
54608
+ const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
54307
54609
  schemelessOptions.skipEscape = true;
54308
54610
  return serialize(resolved, schemelessOptions);
54309
54611
  }
@@ -54428,6 +54730,8 @@ var require_fast_uri = __commonJS({
54428
54730
  return uriTokens.join("");
54429
54731
  }
54430
54732
  var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
54733
+ var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
54734
+ var AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
54431
54735
  function getParseError(parsed, matches) {
54432
54736
  if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
54433
54737
  return 'URI path must start with "/" when authority is present.';
@@ -54457,6 +54761,25 @@ var require_fast_uri = __commonJS({
54457
54761
  uri = "//" + uri;
54458
54762
  }
54459
54763
  }
54764
+ const authorityMatch = uri.match(AUTHORITY_PREFIX);
54765
+ if (authorityMatch !== null && authorityMatch[1].indexOf("\\") !== -1) {
54766
+ parsed.error = "URI authority must not contain a literal backslash.";
54767
+ malformedAuthorityOrPort = true;
54768
+ }
54769
+ const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
54770
+ if (introducerMatch !== null) {
54771
+ const region = introducerMatch[1];
54772
+ const normalizedRegion = region.replace(/[\t\n\r]/g, "");
54773
+ if (normalizedRegion.length >= 2) {
54774
+ if (normalizedRegion.slice(0, 2) !== "//") {
54775
+ parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
54776
+ malformedAuthorityOrPort = true;
54777
+ } else if (region.length !== normalizedRegion.length) {
54778
+ parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
54779
+ malformedAuthorityOrPort = true;
54780
+ }
54781
+ }
54782
+ }
54460
54783
  const matches = uri.match(URI_PARSE);
54461
54784
  if (matches) {
54462
54785
  parsed.scheme = matches[1];
@@ -57954,16 +58277,7 @@ var init_server2 = __esm({
57954
58277
  if (!methodSchema) {
57955
58278
  throw new Error("Schema is missing a method literal");
57956
58279
  }
57957
- let methodValue;
57958
- if (isZ4Schema(methodSchema)) {
57959
- const v4Schema = methodSchema;
57960
- const v4Def = v4Schema._zod?.def;
57961
- methodValue = v4Def?.value ?? v4Schema.value;
57962
- } else {
57963
- const v3Schema = methodSchema;
57964
- const legacyDef = v3Schema._def;
57965
- methodValue = legacyDef?.value ?? v3Schema.value;
57966
- }
58280
+ const methodValue = getLiteralValue(methodSchema);
57967
58281
  if (typeof methodValue !== "string") {
57968
58282
  throw new Error("Schema method literal must be a string");
57969
58283
  }
@@ -59425,12 +59739,21 @@ function deserializeMessage(line) {
59425
59739
  function serializeMessage(message) {
59426
59740
  return JSON.stringify(message) + "\n";
59427
59741
  }
59428
- var ReadBuffer;
59742
+ var STDIO_DEFAULT_MAX_BUFFER_SIZE, ReadBuffer;
59429
59743
  var init_stdio = __esm({
59430
59744
  "node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js"() {
59431
59745
  init_types();
59746
+ STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
59432
59747
  ReadBuffer = class {
59748
+ constructor(options) {
59749
+ this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
59750
+ }
59433
59751
  append(chunk) {
59752
+ const newSize = (this._buffer?.length ?? 0) + chunk.length;
59753
+ if (newSize > this._maxBufferSize) {
59754
+ this.clear();
59755
+ throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
59756
+ }
59434
59757
  this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
59435
59758
  }
59436
59759
  readMessage() {
@@ -59459,18 +59782,24 @@ var init_stdio2 = __esm({
59459
59782
  "node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js"() {
59460
59783
  init_stdio();
59461
59784
  StdioServerTransport = class {
59462
- constructor(_stdin = process3.stdin, _stdout = process3.stdout) {
59785
+ constructor(_stdin = process3.stdin, _stdout = process3.stdout, options) {
59463
59786
  this._stdin = _stdin;
59464
59787
  this._stdout = _stdout;
59465
- this._readBuffer = new ReadBuffer();
59466
59788
  this._started = false;
59467
59789
  this._ondata = (chunk) => {
59468
- this._readBuffer.append(chunk);
59469
- this.processReadBuffer();
59790
+ try {
59791
+ this._readBuffer.append(chunk);
59792
+ this.processReadBuffer();
59793
+ } catch (error51) {
59794
+ this.onerror?.(error51);
59795
+ this.close().catch(() => {
59796
+ });
59797
+ }
59470
59798
  };
59471
59799
  this._onerror = (error51) => {
59472
59800
  this.onerror?.(error51);
59473
59801
  };
59802
+ this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
59474
59803
  }
59475
59804
  /**
59476
59805
  * Starts listening for messages on stdin.
@@ -120155,6 +120484,13 @@ simple-concat/index.js:
120155
120484
  simple-get/index.js:
120156
120485
  (*! simple-get. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> *)
120157
120486
 
120487
+ content-type/index.js:
120488
+ (*!
120489
+ * content-type
120490
+ * Copyright(c) 2015 Douglas Christopher Wilson
120491
+ * MIT Licensed
120492
+ *)
120493
+
120158
120494
  long/umd/index.js:
120159
120495
  (**
120160
120496
  * @license
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jjhub",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "jjhub — GitHub CLI with Jujutsu-native superpowers: stable change IDs, stacks, platform-wide undo, and conflicts that wait, layered over plain GitHub repos by a JJHub server.",
5
5
  "bin": {
6
6
  "jjhub": "./dist/cli/jjhub.mjs"