@gonzih/cc-tg 0.9.14 → 0.9.15
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/bot.js +20 -5
- package/dist/index.js +19 -10
- package/package.json +1 -1
package/dist/bot.js
CHANGED
|
@@ -952,8 +952,9 @@ export class CcTgBot {
|
|
|
952
952
|
await this.bot.sendMessage(chatId, "Clearing npx cache and reloading MCP...");
|
|
953
953
|
try {
|
|
954
954
|
const home = process.env.HOME ?? "~";
|
|
955
|
-
|
|
956
|
-
|
|
955
|
+
const npmBase = process.env.npm_config_cache ? join(process.env.npm_config_cache, "..") : `${home}/.npm`;
|
|
956
|
+
execSync(`rm -rf "${npmBase}/_npx/"`, { encoding: "utf8", shell: "/bin/sh" });
|
|
957
|
+
console.log(`[mcp] cleared ${npmBase}/_npx/`);
|
|
957
958
|
}
|
|
958
959
|
catch (err) {
|
|
959
960
|
await this.bot.sendMessage(chatId, `Warning: failed to clear npx cache: ${err.message}`);
|
|
@@ -995,10 +996,14 @@ export class CcTgBot {
|
|
|
995
996
|
}
|
|
996
997
|
async handleClearNpxCache(chatId) {
|
|
997
998
|
const home = process.env.HOME ?? "/tmp";
|
|
999
|
+
// Use the isolated npm cache dir set in the plist (npm_config_cache), not hardcoded ~/.npm
|
|
1000
|
+
const npmBase = process.env.npm_config_cache
|
|
1001
|
+
? join(process.env.npm_config_cache, "..")
|
|
1002
|
+
: `${home}/.npm`;
|
|
998
1003
|
const cleared = [];
|
|
999
1004
|
const failed = [];
|
|
1000
1005
|
// Clear both npx execution cache and full npm package cache
|
|
1001
|
-
for (const dir of [`${
|
|
1006
|
+
for (const dir of [`${npmBase}/_npx`, `${npmBase}/cache`]) {
|
|
1002
1007
|
try {
|
|
1003
1008
|
execSync(`rm -rf "${dir}"`, { encoding: "utf8", shell: "/bin/sh" });
|
|
1004
1009
|
cleared.push(dir.replace(home, "~"));
|
|
@@ -1022,8 +1027,12 @@ export class CcTgBot {
|
|
|
1022
1027
|
await this.bot.sendMessage(chatId, "Clearing cache and restarting... brb.");
|
|
1023
1028
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
1024
1029
|
// Clear npm caches before restart so launchd brings up fresh version
|
|
1030
|
+
// Use isolated npm_config_cache path from plist, not hardcoded ~/.npm
|
|
1025
1031
|
const home = process.env.HOME ?? "/tmp";
|
|
1026
|
-
|
|
1032
|
+
const npmBase = process.env.npm_config_cache
|
|
1033
|
+
? join(process.env.npm_config_cache, "..")
|
|
1034
|
+
: `${home}/.npm`;
|
|
1035
|
+
for (const dir of [`${npmBase}/_npx`, `${npmBase}/cache`]) {
|
|
1027
1036
|
try {
|
|
1028
1037
|
execSync(`rm -rf "${dir}"`, { shell: "/bin/sh" });
|
|
1029
1038
|
}
|
|
@@ -1073,18 +1082,24 @@ export class CcTgBot {
|
|
|
1073
1082
|
callCcAgentTool(toolName, args = {}) {
|
|
1074
1083
|
return new Promise((resolve) => {
|
|
1075
1084
|
let settled = false;
|
|
1085
|
+
let procRef = null;
|
|
1076
1086
|
const done = (val) => {
|
|
1077
1087
|
if (!settled) {
|
|
1078
1088
|
settled = true;
|
|
1089
|
+
try {
|
|
1090
|
+
procRef?.kill();
|
|
1091
|
+
}
|
|
1092
|
+
catch { }
|
|
1079
1093
|
resolve(val);
|
|
1080
1094
|
}
|
|
1081
1095
|
};
|
|
1082
1096
|
let proc;
|
|
1083
1097
|
try {
|
|
1084
|
-
proc = spawn("npx", ["-y", "@gonzih/cc-agent@latest"], {
|
|
1098
|
+
proc = spawn("npx", ["--prefer-online", "-y", "@gonzih/cc-agent@latest"], {
|
|
1085
1099
|
env: { ...process.env },
|
|
1086
1100
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1087
1101
|
});
|
|
1102
|
+
procRef = proc;
|
|
1088
1103
|
}
|
|
1089
1104
|
catch (err) {
|
|
1090
1105
|
console.error("[mcp] failed to spawn cc-agent:", err.message);
|
package/dist/index.js
CHANGED
|
@@ -18,12 +18,18 @@ import { createServer, createConnection } from "net";
|
|
|
18
18
|
import { unlinkSync } from "fs";
|
|
19
19
|
import { tmpdir } from "os";
|
|
20
20
|
import { join } from "path";
|
|
21
|
+
import { createHash } from "crypto";
|
|
21
22
|
import { CcTgBot } from "./bot.js";
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
// Derive socket path from token hash so multiple instances (feral/law/simorgh)
|
|
24
|
+
// never collide, and the path is stable across restarts on the same machine.
|
|
25
|
+
function lockSocketPath(token) {
|
|
26
|
+
const hash = createHash("sha256").update(token).digest("hex").slice(0, 12);
|
|
27
|
+
return join(tmpdir(), `cc-tg-${hash}.sock`);
|
|
28
|
+
}
|
|
29
|
+
function acquireLock(socketPath) {
|
|
24
30
|
return new Promise((resolve) => {
|
|
25
31
|
const server = createServer();
|
|
26
|
-
server.listen(
|
|
32
|
+
server.listen(socketPath, () => {
|
|
27
33
|
// Bound successfully — we own the lock. Socket auto-released on any exit incl. SIGKILL.
|
|
28
34
|
resolve(true);
|
|
29
35
|
});
|
|
@@ -33,7 +39,7 @@ function acquireLock() {
|
|
|
33
39
|
return;
|
|
34
40
|
}
|
|
35
41
|
// Socket path exists — probe if anything is actually listening
|
|
36
|
-
const probe = createConnection(
|
|
42
|
+
const probe = createConnection(socketPath);
|
|
37
43
|
probe.on("connect", () => {
|
|
38
44
|
probe.destroy();
|
|
39
45
|
console.error("[cc-tg] Another instance is already running. Exiting.");
|
|
@@ -42,20 +48,16 @@ function acquireLock() {
|
|
|
42
48
|
probe.on("error", () => {
|
|
43
49
|
// Nothing listening — stale socket, remove and retry
|
|
44
50
|
try {
|
|
45
|
-
unlinkSync(
|
|
51
|
+
unlinkSync(socketPath);
|
|
46
52
|
}
|
|
47
53
|
catch { }
|
|
48
54
|
const retry = createServer();
|
|
49
|
-
retry.listen(
|
|
55
|
+
retry.listen(socketPath, () => resolve(true));
|
|
50
56
|
retry.on("error", () => resolve(true)); // give up on lock, just start
|
|
51
57
|
});
|
|
52
58
|
});
|
|
53
59
|
});
|
|
54
60
|
}
|
|
55
|
-
const lockAcquired = await acquireLock();
|
|
56
|
-
if (!lockAcquired) {
|
|
57
|
-
process.exit(1);
|
|
58
|
-
}
|
|
59
61
|
function required(name) {
|
|
60
62
|
const val = process.env[name];
|
|
61
63
|
if (!val) {
|
|
@@ -76,6 +78,13 @@ Or add to your shell profile / .env file.
|
|
|
76
78
|
return val;
|
|
77
79
|
}
|
|
78
80
|
const telegramToken = required("TELEGRAM_BOT_TOKEN");
|
|
81
|
+
// Acquire lock before doing anything else. Socket derived from token hash so
|
|
82
|
+
// multiple instances (different bots / users) never share the same socket.
|
|
83
|
+
const LOCK_SOCKET = lockSocketPath(telegramToken);
|
|
84
|
+
const lockAcquired = await acquireLock(LOCK_SOCKET);
|
|
85
|
+
if (!lockAcquired) {
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
79
88
|
// Accept CLAUDE_CODE_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, or ANTHROPIC_API_KEY
|
|
80
89
|
const claudeToken = process.env.CLAUDE_CODE_TOKEN ??
|
|
81
90
|
process.env.CLAUDE_CODE_OAUTH_TOKEN ??
|