@funnycode/myclaude 0.1.22 → 0.1.23
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/CHANGELOG.md +10 -0
- package/README.md +1 -0
- package/dist/myclaude.js +105 -10
- package/dist/myclaude.mjs +105 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.23] - 2026-06-17
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Git Bash "no available terminals" fork error** — enhanced Windows spawn reliability (fixes #6)
|
|
7
|
+
- Reduced spawn semaphore concurrency from 24 → 8 to prevent MSYS2 pty pool exhaustion under heavy parallelism
|
|
8
|
+
- Skip login shell (`-l` flag) on Git Bash/Windows to reduce per-fork startup overhead
|
|
9
|
+
- Added automatic retry with exponential backoff (500ms, 1s, 2s) when pty exhaustion is detected
|
|
10
|
+
- Better error detection: identifies "no available terminals", "cannot fork", and "resource temporarily unavailable" errors
|
|
11
|
+
- Shared cleanup path ensures semaphore is always released, preventing deadlocks
|
|
12
|
+
|
|
3
13
|
## [0.1.22] - 2026-06-17
|
|
4
14
|
|
|
5
15
|
### Added
|
package/README.md
CHANGED
|
@@ -232,6 +232,7 @@ The following features have been tested and confirmed working:
|
|
|
232
232
|
- ✅ Keybinding customization
|
|
233
233
|
- ✅ API key authentication (with any Anthropic-compatible provider)
|
|
234
234
|
- ✅ Multi-model providers (Bedrock / Vertex / Foundry)
|
|
235
|
+
- ✅ Claude Code config compatibility — reads `~/.claude/settings.json`, skills, MCPs, plugins, and hooks shared with Claude Code
|
|
235
236
|
|
|
236
237
|
---
|
|
237
238
|
|
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.
|
|
8
|
-
BUILD_TIME: "2026-06-
|
|
7
|
+
VERSION: "0.1.23",
|
|
8
|
+
BUILD_TIME: "2026-06-16T13:12:22.731Z",
|
|
9
9
|
PACKAGE_URL: "@funnycode/myclaude",
|
|
10
10
|
NATIVE_PACKAGE_URL: "@funnycode/myclaude",
|
|
11
11
|
VERSION_CHANGELOG: '',
|
|
@@ -347542,10 +347542,17 @@ async function createBashShellProvider(shellPath, options) {
|
|
|
347542
347542
|
},
|
|
347543
347543
|
getSpawnArgs(commandString) {
|
|
347544
347544
|
const skipLoginShell = lastSnapshotFilePath !== undefined;
|
|
347545
|
-
|
|
347546
|
-
|
|
347545
|
+
const onWindows = getPlatform() === "windows";
|
|
347546
|
+
if (skipLoginShell || onWindows) {
|
|
347547
|
+
if (!onWindows) {
|
|
347548
|
+
logForDebugging("Spawning shell without login (-l flag skipped)");
|
|
347549
|
+
}
|
|
347547
347550
|
}
|
|
347548
|
-
return [
|
|
347551
|
+
return [
|
|
347552
|
+
"-c",
|
|
347553
|
+
...skipLoginShell || onWindows ? [] : ["-l"],
|
|
347554
|
+
commandString
|
|
347555
|
+
];
|
|
347549
347556
|
},
|
|
347550
347557
|
async getEnvironmentOverrides(command) {
|
|
347551
347558
|
const commandUsesTmux = command.includes("tmux");
|
|
@@ -347595,7 +347602,7 @@ var init_bashProvider = __esm(() => {
|
|
|
347595
347602
|
init_sessionEnvVars();
|
|
347596
347603
|
init_tmuxSocket();
|
|
347597
347604
|
init_windowsPaths();
|
|
347598
|
-
BASH_SPAWN_SEMAPHORE = createSpawnSemaphore(getPlatform() === "windows" ?
|
|
347605
|
+
BASH_SPAWN_SEMAPHORE = createSpawnSemaphore(getPlatform() === "windows" ? 8 : Infinity);
|
|
347599
347606
|
});
|
|
347600
347607
|
|
|
347601
347608
|
// src/utils/shell/powershellDetection.ts
|
|
@@ -347823,6 +347830,12 @@ async function exec3(command, abortSignal, shellType, options) {
|
|
|
347823
347830
|
const shellArgs = isSandboxedPowerShell ? ["-c", commandString] : provider.getSpawnArgs(commandString);
|
|
347824
347831
|
const envOverrides = await provider.getEnvironmentOverrides(command);
|
|
347825
347832
|
const isGitBash = shellType === "bash" && getPlatform() === "windows" && !isSandboxedPowerShell;
|
|
347833
|
+
const MAX_GITBASH_RETRIES = 3;
|
|
347834
|
+
const GITBASH_RETRY_BASE_MS = 500;
|
|
347835
|
+
function isGitBashPtyExhaustion(err2) {
|
|
347836
|
+
const msg = errorMessage(err2).toLowerCase();
|
|
347837
|
+
return msg.includes("no available terminals") || msg.includes("cannot fork") || msg.includes("resource temporarily unavailable");
|
|
347838
|
+
}
|
|
347826
347839
|
if (isGitBash) {
|
|
347827
347840
|
await getBashSpawnSemaphore().acquire();
|
|
347828
347841
|
}
|
|
@@ -347866,14 +347879,14 @@ async function exec3(command, abortSignal, shellType, options) {
|
|
|
347866
347879
|
onStdout(typeof chunk === "string" ? chunk : chunk.toString());
|
|
347867
347880
|
});
|
|
347868
347881
|
}
|
|
347869
|
-
const
|
|
347882
|
+
const nativeCwdFilePath2 = getPlatform() === "windows" ? posixPathToWindowsPath(cwdFilePath) : cwdFilePath;
|
|
347870
347883
|
shellCommand.result.then(async (result) => {
|
|
347871
347884
|
if (shouldUseSandbox) {
|
|
347872
347885
|
SandboxManager2.cleanupAfterCommand();
|
|
347873
347886
|
}
|
|
347874
347887
|
if (result && !preventCwdChanges && !result.backgroundTaskId) {
|
|
347875
347888
|
try {
|
|
347876
|
-
let newCwd = readFileSync17(
|
|
347889
|
+
let newCwd = readFileSync17(nativeCwdFilePath2, {
|
|
347877
347890
|
encoding: "utf8"
|
|
347878
347891
|
}).trim();
|
|
347879
347892
|
if (getPlatform() === "windows") {
|
|
@@ -347889,13 +347902,95 @@ async function exec3(command, abortSignal, shellType, options) {
|
|
|
347889
347902
|
}
|
|
347890
347903
|
}
|
|
347891
347904
|
try {
|
|
347892
|
-
unlinkSync3(
|
|
347905
|
+
unlinkSync3(nativeCwdFilePath2);
|
|
347893
347906
|
} catch {}
|
|
347894
347907
|
});
|
|
347895
347908
|
return shellCommand;
|
|
347896
347909
|
} catch (error49) {
|
|
347897
|
-
if (isGitBash) {
|
|
347910
|
+
if (isGitBash && isGitBashPtyExhaustion(error49)) {
|
|
347898
347911
|
getBashSpawnSemaphore().release();
|
|
347912
|
+
for (let retry = 1;retry <= MAX_GITBASH_RETRIES; retry++) {
|
|
347913
|
+
const delay = GITBASH_RETRY_BASE_MS * Math.pow(2, retry - 1);
|
|
347914
|
+
logForDebugging(`Git Bash pty exhausted, retry ${retry}/${MAX_GITBASH_RETRIES} in ${delay}ms`);
|
|
347915
|
+
await new Promise((resolve30) => setTimeout(resolve30, delay));
|
|
347916
|
+
if (outputHandle !== undefined) {
|
|
347917
|
+
try {
|
|
347918
|
+
await outputHandle.close();
|
|
347919
|
+
} catch {}
|
|
347920
|
+
outputHandle = undefined;
|
|
347921
|
+
}
|
|
347922
|
+
taskOutput.clear();
|
|
347923
|
+
const retryTaskOutput = new TaskOutput(taskId, onProgress ?? null, !usePipeMode);
|
|
347924
|
+
if (!usePipeMode) {
|
|
347925
|
+
const O_NOFOLLOW = fsConstants4.O_NOFOLLOW ?? 0;
|
|
347926
|
+
try {
|
|
347927
|
+
outputHandle = await open8(taskOutput.path, process.platform === "win32" ? "w" : fsConstants4.O_WRONLY | fsConstants4.O_CREAT | fsConstants4.O_APPEND | O_NOFOLLOW);
|
|
347928
|
+
} catch {}
|
|
347929
|
+
}
|
|
347930
|
+
await getBashSpawnSemaphore().acquire();
|
|
347931
|
+
try {
|
|
347932
|
+
const childProcess = spawn8(spawnBinary, shellArgs, {
|
|
347933
|
+
env: {
|
|
347934
|
+
...subprocessEnv(),
|
|
347935
|
+
SHELL: shellType === "bash" ? binShell : undefined,
|
|
347936
|
+
GIT_EDITOR: "true",
|
|
347937
|
+
CLAUDECODE: "1",
|
|
347938
|
+
...envOverrides
|
|
347939
|
+
},
|
|
347940
|
+
cwd: cwd2,
|
|
347941
|
+
stdio: usePipeMode ? ["pipe", "pipe", "pipe"] : ["pipe", outputHandle?.fd, outputHandle?.fd],
|
|
347942
|
+
detached: provider.detached,
|
|
347943
|
+
windowsHide: true
|
|
347944
|
+
});
|
|
347945
|
+
childProcess.once("close", () => getBashSpawnSemaphore().release());
|
|
347946
|
+
const retryCmd = wrapSpawn(childProcess, abortSignal, commandTimeout, retryTaskOutput, shouldAutoBackground);
|
|
347947
|
+
if (outputHandle !== undefined) {
|
|
347948
|
+
try {
|
|
347949
|
+
await outputHandle.close();
|
|
347950
|
+
} catch {}
|
|
347951
|
+
}
|
|
347952
|
+
if (childProcess.stdout && onStdout) {
|
|
347953
|
+
childProcess.stdout.on("data", (chunk) => {
|
|
347954
|
+
onStdout(typeof chunk === "string" ? chunk : chunk.toString());
|
|
347955
|
+
});
|
|
347956
|
+
}
|
|
347957
|
+
retryCmd.result.then(async (result) => {
|
|
347958
|
+
if (shouldUseSandbox)
|
|
347959
|
+
SandboxManager2.cleanupAfterCommand();
|
|
347960
|
+
if (result && !preventCwdChanges && !result.backgroundTaskId) {
|
|
347961
|
+
try {
|
|
347962
|
+
let newCwd = readFileSync17(nativeCwdFilePath, { encoding: "utf8" }).trim();
|
|
347963
|
+
if (getPlatform() === "windows")
|
|
347964
|
+
newCwd = posixPathToWindowsPath(newCwd);
|
|
347965
|
+
if (newCwd.normalize("NFC") !== cwd2) {
|
|
347966
|
+
setCwd(newCwd, cwd2);
|
|
347967
|
+
invalidateSessionEnvCache();
|
|
347968
|
+
onCwdChangedForHooks(cwd2, newCwd);
|
|
347969
|
+
}
|
|
347970
|
+
} catch {
|
|
347971
|
+
logEvent("tengu_shell_set_cwd", { success: false });
|
|
347972
|
+
}
|
|
347973
|
+
}
|
|
347974
|
+
try {
|
|
347975
|
+
unlinkSync3(nativeCwdFilePath);
|
|
347976
|
+
} catch {}
|
|
347977
|
+
});
|
|
347978
|
+
return retryCmd;
|
|
347979
|
+
} catch (retryError) {
|
|
347980
|
+
getBashSpawnSemaphore().release();
|
|
347981
|
+
if (!isGitBashPtyExhaustion(retryError)) {
|
|
347982
|
+
logForDebugging(`Git Bash retry ${retry} failed with non-pty error: ${errorMessage(retryError)}`);
|
|
347983
|
+
break;
|
|
347984
|
+
}
|
|
347985
|
+
if (retry === MAX_GITBASH_RETRIES) {
|
|
347986
|
+
logForDebugging(`Git Bash all ${MAX_GITBASH_RETRIES} retries exhausted, giving up`);
|
|
347987
|
+
}
|
|
347988
|
+
}
|
|
347989
|
+
}
|
|
347990
|
+
} else {
|
|
347991
|
+
if (isGitBash) {
|
|
347992
|
+
getBashSpawnSemaphore().release();
|
|
347993
|
+
}
|
|
347899
347994
|
}
|
|
347900
347995
|
if (outputHandle !== undefined) {
|
|
347901
347996
|
try {
|
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.
|
|
8
|
-
BUILD_TIME: "2026-06-
|
|
7
|
+
VERSION: "0.1.23",
|
|
8
|
+
BUILD_TIME: "2026-06-16T13:12:22.731Z",
|
|
9
9
|
PACKAGE_URL: "@funnycode/myclaude",
|
|
10
10
|
NATIVE_PACKAGE_URL: "@funnycode/myclaude",
|
|
11
11
|
VERSION_CHANGELOG: '',
|
|
@@ -347542,10 +347542,17 @@ async function createBashShellProvider(shellPath, options) {
|
|
|
347542
347542
|
},
|
|
347543
347543
|
getSpawnArgs(commandString) {
|
|
347544
347544
|
const skipLoginShell = lastSnapshotFilePath !== undefined;
|
|
347545
|
-
|
|
347546
|
-
|
|
347545
|
+
const onWindows = getPlatform() === "windows";
|
|
347546
|
+
if (skipLoginShell || onWindows) {
|
|
347547
|
+
if (!onWindows) {
|
|
347548
|
+
logForDebugging("Spawning shell without login (-l flag skipped)");
|
|
347549
|
+
}
|
|
347547
347550
|
}
|
|
347548
|
-
return [
|
|
347551
|
+
return [
|
|
347552
|
+
"-c",
|
|
347553
|
+
...skipLoginShell || onWindows ? [] : ["-l"],
|
|
347554
|
+
commandString
|
|
347555
|
+
];
|
|
347549
347556
|
},
|
|
347550
347557
|
async getEnvironmentOverrides(command) {
|
|
347551
347558
|
const commandUsesTmux = command.includes("tmux");
|
|
@@ -347595,7 +347602,7 @@ var init_bashProvider = __esm(() => {
|
|
|
347595
347602
|
init_sessionEnvVars();
|
|
347596
347603
|
init_tmuxSocket();
|
|
347597
347604
|
init_windowsPaths();
|
|
347598
|
-
BASH_SPAWN_SEMAPHORE = createSpawnSemaphore(getPlatform() === "windows" ?
|
|
347605
|
+
BASH_SPAWN_SEMAPHORE = createSpawnSemaphore(getPlatform() === "windows" ? 8 : Infinity);
|
|
347599
347606
|
});
|
|
347600
347607
|
|
|
347601
347608
|
// src/utils/shell/powershellDetection.ts
|
|
@@ -347823,6 +347830,12 @@ async function exec3(command, abortSignal, shellType, options) {
|
|
|
347823
347830
|
const shellArgs = isSandboxedPowerShell ? ["-c", commandString] : provider.getSpawnArgs(commandString);
|
|
347824
347831
|
const envOverrides = await provider.getEnvironmentOverrides(command);
|
|
347825
347832
|
const isGitBash = shellType === "bash" && getPlatform() === "windows" && !isSandboxedPowerShell;
|
|
347833
|
+
const MAX_GITBASH_RETRIES = 3;
|
|
347834
|
+
const GITBASH_RETRY_BASE_MS = 500;
|
|
347835
|
+
function isGitBashPtyExhaustion(err2) {
|
|
347836
|
+
const msg = errorMessage(err2).toLowerCase();
|
|
347837
|
+
return msg.includes("no available terminals") || msg.includes("cannot fork") || msg.includes("resource temporarily unavailable");
|
|
347838
|
+
}
|
|
347826
347839
|
if (isGitBash) {
|
|
347827
347840
|
await getBashSpawnSemaphore().acquire();
|
|
347828
347841
|
}
|
|
@@ -347866,14 +347879,14 @@ async function exec3(command, abortSignal, shellType, options) {
|
|
|
347866
347879
|
onStdout(typeof chunk === "string" ? chunk : chunk.toString());
|
|
347867
347880
|
});
|
|
347868
347881
|
}
|
|
347869
|
-
const
|
|
347882
|
+
const nativeCwdFilePath2 = getPlatform() === "windows" ? posixPathToWindowsPath(cwdFilePath) : cwdFilePath;
|
|
347870
347883
|
shellCommand.result.then(async (result) => {
|
|
347871
347884
|
if (shouldUseSandbox) {
|
|
347872
347885
|
SandboxManager2.cleanupAfterCommand();
|
|
347873
347886
|
}
|
|
347874
347887
|
if (result && !preventCwdChanges && !result.backgroundTaskId) {
|
|
347875
347888
|
try {
|
|
347876
|
-
let newCwd = readFileSync17(
|
|
347889
|
+
let newCwd = readFileSync17(nativeCwdFilePath2, {
|
|
347877
347890
|
encoding: "utf8"
|
|
347878
347891
|
}).trim();
|
|
347879
347892
|
if (getPlatform() === "windows") {
|
|
@@ -347889,13 +347902,95 @@ async function exec3(command, abortSignal, shellType, options) {
|
|
|
347889
347902
|
}
|
|
347890
347903
|
}
|
|
347891
347904
|
try {
|
|
347892
|
-
unlinkSync3(
|
|
347905
|
+
unlinkSync3(nativeCwdFilePath2);
|
|
347893
347906
|
} catch {}
|
|
347894
347907
|
});
|
|
347895
347908
|
return shellCommand;
|
|
347896
347909
|
} catch (error49) {
|
|
347897
|
-
if (isGitBash) {
|
|
347910
|
+
if (isGitBash && isGitBashPtyExhaustion(error49)) {
|
|
347898
347911
|
getBashSpawnSemaphore().release();
|
|
347912
|
+
for (let retry = 1;retry <= MAX_GITBASH_RETRIES; retry++) {
|
|
347913
|
+
const delay = GITBASH_RETRY_BASE_MS * Math.pow(2, retry - 1);
|
|
347914
|
+
logForDebugging(`Git Bash pty exhausted, retry ${retry}/${MAX_GITBASH_RETRIES} in ${delay}ms`);
|
|
347915
|
+
await new Promise((resolve30) => setTimeout(resolve30, delay));
|
|
347916
|
+
if (outputHandle !== undefined) {
|
|
347917
|
+
try {
|
|
347918
|
+
await outputHandle.close();
|
|
347919
|
+
} catch {}
|
|
347920
|
+
outputHandle = undefined;
|
|
347921
|
+
}
|
|
347922
|
+
taskOutput.clear();
|
|
347923
|
+
const retryTaskOutput = new TaskOutput(taskId, onProgress ?? null, !usePipeMode);
|
|
347924
|
+
if (!usePipeMode) {
|
|
347925
|
+
const O_NOFOLLOW = fsConstants4.O_NOFOLLOW ?? 0;
|
|
347926
|
+
try {
|
|
347927
|
+
outputHandle = await open8(taskOutput.path, process.platform === "win32" ? "w" : fsConstants4.O_WRONLY | fsConstants4.O_CREAT | fsConstants4.O_APPEND | O_NOFOLLOW);
|
|
347928
|
+
} catch {}
|
|
347929
|
+
}
|
|
347930
|
+
await getBashSpawnSemaphore().acquire();
|
|
347931
|
+
try {
|
|
347932
|
+
const childProcess = spawn8(spawnBinary, shellArgs, {
|
|
347933
|
+
env: {
|
|
347934
|
+
...subprocessEnv(),
|
|
347935
|
+
SHELL: shellType === "bash" ? binShell : undefined,
|
|
347936
|
+
GIT_EDITOR: "true",
|
|
347937
|
+
CLAUDECODE: "1",
|
|
347938
|
+
...envOverrides
|
|
347939
|
+
},
|
|
347940
|
+
cwd: cwd2,
|
|
347941
|
+
stdio: usePipeMode ? ["pipe", "pipe", "pipe"] : ["pipe", outputHandle?.fd, outputHandle?.fd],
|
|
347942
|
+
detached: provider.detached,
|
|
347943
|
+
windowsHide: true
|
|
347944
|
+
});
|
|
347945
|
+
childProcess.once("close", () => getBashSpawnSemaphore().release());
|
|
347946
|
+
const retryCmd = wrapSpawn(childProcess, abortSignal, commandTimeout, retryTaskOutput, shouldAutoBackground);
|
|
347947
|
+
if (outputHandle !== undefined) {
|
|
347948
|
+
try {
|
|
347949
|
+
await outputHandle.close();
|
|
347950
|
+
} catch {}
|
|
347951
|
+
}
|
|
347952
|
+
if (childProcess.stdout && onStdout) {
|
|
347953
|
+
childProcess.stdout.on("data", (chunk) => {
|
|
347954
|
+
onStdout(typeof chunk === "string" ? chunk : chunk.toString());
|
|
347955
|
+
});
|
|
347956
|
+
}
|
|
347957
|
+
retryCmd.result.then(async (result) => {
|
|
347958
|
+
if (shouldUseSandbox)
|
|
347959
|
+
SandboxManager2.cleanupAfterCommand();
|
|
347960
|
+
if (result && !preventCwdChanges && !result.backgroundTaskId) {
|
|
347961
|
+
try {
|
|
347962
|
+
let newCwd = readFileSync17(nativeCwdFilePath, { encoding: "utf8" }).trim();
|
|
347963
|
+
if (getPlatform() === "windows")
|
|
347964
|
+
newCwd = posixPathToWindowsPath(newCwd);
|
|
347965
|
+
if (newCwd.normalize("NFC") !== cwd2) {
|
|
347966
|
+
setCwd(newCwd, cwd2);
|
|
347967
|
+
invalidateSessionEnvCache();
|
|
347968
|
+
onCwdChangedForHooks(cwd2, newCwd);
|
|
347969
|
+
}
|
|
347970
|
+
} catch {
|
|
347971
|
+
logEvent("tengu_shell_set_cwd", { success: false });
|
|
347972
|
+
}
|
|
347973
|
+
}
|
|
347974
|
+
try {
|
|
347975
|
+
unlinkSync3(nativeCwdFilePath);
|
|
347976
|
+
} catch {}
|
|
347977
|
+
});
|
|
347978
|
+
return retryCmd;
|
|
347979
|
+
} catch (retryError) {
|
|
347980
|
+
getBashSpawnSemaphore().release();
|
|
347981
|
+
if (!isGitBashPtyExhaustion(retryError)) {
|
|
347982
|
+
logForDebugging(`Git Bash retry ${retry} failed with non-pty error: ${errorMessage(retryError)}`);
|
|
347983
|
+
break;
|
|
347984
|
+
}
|
|
347985
|
+
if (retry === MAX_GITBASH_RETRIES) {
|
|
347986
|
+
logForDebugging(`Git Bash all ${MAX_GITBASH_RETRIES} retries exhausted, giving up`);
|
|
347987
|
+
}
|
|
347988
|
+
}
|
|
347989
|
+
}
|
|
347990
|
+
} else {
|
|
347991
|
+
if (isGitBash) {
|
|
347992
|
+
getBashSpawnSemaphore().release();
|
|
347993
|
+
}
|
|
347899
347994
|
}
|
|
347900
347995
|
if (outputHandle !== undefined) {
|
|
347901
347996
|
try {
|