@gonzih/cc-tg 0.2.18 ā 0.2.19
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.d.ts +1 -0
- package/dist/bot.js +105 -2
- package/package.json +1 -1
package/dist/bot.d.ts
CHANGED
package/dist/bot.js
CHANGED
|
@@ -6,7 +6,7 @@ import TelegramBot from "node-telegram-bot-api";
|
|
|
6
6
|
import { existsSync, createWriteStream, mkdirSync, statSync, readdirSync, readFileSync, writeFileSync } from "fs";
|
|
7
7
|
import { resolve, basename, join } from "path";
|
|
8
8
|
import os from "os";
|
|
9
|
-
import { execSync } from "child_process";
|
|
9
|
+
import { execSync, spawn } from "child_process";
|
|
10
10
|
import https from "https";
|
|
11
11
|
import http from "http";
|
|
12
12
|
import { ClaudeProcess, extractText } from "./claude.js";
|
|
@@ -65,6 +65,28 @@ function formatCronCostFooter(usage) {
|
|
|
65
65
|
const cost = computeCostUsd(usage);
|
|
66
66
|
return `\nš° Cron cost: $${cost.toFixed(4)} (${formatTokens(usage.inputTokens)} in / ${formatTokens(usage.outputTokens)} out tokens)`;
|
|
67
67
|
}
|
|
68
|
+
function formatAgentCostSummary(text) {
|
|
69
|
+
try {
|
|
70
|
+
const data = JSON.parse(text);
|
|
71
|
+
const totalCost = (data.total_cost_usd ?? data.total_cost ?? 0);
|
|
72
|
+
const totalJobs = (data.total_jobs ?? data.job_count ?? 0);
|
|
73
|
+
const byRepo = (data.by_repo ?? []);
|
|
74
|
+
const lines = [
|
|
75
|
+
"š¤ Agent jobs (all time)",
|
|
76
|
+
`Total: $${totalCost.toFixed(2)} across ${totalJobs} jobs`,
|
|
77
|
+
];
|
|
78
|
+
for (const entry of byRepo) {
|
|
79
|
+
const repo = (entry.repo ?? entry.repository ?? "unknown");
|
|
80
|
+
const cost = (entry.cost_usd ?? entry.cost ?? 0);
|
|
81
|
+
const jobs = (entry.job_count ?? entry.jobs ?? 0);
|
|
82
|
+
lines.push(` ${repo}: $${cost.toFixed(2)} (${jobs} jobs)`);
|
|
83
|
+
}
|
|
84
|
+
return lines.join("\n");
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return `š¤ Agent jobs (all time)\n${text}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
68
90
|
class CostStore {
|
|
69
91
|
costs = new Map();
|
|
70
92
|
storePath;
|
|
@@ -237,7 +259,17 @@ export class CcTgBot {
|
|
|
237
259
|
// /cost ā show session token usage and cost
|
|
238
260
|
if (text === "/cost") {
|
|
239
261
|
const cost = this.costStore.get(chatId);
|
|
240
|
-
|
|
262
|
+
let reply = formatCostReport(cost);
|
|
263
|
+
try {
|
|
264
|
+
const rawSummary = await this.callCcAgentTool("cost_summary");
|
|
265
|
+
if (rawSummary) {
|
|
266
|
+
reply += "\n\n" + formatAgentCostSummary(rawSummary);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
console.error("[cost] cc-agent cost_summary failed:", err.message);
|
|
271
|
+
}
|
|
272
|
+
await this.bot.sendMessage(chatId, reply);
|
|
241
273
|
return;
|
|
242
274
|
}
|
|
243
275
|
const session = this.getOrCreateSession(chatId);
|
|
@@ -890,6 +922,77 @@ export class CcTgBot {
|
|
|
890
922
|
}
|
|
891
923
|
await this.bot.sendDocument(chatId, filePath);
|
|
892
924
|
}
|
|
925
|
+
callCcAgentTool(toolName, args = {}) {
|
|
926
|
+
return new Promise((resolve) => {
|
|
927
|
+
let settled = false;
|
|
928
|
+
const done = (val) => {
|
|
929
|
+
if (!settled) {
|
|
930
|
+
settled = true;
|
|
931
|
+
resolve(val);
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
let proc;
|
|
935
|
+
try {
|
|
936
|
+
proc = spawn("npx", ["-y", "@gonzih/cc-agent@latest"], {
|
|
937
|
+
env: { ...process.env },
|
|
938
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
catch (err) {
|
|
942
|
+
console.error("[mcp] failed to spawn cc-agent:", err.message);
|
|
943
|
+
done(null);
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
const timeout = setTimeout(() => {
|
|
947
|
+
console.warn("[mcp] cc-agent tool call timed out");
|
|
948
|
+
proc.kill();
|
|
949
|
+
done(null);
|
|
950
|
+
}, 30_000);
|
|
951
|
+
let buffer = "";
|
|
952
|
+
const sendMsg = (msg) => { proc.stdin.write(JSON.stringify(msg) + "\n"); };
|
|
953
|
+
sendMsg({
|
|
954
|
+
jsonrpc: "2.0", id: 1, method: "initialize",
|
|
955
|
+
params: { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "cc-tg", version: "1.0.0" } },
|
|
956
|
+
});
|
|
957
|
+
proc.stdout.on("data", (chunk) => {
|
|
958
|
+
buffer += chunk.toString();
|
|
959
|
+
const lines = buffer.split("\n");
|
|
960
|
+
buffer = lines.pop() ?? "";
|
|
961
|
+
for (const line of lines) {
|
|
962
|
+
if (!line.trim())
|
|
963
|
+
continue;
|
|
964
|
+
try {
|
|
965
|
+
const msg = JSON.parse(line);
|
|
966
|
+
if (msg.id === 1 && "result" in msg) {
|
|
967
|
+
sendMsg({ jsonrpc: "2.0", method: "notifications/initialized" });
|
|
968
|
+
sendMsg({ jsonrpc: "2.0", id: 2, method: "tools/call", params: { name: toolName, arguments: args } });
|
|
969
|
+
}
|
|
970
|
+
else if (msg.id === 2) {
|
|
971
|
+
clearTimeout(timeout);
|
|
972
|
+
if (msg.error) {
|
|
973
|
+
console.error("[mcp] cost_summary error:", JSON.stringify(msg.error));
|
|
974
|
+
proc.kill();
|
|
975
|
+
done(null);
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const result = msg.result;
|
|
979
|
+
const content = result?.content;
|
|
980
|
+
const text = (content ?? []).filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
981
|
+
proc.kill();
|
|
982
|
+
done(text || null);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
catch { /* ignore non-JSON lines */ }
|
|
986
|
+
}
|
|
987
|
+
});
|
|
988
|
+
proc.on("error", (err) => {
|
|
989
|
+
console.error("[mcp] cc-agent spawn error:", err.message);
|
|
990
|
+
clearTimeout(timeout);
|
|
991
|
+
done(null);
|
|
992
|
+
});
|
|
993
|
+
proc.on("exit", () => { clearTimeout(timeout); done(null); });
|
|
994
|
+
});
|
|
995
|
+
}
|
|
893
996
|
killSession(chatId, keepCrons = true) {
|
|
894
997
|
const session = this.sessions.get(chatId);
|
|
895
998
|
if (session) {
|