@funnycode/myclaude 0.1.88 → 0.1.90

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/myclaude.js CHANGED
@@ -4,8 +4,8 @@
4
4
  // MACRO - build-time constants (injected by build.ts)
5
5
  // MACRO injected by build script
6
6
  globalThis.MACRO = {
7
- VERSION: "0.1.88",
8
- BUILD_TIME: "2026-07-17T10:35:59.798Z",
7
+ VERSION: "0.1.90",
8
+ BUILD_TIME: "2026-07-17T18:18:41.746Z",
9
9
  PACKAGE_URL: "@funnycode/myclaude",
10
10
  NATIVE_PACKAGE_URL: "@funnycode/myclaude",
11
11
  VERSION_CHANGELOG: '',
@@ -117484,7 +117484,7 @@ var package_default;
117484
117484
  var init_package = __esm(() => {
117485
117485
  package_default = {
117486
117486
  name: "@funnycode/myclaude",
117487
- version: "0.1.88",
117487
+ version: "0.1.90",
117488
117488
  private: false,
117489
117489
  description: "An open-source AI coding assistant in your terminal - powered by Claude",
117490
117490
  license: "MIT",
@@ -117548,6 +117548,7 @@ var init_package = __esm(() => {
117548
117548
  "@opentelemetry/semantic-conventions": "1.40.0",
117549
117549
  ajv: "8.18.0",
117550
117550
  asciichart: "1.5.25",
117551
+ "async-mutex": "^0.5.0",
117551
117552
  "auto-bind": "5.0.1",
117552
117553
  axios: "1.14.0",
117553
117554
  "bidi-js": "1.0.3",
@@ -210158,6 +210159,7 @@ function enqueueDumpRequest(agentIdOrSessionId, callback) {
210158
210159
  }
210159
210160
  dumpRequestQueue.get(agentIdOrSessionId).push(callback);
210160
210161
  if (!processingQueues.has(agentIdOrSessionId)) {
210162
+ processingQueues.add(agentIdOrSessionId);
210161
210163
  processQueue(agentIdOrSessionId);
210162
210164
  }
210163
210165
  }
@@ -210288,27 +210290,50 @@ function createDumpPromptsFetch(agentIdOrSessionId) {
210288
210290
  const reader = cloned.body.getReader();
210289
210291
  const decoder = new TextDecoder;
210290
210292
  let buffer = "";
210293
+ const chunks = [];
210291
210294
  try {
210292
210295
  while (true) {
210293
210296
  const { done, value } = await reader.read();
210294
210297
  if (done)
210295
210298
  break;
210296
210299
  buffer += decoder.decode(value, { stream: true });
210300
+ const lastDoubleNewline = buffer.lastIndexOf(`
210301
+
210302
+ `);
210303
+ if (lastDoubleNewline !== -1) {
210304
+ const completeEvents = buffer.slice(0, lastDoubleNewline);
210305
+ buffer = buffer.slice(lastDoubleNewline + 2);
210306
+ for (const event of completeEvents.split(`
210307
+
210308
+ `)) {
210309
+ for (const line of event.split(`
210310
+ `)) {
210311
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
210312
+ try {
210313
+ chunks.push(jsonParse(line.slice(6)));
210314
+ } catch (err2) {
210315
+ logForDebugging(`dumpPrompts.SSE parse error: ${err2}`, { level: "error" });
210316
+ }
210317
+ }
210318
+ }
210319
+ }
210320
+ }
210297
210321
  }
210298
210322
  } finally {
210299
210323
  reader.releaseLock();
210300
210324
  }
210301
- const chunks = [];
210302
- for (const event of buffer.split(`
210325
+ if (buffer.trim()) {
210326
+ for (const event of buffer.split(`
210303
210327
 
210304
210328
  `)) {
210305
- for (const line of event.split(`
210329
+ for (const line of event.split(`
210306
210330
  `)) {
210307
- if (line.startsWith("data: ") && line !== "data: [DONE]") {
210308
- try {
210309
- chunks.push(jsonParse(line.slice(6)));
210310
- } catch (err2) {
210311
- logForDebugging(`dumpPrompts.SSE parse error: ${err2}`, { level: "error" });
210331
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
210332
+ try {
210333
+ chunks.push(jsonParse(line.slice(6)));
210334
+ } catch (err2) {
210335
+ logForDebugging(`dumpPrompts.SSE parse error: ${err2}`, { level: "error" });
210336
+ }
210312
210337
  }
210313
210338
  }
210314
210339
  }
@@ -300875,6 +300900,214 @@ var init_gracefulShutdown = __esm(() => {
300875
300900
  };
300876
300901
  });
300877
300902
 
300903
+ // node_modules/async-mutex/index.mjs
300904
+ class Semaphore {
300905
+ constructor(_value, _cancelError = E_CANCELED) {
300906
+ this._value = _value;
300907
+ this._cancelError = _cancelError;
300908
+ this._queue = [];
300909
+ this._weightedWaiters = [];
300910
+ }
300911
+ acquire(weight = 1, priority = 0) {
300912
+ if (weight <= 0)
300913
+ throw new Error(`invalid weight ${weight}: must be positive`);
300914
+ return new Promise((resolve28, reject2) => {
300915
+ const task = { resolve: resolve28, reject: reject2, weight, priority };
300916
+ const i3 = findIndexFromEnd(this._queue, (other) => priority <= other.priority);
300917
+ if (i3 === -1 && weight <= this._value) {
300918
+ this._dispatchItem(task);
300919
+ } else {
300920
+ this._queue.splice(i3 + 1, 0, task);
300921
+ }
300922
+ });
300923
+ }
300924
+ runExclusive(callback_1) {
300925
+ return __awaiter$2(this, arguments, undefined, function* (callback, weight = 1, priority = 0) {
300926
+ const [value, release] = yield this.acquire(weight, priority);
300927
+ try {
300928
+ return yield callback(value);
300929
+ } finally {
300930
+ release();
300931
+ }
300932
+ });
300933
+ }
300934
+ waitForUnlock(weight = 1, priority = 0) {
300935
+ if (weight <= 0)
300936
+ throw new Error(`invalid weight ${weight}: must be positive`);
300937
+ if (this._couldLockImmediately(weight, priority)) {
300938
+ return Promise.resolve();
300939
+ } else {
300940
+ return new Promise((resolve28) => {
300941
+ if (!this._weightedWaiters[weight - 1])
300942
+ this._weightedWaiters[weight - 1] = [];
300943
+ insertSorted(this._weightedWaiters[weight - 1], { resolve: resolve28, priority });
300944
+ });
300945
+ }
300946
+ }
300947
+ isLocked() {
300948
+ return this._value <= 0;
300949
+ }
300950
+ getValue() {
300951
+ return this._value;
300952
+ }
300953
+ setValue(value) {
300954
+ this._value = value;
300955
+ this._dispatchQueue();
300956
+ }
300957
+ release(weight = 1) {
300958
+ if (weight <= 0)
300959
+ throw new Error(`invalid weight ${weight}: must be positive`);
300960
+ this._value += weight;
300961
+ this._dispatchQueue();
300962
+ }
300963
+ cancel() {
300964
+ this._queue.forEach((entry) => entry.reject(this._cancelError));
300965
+ this._queue = [];
300966
+ }
300967
+ _dispatchQueue() {
300968
+ this._drainUnlockWaiters();
300969
+ while (this._queue.length > 0 && this._queue[0].weight <= this._value) {
300970
+ this._dispatchItem(this._queue.shift());
300971
+ this._drainUnlockWaiters();
300972
+ }
300973
+ }
300974
+ _dispatchItem(item) {
300975
+ const previousValue = this._value;
300976
+ this._value -= item.weight;
300977
+ item.resolve([previousValue, this._newReleaser(item.weight)]);
300978
+ }
300979
+ _newReleaser(weight) {
300980
+ let called = false;
300981
+ return () => {
300982
+ if (called)
300983
+ return;
300984
+ called = true;
300985
+ this.release(weight);
300986
+ };
300987
+ }
300988
+ _drainUnlockWaiters() {
300989
+ if (this._queue.length === 0) {
300990
+ for (let weight = this._value;weight > 0; weight--) {
300991
+ const waiters = this._weightedWaiters[weight - 1];
300992
+ if (!waiters)
300993
+ continue;
300994
+ waiters.forEach((waiter) => waiter.resolve());
300995
+ this._weightedWaiters[weight - 1] = [];
300996
+ }
300997
+ } else {
300998
+ const queuedPriority = this._queue[0].priority;
300999
+ for (let weight = this._value;weight > 0; weight--) {
301000
+ const waiters = this._weightedWaiters[weight - 1];
301001
+ if (!waiters)
301002
+ continue;
301003
+ const i3 = waiters.findIndex((waiter) => waiter.priority <= queuedPriority);
301004
+ (i3 === -1 ? waiters : waiters.splice(0, i3)).forEach((waiter) => waiter.resolve());
301005
+ }
301006
+ }
301007
+ }
301008
+ _couldLockImmediately(weight, priority) {
301009
+ return (this._queue.length === 0 || this._queue[0].priority < priority) && weight <= this._value;
301010
+ }
301011
+ }
301012
+ function insertSorted(a2, v2) {
301013
+ const i3 = findIndexFromEnd(a2, (other) => v2.priority <= other.priority);
301014
+ a2.splice(i3 + 1, 0, v2);
301015
+ }
301016
+ function findIndexFromEnd(a2, predicate) {
301017
+ for (let i3 = a2.length - 1;i3 >= 0; i3--) {
301018
+ if (predicate(a2[i3])) {
301019
+ return i3;
301020
+ }
301021
+ }
301022
+ return -1;
301023
+ }
301024
+
301025
+ class Mutex {
301026
+ constructor(cancelError) {
301027
+ this._semaphore = new Semaphore(1, cancelError);
301028
+ }
301029
+ acquire() {
301030
+ return __awaiter$1(this, arguments, undefined, function* (priority = 0) {
301031
+ const [, releaser] = yield this._semaphore.acquire(1, priority);
301032
+ return releaser;
301033
+ });
301034
+ }
301035
+ runExclusive(callback, priority = 0) {
301036
+ return this._semaphore.runExclusive(() => callback(), 1, priority);
301037
+ }
301038
+ isLocked() {
301039
+ return this._semaphore.isLocked();
301040
+ }
301041
+ waitForUnlock(priority = 0) {
301042
+ return this._semaphore.waitForUnlock(1, priority);
301043
+ }
301044
+ release() {
301045
+ if (this._semaphore.isLocked())
301046
+ this._semaphore.release();
301047
+ }
301048
+ cancel() {
301049
+ return this._semaphore.cancel();
301050
+ }
301051
+ }
301052
+ var E_TIMEOUT, E_ALREADY_LOCKED, E_CANCELED, __awaiter$2 = function(thisArg, _arguments, P2, generator) {
301053
+ function adopt(value) {
301054
+ return value instanceof P2 ? value : new P2(function(resolve28) {
301055
+ resolve28(value);
301056
+ });
301057
+ }
301058
+ return new (P2 || (P2 = Promise))(function(resolve28, reject2) {
301059
+ function fulfilled(value) {
301060
+ try {
301061
+ step(generator.next(value));
301062
+ } catch (e) {
301063
+ reject2(e);
301064
+ }
301065
+ }
301066
+ function rejected(value) {
301067
+ try {
301068
+ step(generator["throw"](value));
301069
+ } catch (e) {
301070
+ reject2(e);
301071
+ }
301072
+ }
301073
+ function step(result) {
301074
+ result.done ? resolve28(result.value) : adopt(result.value).then(fulfilled, rejected);
301075
+ }
301076
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
301077
+ });
301078
+ }, __awaiter$1 = function(thisArg, _arguments, P2, generator) {
301079
+ function adopt(value) {
301080
+ return value instanceof P2 ? value : new P2(function(resolve28) {
301081
+ resolve28(value);
301082
+ });
301083
+ }
301084
+ return new (P2 || (P2 = Promise))(function(resolve28, reject2) {
301085
+ function fulfilled(value) {
301086
+ try {
301087
+ step(generator.next(value));
301088
+ } catch (e) {
301089
+ reject2(e);
301090
+ }
301091
+ }
301092
+ function rejected(value) {
301093
+ try {
301094
+ step(generator["throw"](value));
301095
+ } catch (e) {
301096
+ reject2(e);
301097
+ }
301098
+ }
301099
+ function step(result) {
301100
+ result.done ? resolve28(result.value) : adopt(result.value).then(fulfilled, rejected);
301101
+ }
301102
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
301103
+ });
301104
+ };
301105
+ var init_async_mutex = __esm(() => {
301106
+ E_TIMEOUT = new Error("timeout while waiting for mutex to become available");
301107
+ E_ALREADY_LOCKED = new Error("mutex already locked");
301108
+ E_CANCELED = new Error("request for lock canceled");
301109
+ });
301110
+
300878
301111
  // src/services/api/grove.ts
300879
301112
  function memoizeWithTTL(fn, ttlMs) {
300880
301113
  let lastCachedAt = 0;
@@ -300886,11 +301119,20 @@ function memoizeWithTTL(fn, ttlMs) {
300886
301119
  originalClear();
300887
301120
  lastCachedAt = 0;
300888
301121
  }
300889
- const result = await memoized(...args);
300890
- if (result && typeof result === "object" && "success" in result && result.success === true) {
300891
- lastCachedAt = Date.now();
301122
+ try {
301123
+ const result = await memoized(...args);
301124
+ if (result && typeof result === "object" && "success" in result && result.success === true) {
301125
+ lastCachedAt = Date.now();
301126
+ } else if (result && typeof result === "object" && "success" in result && result.success === false) {
301127
+ originalClear();
301128
+ lastCachedAt = 0;
301129
+ }
301130
+ return result;
301131
+ } catch (error49) {
301132
+ originalClear();
301133
+ lastCachedAt = 0;
301134
+ throw error49;
300892
301135
  }
300893
- return result;
300894
301136
  };
300895
301137
  wrapped.cache = {
300896
301138
  clear: () => {
@@ -300965,13 +301207,12 @@ async function isQualifiedForGrove() {
300965
301207
  return cachedEntry.grove_enabled;
300966
301208
  }
300967
301209
  async function fetchAndStoreGroveConfig(accountId) {
300968
- let releaseLock;
300969
- const lockPromise = new Promise((resolve28) => {
300970
- releaseLock = resolve28;
300971
- });
300972
- const previous = groveConfigLocks.get(accountId) ?? Promise.resolve();
300973
- groveConfigLocks.set(accountId, lockPromise);
300974
- await previous;
301210
+ let mutex = groveConfigMutexes.get(accountId);
301211
+ if (!mutex) {
301212
+ mutex = new Mutex;
301213
+ groveConfigMutexes.set(accountId, mutex);
301214
+ }
301215
+ const release = await mutex.acquire();
300975
301216
  try {
300976
301217
  const result = await getGroveNoticeConfig();
300977
301218
  if (!result.success) {
@@ -300995,10 +301236,7 @@ async function fetchAndStoreGroveConfig(accountId) {
300995
301236
  } catch (err2) {
300996
301237
  logForDebugging(`Grove: Failed to fetch and store config: ${err2}`);
300997
301238
  } finally {
300998
- releaseLock();
300999
- if (groveConfigLocks.get(accountId) === lockPromise) {
301000
- groveConfigLocks.delete(accountId);
301001
- }
301239
+ release();
301002
301240
  }
301003
301241
  }
301004
301242
  function calculateShouldShowGrove(settingsResult, configResult, showIfAlreadyViewed) {
@@ -301052,7 +301290,7 @@ An update to our Consumer Terms and Privacy Policy will take effect on October 8
301052
301290
  }
301053
301291
  }
301054
301292
  }
301055
- var groveConfigLocks, GROVE_CACHE_EXPIRATION_MS, getGroveSettings, getGroveNoticeConfig;
301293
+ var groveConfigMutexes, GROVE_CACHE_EXPIRATION_MS, GROVE_API_TIMEOUT_MS, getGroveSettings, getGroveNoticeConfig;
301056
301294
  var init_grove = __esm(() => {
301057
301295
  init_axios2();
301058
301296
  init_memoize();
@@ -301064,8 +301302,10 @@ var init_grove = __esm(() => {
301064
301302
  init_config();
301065
301303
  init_http2();
301066
301304
  init_log3();
301067
- groveConfigLocks = new Map;
301305
+ init_async_mutex();
301306
+ groveConfigMutexes = new Map;
301068
301307
  GROVE_CACHE_EXPIRATION_MS = 24 * 60 * 60 * 1000;
301308
+ GROVE_API_TIMEOUT_MS = parseInt(process.env.GROVE_API_TIMEOUT_MS ?? "3000", 10);
301069
301309
  getGroveSettings = memoizeWithTTL(async () => {
301070
301310
  if (isEssentialTrafficOnly()) {
301071
301311
  return { success: false };
@@ -301105,7 +301345,7 @@ var init_grove = __esm(() => {
301105
301345
  ...authHeaders.headers,
301106
301346
  "User-Agent": getUserAgent()
301107
301347
  },
301108
- timeout: 3000
301348
+ timeout: GROVE_API_TIMEOUT_MS
301109
301349
  });
301110
301350
  });
301111
301351
  const {
@@ -301125,6 +301365,9 @@ var init_grove = __esm(() => {
301125
301365
  };
301126
301366
  } catch (err2) {
301127
301367
  logError2(err2);
301368
+ if (axios_default.isAxiosError(err2) && err2.code === "ECONNABORTED") {
301369
+ logForDebugging(`Grove: API request timed out after ${GROVE_API_TIMEOUT_MS}ms. This may cause the Grove dialog to be suppressed for users with slow connections.`);
301370
+ }
301128
301371
  getGroveNoticeConfig.cache.clear?.();
301129
301372
  return { success: false };
301130
301373
  }
@@ -342099,17 +342342,20 @@ async function appendSessionLogImpl(sessionId, entry, url3, headers) {
342099
342342
  logForDebugging(`Session 409: adopting server lastUuid=${serverLastUuid} from header, retrying entry ${entry.uuid}`);
342100
342343
  } else {
342101
342344
  const sequentialFetch = getOrCreateSequentialFetch(sessionId);
342102
- const logs2 = await sequentialFetch(sessionId, url3, headers);
342345
+ let logs2 = null;
342346
+ try {
342347
+ logs2 = await sequentialFetch(sessionId, url3, headers);
342348
+ } catch (fetchError) {
342349
+ logError2(new Error(`Session 409: fetch failed for session ${sessionId}, entry ${entry.uuid}: ${fetchError instanceof Error ? fetchError.message : String(fetchError)}`));
342350
+ logForDiagnosticsNoPII("error", "session_persist_409_fetch_fail");
342351
+ }
342103
342352
  const adoptedUuid = findLastUuid(logs2);
342104
342353
  if (adoptedUuid) {
342105
342354
  lastUuidMap.set(sessionId, adoptedUuid);
342106
342355
  logForDebugging(`Session 409: re-fetched ${logs2.length} entries, adopting lastUuid=${adoptedUuid}, retrying entry ${entry.uuid}`);
342107
342356
  } else {
342108
- const errorData = response.data;
342109
- const errorMessage2 = errorData.error?.message || "Concurrent modification detected";
342110
- logError2(new Error(`Session persistence conflict: UUID mismatch for session ${sessionId}, entry ${entry.uuid}. ${errorMessage2}`));
342111
- logForDiagnosticsNoPII("error", "session_persist_fail_concurrent_modification");
342112
- return false;
342357
+ logForDebugging(`Session 409: could not determine server state for session ${sessionId}, entry ${entry.uuid}`);
342358
+ logForDiagnosticsNoPII("warn", "session_persist_409_no_adopted_uuid");
342113
342359
  }
342114
342360
  }
342115
342361
  logForDiagnosticsNoPII("info", "session_persist_409_adopt_server_uuid");
@@ -342126,10 +342372,11 @@ async function appendSessionLogImpl(sessionId, entry, url3, headers) {
342126
342372
  attempt
342127
342373
  });
342128
342374
  } catch (error49) {
342129
- const axiosError = error49;
342130
- logError2(new Error(`Error persisting session log: ${axiosError.message}`));
342375
+ const errorMessage2 = error49 instanceof Error ? error49.message : String(error49);
342376
+ const axiosStatus = error49 && typeof error49 === "object" && "status" in error49 ? error49.status : undefined;
342377
+ logError2(new Error(`Error persisting session log: ${errorMessage2}`));
342131
342378
  logForDiagnosticsNoPII("error", "session_persist_fail_status", {
342132
- status: axiosError.status,
342379
+ status: axiosStatus,
342133
342380
  attempt
342134
342381
  });
342135
342382
  }
@@ -348833,7 +349080,7 @@ var require_semaphore = __commonJS((exports) => {
348833
349080
  exports.Semaphore = undefined;
348834
349081
  var ral_1 = require_ral();
348835
349082
 
348836
- class Semaphore {
349083
+ class Semaphore2 {
348837
349084
  constructor(capacity = 1) {
348838
349085
  if (capacity <= 0) {
348839
349086
  throw new Error("Capacity must be greater than 0");
@@ -348890,7 +349137,7 @@ var require_semaphore = __commonJS((exports) => {
348890
349137
  }
348891
349138
  }
348892
349139
  }
348893
- exports.Semaphore = Semaphore;
349140
+ exports.Semaphore = Semaphore2;
348894
349141
  });
348895
349142
 
348896
349143
  // node_modules/vscode-jsonrpc/lib/common/messageReader.js
@@ -453604,7 +453851,11 @@ async function fetchAndStorePassesEligibility() {
453604
453851
  logForDebugging("Passes: Reusing in-flight eligibility fetch");
453605
453852
  return fetchInProgress;
453606
453853
  }
453607
- fetchInProgress = (async () => {
453854
+ let resolvePromise;
453855
+ fetchInProgress = new Promise((resolve47) => {
453856
+ resolvePromise = resolve47;
453857
+ });
453858
+ (async () => {
453608
453859
  try {
453609
453860
  const response = await fetchReferralEligibility();
453610
453861
  const cacheEntry = {
@@ -453619,11 +453870,11 @@ async function fetchAndStorePassesEligibility() {
453619
453870
  }
453620
453871
  }));
453621
453872
  logForDebugging(`Passes eligibility cached for org ${orgId}: ${response.eligible}`);
453622
- return response;
453873
+ resolvePromise(response);
453623
453874
  } catch (error49) {
453624
453875
  logForDebugging("Failed to fetch and cache passes eligibility");
453625
453876
  logError2(error49);
453626
- return null;
453877
+ resolvePromise(null);
453627
453878
  } finally {
453628
453879
  fetchInProgress = null;
453629
453880
  }
package/dist/myclaude.mjs CHANGED
@@ -4,8 +4,8 @@
4
4
  // MACRO - build-time constants (injected by build.ts)
5
5
  // MACRO injected by build script
6
6
  globalThis.MACRO = {
7
- VERSION: "0.1.88",
8
- BUILD_TIME: "2026-07-17T10:35:59.798Z",
7
+ VERSION: "0.1.90",
8
+ BUILD_TIME: "2026-07-17T18:18:41.746Z",
9
9
  PACKAGE_URL: "@funnycode/myclaude",
10
10
  NATIVE_PACKAGE_URL: "@funnycode/myclaude",
11
11
  VERSION_CHANGELOG: '',
@@ -117484,7 +117484,7 @@ var package_default;
117484
117484
  var init_package = __esm(() => {
117485
117485
  package_default = {
117486
117486
  name: "@funnycode/myclaude",
117487
- version: "0.1.88",
117487
+ version: "0.1.90",
117488
117488
  private: false,
117489
117489
  description: "An open-source AI coding assistant in your terminal - powered by Claude",
117490
117490
  license: "MIT",
@@ -117548,6 +117548,7 @@ var init_package = __esm(() => {
117548
117548
  "@opentelemetry/semantic-conventions": "1.40.0",
117549
117549
  ajv: "8.18.0",
117550
117550
  asciichart: "1.5.25",
117551
+ "async-mutex": "^0.5.0",
117551
117552
  "auto-bind": "5.0.1",
117552
117553
  axios: "1.14.0",
117553
117554
  "bidi-js": "1.0.3",
@@ -210158,6 +210159,7 @@ function enqueueDumpRequest(agentIdOrSessionId, callback) {
210158
210159
  }
210159
210160
  dumpRequestQueue.get(agentIdOrSessionId).push(callback);
210160
210161
  if (!processingQueues.has(agentIdOrSessionId)) {
210162
+ processingQueues.add(agentIdOrSessionId);
210161
210163
  processQueue(agentIdOrSessionId);
210162
210164
  }
210163
210165
  }
@@ -210288,27 +210290,50 @@ function createDumpPromptsFetch(agentIdOrSessionId) {
210288
210290
  const reader = cloned.body.getReader();
210289
210291
  const decoder = new TextDecoder;
210290
210292
  let buffer = "";
210293
+ const chunks = [];
210291
210294
  try {
210292
210295
  while (true) {
210293
210296
  const { done, value } = await reader.read();
210294
210297
  if (done)
210295
210298
  break;
210296
210299
  buffer += decoder.decode(value, { stream: true });
210300
+ const lastDoubleNewline = buffer.lastIndexOf(`
210301
+
210302
+ `);
210303
+ if (lastDoubleNewline !== -1) {
210304
+ const completeEvents = buffer.slice(0, lastDoubleNewline);
210305
+ buffer = buffer.slice(lastDoubleNewline + 2);
210306
+ for (const event of completeEvents.split(`
210307
+
210308
+ `)) {
210309
+ for (const line of event.split(`
210310
+ `)) {
210311
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
210312
+ try {
210313
+ chunks.push(jsonParse(line.slice(6)));
210314
+ } catch (err2) {
210315
+ logForDebugging(`dumpPrompts.SSE parse error: ${err2}`, { level: "error" });
210316
+ }
210317
+ }
210318
+ }
210319
+ }
210320
+ }
210297
210321
  }
210298
210322
  } finally {
210299
210323
  reader.releaseLock();
210300
210324
  }
210301
- const chunks = [];
210302
- for (const event of buffer.split(`
210325
+ if (buffer.trim()) {
210326
+ for (const event of buffer.split(`
210303
210327
 
210304
210328
  `)) {
210305
- for (const line of event.split(`
210329
+ for (const line of event.split(`
210306
210330
  `)) {
210307
- if (line.startsWith("data: ") && line !== "data: [DONE]") {
210308
- try {
210309
- chunks.push(jsonParse(line.slice(6)));
210310
- } catch (err2) {
210311
- logForDebugging(`dumpPrompts.SSE parse error: ${err2}`, { level: "error" });
210331
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
210332
+ try {
210333
+ chunks.push(jsonParse(line.slice(6)));
210334
+ } catch (err2) {
210335
+ logForDebugging(`dumpPrompts.SSE parse error: ${err2}`, { level: "error" });
210336
+ }
210312
210337
  }
210313
210338
  }
210314
210339
  }
@@ -300875,6 +300900,214 @@ var init_gracefulShutdown = __esm(() => {
300875
300900
  };
300876
300901
  });
300877
300902
 
300903
+ // node_modules/async-mutex/index.mjs
300904
+ class Semaphore {
300905
+ constructor(_value, _cancelError = E_CANCELED) {
300906
+ this._value = _value;
300907
+ this._cancelError = _cancelError;
300908
+ this._queue = [];
300909
+ this._weightedWaiters = [];
300910
+ }
300911
+ acquire(weight = 1, priority = 0) {
300912
+ if (weight <= 0)
300913
+ throw new Error(`invalid weight ${weight}: must be positive`);
300914
+ return new Promise((resolve28, reject2) => {
300915
+ const task = { resolve: resolve28, reject: reject2, weight, priority };
300916
+ const i3 = findIndexFromEnd(this._queue, (other) => priority <= other.priority);
300917
+ if (i3 === -1 && weight <= this._value) {
300918
+ this._dispatchItem(task);
300919
+ } else {
300920
+ this._queue.splice(i3 + 1, 0, task);
300921
+ }
300922
+ });
300923
+ }
300924
+ runExclusive(callback_1) {
300925
+ return __awaiter$2(this, arguments, undefined, function* (callback, weight = 1, priority = 0) {
300926
+ const [value, release] = yield this.acquire(weight, priority);
300927
+ try {
300928
+ return yield callback(value);
300929
+ } finally {
300930
+ release();
300931
+ }
300932
+ });
300933
+ }
300934
+ waitForUnlock(weight = 1, priority = 0) {
300935
+ if (weight <= 0)
300936
+ throw new Error(`invalid weight ${weight}: must be positive`);
300937
+ if (this._couldLockImmediately(weight, priority)) {
300938
+ return Promise.resolve();
300939
+ } else {
300940
+ return new Promise((resolve28) => {
300941
+ if (!this._weightedWaiters[weight - 1])
300942
+ this._weightedWaiters[weight - 1] = [];
300943
+ insertSorted(this._weightedWaiters[weight - 1], { resolve: resolve28, priority });
300944
+ });
300945
+ }
300946
+ }
300947
+ isLocked() {
300948
+ return this._value <= 0;
300949
+ }
300950
+ getValue() {
300951
+ return this._value;
300952
+ }
300953
+ setValue(value) {
300954
+ this._value = value;
300955
+ this._dispatchQueue();
300956
+ }
300957
+ release(weight = 1) {
300958
+ if (weight <= 0)
300959
+ throw new Error(`invalid weight ${weight}: must be positive`);
300960
+ this._value += weight;
300961
+ this._dispatchQueue();
300962
+ }
300963
+ cancel() {
300964
+ this._queue.forEach((entry) => entry.reject(this._cancelError));
300965
+ this._queue = [];
300966
+ }
300967
+ _dispatchQueue() {
300968
+ this._drainUnlockWaiters();
300969
+ while (this._queue.length > 0 && this._queue[0].weight <= this._value) {
300970
+ this._dispatchItem(this._queue.shift());
300971
+ this._drainUnlockWaiters();
300972
+ }
300973
+ }
300974
+ _dispatchItem(item) {
300975
+ const previousValue = this._value;
300976
+ this._value -= item.weight;
300977
+ item.resolve([previousValue, this._newReleaser(item.weight)]);
300978
+ }
300979
+ _newReleaser(weight) {
300980
+ let called = false;
300981
+ return () => {
300982
+ if (called)
300983
+ return;
300984
+ called = true;
300985
+ this.release(weight);
300986
+ };
300987
+ }
300988
+ _drainUnlockWaiters() {
300989
+ if (this._queue.length === 0) {
300990
+ for (let weight = this._value;weight > 0; weight--) {
300991
+ const waiters = this._weightedWaiters[weight - 1];
300992
+ if (!waiters)
300993
+ continue;
300994
+ waiters.forEach((waiter) => waiter.resolve());
300995
+ this._weightedWaiters[weight - 1] = [];
300996
+ }
300997
+ } else {
300998
+ const queuedPriority = this._queue[0].priority;
300999
+ for (let weight = this._value;weight > 0; weight--) {
301000
+ const waiters = this._weightedWaiters[weight - 1];
301001
+ if (!waiters)
301002
+ continue;
301003
+ const i3 = waiters.findIndex((waiter) => waiter.priority <= queuedPriority);
301004
+ (i3 === -1 ? waiters : waiters.splice(0, i3)).forEach((waiter) => waiter.resolve());
301005
+ }
301006
+ }
301007
+ }
301008
+ _couldLockImmediately(weight, priority) {
301009
+ return (this._queue.length === 0 || this._queue[0].priority < priority) && weight <= this._value;
301010
+ }
301011
+ }
301012
+ function insertSorted(a2, v2) {
301013
+ const i3 = findIndexFromEnd(a2, (other) => v2.priority <= other.priority);
301014
+ a2.splice(i3 + 1, 0, v2);
301015
+ }
301016
+ function findIndexFromEnd(a2, predicate) {
301017
+ for (let i3 = a2.length - 1;i3 >= 0; i3--) {
301018
+ if (predicate(a2[i3])) {
301019
+ return i3;
301020
+ }
301021
+ }
301022
+ return -1;
301023
+ }
301024
+
301025
+ class Mutex {
301026
+ constructor(cancelError) {
301027
+ this._semaphore = new Semaphore(1, cancelError);
301028
+ }
301029
+ acquire() {
301030
+ return __awaiter$1(this, arguments, undefined, function* (priority = 0) {
301031
+ const [, releaser] = yield this._semaphore.acquire(1, priority);
301032
+ return releaser;
301033
+ });
301034
+ }
301035
+ runExclusive(callback, priority = 0) {
301036
+ return this._semaphore.runExclusive(() => callback(), 1, priority);
301037
+ }
301038
+ isLocked() {
301039
+ return this._semaphore.isLocked();
301040
+ }
301041
+ waitForUnlock(priority = 0) {
301042
+ return this._semaphore.waitForUnlock(1, priority);
301043
+ }
301044
+ release() {
301045
+ if (this._semaphore.isLocked())
301046
+ this._semaphore.release();
301047
+ }
301048
+ cancel() {
301049
+ return this._semaphore.cancel();
301050
+ }
301051
+ }
301052
+ var E_TIMEOUT, E_ALREADY_LOCKED, E_CANCELED, __awaiter$2 = function(thisArg, _arguments, P2, generator) {
301053
+ function adopt(value) {
301054
+ return value instanceof P2 ? value : new P2(function(resolve28) {
301055
+ resolve28(value);
301056
+ });
301057
+ }
301058
+ return new (P2 || (P2 = Promise))(function(resolve28, reject2) {
301059
+ function fulfilled(value) {
301060
+ try {
301061
+ step(generator.next(value));
301062
+ } catch (e) {
301063
+ reject2(e);
301064
+ }
301065
+ }
301066
+ function rejected(value) {
301067
+ try {
301068
+ step(generator["throw"](value));
301069
+ } catch (e) {
301070
+ reject2(e);
301071
+ }
301072
+ }
301073
+ function step(result) {
301074
+ result.done ? resolve28(result.value) : adopt(result.value).then(fulfilled, rejected);
301075
+ }
301076
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
301077
+ });
301078
+ }, __awaiter$1 = function(thisArg, _arguments, P2, generator) {
301079
+ function adopt(value) {
301080
+ return value instanceof P2 ? value : new P2(function(resolve28) {
301081
+ resolve28(value);
301082
+ });
301083
+ }
301084
+ return new (P2 || (P2 = Promise))(function(resolve28, reject2) {
301085
+ function fulfilled(value) {
301086
+ try {
301087
+ step(generator.next(value));
301088
+ } catch (e) {
301089
+ reject2(e);
301090
+ }
301091
+ }
301092
+ function rejected(value) {
301093
+ try {
301094
+ step(generator["throw"](value));
301095
+ } catch (e) {
301096
+ reject2(e);
301097
+ }
301098
+ }
301099
+ function step(result) {
301100
+ result.done ? resolve28(result.value) : adopt(result.value).then(fulfilled, rejected);
301101
+ }
301102
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
301103
+ });
301104
+ };
301105
+ var init_async_mutex = __esm(() => {
301106
+ E_TIMEOUT = new Error("timeout while waiting for mutex to become available");
301107
+ E_ALREADY_LOCKED = new Error("mutex already locked");
301108
+ E_CANCELED = new Error("request for lock canceled");
301109
+ });
301110
+
300878
301111
  // src/services/api/grove.ts
300879
301112
  function memoizeWithTTL(fn, ttlMs) {
300880
301113
  let lastCachedAt = 0;
@@ -300886,11 +301119,20 @@ function memoizeWithTTL(fn, ttlMs) {
300886
301119
  originalClear();
300887
301120
  lastCachedAt = 0;
300888
301121
  }
300889
- const result = await memoized(...args);
300890
- if (result && typeof result === "object" && "success" in result && result.success === true) {
300891
- lastCachedAt = Date.now();
301122
+ try {
301123
+ const result = await memoized(...args);
301124
+ if (result && typeof result === "object" && "success" in result && result.success === true) {
301125
+ lastCachedAt = Date.now();
301126
+ } else if (result && typeof result === "object" && "success" in result && result.success === false) {
301127
+ originalClear();
301128
+ lastCachedAt = 0;
301129
+ }
301130
+ return result;
301131
+ } catch (error49) {
301132
+ originalClear();
301133
+ lastCachedAt = 0;
301134
+ throw error49;
300892
301135
  }
300893
- return result;
300894
301136
  };
300895
301137
  wrapped.cache = {
300896
301138
  clear: () => {
@@ -300965,13 +301207,12 @@ async function isQualifiedForGrove() {
300965
301207
  return cachedEntry.grove_enabled;
300966
301208
  }
300967
301209
  async function fetchAndStoreGroveConfig(accountId) {
300968
- let releaseLock;
300969
- const lockPromise = new Promise((resolve28) => {
300970
- releaseLock = resolve28;
300971
- });
300972
- const previous = groveConfigLocks.get(accountId) ?? Promise.resolve();
300973
- groveConfigLocks.set(accountId, lockPromise);
300974
- await previous;
301210
+ let mutex = groveConfigMutexes.get(accountId);
301211
+ if (!mutex) {
301212
+ mutex = new Mutex;
301213
+ groveConfigMutexes.set(accountId, mutex);
301214
+ }
301215
+ const release = await mutex.acquire();
300975
301216
  try {
300976
301217
  const result = await getGroveNoticeConfig();
300977
301218
  if (!result.success) {
@@ -300995,10 +301236,7 @@ async function fetchAndStoreGroveConfig(accountId) {
300995
301236
  } catch (err2) {
300996
301237
  logForDebugging(`Grove: Failed to fetch and store config: ${err2}`);
300997
301238
  } finally {
300998
- releaseLock();
300999
- if (groveConfigLocks.get(accountId) === lockPromise) {
301000
- groveConfigLocks.delete(accountId);
301001
- }
301239
+ release();
301002
301240
  }
301003
301241
  }
301004
301242
  function calculateShouldShowGrove(settingsResult, configResult, showIfAlreadyViewed) {
@@ -301052,7 +301290,7 @@ An update to our Consumer Terms and Privacy Policy will take effect on October 8
301052
301290
  }
301053
301291
  }
301054
301292
  }
301055
- var groveConfigLocks, GROVE_CACHE_EXPIRATION_MS, getGroveSettings, getGroveNoticeConfig;
301293
+ var groveConfigMutexes, GROVE_CACHE_EXPIRATION_MS, GROVE_API_TIMEOUT_MS, getGroveSettings, getGroveNoticeConfig;
301056
301294
  var init_grove = __esm(() => {
301057
301295
  init_axios2();
301058
301296
  init_memoize();
@@ -301064,8 +301302,10 @@ var init_grove = __esm(() => {
301064
301302
  init_config();
301065
301303
  init_http2();
301066
301304
  init_log3();
301067
- groveConfigLocks = new Map;
301305
+ init_async_mutex();
301306
+ groveConfigMutexes = new Map;
301068
301307
  GROVE_CACHE_EXPIRATION_MS = 24 * 60 * 60 * 1000;
301308
+ GROVE_API_TIMEOUT_MS = parseInt(process.env.GROVE_API_TIMEOUT_MS ?? "3000", 10);
301069
301309
  getGroveSettings = memoizeWithTTL(async () => {
301070
301310
  if (isEssentialTrafficOnly()) {
301071
301311
  return { success: false };
@@ -301105,7 +301345,7 @@ var init_grove = __esm(() => {
301105
301345
  ...authHeaders.headers,
301106
301346
  "User-Agent": getUserAgent()
301107
301347
  },
301108
- timeout: 3000
301348
+ timeout: GROVE_API_TIMEOUT_MS
301109
301349
  });
301110
301350
  });
301111
301351
  const {
@@ -301125,6 +301365,9 @@ var init_grove = __esm(() => {
301125
301365
  };
301126
301366
  } catch (err2) {
301127
301367
  logError2(err2);
301368
+ if (axios_default.isAxiosError(err2) && err2.code === "ECONNABORTED") {
301369
+ logForDebugging(`Grove: API request timed out after ${GROVE_API_TIMEOUT_MS}ms. This may cause the Grove dialog to be suppressed for users with slow connections.`);
301370
+ }
301128
301371
  getGroveNoticeConfig.cache.clear?.();
301129
301372
  return { success: false };
301130
301373
  }
@@ -342099,17 +342342,20 @@ async function appendSessionLogImpl(sessionId, entry, url3, headers) {
342099
342342
  logForDebugging(`Session 409: adopting server lastUuid=${serverLastUuid} from header, retrying entry ${entry.uuid}`);
342100
342343
  } else {
342101
342344
  const sequentialFetch = getOrCreateSequentialFetch(sessionId);
342102
- const logs2 = await sequentialFetch(sessionId, url3, headers);
342345
+ let logs2 = null;
342346
+ try {
342347
+ logs2 = await sequentialFetch(sessionId, url3, headers);
342348
+ } catch (fetchError) {
342349
+ logError2(new Error(`Session 409: fetch failed for session ${sessionId}, entry ${entry.uuid}: ${fetchError instanceof Error ? fetchError.message : String(fetchError)}`));
342350
+ logForDiagnosticsNoPII("error", "session_persist_409_fetch_fail");
342351
+ }
342103
342352
  const adoptedUuid = findLastUuid(logs2);
342104
342353
  if (adoptedUuid) {
342105
342354
  lastUuidMap.set(sessionId, adoptedUuid);
342106
342355
  logForDebugging(`Session 409: re-fetched ${logs2.length} entries, adopting lastUuid=${adoptedUuid}, retrying entry ${entry.uuid}`);
342107
342356
  } else {
342108
- const errorData = response.data;
342109
- const errorMessage2 = errorData.error?.message || "Concurrent modification detected";
342110
- logError2(new Error(`Session persistence conflict: UUID mismatch for session ${sessionId}, entry ${entry.uuid}. ${errorMessage2}`));
342111
- logForDiagnosticsNoPII("error", "session_persist_fail_concurrent_modification");
342112
- return false;
342357
+ logForDebugging(`Session 409: could not determine server state for session ${sessionId}, entry ${entry.uuid}`);
342358
+ logForDiagnosticsNoPII("warn", "session_persist_409_no_adopted_uuid");
342113
342359
  }
342114
342360
  }
342115
342361
  logForDiagnosticsNoPII("info", "session_persist_409_adopt_server_uuid");
@@ -342126,10 +342372,11 @@ async function appendSessionLogImpl(sessionId, entry, url3, headers) {
342126
342372
  attempt
342127
342373
  });
342128
342374
  } catch (error49) {
342129
- const axiosError = error49;
342130
- logError2(new Error(`Error persisting session log: ${axiosError.message}`));
342375
+ const errorMessage2 = error49 instanceof Error ? error49.message : String(error49);
342376
+ const axiosStatus = error49 && typeof error49 === "object" && "status" in error49 ? error49.status : undefined;
342377
+ logError2(new Error(`Error persisting session log: ${errorMessage2}`));
342131
342378
  logForDiagnosticsNoPII("error", "session_persist_fail_status", {
342132
- status: axiosError.status,
342379
+ status: axiosStatus,
342133
342380
  attempt
342134
342381
  });
342135
342382
  }
@@ -348833,7 +349080,7 @@ var require_semaphore = __commonJS((exports) => {
348833
349080
  exports.Semaphore = undefined;
348834
349081
  var ral_1 = require_ral();
348835
349082
 
348836
- class Semaphore {
349083
+ class Semaphore2 {
348837
349084
  constructor(capacity = 1) {
348838
349085
  if (capacity <= 0) {
348839
349086
  throw new Error("Capacity must be greater than 0");
@@ -348890,7 +349137,7 @@ var require_semaphore = __commonJS((exports) => {
348890
349137
  }
348891
349138
  }
348892
349139
  }
348893
- exports.Semaphore = Semaphore;
349140
+ exports.Semaphore = Semaphore2;
348894
349141
  });
348895
349142
 
348896
349143
  // node_modules/vscode-jsonrpc/lib/common/messageReader.js
@@ -453604,7 +453851,11 @@ async function fetchAndStorePassesEligibility() {
453604
453851
  logForDebugging("Passes: Reusing in-flight eligibility fetch");
453605
453852
  return fetchInProgress;
453606
453853
  }
453607
- fetchInProgress = (async () => {
453854
+ let resolvePromise;
453855
+ fetchInProgress = new Promise((resolve47) => {
453856
+ resolvePromise = resolve47;
453857
+ });
453858
+ (async () => {
453608
453859
  try {
453609
453860
  const response = await fetchReferralEligibility();
453610
453861
  const cacheEntry = {
@@ -453619,11 +453870,11 @@ async function fetchAndStorePassesEligibility() {
453619
453870
  }
453620
453871
  }));
453621
453872
  logForDebugging(`Passes eligibility cached for org ${orgId}: ${response.eligible}`);
453622
- return response;
453873
+ resolvePromise(response);
453623
453874
  } catch (error49) {
453624
453875
  logForDebugging("Failed to fetch and cache passes eligibility");
453625
453876
  logError2(error49);
453626
- return null;
453877
+ resolvePromise(null);
453627
453878
  } finally {
453628
453879
  fetchInProgress = null;
453629
453880
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnycode/myclaude",
3
- "version": "0.1.88",
3
+ "version": "0.1.90",
4
4
  "private": false,
5
5
  "description": "An open-source AI coding assistant in your terminal - powered by Claude",
6
6
  "license": "MIT",
@@ -64,6 +64,7 @@
64
64
  "@opentelemetry/semantic-conventions": "1.40.0",
65
65
  "ajv": "8.18.0",
66
66
  "asciichart": "1.5.25",
67
+ "async-mutex": "^0.5.0",
67
68
  "auto-bind": "5.0.1",
68
69
  "axios": "1.14.0",
69
70
  "bidi-js": "1.0.3",