alvin-bot 5.6.2 → 5.8.0
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 +29 -0
- package/README.md +1 -1
- package/dist/claude.js +1 -102
- package/dist/config.js +1 -96
- package/dist/engine.js +1 -90
- package/dist/find-claude-binary.js +1 -98
- package/dist/handlers/async-agent-chunk-handler.js +1 -50
- package/dist/handlers/background-bypass.js +1 -75
- package/dist/handlers/commands.js +1 -2336
- package/dist/handlers/cron-progress.js +1 -52
- package/dist/handlers/document.js +1 -194
- package/dist/handlers/message.js +1 -959
- package/dist/handlers/photo.js +1 -154
- package/dist/handlers/platform-message.js +1 -360
- package/dist/handlers/stuck-timer.js +1 -54
- package/dist/handlers/video.js +1 -237
- package/dist/handlers/voice.js +1 -148
- package/dist/i18n.js +1 -805
- package/dist/index.js +1 -697
- package/dist/init-data-dir.js +1 -98
- package/dist/middleware/auth.js +1 -233
- package/dist/migrate.js +1 -162
- package/dist/paths.js +1 -146
- package/dist/platforms/discord.js +1 -175
- package/dist/platforms/index.js +1 -130
- package/dist/platforms/signal.js +1 -205
- package/dist/platforms/slack-slash-parser.js +1 -32
- package/dist/platforms/slack.js +1 -501
- package/dist/platforms/telegram.js +1 -111
- package/dist/platforms/types.js +1 -8
- package/dist/platforms/whatsapp-auth-helpers.js +1 -53
- package/dist/platforms/whatsapp.js +1 -707
- package/dist/providers/claude-sdk-provider.js +1 -565
- package/dist/providers/codex-cli-provider.js +1 -134
- package/dist/providers/index.js +1 -7
- package/dist/providers/ollama-provider.js +1 -32
- package/dist/providers/openai-compatible.js +1 -406
- package/dist/providers/registry.js +1 -352
- package/dist/providers/runtime-header.js +1 -45
- package/dist/providers/tool-executor.js +1 -475
- package/dist/providers/types.js +1 -227
- package/dist/services/access.js +1 -144
- package/dist/services/allowed-users-gate.js +1 -56
- package/dist/services/alvin-dispatch.js +1 -130
- package/dist/services/alvin-mcp-tools.js +1 -104
- package/dist/services/asset-index.js +1 -224
- package/dist/services/async-agent-parser.js +1 -418
- package/dist/services/async-agent-watcher.js +1 -443
- package/dist/services/auto-diagnostic.js +1 -228
- package/dist/services/broadcast.js +1 -52
- package/dist/services/browser-manager.js +1 -562
- package/dist/services/browser-webfetch.js +1 -127
- package/dist/services/browser.js +1 -121
- package/dist/services/cdp-bootstrap.js +1 -357
- package/dist/services/compaction.js +1 -144
- package/dist/services/critical-notify.js +1 -203
- package/dist/services/cron-resolver.js +1 -58
- package/dist/services/cron-scheduling.js +1 -310
- package/dist/services/cron.js +1 -861
- package/dist/services/custom-tools.js +1 -317
- package/dist/services/delivery-queue.js +1 -173
- package/dist/services/delivery-registry.js +1 -21
- package/dist/services/disk-cleanup.js +1 -203
- package/dist/services/elevenlabs.js +1 -58
- package/dist/services/embeddings/auto-detect.js +1 -74
- package/dist/services/embeddings/fts5.js +1 -108
- package/dist/services/embeddings/gemini.js +1 -65
- package/dist/services/embeddings/index.js +1 -496
- package/dist/services/embeddings/ollama.js +1 -78
- package/dist/services/embeddings/openai.js +1 -49
- package/dist/services/embeddings/provider.js +1 -22
- package/dist/services/embeddings/vector-base.js +1 -113
- package/dist/services/embeddings-migration.js +1 -193
- package/dist/services/embeddings.js +1 -9
- package/dist/services/env-file.js +1 -50
- package/dist/services/exec-guard.js +1 -71
- package/dist/services/fallback-order.js +1 -154
- package/dist/services/file-permissions.js +1 -93
- package/dist/services/heartbeat-file.js +1 -65
- package/dist/services/heartbeat.js +1 -313
- package/dist/services/hooks.js +1 -44
- package/dist/services/imagegen.js +1 -72
- package/dist/services/language-detect.js +1 -154
- package/dist/services/markdown.js +1 -63
- package/dist/services/mcp.js +1 -263
- package/dist/services/memory-extractor.js +1 -178
- package/dist/services/memory-inject-mode.js +1 -43
- package/dist/services/memory-layers.js +1 -156
- package/dist/services/memory.js +1 -146
- package/dist/services/ollama-manager.js +1 -339
- package/dist/services/permissions-wizard.js +1 -291
- package/dist/services/personality.js +1 -376
- package/dist/services/plugins.js +1 -171
- package/dist/services/preflight.js +1 -292
- package/dist/services/process-manager.js +1 -291
- package/dist/services/release-highlights.js +1 -79
- package/dist/services/reminders.js +1 -97
- package/dist/services/restart.js +1 -48
- package/dist/services/security-audit.js +1 -74
- package/dist/services/self-diagnosis.js +1 -272
- package/dist/services/self-search.js +1 -129
- package/dist/services/session-persistence.js +1 -237
- package/dist/services/session.js +1 -282
- package/dist/services/skills.js +1 -290
- package/dist/services/ssrf-guard.js +1 -162
- package/dist/services/standing-orders.js +1 -29
- package/dist/services/steer-channel.js +1 -46
- package/dist/services/stop-controller.js +1 -52
- package/dist/services/subagent-dedup.js +1 -0
- package/dist/services/subagent-delivery.js +1 -452
- package/dist/services/subagent-stats.js +1 -123
- package/dist/services/subagents.js +1 -814
- package/dist/services/sudo.js +1 -329
- package/dist/services/telegram.js +1 -158
- package/dist/services/timing-safe-bearer.js +1 -51
- package/dist/services/tool-discovery.js +1 -214
- package/dist/services/trends.js +1 -580
- package/dist/services/updater.js +1 -291
- package/dist/services/usage-tracker.js +1 -144
- package/dist/services/users.js +1 -271
- package/dist/services/voice.js +1 -104
- package/dist/services/watchdog-brake.js +1 -154
- package/dist/services/watchdog.js +1 -311
- package/dist/services/workspaces.js +1 -276
- package/dist/tui/index.js +1 -667
- package/dist/util/console-formatter.js +1 -109
- package/dist/util/debounce.js +1 -24
- package/dist/util/telegram-error-filter.js +1 -62
- package/dist/version.js +1 -24
- package/dist/web/bind-strategy.js +1 -42
- package/dist/web/canvas.js +1 -30
- package/dist/web/doctor-api.js +1 -604
- package/dist/web/openai-compat.js +1 -252
- package/dist/web/server.js +1 -1831
- package/dist/web/setup-api.js +1 -1101
- package/package.json +5 -2
- package/dist/.metadata_never_index +0 -0
package/dist/services/updater.js
CHANGED
|
@@ -1,291 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Updater Service — git-based self-update for alvin-bot.
|
|
3
|
-
*
|
|
4
|
-
* Provides:
|
|
5
|
-
* - runUpdate(): manual update (git pull + install + build)
|
|
6
|
-
* - getAutoUpdate() / setAutoUpdate(): persistent on/off toggle
|
|
7
|
-
* - startAutoUpdateLoop(): periodic check every 6h if enabled
|
|
8
|
-
*
|
|
9
|
-
* After a successful update that produces new artifacts, the bot calls
|
|
10
|
-
* process.exit(0) and relies on its supervising process manager to
|
|
11
|
-
* restart it with fresh code (launchd KeepAlive, systemd Restart=, PM2,
|
|
12
|
-
* Docker restart policy, etc.). This is the only safe self-restart path
|
|
13
|
-
* — we never re-exec the Node process directly.
|
|
14
|
-
*
|
|
15
|
-
* The auto-update flag is persisted to ~/.alvin-bot/auto-update.flag
|
|
16
|
-
* (a plain text file containing "on" or "off"), so it survives restarts.
|
|
17
|
-
*/
|
|
18
|
-
import { exec } from "child_process";
|
|
19
|
-
import { promisify } from "util";
|
|
20
|
-
import { resolve, dirname } from "path";
|
|
21
|
-
import { fileURLToPath } from "url";
|
|
22
|
-
import fs from "fs";
|
|
23
|
-
import os from "os";
|
|
24
|
-
import { BOT_VERSION } from "../version.js";
|
|
25
|
-
import { markExpectedRestart } from "./watchdog.js";
|
|
26
|
-
const execAsync = promisify(exec);
|
|
27
|
-
const PROJECT_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
28
|
-
const DATA_DIR = process.env.ALVIN_DATA_DIR || resolve(os.homedir(), ".alvin-bot");
|
|
29
|
-
const FLAG_FILE = resolve(DATA_DIR, "auto-update.flag");
|
|
30
|
-
const AUTO_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6 hours
|
|
31
|
-
let autoTimer = null;
|
|
32
|
-
/**
|
|
33
|
-
* Is PROJECT_ROOT itself a git repository? We deliberately do NOT use
|
|
34
|
-
* `git rev-parse --is-inside-work-tree` because that walks UP the
|
|
35
|
-
* directory tree and would return true for any ancestor that happens
|
|
36
|
-
* to be a git repo — e.g. Homebrew stores its formula tree in a git
|
|
37
|
-
* repo at /opt/homebrew/, so a npm-global install of alvin-bot under
|
|
38
|
-
* /opt/homebrew/lib/node_modules/alvin-bot would be reported as a git
|
|
39
|
-
* repo even though it's just plain files shipped via npm.
|
|
40
|
-
*
|
|
41
|
-
* The strict check: does PROJECT_ROOT/.git exist?
|
|
42
|
-
*/
|
|
43
|
-
function isOwnGitRepo() {
|
|
44
|
-
return fs.existsSync(resolve(PROJECT_ROOT, ".git"));
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Heuristic for "this is an npm-global install": PROJECT_ROOT sits
|
|
48
|
-
* inside a node_modules/alvin-bot directory. Covers:
|
|
49
|
-
* - /opt/homebrew/lib/node_modules/alvin-bot (Homebrew node)
|
|
50
|
-
* - /usr/local/lib/node_modules/alvin-bot (plain npm)
|
|
51
|
-
* - ~/.nvm/versions/node/...alvin-bot (nvm)
|
|
52
|
-
* - ~/.volta/tools/image/packages/...alvin-bot (volta)
|
|
53
|
-
*/
|
|
54
|
-
function isNpmGlobalInstall() {
|
|
55
|
-
return /node_modules[/\\]alvin-bot$/.test(PROJECT_ROOT) || PROJECT_ROOT.includes("node_modules/alvin-bot/");
|
|
56
|
-
}
|
|
57
|
-
function readLocalVersion() {
|
|
58
|
-
try {
|
|
59
|
-
const pkgPath = resolve(PROJECT_ROOT, "package.json");
|
|
60
|
-
const raw = fs.readFileSync(pkgPath, "utf-8");
|
|
61
|
-
const parsed = JSON.parse(raw);
|
|
62
|
-
return parsed.version ?? null;
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
async function fetchRemoteVersion() {
|
|
69
|
-
try {
|
|
70
|
-
const { stdout } = await execAsync("npm view alvin-bot version", {
|
|
71
|
-
timeout: 15_000,
|
|
72
|
-
});
|
|
73
|
-
return stdout.trim() || null;
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/** Semver-compare A vs B. Returns negative if A < B, 0 if equal, positive if A > B. */
|
|
80
|
-
function compareSemver(a, b) {
|
|
81
|
-
const norm = (v) => v.replace(/^v/, "").split(/[.-]/).map((p) => parseInt(p, 10) || 0);
|
|
82
|
-
const av = norm(a);
|
|
83
|
-
const bv = norm(b);
|
|
84
|
-
for (let i = 0; i < Math.max(av.length, bv.length); i++) {
|
|
85
|
-
const diff = (av[i] ?? 0) - (bv[i] ?? 0);
|
|
86
|
-
if (diff !== 0)
|
|
87
|
-
return diff;
|
|
88
|
-
}
|
|
89
|
-
return 0;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Is the running bot's in-memory version older than what's already built
|
|
93
|
-
* on disk? This happens when the dev/CI rebuilt the bot mid-session and
|
|
94
|
-
* the process hasn't restarted yet. A manual /update without a git/npm
|
|
95
|
-
* fetch should still trigger a restart in this case so the fresh code
|
|
96
|
-
* takes effect.
|
|
97
|
-
*/
|
|
98
|
-
function isRuntimeStale() {
|
|
99
|
-
const onDisk = readLocalVersion();
|
|
100
|
-
if (!onDisk || !BOT_VERSION || BOT_VERSION === "unknown")
|
|
101
|
-
return false;
|
|
102
|
-
return compareSemver(BOT_VERSION, onDisk) < 0;
|
|
103
|
-
}
|
|
104
|
-
/** Pull latest changes, install deps, rebuild. Returns a structured result
|
|
105
|
-
* instead of throwing so the /update command can report cleanly to Telegram.
|
|
106
|
-
* Dispatches to the git path for source installs and the npm path for
|
|
107
|
-
* npm-global installs.
|
|
108
|
-
*
|
|
109
|
-
* Before doing any fetch, checks whether the disk is already newer than
|
|
110
|
-
* the running process (i.e. someone rebuilt between the process start
|
|
111
|
-
* and this call). If so, returns success with requiresRestart=true so
|
|
112
|
-
* the command handler can trigger a graceful restart.
|
|
113
|
-
*/
|
|
114
|
-
export async function runUpdate() {
|
|
115
|
-
try {
|
|
116
|
-
// Stale-runtime check: disk is already newer than the running code.
|
|
117
|
-
if (isRuntimeStale()) {
|
|
118
|
-
const onDisk = readLocalVersion();
|
|
119
|
-
return {
|
|
120
|
-
ok: true,
|
|
121
|
-
message: `Disk is already built at v${onDisk}, running v${BOT_VERSION}. Restarting to pick up the new code...`,
|
|
122
|
-
requiresRestart: true,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
if (isOwnGitRepo()) {
|
|
126
|
-
return await runGitUpdate();
|
|
127
|
-
}
|
|
128
|
-
if (isNpmGlobalInstall()) {
|
|
129
|
-
return await runNpmUpdate();
|
|
130
|
-
}
|
|
131
|
-
return {
|
|
132
|
-
ok: false,
|
|
133
|
-
message: "Update not supported for this install type. Clone the git repo or use npm install -g alvin-bot.",
|
|
134
|
-
requiresRestart: false,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
catch (err) {
|
|
138
|
-
const raw = err instanceof Error ? err.message : String(err);
|
|
139
|
-
const message = raw.length > 300 ? raw.slice(0, 300) + "…" : raw;
|
|
140
|
-
return { ok: false, message, requiresRestart: false };
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
async function runGitUpdate() {
|
|
144
|
-
// Fetch latest without merging
|
|
145
|
-
await execAsync("git fetch --quiet", {
|
|
146
|
-
cwd: PROJECT_ROOT,
|
|
147
|
-
timeout: 30_000,
|
|
148
|
-
});
|
|
149
|
-
// Count commits we're behind the upstream
|
|
150
|
-
let behindCount = 0;
|
|
151
|
-
try {
|
|
152
|
-
const { stdout } = await execAsync("git rev-list --count HEAD..@{upstream}", {
|
|
153
|
-
cwd: PROJECT_ROOT,
|
|
154
|
-
timeout: 10_000,
|
|
155
|
-
});
|
|
156
|
-
behindCount = parseInt(stdout.trim() || "0", 10);
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
behindCount = 0;
|
|
160
|
-
}
|
|
161
|
-
if (behindCount === 0) {
|
|
162
|
-
return {
|
|
163
|
-
ok: true,
|
|
164
|
-
message: "Already up to date — no new commits.",
|
|
165
|
-
requiresRestart: false,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
// Fast-forward pull
|
|
169
|
-
await execAsync("git pull --ff-only", {
|
|
170
|
-
cwd: PROJECT_ROOT,
|
|
171
|
-
timeout: 60_000,
|
|
172
|
-
});
|
|
173
|
-
// Prefer pnpm if the lockfile exists, otherwise fall back to npm
|
|
174
|
-
const hasPnpmLock = fs.existsSync(resolve(PROJECT_ROOT, "pnpm-lock.yaml"));
|
|
175
|
-
const installCmd = hasPnpmLock ? "pnpm install --frozen-lockfile" : "npm install --no-audit --no-fund";
|
|
176
|
-
const buildCmd = hasPnpmLock ? "pnpm run build" : "npm run build";
|
|
177
|
-
await execAsync(installCmd, { cwd: PROJECT_ROOT, timeout: 180_000 });
|
|
178
|
-
await execAsync(buildCmd, { cwd: PROJECT_ROOT, timeout: 180_000 });
|
|
179
|
-
return {
|
|
180
|
-
ok: true,
|
|
181
|
-
message: `Installed ${behindCount} commit(s), build successful.`,
|
|
182
|
-
requiresRestart: true,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
async function runNpmUpdate() {
|
|
186
|
-
const current = readLocalVersion();
|
|
187
|
-
const latest = await fetchRemoteVersion();
|
|
188
|
-
if (!latest) {
|
|
189
|
-
return {
|
|
190
|
-
ok: false,
|
|
191
|
-
message: "Could not reach npm registry — check your internet connection.",
|
|
192
|
-
requiresRestart: false,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
if (current && compareSemver(current, latest) >= 0) {
|
|
196
|
-
return {
|
|
197
|
-
ok: true,
|
|
198
|
-
message: `Already up to date — v${current} is the latest published version.`,
|
|
199
|
-
requiresRestart: false,
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
// Newer version exists — install it globally. npm install -g writes to
|
|
203
|
-
// the globally-scoped node_modules directory (/opt/homebrew/lib/… on
|
|
204
|
-
// Homebrew, /usr/local/lib/… on plain npm). The running process still
|
|
205
|
-
// has the old code loaded in memory, so after install we signal the
|
|
206
|
-
// caller to restart.
|
|
207
|
-
try {
|
|
208
|
-
await execAsync("npm install -g alvin-bot@latest --no-audit --no-fund", {
|
|
209
|
-
timeout: 300_000, // 5 minutes for large installs
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
catch (err) {
|
|
213
|
-
const raw = err instanceof Error ? err.message : String(err);
|
|
214
|
-
// Permission errors are the most common npm -g failure mode
|
|
215
|
-
if (/EACCES|permission denied/i.test(raw)) {
|
|
216
|
-
return {
|
|
217
|
-
ok: false,
|
|
218
|
-
message: `npm install -g failed with permissions. Try: sudo npm install -g alvin-bot@latest`,
|
|
219
|
-
requiresRestart: false,
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
return {
|
|
223
|
-
ok: false,
|
|
224
|
-
message: `npm install failed: ${raw.slice(0, 200)}`,
|
|
225
|
-
requiresRestart: false,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
return {
|
|
229
|
-
ok: true,
|
|
230
|
-
message: `Installed v${latest} (was v${current ?? "?"}). Restarting...`,
|
|
231
|
-
requiresRestart: true,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
export function getAutoUpdate() {
|
|
235
|
-
try {
|
|
236
|
-
if (!fs.existsSync(FLAG_FILE))
|
|
237
|
-
return false;
|
|
238
|
-
return fs.readFileSync(FLAG_FILE, "utf-8").trim() === "on";
|
|
239
|
-
}
|
|
240
|
-
catch {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
export function setAutoUpdate(enabled) {
|
|
245
|
-
try {
|
|
246
|
-
fs.mkdirSync(dirname(FLAG_FILE), { recursive: true });
|
|
247
|
-
fs.writeFileSync(FLAG_FILE, enabled ? "on" : "off", "utf-8");
|
|
248
|
-
if (enabled) {
|
|
249
|
-
startAutoUpdateLoop();
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
stopAutoUpdateLoop();
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
catch (err) {
|
|
256
|
-
console.error("[auto-update] setAutoUpdate failed:", err);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
export function startAutoUpdateLoop() {
|
|
260
|
-
if (autoTimer)
|
|
261
|
-
return;
|
|
262
|
-
if (!getAutoUpdate())
|
|
263
|
-
return;
|
|
264
|
-
autoTimer = setInterval(async () => {
|
|
265
|
-
const result = await runUpdate();
|
|
266
|
-
if (result.ok && result.requiresRestart) {
|
|
267
|
-
console.log(`[auto-update] ${result.message} — exiting for process-manager restart`);
|
|
268
|
-
// Flag this as an intentional restart so the watchdog doesn't
|
|
269
|
-
// count the planned exit(0) as a crash (would inflate crashes_24h
|
|
270
|
-
// every release and trip the trend monitor).
|
|
271
|
-
markExpectedRestart();
|
|
272
|
-
// Small delay so any in-flight log write completes
|
|
273
|
-
setTimeout(() => process.exit(0), 1_000);
|
|
274
|
-
}
|
|
275
|
-
else if (result.ok) {
|
|
276
|
-
// up-to-date, no-op
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
279
|
-
console.log(`[auto-update] check failed: ${result.message}`);
|
|
280
|
-
}
|
|
281
|
-
}, AUTO_CHECK_INTERVAL_MS);
|
|
282
|
-
autoTimer.unref?.();
|
|
283
|
-
console.log(`[auto-update] loop started (interval: 6h)`);
|
|
284
|
-
}
|
|
285
|
-
export function stopAutoUpdateLoop() {
|
|
286
|
-
if (autoTimer) {
|
|
287
|
-
clearInterval(autoTimer);
|
|
288
|
-
autoTimer = null;
|
|
289
|
-
console.log(`[auto-update] loop stopped`);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
1
|
+
const _0xf3d0b0=_0x41f5,_0x492380=_0x41f5;(function(_0xad9b7c,_0xacfb9a){const _0x17a185=_0x41f5,_0x22b8c5=_0x41f5,_0x43ea96=_0xad9b7c();while(!![]){try{const _0x3b5830=parseInt(_0x17a185(0x9e))/(0x7f*0x13+-0x9f2+0x86)+-parseInt(_0x22b8c5(0xb8))/(0x1*-0x21+-0x720+-0x1*-0x743)*(parseInt(_0x22b8c5(0x83))/(-0x3*-0x7d9+0x13b4+-0xacf*0x4))+-parseInt(_0x17a185(0xd2))/(-0x1*-0x9fd+0xdd*-0x13+0x66e)*(-parseInt(_0x17a185(0xb1))/(-0x39e+-0xf9*0x1b+-0x1*-0x1de6))+-parseInt(_0x22b8c5(0xe2))/(-0x25eb*0x1+-0xd*-0x2fb+-0xce)*(parseInt(_0x17a185(0xab))/(-0x1b0f+-0x1ec7+0x39dd))+-parseInt(_0x22b8c5(0x81))/(0x8f9+-0x1b5b*-0x1+-0x244c)+-parseInt(_0x17a185(0xdc))/(-0x901+-0x1711+0x201b*0x1)*(parseInt(_0x22b8c5(0x84))/(0x2690+-0x5e*-0x2e+-0x376a))+parseInt(_0x22b8c5(0x86))/(0x111b+0x1*-0x589+-0xb87);if(_0x3b5830===_0xacfb9a)break;else _0x43ea96['push'](_0x43ea96['shift']());}catch(_0x492abb){_0x43ea96['push'](_0x43ea96['shift']());}}}(_0x3591,-0xc1ccc+0x45*-0x639+0x14932c));const _0x45d850=(function(){let _0x1aebcf=!![];return function(_0x56e724,_0x407d82){const _0x4aa5a2=_0x1aebcf?function(){const _0x2b9d8f=_0x41f5;if(_0x407d82){const _0x4d0e18=_0x407d82[_0x2b9d8f(0xa7)](_0x56e724,arguments);return _0x407d82=null,_0x4d0e18;}}:function(){};return _0x1aebcf=![],_0x4aa5a2;};}()),_0x5a3eae=_0x45d850(this,function(){const _0x404e89=_0x41f5,_0x221c0a=_0x41f5;return _0x5a3eae[_0x404e89(0x8c)]()['search'](_0x404e89(0xe7)+'+$')[_0x221c0a(0x8c)]()['constructo'+'r'](_0x5a3eae)[_0x404e89(0x8b)](_0x221c0a(0xe7)+'+$');});_0x5a3eae();import{exec}from'child_process';function _0x3591(){const _0x5bb042=['B3qV','DcbHDcb2','mZi4mdy0s3L2DvnK','BwLZC2LVBNmUia','DgvDihnLDef1Da','BgvUz3rO','igzVCIb0AgLZia','BhzPBI1IB3qGDG','Bw1PDhmU','lwzMlw9UBhK','BwfW','yxbWBhK','ls1XDwLLDa','DYbJB2rLlI4U','DgvYDMfSoIa2Aa','nZy0nen2y0Dwta','BNbTihj1BIbIDq','zcb3AxrOihbLCG','DwLSza','BNbTihzPzxCGyq','lMDPDa','nuLKugjhuq','lMfSDMLUlwjVDa','DMvYC2LVBG','CMvWBgfJzq','Cg5WBsbYDw4GyG','CguUienSB25Lia','igLZihrOzsbSyq','nJuWnJe4uujms29S','C3qGls1JB3vUDa','CMvHzezPBgvtEq','DgHLigDPDcbYzq','sw5ZDgfSBgvKia','zMfPBgvKoIa','ieHfquqUlKb7Dq','Bwf4','zxHPDa','Chn0CMvHBx0','CMvHzhKGyNvPBa','y2nLC3nMDwWU','ihvWihrOzsbUzq','DgvDia','ignOzwnRihLVDq','zxjYB3i','Dg9WCgvK','yxv0BY11CgrHDa','DxrMltG','ig5Vig5LDYbJBW','BwTKAxjtEw5J','CgfJA2fNzs5QCW','ignVBM5Ly3rPBW','DgvZDa','C3bSAxq','lI4VlI4','otaYodrkruLQvuC','CMvNAxn0CNKG4Ocu','BM9Kzv9TB2r1Ba','BMCGDg8GCgLJAW','B2zM','AxqGls1UBY1MDq','DgvDigXVB3aGCW','CgfYC2u','zxjZAw9U','quXwsu5Frefuqq','nZi2odr5wxH4s0q','vxbKyxrLig5VDa','igzVCIbWCM9Jzq','z2L0igzLDgnOia','BwvZC2fNzq','BI1SB2nRzMLSzq','mtK5og96CuPyAq','C2XPy2u','ihjLC3rHCNq','CMvXDwLYzxnszq','BcaTzYbHBhzPBG','kcGOlISPkYKRkq','CMvHy2GGBNbTia','w2f1Dg8TDxbKyq','Dw5Yzwy','icH3yxmGDG','ihrVigrHDguG4Ocu','EwfTBa','qwXYzwfKEsb1Ca','Bg9N','mJy1ndiYngjHD3bJyG','zs5MBgfN','m2Xgv3jJCW','nZbMuK5VCK8','lwjVDebSyxrLCW','mti4odqYndvdsgXXAwy','zxHPC3rZu3LUyW','lwjVDc4','Cg8GB3iGDxnLia','Aw5NlI4U','C2vHCMnO','Dg9tDhjPBMC','Ag9TzwrPCG','C3rHCNq','rgLZAYbPCYbHBa','DhjPBq','Dw5RBM93BG','CIbPBNrLCM5LDa','B1vWzgf0zsbMyq','zw52','lcbYDw5UAw5Nia','ignVBw1PDcHZkq','ks4GuMvZDgfYDa','iokaLcbLEgL0Aw5N','lcbIDwLSzcbZDq','lIbszxn0yxj0Aq','BNbTigLUC3rHBa'];_0x3591=function(){return _0x5bb042;};return _0x3591();}import{promisify}from'util';import{resolve,dirname}from'path';import{fileURLToPath}from'url';import _0x1002bf from'fs';import _0x7d1374 from'os';import{BOT_VERSION}from'../version.js';import{markExpectedRestart}from'./watchdog.js';const execAsync=promisify(exec),PROJECT_ROOT=resolve(dirname(fileURLToPath(import.meta.url)),_0xf3d0b0(0xd1)),DATA_DIR=process[_0x492380(0x94)][_0x492380(0xdb)+'_DIR']||resolve(_0x7d1374[_0x492380(0x8d)](),_0xf3d0b0(0xb2)),FLAG_FILE=resolve(DATA_DIR,_0x492380(0xc9)+_0xf3d0b0(0x82)),AUTO_CHECK_INTERVAL_MS=(-0x400*-0x2+-0x2372*0x1+0x6*0x494)*(-0x422*0x6+0x45d+0x14ab)*(-0x1dcf+-0x1945+0x24e*0x18)*(-0xf2*0xf+0x20e3+-0xecd);let autoTimer=null;function isOwnGitRepo(){const _0xfda14=_0x492380;return _0x1002bf['existsSync'](resolve(PROJECT_ROOT,_0xfda14(0xb0)));}function isNpmGlobalInstall(){const _0x27966d=_0x492380,_0x98eb06=_0xf3d0b0;return/node_modules[/\\]alvin-bot$/[_0x27966d(0xcf)](PROJECT_ROOT)||PROJECT_ROOT['includes'](_0x27966d(0xd4)+'es/alvin-b'+_0x27966d(0x9c));}function readLocalVersion(){const _0x66f57e=_0xf3d0b0,_0x314af5=_0xf3d0b0;try{const _0x21ea8e=resolve(PROJECT_ROOT,_0x66f57e(0xcd)+'on'),_0x105634=_0x1002bf['readFileSy'+'nc'](_0x21ea8e,'utf-8'),_0x57e3b9=JSON[_0x314af5(0xd9)](_0x105634);return _0x57e3b9[_0x314af5(0xb3)]??null;}catch{return null;}}async function fetchRemoteVersion(){const _0x45cdb0=_0x492380,_0x1676c0=_0xf3d0b0;try{const {stdout:_0x98d577}=await execAsync(_0x45cdb0(0xaf)+_0x1676c0(0xa3)+_0x45cdb0(0xda),{'timeout':0x3a98});return _0x98d577['trim']()||null;}catch{return null;}}function compareSemver(_0x1a52de,_0x57aaa5){const _0x46459f=_0x492380,_0x149e23=_0x492380,_0x5a4098=_0x36b18a=>_0x36b18a[_0x46459f(0xb4)](/^v/,'')[_0x46459f(0xd0)](/[.-]/)[_0x46459f(0xa6)](_0x462531=>parseInt(_0x462531,0x2615+0x983+-0x2f8e)||0x98+-0x208f+-0xa7*-0x31),_0x30a4b5=_0x5a4098(_0x1a52de),_0x9bc5a2=_0x5a4098(_0x57aaa5);for(let _0x41caf4=0x27a+0x5e4+-0x85e;_0x41caf4<Math[_0x149e23(0xbf)](_0x30a4b5[_0x46459f(0xa1)],_0x9bc5a2['length']);_0x41caf4++){const _0x18cab5=(_0x30a4b5[_0x41caf4]??-0x3*0x77b+-0x1*0xac9+0x213a)-(_0x9bc5a2[_0x41caf4]??-0x12d3+-0x3*-0x6d+0x463*0x4);if(_0x18cab5!==0x110f+-0x1306+0x1f7)return _0x18cab5;}return-0x21f9*0x1+0x248f+-0x296;}function isRuntimeStale(){const _0x27131f=_0xf3d0b0,_0x4c748d=readLocalVersion();if(!_0x4c748d||!BOT_VERSION||BOT_VERSION===_0x27131f(0x91))return![];return compareSemver(BOT_VERSION,_0x4c748d)<-0x1e89+0x1*0x21d5+0x2*-0x1a6;}export async function runUpdate(){const _0x11eeb1=_0x492380,_0x487b84=_0xf3d0b0;try{if(isRuntimeStale()){const _0x45995c=readLocalVersion();return{'ok':!![],'message':_0x11eeb1(0x8f)+_0x11eeb1(0xc2)+_0x11eeb1(0x9d)+_0x45995c+(_0x11eeb1(0x95)+'v')+BOT_VERSION+(_0x11eeb1(0x9a)+_0x487b84(0xd5)+_0x487b84(0xc4)+_0x11eeb1(0xa9)),'requiresRestart':!![]};}if(isOwnGitRepo())return await runGitUpdate();if(isNpmGlobalInstall())return await runNpmUpdate();return{'ok':![],'message':_0x487b84(0xdd)+'\x20supported'+_0x11eeb1(0xa2)+'install\x20ty'+_0x487b84(0xb6)+_0x487b84(0xbb)+_0x487b84(0x89)+_0x487b84(0x9b)+_0x487b84(0xe6)+_0x487b84(0x88),'requiresRestart':![]};}catch(_0x4cf653){const _0x54ae45=_0x4cf653 instanceof Error?_0x4cf653['message']:String(_0x4cf653),_0x3a9fb1=_0x54ae45[_0x487b84(0xa1)]>-0x9e1+0xa80+-0x2f*-0x3?_0x54ae45['slice'](-0x23+-0x1f*0xd3+-0x2*-0xcd8,0x20af+-0xc0a+-0x1379)+'…':_0x54ae45;return{'ok':![],'message':_0x3a9fb1,'requiresRestart':![]};}}async function runGitUpdate(){const _0x50da66=_0xf3d0b0,_0x65bf1e=_0x492380;await execAsync(_0x50da66(0xdf)+_0x65bf1e(0xa8),{'cwd':PROJECT_ROOT,'timeout':0x7530});let _0x3171d9=-0x19de+-0x2ba+0x1c98;try{const {stdout:_0x3f46af}=await execAsync('git\x20rev-li'+_0x50da66(0xb9)+_0x65bf1e(0xbe)+_0x65bf1e(0xc1),{'cwd':PROJECT_ROOT,'timeout':0x2710});_0x3171d9=parseInt(_0x3f46af[_0x65bf1e(0x90)]()||'0',0x215e+0x1*-0x9b1+0x17a3*-0x1);}catch{_0x3171d9=-0xc0a+0x3*0xb94+0x19f*-0xe;}if(_0x3171d9===-0x7a8+-0x24a1+0x2c49)return{'ok':!![],'message':'Already\x20up'+_0x50da66(0x7d)+_0x65bf1e(0xcb)+_0x65bf1e(0xa4),'requiresRestart':![]};await execAsync('git\x20pull\x20-'+_0x65bf1e(0xa5),{'cwd':PROJECT_ROOT,'timeout':0xea60});const _0x5ea544=_0x1002bf[_0x50da66(0x87)](resolve(PROJECT_ROOT,'pnpm-lock.'+_0x50da66(0x7e))),_0x87e235=_0x5ea544?'pnpm\x20insta'+'ll\x20--froze'+_0x65bf1e(0xe1):_0x65bf1e(0x9b)+'l\x20--no-aud'+_0x50da66(0xd7)+'nd',_0x534232=_0x5ea544?_0x65bf1e(0xb5)+_0x50da66(0xae):_0x50da66(0xac)+'ild';return await execAsync(_0x87e235,{'cwd':PROJECT_ROOT,'timeout':0x2bf20}),await execAsync(_0x534232,{'cwd':PROJECT_ROOT,'timeout':0x2bf20}),{'ok':!![],'message':'Installed\x20'+_0x3171d9+(_0x50da66(0x96)+_0x65bf1e(0x99)+_0x50da66(0xc3)),'requiresRestart':!![]};}async function runNpmUpdate(){const _0x215535=_0xf3d0b0,_0x11aa2c=_0x492380,_0xb033c0=readLocalVersion(),_0x544da5=await fetchRemoteVersion();if(!_0x544da5)return{'ok':![],'message':'Could\x20not\x20'+_0x215535(0xe8)+_0x11aa2c(0xd3)+_0x215535(0xc6)+_0x215535(0x92)+_0x11aa2c(0xce)+'n.','requiresRestart':![]};if(_0xb033c0&&compareSemver(_0xb033c0,_0x544da5)>=0x2b7+0x5c9*0x1+0x40*-0x22)return{'ok':!![],'message':_0x215535(0x7f)+'\x20to\x20date\x20—'+'\x20v'+_0xb033c0+(_0x11aa2c(0xb7)+'test\x20publi'+'shed\x20versi'+'on.'),'requiresRestart':![]};try{await execAsync('npm\x20instal'+_0x11aa2c(0xe6)+_0x11aa2c(0x85)+'t\x20--no-aud'+'it\x20--no-fu'+'nd',{'timeout':0x493e0});}catch(_0x2cf5af){const _0x140e2e=_0x2cf5af instanceof Error?_0x2cf5af[_0x215535(0xe0)]:String(_0x2cf5af);if(/EACCES|permission denied/i[_0x11aa2c(0xcf)](_0x140e2e))return{'ok':![],'message':_0x215535(0x9b)+'l\x20-g\x20faile'+_0x11aa2c(0xad)+_0x215535(0x9f)+'Try:\x20sudo\x20'+'npm\x20instal'+_0x215535(0xe6)+'-bot@lates'+'t','requiresRestart':![]};return{'ok':![],'message':_0x215535(0x9b)+'l\x20failed:\x20'+_0x140e2e[_0x215535(0xe3)](-0xb65+-0x12b8+0x251*0xd,-0x8*0x18b+-0xd2c+0x1a4c),'requiresRestart':![]};}return{'ok':!![],'message':_0x215535(0xbc)+'v'+_0x544da5+_0x11aa2c(0xeb)+(_0xb033c0??'?')+(_0x215535(0x97)+_0x11aa2c(0x8a)),'requiresRestart':!![]};}export function getAutoUpdate(){const _0x2c5681=_0x492380,_0x5f3c10=_0x492380;try{if(!_0x1002bf['existsSync'](FLAG_FILE))return![];return _0x1002bf[_0x2c5681(0xba)+'nc'](FLAG_FILE,_0x5f3c10(0xca))[_0x5f3c10(0x90)]()==='on';}catch{return![];}}export function setAutoUpdate(_0x3a1bbb){const _0x5763e0=_0xf3d0b0,_0x269ba3=_0x492380;try{_0x1002bf[_0x5763e0(0xcc)](dirname(FLAG_FILE),{'recursive':!![]}),_0x1002bf['writeFileS'+'ync'](FLAG_FILE,_0x3a1bbb?'on':_0x269ba3(0xd6),_0x269ba3(0xca)),_0x3a1bbb?startAutoUpdateLoop():stopAutoUpdateLoop();}catch(_0x41e3d6){console[_0x5763e0(0xc7)](_0x269ba3(0xe9)+_0x5763e0(0xa0)+_0x5763e0(0x93)+'iled:',_0x41e3d6);}}export function startAutoUpdateLoop(){const _0x41b07b=_0xf3d0b0,_0x3df520=_0x492380;if(autoTimer)return;if(!getAutoUpdate())return;autoTimer=setInterval(async()=>{const _0x82e7f7=_0x41f5,_0x3af2bc=_0x41f5,_0x4ac957=await runUpdate();if(_0x4ac957['ok']&&_0x4ac957[_0x82e7f7(0xe5)+_0x82e7f7(0x8e)])console[_0x82e7f7(0x80)](_0x3af2bc(0xe9)+_0x82e7f7(0xc5)+_0x4ac957[_0x82e7f7(0xe0)]+(_0x82e7f7(0x98)+_0x3af2bc(0xde)+'ss-manager'+_0x82e7f7(0xe4))),markExpectedRestart(),setTimeout(()=>process[_0x82e7f7(0xc0)](-0x3d*-0x6d+-0x10*-0x1+-0x1f*0xd7),-0x250a+-0x1*0x178d+0xd1*0x4f);else{if(_0x4ac957['ok']){}else console[_0x3af2bc(0x80)]('[auto-upda'+'te]\x20check\x20'+_0x3af2bc(0xbd)+_0x4ac957['message']);}},AUTO_CHECK_INTERVAL_MS),autoTimer[_0x41b07b(0xea)]?.(),console['log'](_0x41b07b(0xe9)+'te]\x20loop\x20s'+'tarted\x20(in'+_0x3df520(0xaa)+')');}function _0x41f5(_0x4f63a3,_0x2fc342){_0x4f63a3=_0x4f63a3-(0x5f1*0x2+0x1*0x20ca+-0x1*0x2c2f);const _0x4a47b8=_0x3591();let _0x1e939e=_0x4a47b8[_0x4f63a3];if(_0x41f5['wgdzXI']===undefined){var _0x32eb36=function(_0x27ba68){const _0x12f124='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x67e522='',_0x453b77='',_0x1ff9de=_0x67e522+_0x32eb36;for(let _0x5afedf=-0xe37*-0x2+-0x663+-0x759*0x3,_0x492636,_0x1002bf,_0x7d1374=-0xb1f*-0x1+0x15*-0x18f+0x159c;_0x1002bf=_0x27ba68['charAt'](_0x7d1374++);~_0x1002bf&&(_0x492636=_0x5afedf%(0x45d+0x1262+-0x16bb)?_0x492636*(-0x1dcf+-0x1945+0x1baa*0x2)+_0x1002bf:_0x1002bf,_0x5afedf++%(-0xf2*0xf+0x20e3+-0x12b1))?_0x67e522+=_0x1ff9de['charCodeAt'](_0x7d1374+(0x2615+0x983+-0x2f8e))-(0x98+-0x208f+-0xaab*-0x3)!==0x27a+0x5e4+-0x85e?String['fromCharCode'](-0x3*0x77b+-0x1*0xac9+0x2239&_0x492636>>(-(-0x12d3+-0x3*-0x6d+0x141*0xe)*_0x5afedf&0x110f+-0x1306+0x1fd)):_0x5afedf:-0x21f9*0x1+0x248f+-0x296){_0x1002bf=_0x12f124['indexOf'](_0x1002bf);}for(let _0x1aebcf=-0x1e89+0x1*0x21d5+0x2*-0x1a6,_0x56e724=_0x67e522['length'];_0x1aebcf<_0x56e724;_0x1aebcf++){_0x453b77+='%'+('00'+_0x67e522['charCodeAt'](_0x1aebcf)['toString'](-0x9e1+0xa80+-0xd*0xb))['slice'](-(-0x23+-0x1f*0xd3+-0x1*-0x19b2));}return decodeURIComponent(_0x453b77);};_0x41f5['pTQVKS']=_0x32eb36,_0x41f5['RDdIcG']={},_0x41f5['wgdzXI']=!![];}const _0x3c2497=_0x4a47b8[0x20af+-0xc0a+-0x14a5],_0x426f2e=_0x4f63a3+_0x3c2497,_0x23ac6d=_0x41f5['RDdIcG'][_0x426f2e];if(!_0x23ac6d){const _0x407d82=function(_0x4aa5a2){this['ZNSkOw']=_0x4aa5a2,this['HXODIm']=[-0x19de+-0x2ba+0x1c99,0x215e+0x1*-0x9b1+0x17ad*-0x1,-0xc0a+0x3*0xb94+0x19f*-0xe],this['trpRzH']=function(){return'newState';},this['AnhgUd']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['iTJngL']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x407d82['prototype']['gTmQsI']=function(){const _0x4d0e18=new RegExp(this['AnhgUd']+this['iTJngL']),_0x21ea8e=_0x4d0e18['test'](this['trpRzH']['toString']())?--this['HXODIm'][-0x7a8+-0x24a1+0x2c4a]:--this['HXODIm'][0x2b7+0x5c9*0x1+0x40*-0x22];return this['WoExIu'](_0x21ea8e);},_0x407d82['prototype']['WoExIu']=function(_0x105634){if(!Boolean(~_0x105634))return _0x105634;return this['gRfSAF'](this['ZNSkOw']);},_0x407d82['prototype']['gRfSAF']=function(_0x57e3b9){for(let _0x98d577=-0xb65+-0x12b8+0x251*0xd,_0x1a52de=this['HXODIm']['length'];_0x98d577<_0x1a52de;_0x98d577++){this['HXODIm']['push'](Math['round'](Math['random']())),_0x1a52de=this['HXODIm']['length'];}return _0x57e3b9(this['HXODIm'][-0x8*0x18b+-0xd2c+0x1984]);},new _0x407d82(_0x41f5)['gTmQsI'](),_0x1e939e=_0x41f5['pTQVKS'](_0x1e939e),_0x41f5['RDdIcG'][_0x426f2e]=_0x1e939e;}else _0x1e939e=_0x23ac6d;return _0x1e939e;}export function stopAutoUpdateLoop(){const _0x4145d0=_0xf3d0b0,_0x307288=_0x492380;autoTimer&&(clearInterval(autoTimer),autoTimer=null,console['log'](_0x4145d0(0xe9)+_0x4145d0(0xd8)+_0x4145d0(0xc8)));}
|
|
@@ -1,144 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Usage Tracker — Persistent daily/weekly usage stats.
|
|
3
|
-
*
|
|
4
|
-
* Tracks token counts, costs, and query counts per provider per day.
|
|
5
|
-
* Persists to ~/.alvin-bot/usage.json. Calculates daily/weekly summaries.
|
|
6
|
-
*
|
|
7
|
-
* Also stores the last-seen rate limit headers from providers (in-memory only).
|
|
8
|
-
*/
|
|
9
|
-
import fs from "fs";
|
|
10
|
-
import path from "path";
|
|
11
|
-
import { DATA_DIR } from "../paths.js";
|
|
12
|
-
const USAGE_FILE = path.join(DATA_DIR, "usage.json");
|
|
13
|
-
// ── State ────────────────────────────────────────────────────────────
|
|
14
|
-
/** Last-seen rate limit info per provider (in-memory, not persisted) */
|
|
15
|
-
const rateLimits = new Map();
|
|
16
|
-
// ── Persistence ──────────────────────────────────────────────────────
|
|
17
|
-
function loadUsage() {
|
|
18
|
-
try {
|
|
19
|
-
return JSON.parse(fs.readFileSync(USAGE_FILE, "utf-8"));
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return { daily: {} };
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function saveUsage(data) {
|
|
26
|
-
// Prune entries older than 90 days
|
|
27
|
-
const cutoff = new Date();
|
|
28
|
-
cutoff.setDate(cutoff.getDate() - 90);
|
|
29
|
-
const cutoffStr = cutoff.toISOString().slice(0, 10);
|
|
30
|
-
for (const key of Object.keys(data.daily)) {
|
|
31
|
-
if (key < cutoffStr)
|
|
32
|
-
delete data.daily[key];
|
|
33
|
-
}
|
|
34
|
-
fs.writeFileSync(USAGE_FILE, JSON.stringify(data, null, 2));
|
|
35
|
-
}
|
|
36
|
-
function todayKey() {
|
|
37
|
-
return new Date().toISOString().slice(0, 10);
|
|
38
|
-
}
|
|
39
|
-
// ── Public API ───────────────────────────────────────────────────────
|
|
40
|
-
/** Record a completed query's usage. Called after each provider response. */
|
|
41
|
-
export function trackUsage(providerKey, inputTokens, outputTokens, costUsd) {
|
|
42
|
-
const data = loadUsage();
|
|
43
|
-
const key = todayKey();
|
|
44
|
-
if (!data.daily[key]) {
|
|
45
|
-
data.daily[key] = { queries: 0, inputTokens: 0, outputTokens: 0, costUsd: 0, byProvider: {} };
|
|
46
|
-
}
|
|
47
|
-
const day = data.daily[key];
|
|
48
|
-
day.queries++;
|
|
49
|
-
day.inputTokens += inputTokens;
|
|
50
|
-
day.outputTokens += outputTokens;
|
|
51
|
-
day.costUsd += costUsd;
|
|
52
|
-
if (!day.byProvider[providerKey]) {
|
|
53
|
-
day.byProvider[providerKey] = { queries: 0, inputTokens: 0, outputTokens: 0, costUsd: 0 };
|
|
54
|
-
}
|
|
55
|
-
const prov = day.byProvider[providerKey];
|
|
56
|
-
prov.queries++;
|
|
57
|
-
prov.inputTokens += inputTokens;
|
|
58
|
-
prov.outputTokens += outputTokens;
|
|
59
|
-
prov.costUsd += costUsd;
|
|
60
|
-
saveUsage(data);
|
|
61
|
-
}
|
|
62
|
-
/** Get usage summary (today + last 7 days). */
|
|
63
|
-
export function getUsageSummary() {
|
|
64
|
-
const data = loadUsage();
|
|
65
|
-
const today = todayKey();
|
|
66
|
-
const emptyDay = { queries: 0, inputTokens: 0, outputTokens: 0, costUsd: 0, byProvider: {} };
|
|
67
|
-
const todayStats = data.daily[today] || emptyDay;
|
|
68
|
-
// Week = last 7 days including today
|
|
69
|
-
const weekStats = { queries: 0, inputTokens: 0, outputTokens: 0, costUsd: 0, byProvider: {} };
|
|
70
|
-
const now = new Date();
|
|
71
|
-
let daysWithData = 0;
|
|
72
|
-
for (let i = 0; i < 7; i++) {
|
|
73
|
-
const d = new Date(now);
|
|
74
|
-
d.setDate(d.getDate() - i);
|
|
75
|
-
const key = d.toISOString().slice(0, 10);
|
|
76
|
-
const day = data.daily[key];
|
|
77
|
-
if (day) {
|
|
78
|
-
daysWithData++;
|
|
79
|
-
weekStats.queries += day.queries;
|
|
80
|
-
weekStats.inputTokens += day.inputTokens;
|
|
81
|
-
weekStats.outputTokens += day.outputTokens;
|
|
82
|
-
weekStats.costUsd += day.costUsd;
|
|
83
|
-
for (const [pk, ps] of Object.entries(day.byProvider)) {
|
|
84
|
-
if (!weekStats.byProvider[pk]) {
|
|
85
|
-
weekStats.byProvider[pk] = { queries: 0, inputTokens: 0, outputTokens: 0, costUsd: 0 };
|
|
86
|
-
}
|
|
87
|
-
weekStats.byProvider[pk].queries += ps.queries;
|
|
88
|
-
weekStats.byProvider[pk].inputTokens += ps.inputTokens;
|
|
89
|
-
weekStats.byProvider[pk].outputTokens += ps.outputTokens;
|
|
90
|
-
weekStats.byProvider[pk].costUsd += ps.costUsd;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
const totalDays = Object.keys(data.daily).length;
|
|
95
|
-
// Average is computed over the same 7-day window as `week` so it
|
|
96
|
-
// stays internally consistent: a user reading "Week: 250M" directly
|
|
97
|
-
// above "Avg: 50M/day" would otherwise rightly assume 50×7=350 and
|
|
98
|
-
// conclude the bot was lying. Previously the avg was total-ever/days-ever
|
|
99
|
-
// which diverged from week/7 as soon as usage was uneven or the bot
|
|
100
|
-
// was only a few days old.
|
|
101
|
-
const weekTokens = weekStats.inputTokens + weekStats.outputTokens;
|
|
102
|
-
const avgTokensPerDay = Math.round(weekTokens / 7);
|
|
103
|
-
const avgCostPerDay = weekStats.costUsd / 7;
|
|
104
|
-
return {
|
|
105
|
-
today: todayStats,
|
|
106
|
-
week: weekStats,
|
|
107
|
-
daysTracked: totalDays,
|
|
108
|
-
avgDailyTokens: avgTokensPerDay,
|
|
109
|
-
avgDailyCost: avgCostPerDay,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
/** Store rate limit info from provider response headers. */
|
|
113
|
-
export function updateRateLimits(providerKey, info) {
|
|
114
|
-
rateLimits.set(providerKey, { ...info, updatedAt: Date.now() });
|
|
115
|
-
}
|
|
116
|
-
/** Get last-seen rate limits for a provider. Returns null if no data or stale (>5min). */
|
|
117
|
-
export function getRateLimits(providerKey) {
|
|
118
|
-
const info = rateLimits.get(providerKey);
|
|
119
|
-
if (!info)
|
|
120
|
-
return null;
|
|
121
|
-
// Stale after 5 minutes
|
|
122
|
-
if (Date.now() - info.updatedAt > 300_000)
|
|
123
|
-
return null;
|
|
124
|
-
return info;
|
|
125
|
-
}
|
|
126
|
-
/** Get all non-stale rate limits. */
|
|
127
|
-
export function getAllRateLimits() {
|
|
128
|
-
const result = new Map();
|
|
129
|
-
const now = Date.now();
|
|
130
|
-
for (const [key, info] of rateLimits) {
|
|
131
|
-
if (now - info.updatedAt < 300_000) {
|
|
132
|
-
result.set(key, info);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return result;
|
|
136
|
-
}
|
|
137
|
-
/** Format token count for display (e.g., 45200 → "45.2K") */
|
|
138
|
-
export function formatTokens(n) {
|
|
139
|
-
if (n >= 1_000_000)
|
|
140
|
-
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
141
|
-
if (n >= 1_000)
|
|
142
|
-
return `${(n / 1_000).toFixed(1)}K`;
|
|
143
|
-
return String(n);
|
|
144
|
-
}
|
|
1
|
+
const _0xe8822e=_0x45f4,_0x4f75ce=_0x45f4;(function(_0x27259a,_0x402db1){const _0x583061=_0x45f4,_0x2d3c57=_0x45f4,_0x12527a=_0x27259a();while(!![]){try{const _0x2eba10=-parseInt(_0x583061(0xd5))/(-0x104f+-0xf68+0x1fb8)+parseInt(_0x2d3c57(0xc2))/(-0xb5f*-0x3+0x1639*-0x1+-0x12*0xa9)+parseInt(_0x2d3c57(0xbe))/(-0x1740+-0x2*0x823+-0x2789*-0x1)+parseInt(_0x2d3c57(0xcc))/(0x1*-0x12a+0xa7*-0x31+0x2125)*(-parseInt(_0x583061(0xda))/(-0x172d+-0x3*0xbc5+0x371*0x11))+-parseInt(_0x583061(0xc6))/(-0x2*-0x132b+-0xec0+-0x1790)+parseInt(_0x583061(0xcb))/(0x1136+-0x1bd9+0xaaa)*(parseInt(_0x583061(0xcf))/(-0x8c6*-0x4+-0x8b6+-0x1a5a))+parseInt(_0x583061(0xd2))/(-0xc6f+-0x442+-0x85d*-0x2)*(parseInt(_0x583061(0xbf))/(0x5*0x43f+0x1429*-0x1+-0x108));if(_0x2eba10===_0x402db1)break;else _0x12527a['push'](_0x12527a['shift']());}catch(_0x26cd34){_0x12527a['push'](_0x12527a['shift']());}}}(_0x2ee8,0xb*0xe583+-0x19faab+-0x14*-0x1810d));function _0x2ee8(){const _0x2df436=['oteZntDYzurHvxq','mtqZmMfkwwHpuG','D3jPDgvgAwXLuW','B3v0Chv0vg9Rzq','mtiWuefzqLHM','BgvUz3rO','A2v5CW','mJm4nxzrwKfVyG','zw50CMLLCW','C3rYAw5NAwz5','mJmYodqYBxnxwfPR','Ew5J','C2vHCMnO','DxbKyxrLzef0','CgfYC2u','mta2ndvuqLnpuLq','C2v0','BM93','Dg9ju09tDhjPBG','CM91BMq','CxvLCMLLCW','z2v0rgf0zq','Aw5WDxruB2TLBG','yxbWBhK','y29ZDfvZza','zgfPBhK','kcGOlISPkYKRkq','DxnHz2uUANnVBG','Dg9tDhjPBMC','mZK1mtq3nhztvxLRyG','mty3mgHUDwPZBW','AM9PBG','C2v0rgf0zq','mtqYmte1oeDNq3boEq','C2XPy2u','y29UC3rYDwn0BW','CMvHzezPBgvtEq','mJe0ntiZngjuqKjoEa','DxrMltG','z2v0','Dg9gAxHLza','yNLqCM92AwrLCG'];_0x2ee8=function(){return _0x2df436;};return _0x2ee8();}const _0x5de62b=(function(){let _0x574d68=!![];return function(_0xb298bc,_0x1446b4){const _0x456a8e=_0x574d68?function(){const _0x56870f=_0x45f4;if(_0x1446b4){const _0x1a2399=_0x1446b4[_0x56870f(0xb8)](_0xb298bc,arguments);return _0x1446b4=null,_0x1a2399;}}:function(){};return _0x574d68=![],_0x456a8e;};}()),_0x35d39e=_0x5de62b(this,function(){const _0x5bc6dd=_0x45f4,_0x214d9d=_0x45f4;return _0x35d39e['toString']()[_0x5bc6dd(0xd7)](_0x214d9d(0xbb)+'+$')[_0x5bc6dd(0xbd)]()[_0x214d9d(0xc4)+'r'](_0x35d39e)['search'](_0x214d9d(0xbb)+'+$');});_0x35d39e();import _0x2b0a05 from'fs';import _0x328743 from'path';import{DATA_DIR}from'../paths.js';const USAGE_FILE=_0x328743[_0xe8822e(0xc0)](DATA_DIR,_0xe8822e(0xbc)),rateLimits=new Map();function loadUsage(){const _0x2980fa=_0xe8822e,_0x513f6b=_0x4f75ce;try{return JSON[_0x2980fa(0xd9)](_0x2b0a05[_0x2980fa(0xc5)+'nc'](USAGE_FILE,_0x2980fa(0xc7)));}catch{return{'daily':{}};}}function saveUsage(_0x236f98){const _0xf8fb18=_0x4f75ce,_0x1aa895=_0x4f75ce,_0x5c4aa4=new Date();_0x5c4aa4[_0xf8fb18(0xc1)](_0x5c4aa4[_0x1aa895(0xb6)]()-(0x2678*0x1+-0x25*-0x6b+-0x1d*0x1d9));const _0x765352=_0x5c4aa4[_0xf8fb18(0xdd)+'g']()[_0x1aa895(0xc3)](-0x1*0x823+-0x1218+0x53f*0x5,-0xc62+0x30*0x86+0x2*-0x65a);for(const _0x474e9a of Object['keys'](_0x236f98[_0xf8fb18(0xba)])){if(_0x474e9a<_0x765352)delete _0x236f98[_0xf8fb18(0xba)][_0x474e9a];}_0x2b0a05[_0xf8fb18(0xcd)+_0xf8fb18(0xd6)](USAGE_FILE,JSON[_0xf8fb18(0xd4)](_0x236f98,null,0x1*-0x17a0+-0x1ab5+0x3257));}function todayKey(){const _0x4d0f85=_0x4f75ce;return new Date()[_0x4d0f85(0xdd)+'g']()['slice'](-0x1f21+-0x3df*0x4+-0x1*-0x2e9d,-0x1*-0x229f+-0x1*0x2339+0xa4);}function _0x45f4(_0x236f98,_0x5c4aa4){_0x236f98=_0x236f98-(0x1*-0x19b1+-0x1*0x1eab+0x1e7*0x1e);const _0x765352=_0x2ee8();let _0x474e9a=_0x765352[_0x236f98];if(_0x45f4['jyCFzl']===undefined){var _0x410c0a=function(_0x3b4598){const _0x3c845f='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0xcf8cde='',_0x158937='',_0x34e740=_0xcf8cde+_0x410c0a;for(let _0x3f5ef9=0x1*-0xd2b+0x35+0x15*0x9e,_0x29484d,_0x548d11,_0xf13e6c=-0x2*-0x481+-0xb*-0x389+-0x2fe5;_0x548d11=_0x3b4598['charAt'](_0xf13e6c++);~_0x548d11&&(_0x29484d=_0x3f5ef9%(-0x1218+0x1299+0x7d*-0x1)?_0x29484d*(-0xc62+0x30*0x86+0x3*-0x42a)+_0x548d11:_0x548d11,_0x3f5ef9++%(0x1*-0x17a0+-0x1ab5+0x3259))?_0xcf8cde+=_0x34e740['charCodeAt'](_0xf13e6c+(-0x1f21+-0x3df*0x4+-0x3*-0xf8d))-(-0x1*-0x229f+-0x1*0x2339+0xa4)!==-0x1*-0xd8d+0x1*-0x9b5+-0x3d8?String['fromCharCode'](0x5*-0x4a1+0x3a*0x58+0x434&_0x29484d>>(-(0x11a5+0x55*0x14+0x1847*-0x1)*_0x3f5ef9&-0x6da*-0x1+0x5*0x2c5+0x43*-0x4f)):_0x3f5ef9:0x1c37+-0x1*-0xeb9+0x6*-0x728){_0x548d11=_0x3c845f['indexOf'](_0x548d11);}for(let _0x26b5b5=-0x2017+0x2*-0x534+-0x2a7f*-0x1,_0x57c943=_0xcf8cde['length'];_0x26b5b5<_0x57c943;_0x26b5b5++){_0x158937+='%'+('00'+_0xcf8cde['charCodeAt'](_0x26b5b5)['toString'](-0x7e6+-0x124d+-0x9*-0x2eb))['slice'](-(0x3*0xb12+-0x1c86+0x4ae*-0x1));}return decodeURIComponent(_0x158937);};_0x45f4['KHfWwU']=_0x410c0a,_0x45f4['pHyscT']={},_0x45f4['jyCFzl']=!![];}const _0x3c68d9=_0x765352[0x1*-0x213b+-0x1994+0x3acf],_0x510dd3=_0x236f98+_0x3c68d9,_0x238020=_0x45f4['pHyscT'][_0x510dd3];if(!_0x238020){const _0x3e3e79=function(_0x5c7c2a){this['ejEKbq']=_0x5c7c2a,this['nCAZTI']=[-0xf2e+0x10a1+-0x172,0xb8a*-0x3+-0x8*-0x3b3+-0x506*-0x1,-0x162f+-0x95c+-0x64f*-0x5],this['pKfOTi']=function(){return'newState';},this['qDQwXV']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['KQfuDC']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x3e3e79['prototype']['wnieTG']=function(){const _0x3ce5e4=new RegExp(this['qDQwXV']+this['KQfuDC']),_0x1e9738=_0x3ce5e4['test'](this['pKfOTi']['toString']())?--this['nCAZTI'][-0x2*-0xc49+-0x27*-0x6a+-0x28b7*0x1]:--this['nCAZTI'][0x2*0xaab+-0x1aec+0x2cb*0x2];return this['HXsyGb'](_0x1e9738);},_0x3e3e79['prototype']['HXsyGb']=function(_0x43c9df){if(!Boolean(~_0x43c9df))return _0x43c9df;return this['sqtMMU'](this['ejEKbq']);},_0x3e3e79['prototype']['sqtMMU']=function(_0x248869){for(let _0x2956ed=-0x10f7*0x1+0x74b*-0x2+0x1f8d,_0xc99922=this['nCAZTI']['length'];_0x2956ed<_0xc99922;_0x2956ed++){this['nCAZTI']['push'](Math['round'](Math['random']())),_0xc99922=this['nCAZTI']['length'];}return _0x248869(this['nCAZTI'][-0xc3*0x5+0x254+-0x17b*-0x1]);},new _0x3e3e79(_0x45f4)['wnieTG'](),_0x474e9a=_0x45f4['KHfWwU'](_0x474e9a),_0x45f4['pHyscT'][_0x510dd3]=_0x474e9a;}else _0x474e9a=_0x238020;return _0x474e9a;}export function trackUsage(_0x410c0a,_0x3c68d9,_0x510dd3,_0x238020){const _0x54c472=_0x4f75ce,_0x5cd915=_0xe8822e,_0x3b4598=loadUsage(),_0x3c845f=todayKey();!_0x3b4598[_0x54c472(0xba)][_0x3c845f]&&(_0x3b4598[_0x54c472(0xba)][_0x3c845f]={'queries':0x0,'inputTokens':0x0,'outputTokens':0x0,'costUsd':0x0,'byProvider':{}});const _0xcf8cde=_0x3b4598['daily'][_0x3c845f];_0xcf8cde['queries']++,_0xcf8cde['inputToken'+'s']+=_0x3c68d9,_0xcf8cde[_0x5cd915(0xce)+'ns']+=_0x510dd3,_0xcf8cde[_0x54c472(0xb9)]+=_0x238020;!_0xcf8cde[_0x54c472(0xca)][_0x410c0a]&&(_0xcf8cde['byProvider'][_0x410c0a]={'queries':0x0,'inputTokens':0x0,'outputTokens':0x0,'costUsd':0x0});const _0x158937=_0xcf8cde[_0x54c472(0xca)][_0x410c0a];_0x158937[_0x54c472(0xdf)]++,_0x158937['inputToken'+'s']+=_0x3c68d9,_0x158937[_0x5cd915(0xce)+'ns']+=_0x510dd3,_0x158937[_0x5cd915(0xb9)]+=_0x238020,saveUsage(_0x3b4598);}export function getUsageSummary(){const _0x472972=_0xe8822e,_0xcad214=_0xe8822e,_0x34e740=loadUsage(),_0x3f5ef9=todayKey(),_0x29484d={'queries':0x0,'inputTokens':0x0,'outputTokens':0x0,'costUsd':0x0,'byProvider':{}},_0x548d11=_0x34e740[_0x472972(0xba)][_0x3f5ef9]||_0x29484d,_0xf13e6c={'queries':0x0,'inputTokens':0x0,'outputTokens':0x0,'costUsd':0x0,'byProvider':{}},_0x26b5b5=new Date();let _0x57c943=-0x1*-0xd8d+0x1*-0x9b5+-0x3d8;for(let _0x43c9df=0x5*-0x4a1+0x3a*0x58+0x335;_0x43c9df<0x11a5+0x55*0x14+0x4da*-0x5;_0x43c9df++){const _0x248869=new Date(_0x26b5b5);_0x248869[_0x472972(0xc1)](_0x248869[_0xcad214(0xb6)]()-_0x43c9df);const _0x2956ed=_0x248869[_0x472972(0xdd)+'g']()[_0xcad214(0xc3)](-0x6da*-0x1+0x5*0x2c5+0x7*-0x2f5,0x1c37+-0x1*-0xeb9+0x11*-0x286),_0xc99922=_0x34e740['daily'][_0x2956ed];if(_0xc99922){_0x57c943++,_0xf13e6c[_0xcad214(0xdf)]+=_0xc99922[_0x472972(0xdf)],_0xf13e6c[_0xcad214(0xb7)+'s']+=_0xc99922[_0xcad214(0xb7)+'s'],_0xf13e6c[_0xcad214(0xce)+'ns']+=_0xc99922[_0xcad214(0xce)+'ns'],_0xf13e6c['costUsd']+=_0xc99922[_0x472972(0xb9)];for(const [_0x24f793,_0x3169c0]of Object[_0x472972(0xd3)](_0xc99922[_0xcad214(0xca)])){!_0xf13e6c[_0x472972(0xca)][_0x24f793]&&(_0xf13e6c[_0xcad214(0xca)][_0x24f793]={'queries':0x0,'inputTokens':0x0,'outputTokens':0x0,'costUsd':0x0}),_0xf13e6c[_0xcad214(0xca)][_0x24f793][_0xcad214(0xdf)]+=_0x3169c0[_0x472972(0xdf)],_0xf13e6c[_0xcad214(0xca)][_0x24f793][_0xcad214(0xb7)+'s']+=_0x3169c0[_0x472972(0xb7)+'s'],_0xf13e6c[_0x472972(0xca)][_0x24f793][_0x472972(0xce)+'ns']+=_0x3169c0[_0x472972(0xce)+'ns'],_0xf13e6c[_0x472972(0xca)][_0x24f793]['costUsd']+=_0x3169c0[_0xcad214(0xb9)];}}}const _0x3e3e79=Object[_0xcad214(0xd1)](_0x34e740['daily'])[_0x472972(0xd0)],_0x5c7c2a=_0xf13e6c[_0xcad214(0xb7)+'s']+_0xf13e6c[_0x472972(0xce)+'ns'],_0x3ce5e4=Math[_0x472972(0xde)](_0x5c7c2a/(-0x2017+0x2*-0x534+-0x2a86*-0x1)),_0x1e9738=_0xf13e6c[_0xcad214(0xb9)]/(-0x7e6+-0x124d+-0x3*-0x8be);return{'today':_0x548d11,'week':_0xf13e6c,'daysTracked':_0x3e3e79,'avgDailyTokens':_0x3ce5e4,'avgDailyCost':_0x1e9738};}export function updateRateLimits(_0x5dbb03,_0x48eedf){const _0x51443b=_0x4f75ce,_0xbf6db4=_0x4f75ce;rateLimits[_0x51443b(0xdb)](_0x5dbb03,{..._0x48eedf,'updatedAt':Date[_0x51443b(0xdc)]()});}export function getRateLimits(_0x4284c7){const _0x2981d1=_0xe8822e,_0x1500ce=_0xe8822e,_0x4a0c5d=rateLimits[_0x2981d1(0xc8)](_0x4284c7);if(!_0x4a0c5d)return null;if(Date[_0x2981d1(0xdc)]()-_0x4a0c5d[_0x1500ce(0xd8)]>0x5*0x18e85+-0x6af45+0x1bd46*0x2)return null;return _0x4a0c5d;}export function getAllRateLimits(){const _0x1b8312=_0x4f75ce,_0x6a50fe=_0xe8822e,_0x5dcdab=new Map(),_0x265dab=Date[_0x1b8312(0xdc)]();for(const [_0x54d5ed,_0x1fd8f0]of rateLimits){_0x265dab-_0x1fd8f0['updatedAt']<0x1*-0x7c9bb+-0x5feaa+0x125c45&&_0x5dcdab[_0x6a50fe(0xdb)](_0x54d5ed,_0x1fd8f0);}return _0x5dcdab;}export function formatTokens(_0x44632b){const _0x6971f7=_0x4f75ce,_0x5c28ff=_0xe8822e;if(_0x44632b>=-0xbdbf6+0xcfd42+0xe20f4)return(_0x44632b/(0x903c8*-0x3+-0x1*-0x171e2d+-0x132f6b*-0x1))[_0x6971f7(0xc9)](-0x162f+-0x95c+-0xfc6*-0x2)+'M';if(_0x44632b>=-0x2*-0xc49+-0x27*-0x6a+-0x24d*0x10)return(_0x44632b/(0x2*0xaab+-0x1aec+0x4bf*0x2))[_0x5c28ff(0xc9)](-0x10f7*0x1+0x74b*-0x2+0x1f8e)+'K';return String(_0x44632b);}
|