@raysonmeng/agentbridge 0.1.13 → 0.1.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/.claude-plugin/marketplace.json +1 -1
- package/README.md +2 -1
- package/README.zh-CN.md +2 -1
- package/dist/cli.js +391 -108
- package/dist/daemon.js +148 -13
- package/package.json +1 -1
- package/plugins/agentbridge/.claude-plugin/plugin.json +1 -1
- package/plugins/agentbridge/server/bridge-server.js +133 -6
- package/plugins/agentbridge/server/daemon.js +148 -13
package/dist/cli.js
CHANGED
|
@@ -176,7 +176,7 @@ function parsePositiveIntEnv(name, fallback, log = () => {}, env = process.env)
|
|
|
176
176
|
var require_package = __commonJS((exports, module) => {
|
|
177
177
|
module.exports = {
|
|
178
178
|
name: "@raysonmeng/agentbridge",
|
|
179
|
-
version: "0.1.
|
|
179
|
+
version: "0.1.15",
|
|
180
180
|
description: "Bridge between Claude Code and Codex \u2014 bidirectional agent communication via MCP Channel + JSON-RPC",
|
|
181
181
|
type: "module",
|
|
182
182
|
packageManager: "bun@1.3.11",
|
|
@@ -255,9 +255,13 @@ __export(exports_update_notifier, {
|
|
|
255
255
|
isUpdateCheckSuppressed: () => isUpdateCheckSuppressed,
|
|
256
256
|
getCurrentVersion: () => getCurrentVersion,
|
|
257
257
|
buildUpdateNotice: () => buildUpdateNotice,
|
|
258
|
-
|
|
258
|
+
buildDismissedUpdateNotice: () => buildDismissedUpdateNotice,
|
|
259
|
+
PACKAGE_NAME: () => PACKAGE_NAME,
|
|
260
|
+
DEFAULT_UPDATE_PROMPT_TIMEOUT_MS: () => DEFAULT_UPDATE_PROMPT_TIMEOUT_MS
|
|
259
261
|
});
|
|
260
262
|
import { readFileSync } from "fs";
|
|
263
|
+
import { spawnSync } from "child_process";
|
|
264
|
+
import { createInterface } from "readline";
|
|
261
265
|
function getCurrentVersion() {
|
|
262
266
|
try {
|
|
263
267
|
return require_package().version;
|
|
@@ -285,7 +289,8 @@ function readCache(stateDir) {
|
|
|
285
289
|
return null;
|
|
286
290
|
return {
|
|
287
291
|
lastCheckMs: parsed.lastCheckMs,
|
|
288
|
-
latest: typeof parsed.latest === "string" ? parsed.latest : null
|
|
292
|
+
latest: typeof parsed.latest === "string" ? parsed.latest : null,
|
|
293
|
+
dismissedVersion: typeof parsed.dismissedVersion === "string" ? parsed.dismissedVersion : undefined
|
|
289
294
|
};
|
|
290
295
|
} catch {
|
|
291
296
|
return null;
|
|
@@ -327,7 +332,11 @@ async function refreshUpdateCache(deps = {}) {
|
|
|
327
332
|
try {
|
|
328
333
|
const latest = await fetchLatest(fetchImpl);
|
|
329
334
|
const prev = readCache(stateDir);
|
|
330
|
-
writeCache(stateDir, {
|
|
335
|
+
writeCache(stateDir, {
|
|
336
|
+
lastCheckMs: now(),
|
|
337
|
+
latest: latest ?? prev?.latest ?? null,
|
|
338
|
+
dismissedVersion: prev?.dismissedVersion
|
|
339
|
+
});
|
|
331
340
|
} catch {}
|
|
332
341
|
}
|
|
333
342
|
function buildUpdateNotice(current, latest, isTTY) {
|
|
@@ -342,30 +351,109 @@ function buildUpdateNotice(current, latest, isTTY) {
|
|
|
342
351
|
].join(`
|
|
343
352
|
`);
|
|
344
353
|
}
|
|
354
|
+
function buildDismissedUpdateNotice(current, latest, isTTY) {
|
|
355
|
+
const yellow = isTTY ? "\x1B[33m" : "";
|
|
356
|
+
const bold = isTTY ? "\x1B[1m" : "";
|
|
357
|
+
const reset = isTTY ? "\x1B[0m" : "";
|
|
358
|
+
return `${yellow}\u26A0 AgentBridge update available: ${bold}${current}${reset}${yellow} \u2192 ${bold}${latest}${reset} (previously dismissed)`;
|
|
359
|
+
}
|
|
345
360
|
function checkIntervalMs(env) {
|
|
346
361
|
return parsePositiveIntEnv(CHECK_INTERVAL_ENV, DEFAULT_CHECK_INTERVAL_MS, undefined, env);
|
|
347
362
|
}
|
|
348
|
-
function
|
|
363
|
+
function updatePromptDisabled(env) {
|
|
364
|
+
return env.AGENTBRIDGE_UPDATE_PROMPT === "0";
|
|
365
|
+
}
|
|
366
|
+
function defaultInstallUpdate(cmd, args) {
|
|
367
|
+
const res = spawnSync(cmd, args, { stdio: "inherit" });
|
|
368
|
+
if (res.error)
|
|
369
|
+
return { ok: false, status: res.status, error: res.error };
|
|
370
|
+
return { ok: res.status === 0, status: res.status };
|
|
371
|
+
}
|
|
372
|
+
function defaultPromptUpdate(opts) {
|
|
373
|
+
return new Promise((resolve) => {
|
|
374
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
375
|
+
let settled = false;
|
|
376
|
+
let timer;
|
|
377
|
+
const finish = (answer) => {
|
|
378
|
+
if (settled)
|
|
379
|
+
return;
|
|
380
|
+
settled = true;
|
|
381
|
+
clearTimeout(timer);
|
|
382
|
+
rl.close();
|
|
383
|
+
resolve(answer);
|
|
384
|
+
};
|
|
385
|
+
timer = setTimeout(() => {
|
|
386
|
+
process.stderr.write(`
|
|
387
|
+
`);
|
|
388
|
+
finish(false);
|
|
389
|
+
}, opts.timeoutMs);
|
|
390
|
+
timer.unref?.();
|
|
391
|
+
rl.question(`Update AgentBridge now? [y/N] `, (answer) => {
|
|
392
|
+
finish(/^y(?:es)?$/i.test(answer.trim()));
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
function recordDismissal(stateDir, cache, latest) {
|
|
397
|
+
writeCache(stateDir, {
|
|
398
|
+
...cache,
|
|
399
|
+
latest,
|
|
400
|
+
dismissedVersion: latest
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
async function maybeNotifyUpdate(deps = {}) {
|
|
349
404
|
try {
|
|
350
405
|
const env = deps.env ?? process.env;
|
|
351
406
|
const isTTY = deps.isTTY ?? Boolean(process.stderr.isTTY);
|
|
352
407
|
if (isUpdateCheckSuppressed(env, isTTY))
|
|
353
|
-
return;
|
|
408
|
+
return "continue";
|
|
354
409
|
const current = deps.current ?? getCurrentVersion();
|
|
355
410
|
const stateDir = deps.stateDir ?? new StateDirResolver;
|
|
356
411
|
const now = deps.now ?? Date.now;
|
|
357
412
|
const print = deps.print ?? ((m) => process.stderr.write(m + `
|
|
358
413
|
`));
|
|
414
|
+
const inputIsTTY = deps.inputIsTTY ?? Boolean(process.stdin.isTTY);
|
|
415
|
+
const promptTimeoutMs = deps.promptTimeoutMs ?? DEFAULT_UPDATE_PROMPT_TIMEOUT_MS;
|
|
359
416
|
const cache = readCache(stateDir);
|
|
360
417
|
if (cache?.latest && isStableUpgrade(current, cache.latest)) {
|
|
361
|
-
|
|
418
|
+
if (cache.dismissedVersion === cache.latest) {
|
|
419
|
+
print(buildDismissedUpdateNotice(current, cache.latest, isTTY));
|
|
420
|
+
} else {
|
|
421
|
+
print(buildUpdateNotice(current, cache.latest, isTTY));
|
|
422
|
+
if (!updatePromptDisabled(env) && inputIsTTY) {
|
|
423
|
+
const promptUpdate = deps.promptUpdate ?? defaultPromptUpdate;
|
|
424
|
+
let accepted = false;
|
|
425
|
+
try {
|
|
426
|
+
accepted = await promptUpdate({ current, latest: cache.latest, timeoutMs: promptTimeoutMs });
|
|
427
|
+
} catch {
|
|
428
|
+
accepted = false;
|
|
429
|
+
}
|
|
430
|
+
if (accepted) {
|
|
431
|
+
const installUpdate = deps.installUpdate ?? defaultInstallUpdate;
|
|
432
|
+
const cmd = "npm";
|
|
433
|
+
const args = ["install", "-g", `${PACKAGE_NAME}@latest`];
|
|
434
|
+
const result = installUpdate(cmd, args);
|
|
435
|
+
if (result.ok) {
|
|
436
|
+
print("AgentBridge CLI updated. \u8BF7\u91CD\u65B0\u8FD0\u884C\u547D\u4EE4\u3002");
|
|
437
|
+
print("Plugin: in Claude, run `/plugin marketplace update agentbridge` and then `/reload-plugins`.");
|
|
438
|
+
return "updated";
|
|
439
|
+
}
|
|
440
|
+
const detail = result.error?.message ? ` (${result.error.message})` : typeof result.status === "number" ? ` (exit ${result.status})` : "";
|
|
441
|
+
print(`\u26A0 AgentBridge update failed${detail}; continuing with the current command.`);
|
|
442
|
+
} else {
|
|
443
|
+
recordDismissal(stateDir, cache, cache.latest);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
362
447
|
}
|
|
363
448
|
if (deps.refresh && (!cache || now() - cache.lastCheckMs >= checkIntervalMs(env))) {
|
|
364
449
|
refreshUpdateCache({ stateDir, now, fetchImpl: deps.fetchImpl }).catch(() => {});
|
|
365
450
|
}
|
|
366
|
-
|
|
451
|
+
return "continue";
|
|
452
|
+
} catch {
|
|
453
|
+
return "continue";
|
|
454
|
+
}
|
|
367
455
|
}
|
|
368
|
-
var PACKAGE_NAME = "@raysonmeng/agentbridge", REGISTRY_URL, ABBREVIATED_ACCEPT = "application/vnd.npm.install-v1+json", DEFAULT_CHECK_INTERVAL_MS, FETCH_TIMEOUT_MS = 2500, CHECK_INTERVAL_ENV = "AGENTBRIDGE_UPDATE_CHECK_INTERVAL_MS";
|
|
456
|
+
var PACKAGE_NAME = "@raysonmeng/agentbridge", REGISTRY_URL, ABBREVIATED_ACCEPT = "application/vnd.npm.install-v1+json", DEFAULT_CHECK_INTERVAL_MS, FETCH_TIMEOUT_MS = 2500, DEFAULT_UPDATE_PROMPT_TIMEOUT_MS = 15000, CHECK_INTERVAL_ENV = "AGENTBRIDGE_UPDATE_CHECK_INTERVAL_MS";
|
|
369
457
|
var init_update_notifier = __esm(() => {
|
|
370
458
|
init_atomic_json();
|
|
371
459
|
init_state_dir();
|
|
@@ -438,6 +526,9 @@ function normalizeBoundedInteger(value, fallback, min, max) {
|
|
|
438
526
|
return fallback;
|
|
439
527
|
return parsed;
|
|
440
528
|
}
|
|
529
|
+
function normalizeStrategy(value, fallback) {
|
|
530
|
+
return value === "conserve" || value === "maximize" ? value : fallback;
|
|
531
|
+
}
|
|
441
532
|
function normalizeBoolean(value, fallback) {
|
|
442
533
|
if (typeof value === "boolean")
|
|
443
534
|
return value;
|
|
@@ -486,9 +577,27 @@ function normalizeBudgetConfig(raw, fallback = DEFAULT_BUDGET_CONFIG) {
|
|
|
486
577
|
timeWindowSec: normalizeBoundedInteger(parallel.timeWindowSec, fallback.parallel.timeWindowSec, 60, 604800)
|
|
487
578
|
},
|
|
488
579
|
codexTierControl: normalizeBoolean(budget.codexTierControl, fallback.codexTierControl) && codexTiers.full !== null,
|
|
489
|
-
codexTiers
|
|
580
|
+
codexTiers,
|
|
581
|
+
strategy: normalizeStrategy(budget.strategy, fallback.strategy)
|
|
490
582
|
};
|
|
491
583
|
}
|
|
584
|
+
function applyBudgetEnvOverrides(budget, env = process.env) {
|
|
585
|
+
const overlay = {
|
|
586
|
+
enabled: env.AGENTBRIDGE_BUDGET_ENABLED ?? budget.enabled,
|
|
587
|
+
pollSeconds: env.AGENTBRIDGE_BUDGET_POLL_SECONDS ?? budget.pollSeconds,
|
|
588
|
+
pauseAt: env.AGENTBRIDGE_BUDGET_PAUSE_AT ?? budget.pauseAt,
|
|
589
|
+
resumeBelow: env.AGENTBRIDGE_BUDGET_RESUME_BELOW ?? budget.resumeBelow,
|
|
590
|
+
syncDriftPct: env.AGENTBRIDGE_BUDGET_SYNC_DRIFT_PCT ?? budget.syncDriftPct,
|
|
591
|
+
parallel: {
|
|
592
|
+
minRemainingPct: env.AGENTBRIDGE_BUDGET_PARALLEL_MIN_REMAINING_PCT ?? budget.parallel.minRemainingPct,
|
|
593
|
+
timeWindowSec: env.AGENTBRIDGE_BUDGET_PARALLEL_TIME_WINDOW_SEC ?? budget.parallel.timeWindowSec
|
|
594
|
+
},
|
|
595
|
+
codexTierControl: env.AGENTBRIDGE_BUDGET_CODEX_TIER_CONTROL ?? budget.codexTierControl,
|
|
596
|
+
codexTiers: budget.codexTiers,
|
|
597
|
+
strategy: env.AGENTBRIDGE_BUDGET_STRATEGY ?? budget.strategy
|
|
598
|
+
};
|
|
599
|
+
return normalizeBudgetConfig(overlay, budget);
|
|
600
|
+
}
|
|
492
601
|
function normalizeConfig(raw) {
|
|
493
602
|
if (!isRecord(raw))
|
|
494
603
|
return null;
|
|
@@ -615,7 +724,8 @@ var init_config_service = __esm(() => {
|
|
|
615
724
|
full: null,
|
|
616
725
|
balanced: { effort: "medium" },
|
|
617
726
|
eco: { effort: "low" }
|
|
618
|
-
}
|
|
727
|
+
},
|
|
728
|
+
strategy: "conserve"
|
|
619
729
|
};
|
|
620
730
|
DEFAULT_CONFIG = {
|
|
621
731
|
version: "1.0",
|
|
@@ -1015,7 +1125,7 @@ var exports_dev = {};
|
|
|
1015
1125
|
__export(exports_dev, {
|
|
1016
1126
|
runDev: () => runDev
|
|
1017
1127
|
});
|
|
1018
|
-
import { execFileSync as execFileSync3, spawnSync } from "child_process";
|
|
1128
|
+
import { execFileSync as execFileSync3, spawnSync as spawnSync2 } from "child_process";
|
|
1019
1129
|
import { resolve as resolve2 } from "path";
|
|
1020
1130
|
import { existsSync as existsSync5, cpSync, rmSync } from "fs";
|
|
1021
1131
|
async function runDev(args = []) {
|
|
@@ -1041,7 +1151,7 @@ async function runDev(args = []) {
|
|
|
1041
1151
|
`);
|
|
1042
1152
|
} else {
|
|
1043
1153
|
console.log("Building CLI from source...");
|
|
1044
|
-
const cliBuild =
|
|
1154
|
+
const cliBuild = spawnSync2("bun", ["run", "build:cli"], {
|
|
1045
1155
|
cwd: projectRoot,
|
|
1046
1156
|
stdio: "inherit"
|
|
1047
1157
|
});
|
|
@@ -1052,7 +1162,7 @@ async function runDev(args = []) {
|
|
|
1052
1162
|
console.log(` \u2713 CLI built successfully
|
|
1053
1163
|
`);
|
|
1054
1164
|
console.log("Building plugin from source...");
|
|
1055
|
-
const buildResult =
|
|
1165
|
+
const buildResult = spawnSync2("bun", ["run", "build:plugin"], {
|
|
1056
1166
|
cwd: projectRoot,
|
|
1057
1167
|
stdio: "inherit"
|
|
1058
1168
|
});
|
|
@@ -1475,11 +1585,11 @@ function formatBuildInfo(build) {
|
|
|
1475
1585
|
var CODE_HASH_SENTINEL = "source", BUILD_INFO;
|
|
1476
1586
|
var init_build_info = __esm(() => {
|
|
1477
1587
|
BUILD_INFO = Object.freeze({
|
|
1478
|
-
version: defineString("0.1.
|
|
1479
|
-
commit: defineString("
|
|
1588
|
+
version: defineString("0.1.15", "0.0.0-source"),
|
|
1589
|
+
commit: defineString("89d4c9a", "source"),
|
|
1480
1590
|
bundle: defineBundle("dist"),
|
|
1481
1591
|
contractVersion: defineNumber(1, CONTRACT_VERSION),
|
|
1482
|
-
codeHash: defineString("
|
|
1592
|
+
codeHash: defineString("71ce81854ec9", "source")
|
|
1483
1593
|
});
|
|
1484
1594
|
});
|
|
1485
1595
|
|
|
@@ -3660,12 +3770,26 @@ function readUsableCurrentThread(identity, env = process.env) {
|
|
|
3660
3770
|
const state = readRawCurrentThread(identity.stateDir);
|
|
3661
3771
|
if (!state)
|
|
3662
3772
|
return null;
|
|
3663
|
-
if (state.status !== "current")
|
|
3664
|
-
return null;
|
|
3665
3773
|
if (state.pairId !== identity.pairId)
|
|
3666
3774
|
return null;
|
|
3667
3775
|
if (state.cwd !== identity.cwd)
|
|
3668
3776
|
return null;
|
|
3777
|
+
if (state.status === "pending") {
|
|
3778
|
+
const rolloutPath2 = findCodexRolloutFile(state.threadId, env);
|
|
3779
|
+
if (!rolloutPath2)
|
|
3780
|
+
return null;
|
|
3781
|
+
const promoted = {
|
|
3782
|
+
...state,
|
|
3783
|
+
status: "current",
|
|
3784
|
+
rolloutPath: rolloutPath2,
|
|
3785
|
+
rolloutVerifiedAt: nowIso(),
|
|
3786
|
+
updatedAt: nowIso()
|
|
3787
|
+
};
|
|
3788
|
+
try {
|
|
3789
|
+
atomicWriteJson(identity.stateDir.currentThreadFile, promoted);
|
|
3790
|
+
} catch {}
|
|
3791
|
+
return promoted;
|
|
3792
|
+
}
|
|
3669
3793
|
if (state.rolloutPath && existsSync12(state.rolloutPath))
|
|
3670
3794
|
return state;
|
|
3671
3795
|
const rolloutPath = findCodexRolloutFile(state.threadId, env);
|
|
@@ -3759,10 +3883,12 @@ function resolveCodexResumeArgs(parsed, pair, env = process.env) {
|
|
|
3759
3883
|
const current = readUsableCurrentThread(identity, env);
|
|
3760
3884
|
if (parsed.resumeCurrent) {
|
|
3761
3885
|
if (!current) {
|
|
3886
|
+
const raw = readRawCurrentThread(identity.stateDir);
|
|
3887
|
+
const pending = raw && raw.status === "pending" && raw.pairId === identity.pairId && raw.cwd === identity.cwd ? raw : null;
|
|
3762
3888
|
return {
|
|
3763
3889
|
rest: parsed.rest,
|
|
3764
3890
|
mode: "resume-current",
|
|
3765
|
-
error: "No verified current Codex thread for this pair. Start a new one with `abg codex --new`, or resume a specific thread with `abg codex resume <threadId>`."
|
|
3891
|
+
error: pending ? `No verified current Codex thread for this pair. Found a pending (unverified) thread ${pending.threadId} \u2014 its Codex rollout file was not found. Try \`abg codex resume ${pending.threadId}\`, or start fresh with \`abg codex --new\`.` : "No verified current Codex thread for this pair. Start a new one with `abg codex --new`, or resume a specific thread with `abg codex resume <threadId>`."
|
|
3766
3892
|
};
|
|
3767
3893
|
}
|
|
3768
3894
|
return {
|
|
@@ -5069,6 +5195,215 @@ var init_pairs = __esm(() => {
|
|
|
5069
5195
|
init_thread_state();
|
|
5070
5196
|
init_kill();
|
|
5071
5197
|
});
|
|
5198
|
+
// src/budget/types.ts
|
|
5199
|
+
var STALE_MAX_AGE_SEC = 600;
|
|
5200
|
+
|
|
5201
|
+
// src/budget/budget-state.ts
|
|
5202
|
+
function isDecisionGrade(usage, now) {
|
|
5203
|
+
if (!usage)
|
|
5204
|
+
return false;
|
|
5205
|
+
const freshWindow = usage.fiveHour !== null && usage.fiveHour.resetEpoch > now || usage.weekly !== null && usage.weekly.resetEpoch > now;
|
|
5206
|
+
if (!freshWindow)
|
|
5207
|
+
return false;
|
|
5208
|
+
if (usage.fetchedAt > 0 && now - usage.fetchedAt > STALE_MAX_AGE_SEC)
|
|
5209
|
+
return false;
|
|
5210
|
+
return true;
|
|
5211
|
+
}
|
|
5212
|
+
var init_budget_state = () => {};
|
|
5213
|
+
|
|
5214
|
+
// src/budget/burn-view.ts
|
|
5215
|
+
function agentWeeklyFiveHourWindowsLeft(usage, now) {
|
|
5216
|
+
if (!usage || usage.stale || !usage.ok)
|
|
5217
|
+
return null;
|
|
5218
|
+
if (!isDecisionGrade(usage, now))
|
|
5219
|
+
return null;
|
|
5220
|
+
const weekly = usage.weekly;
|
|
5221
|
+
if (!weekly || weekly.resetEpoch <= now)
|
|
5222
|
+
return null;
|
|
5223
|
+
if (weekly.burnConfident !== true)
|
|
5224
|
+
return null;
|
|
5225
|
+
if (weekly.runwaySeconds === undefined)
|
|
5226
|
+
return null;
|
|
5227
|
+
return weekly.fiveHourWindowsLeft ?? null;
|
|
5228
|
+
}
|
|
5229
|
+
var init_burn_view = __esm(() => {
|
|
5230
|
+
init_budget_state();
|
|
5231
|
+
});
|
|
5232
|
+
|
|
5233
|
+
// src/budget/render.ts
|
|
5234
|
+
function resolveGuardHardHint(env = process.env) {
|
|
5235
|
+
const raw = env.AGENTBRIDGE_GUARD_HARD_HINT;
|
|
5236
|
+
if (raw === undefined || raw.trim() === "")
|
|
5237
|
+
return DEFAULT_GUARD_HARD_PCT;
|
|
5238
|
+
const parsed = Number(raw);
|
|
5239
|
+
if (!Number.isFinite(parsed) || parsed < 1 || parsed > 100)
|
|
5240
|
+
return DEFAULT_GUARD_HARD_PCT;
|
|
5241
|
+
return parsed;
|
|
5242
|
+
}
|
|
5243
|
+
function formatEpoch(epochSeconds) {
|
|
5244
|
+
if (!epochSeconds || epochSeconds <= 0)
|
|
5245
|
+
return "\u672A\u77E5";
|
|
5246
|
+
return new Date(epochSeconds * 1000).toISOString().replace("T", " ").replace(/\.\d+Z$/, "Z");
|
|
5247
|
+
}
|
|
5248
|
+
function formatWindow(window, label) {
|
|
5249
|
+
if (!window)
|
|
5250
|
+
return `${label} \u672A\u77E5`;
|
|
5251
|
+
return `${label} ${window.util}%\uFF08\u91CD\u7F6E ${formatEpoch(window.resetEpoch)}\uFF09`;
|
|
5252
|
+
}
|
|
5253
|
+
function formatAgent(name, usage, snapshotAt) {
|
|
5254
|
+
if (!usage)
|
|
5255
|
+
return `${name}\uFF1A\u672A\u77E5\uFF08\u63A2\u6D4B\u4E0D\u53EF\u7528\uFF09`;
|
|
5256
|
+
const parts = [
|
|
5257
|
+
formatWindow(usage.fiveHour, "5h"),
|
|
5258
|
+
formatWindow(usage.weekly, "\u5468"),
|
|
5259
|
+
`\u95E8\u63A7 ${usage.gateUtil}%`,
|
|
5260
|
+
`\u9884\u8B66 ${usage.warnUtil}%`
|
|
5261
|
+
];
|
|
5262
|
+
if (usage.rateLimitedUntil > 0) {
|
|
5263
|
+
parts.push(`\u9650\u6D41\u81F3 ${formatEpoch(usage.rateLimitedUntil)}`);
|
|
5264
|
+
}
|
|
5265
|
+
if (usage.parsedVia === "positional") {
|
|
5266
|
+
parts.push("\u26A0\uFE0F \u7A97\u53E3\u8BC6\u522B\u4F7F\u7528\u4F4D\u7F6E\u515C\u5E95");
|
|
5267
|
+
}
|
|
5268
|
+
const ageSec = usage.fetchedAt > 0 ? snapshotAt - usage.fetchedAt : 0;
|
|
5269
|
+
if (ageSec > 300) {
|
|
5270
|
+
parts.push(`\u26A0\uFE0F \u6570\u636E\u91C7\u96C6\u4E8E ${Math.round(ageSec / 60)} \u5206\u949F\u524D`);
|
|
5271
|
+
} else if (usage.stale) {
|
|
5272
|
+
parts.push("\uFF08\u7F13\u5B58\u6570\u636E\uFF09");
|
|
5273
|
+
}
|
|
5274
|
+
return `${name}\uFF1A${parts.join(" \xB7 ")}`;
|
|
5275
|
+
}
|
|
5276
|
+
function formatDuration(seconds) {
|
|
5277
|
+
const totalMinutes = Math.max(0, Math.round(seconds / 60));
|
|
5278
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
5279
|
+
const minutes = totalMinutes % 60;
|
|
5280
|
+
if (hours === 0)
|
|
5281
|
+
return `${minutes}\u5206\u949F`;
|
|
5282
|
+
return `${hours}\u5C0F\u65F6${minutes}\u5206\u949F`;
|
|
5283
|
+
}
|
|
5284
|
+
function formatClockTime(epochSeconds) {
|
|
5285
|
+
const date = new Date(epochSeconds * 1000);
|
|
5286
|
+
const hh = String(date.getHours()).padStart(2, "0");
|
|
5287
|
+
const mm = String(date.getMinutes()).padStart(2, "0");
|
|
5288
|
+
return `${hh}:${mm}`;
|
|
5289
|
+
}
|
|
5290
|
+
function formatWindowRate(label, rate) {
|
|
5291
|
+
if (!rate)
|
|
5292
|
+
return null;
|
|
5293
|
+
if (!rate.confident)
|
|
5294
|
+
return `${label} \u91C7\u6837\u4E2D`;
|
|
5295
|
+
return `${label} \u2248${rate.pctPerHour.toFixed(2)}%/h`;
|
|
5296
|
+
}
|
|
5297
|
+
function formatRunwaySegment(runway, basisWindow, snapshotAt) {
|
|
5298
|
+
const truncatedByReset = basisWindow !== null && basisWindow.resetEpoch > 0 && snapshotAt + runway.seconds >= basisWindow.resetEpoch - RESET_TRUNCATION_EPSILON_SEC;
|
|
5299
|
+
const clock = runway.depletedAtEpoch ? formatClockTime(runway.depletedAtEpoch) : null;
|
|
5300
|
+
let clockNote;
|
|
5301
|
+
if (clock) {
|
|
5302
|
+
clockNote = truncatedByReset ? `\u81F3 ${clock} \u7A97\u53E3\u5237\u65B0\u5373\u622A\u65AD\uFF0C` : `\u81F3 ${clock}\uFF0C`;
|
|
5303
|
+
} else {
|
|
5304
|
+
clockNote = truncatedByReset ? "\u7A97\u53E3\u5237\u65B0\u5373\u622A\u65AD\uFF0C" : "";
|
|
5305
|
+
}
|
|
5306
|
+
return `\u7EA6\u53EF\u518D\u5DE5\u4F5C ${formatDuration(runway.seconds)}\uFF08${clockNote}${WINDOW_LABELS[runway.basis]}\u4E3A\u7EA6\u675F\uFF09`;
|
|
5307
|
+
}
|
|
5308
|
+
function formatBurnRateLine(name, usage, rates, runway, snapshotAt, guardHardPct) {
|
|
5309
|
+
const parts = [
|
|
5310
|
+
formatWindowRate("5h", rates.fiveHour),
|
|
5311
|
+
formatWindowRate("\u5468", rates.weekly)
|
|
5312
|
+
].filter((part) => part !== null);
|
|
5313
|
+
if (parts.length === 0 && !runway)
|
|
5314
|
+
return null;
|
|
5315
|
+
if (runway) {
|
|
5316
|
+
const basisWindow = usage ? usage[runway.basis] : null;
|
|
5317
|
+
parts.push(formatRunwaySegment(runway, basisWindow, snapshotAt));
|
|
5318
|
+
}
|
|
5319
|
+
if (guardHardPct !== null) {
|
|
5320
|
+
parts.push(`\u5916\u5C42 guard \u786C\u7EBF ${guardHardPct}%\uFF08v3 \u4E0D\u53EF\u8D8A\u8FC7\uFF1Brunway \u4E3A\u4E2D\u6027\u53E3\u5F84\uFF0CClaude \u4F1A\u5148\u5728\u786C\u7EBF\u88AB\u5916\u5C42\u505C\u4F4F\uFF09`);
|
|
5321
|
+
}
|
|
5322
|
+
return `${name} \u71C3\u5C3D\u7387\uFF1A${parts.join(" \xB7 ")}`;
|
|
5323
|
+
}
|
|
5324
|
+
function formatFiveHourWindowsLeftLine(snapshot) {
|
|
5325
|
+
const values = [];
|
|
5326
|
+
const claude = agentWeeklyFiveHourWindowsLeft(snapshot.claude, snapshot.updatedAt);
|
|
5327
|
+
const codex = agentWeeklyFiveHourWindowsLeft(snapshot.codex, snapshot.updatedAt);
|
|
5328
|
+
if (claude !== null)
|
|
5329
|
+
values.push(["Claude", claude]);
|
|
5330
|
+
if (codex !== null)
|
|
5331
|
+
values.push(["Codex", codex]);
|
|
5332
|
+
if (values.length === 0)
|
|
5333
|
+
return null;
|
|
5334
|
+
const unique = [...new Set(values.map(([, value]) => value.toFixed(1)))];
|
|
5335
|
+
if (unique.length === 1)
|
|
5336
|
+
return `\u6309\u5F53\u524D\u8282\u594F\uFF0C\u5468\u989D\u5EA6\u8FD8\u591F ~${unique[0]} \u4E2A 5h \u7A97\u53E3`;
|
|
5337
|
+
const byAgent = values.map(([name, value]) => `${name} ~${value.toFixed(1)}`).join(" / ");
|
|
5338
|
+
return `\u6309\u5F53\u524D\u8282\u594F\uFF0C\u5468\u989D\u5EA6\u8FD8\u591F ${byAgent} \u4E2A 5h \u7A97\u53E3`;
|
|
5339
|
+
}
|
|
5340
|
+
function renderBudgetSnapshot(snapshot, options = {}) {
|
|
5341
|
+
const guardHardPct = options.guardHardPct ?? resolveGuardHardHint();
|
|
5342
|
+
const lines = [];
|
|
5343
|
+
lines.push(`\u3010\u9884\u7B97\u5FEB\u7167 \xB7 \u8D26\u53F7\u7EA7\u3011\u9636\u6BB5\uFF1A${PHASE_LABELS[snapshot.phase]} \xB7 \u66F4\u65B0\u4E8E ${formatEpoch(snapshot.updatedAt)}`);
|
|
5344
|
+
lines.push(formatAgent("Claude", snapshot.claude, snapshot.updatedAt));
|
|
5345
|
+
lines.push(formatAgent("Codex", snapshot.codex, snapshot.updatedAt));
|
|
5346
|
+
if (snapshot.burnRate) {
|
|
5347
|
+
const claudeLine = formatBurnRateLine("Claude", snapshot.claude, snapshot.burnRate.claude, snapshot.runway?.claude ?? null, snapshot.updatedAt, guardHardPct);
|
|
5348
|
+
if (claudeLine)
|
|
5349
|
+
lines.push(claudeLine);
|
|
5350
|
+
const codexLine = formatBurnRateLine("Codex", snapshot.codex, snapshot.burnRate.codex, snapshot.runway?.codex ?? null, snapshot.updatedAt, null);
|
|
5351
|
+
if (codexLine)
|
|
5352
|
+
lines.push(codexLine);
|
|
5353
|
+
}
|
|
5354
|
+
const fiveHourWindowsLeftLine = formatFiveHourWindowsLeftLine(snapshot);
|
|
5355
|
+
if (fiveHourWindowsLeftLine)
|
|
5356
|
+
lines.push(fiveHourWindowsLeftLine);
|
|
5357
|
+
if (snapshot.claude && snapshot.codex) {
|
|
5358
|
+
const abs = Math.abs(snapshot.driftPct);
|
|
5359
|
+
if (abs > 0) {
|
|
5360
|
+
const heavier = snapshot.driftPct > 0 ? "Claude" : "Codex";
|
|
5361
|
+
const lighter = snapshot.driftPct > 0 ? "Codex" : "Claude";
|
|
5362
|
+
lines.push(`\u6F02\u79FB\uFF1A${heavier} \u6BD4 ${lighter} \u9AD8 ${abs} \u4E2A\u767E\u5206\u70B9`);
|
|
5363
|
+
} else {
|
|
5364
|
+
lines.push("\u6F02\u79FB\uFF1A\u53CC\u65B9\u6301\u5E73");
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
if (snapshot.paused) {
|
|
5368
|
+
const resume = snapshot.resumeAfterEpoch ? `\uFF1B\u9884\u8BA1\u6062\u590D ${formatEpoch(snapshot.resumeAfterEpoch)}\uFF08\u4EE5\u5B9E\u6D4B\u4E3A\u51C6\uFF1B\u63D0\u524D\u5237\u65B0\u4F1A\u66F4\u65E9\u89E3\u9664\uFF09` : "";
|
|
5369
|
+
const reason = snapshot.pauseReason ?? "\u989D\u5EA6\u63A5\u8FD1\u8017\u5C3D";
|
|
5370
|
+
if (snapshot.pauseSide === "claude" && !snapshot.gateClosed) {
|
|
5371
|
+
lines.push(`\u63A5\u529B\u4E2D\uFF1AClaude \u4FA7\u989D\u5EA6\u8017\u5C3D\uFF0C\u5DF2\u4EA4\u63A5 Codex \u7EE7\u7EED\u63A8\u8FDB\uFF08\u95F8\u95E8\u5F00\u653E\uFF09 \u2014 ${reason}${resume}`);
|
|
5372
|
+
} else if (snapshot.pauseSide === "codex") {
|
|
5373
|
+
lines.push(`\u6682\u505C\uFF1ACodex \u4FA7\u989D\u5EA6\u8017\u5C3D\uFF08\u95F8\u95E8\u5173\u95ED\uFF0CClaude \u53EF solo \u63A8\u8FDB\u72EC\u7ACB\u90E8\u5206\uFF09 \u2014 ${reason}${resume}`);
|
|
5374
|
+
} else {
|
|
5375
|
+
lines.push(`\u6682\u505C\uFF1A\u53CC\u4FA7\u8054\u5408\u6682\u505C\uFF08\u95F8\u95E8\u5173\u95ED\uFF09 \u2014 ${reason}${resume}`);
|
|
5376
|
+
}
|
|
5377
|
+
} else {
|
|
5378
|
+
lines.push("\u6682\u505C\uFF1A\u5426");
|
|
5379
|
+
}
|
|
5380
|
+
if (snapshot.parallelRecommended) {
|
|
5381
|
+
lines.push("\u5E76\u884C\u5EFA\u8BAE\uFF1A\u989D\u5EA6\u5BCC\u4F59\u4E14\u4E34\u8FD1\u7ED3\u7B97\uFF0C\u5EFA\u8BAE\u62C6\u5206\u66F4\u591A\u5E76\u884C\u5B50\u4EFB\u52A1");
|
|
5382
|
+
}
|
|
5383
|
+
if (snapshot.codexTier !== "full") {
|
|
5384
|
+
lines.push(`Codex \u6863\u4F4D\uFF1A${snapshot.codexTier}`);
|
|
5385
|
+
}
|
|
5386
|
+
if (snapshot.claudeAdvice) {
|
|
5387
|
+
lines.push(`Claude \u5EFA\u8BAE\uFF1A${snapshot.claudeAdvice}`);
|
|
5388
|
+
}
|
|
5389
|
+
lines.push("\u6CE8\uFF1A\u767E\u5206\u6BD4\u4E3A\u8BA2\u9605\u8D26\u53F7\u7EA7\u7528\u91CF\uFF08\u540C\u673A\u5176\u4ED6\u4F1A\u8BDD\u5171\u4EAB\u540C\u4E00\u989D\u5EA6\u6C60\uFF09\u3002");
|
|
5390
|
+
return lines.join(`
|
|
5391
|
+
`);
|
|
5392
|
+
}
|
|
5393
|
+
var DEFAULT_GUARD_HARD_PCT = 92, WINDOW_LABELS, RESET_TRUNCATION_EPSILON_SEC = 60, PHASE_LABELS, BUDGET_UNAVAILABLE_TEXT = "\u9884\u7B97\u611F\u77E5\u4E0D\u53EF\u7528\uFF1A\u672A\u68C0\u6D4B\u5230 agent-quota-guard \u63A2\u9488\uFF08~/.budget-guard/bin/budget-probe\uFF09\u6216 budget \u529F\u80FD\u5DF2\u7981\u7528\u3002\u534F\u4F5C\u4E0D\u53D7\u5F71\u54CD\u3002";
|
|
5394
|
+
var init_render = __esm(() => {
|
|
5395
|
+
init_burn_view();
|
|
5396
|
+
WINDOW_LABELS = {
|
|
5397
|
+
fiveHour: "5h \u7A97\u53E3",
|
|
5398
|
+
weekly: "\u5468\u7A97\u53E3"
|
|
5399
|
+
};
|
|
5400
|
+
PHASE_LABELS = {
|
|
5401
|
+
normal: "normal\uFF08\u6B63\u5E38\uFF09",
|
|
5402
|
+
balance: "balance\uFF08\u9700\u5747\u8861\uFF09",
|
|
5403
|
+
parallel: "parallel\uFF08\u5EFA\u8BAE\u5E76\u884C\u63D0\u901F\uFF09",
|
|
5404
|
+
paused: "paused\uFF08\u9884\u7B97\u5E72\u9884\u4E2D\uFF09"
|
|
5405
|
+
};
|
|
5406
|
+
});
|
|
5072
5407
|
|
|
5073
5408
|
// src/daemon-status.ts
|
|
5074
5409
|
async function fetchDaemonStatus(port, path = "/healthz", timeoutMs = DAEMON_STATUS_FETCH_TIMEOUT_MS) {
|
|
@@ -5272,8 +5607,10 @@ var exports_doctor = {};
|
|
|
5272
5607
|
__export(exports_doctor, {
|
|
5273
5608
|
runDoctor: () => runDoctor,
|
|
5274
5609
|
formatDoctorReport: () => formatDoctorReport,
|
|
5610
|
+
evaluateBudgetStrategyGuard: () => evaluateBudgetStrategyGuard,
|
|
5275
5611
|
evaluateArtifactAlignment: () => evaluateArtifactAlignment,
|
|
5276
|
-
describeBuildDrift: () => describeBuildDrift
|
|
5612
|
+
describeBuildDrift: () => describeBuildDrift,
|
|
5613
|
+
V3_DEFAULT_TARGET_UTIL: () => V3_DEFAULT_TARGET_UTIL
|
|
5277
5614
|
});
|
|
5278
5615
|
import { existsSync as existsSync15, readFileSync as readFileSync13, readdirSync as readdirSync6, realpathSync as realpathSync3, statSync as statSync7 } from "fs";
|
|
5279
5616
|
import { join as join17 } from "path";
|
|
@@ -5381,6 +5718,7 @@ async function buildDoctorReport(pair, registered) {
|
|
|
5381
5718
|
hint: env.ok ? undefined : `\u73AF\u5883\u53D8\u91CF\u4E0E\u5F53\u524D\u76EE\u5F55\u4E0D\u5339\u914D\uFF1A\u8BF7\u5728\u6B63\u786E\u7684\u9879\u76EE\u76EE\u5F55\u91CC\u91CD\u65B0\u8FD0\u884C \`${cli} claude\`\uFF0C\u4E0D\u8981\u590D\u7528\u5176\u4ED6\u76EE\u5F55\u7684\u4F1A\u8BDD\u73AF\u5883\u3002`
|
|
5382
5719
|
});
|
|
5383
5720
|
checks.push(configParseabilityCheck(cwd, cli));
|
|
5721
|
+
checks.push(budgetStrategyGuardCheck(cwd));
|
|
5384
5722
|
checks.push({
|
|
5385
5723
|
name: "daemon health",
|
|
5386
5724
|
status: health ? "ok" : "warn",
|
|
@@ -5580,6 +5918,33 @@ function configParseabilityCheck(cwd, cli) {
|
|
|
5580
5918
|
detail: desc.customValues ? `parsed at ${desc.path} \u2014 custom values in effect` : `parsed at ${desc.path} \u2014 all values match defaults`
|
|
5581
5919
|
};
|
|
5582
5920
|
}
|
|
5921
|
+
function evaluateBudgetStrategyGuard(strategy, guardHardPct, targetUtilPct = V3_DEFAULT_TARGET_UTIL) {
|
|
5922
|
+
if (strategy !== "maximize") {
|
|
5923
|
+
return {
|
|
5924
|
+
name: "budget strategy",
|
|
5925
|
+
status: "ok",
|
|
5926
|
+
detail: "strategy=conserve \u2014 v2-equivalent budget behavior (v3 maximize is opt-in)"
|
|
5927
|
+
};
|
|
5928
|
+
}
|
|
5929
|
+
if (guardHardPct >= targetUtilPct) {
|
|
5930
|
+
return {
|
|
5931
|
+
name: "budget strategy",
|
|
5932
|
+
status: "ok",
|
|
5933
|
+
detail: `strategy=maximize \u2014 outer guard hard line ${guardHardPct}% covers targetUtil ${targetUtilPct}%`
|
|
5934
|
+
};
|
|
5935
|
+
}
|
|
5936
|
+
return {
|
|
5937
|
+
name: "budget strategy",
|
|
5938
|
+
status: "warn",
|
|
5939
|
+
detail: `strategy=maximize but the outer quota-guard hard line (${guardHardPct}%) is below ` + `targetUtil (${targetUtilPct}%) \u2014 the ${guardHardPct}\u2192${targetUtilPct} band is unreachable for Claude`,
|
|
5940
|
+
hint: "v3 \u4E0D\u53EF\u8D8A\u8FC7\u5916\u5C42 quota-guard \u786C\u7EBF\uFF1AClaude \u4FA7\u8FBE\u5230 guard \u786C\u7EBF\u65F6\u8FDB\u7A0B\u4F1A\u88AB\u5916\u5C42\u5F3A\u505C\uFF0C" + `maximize \u7684 ${guardHardPct}%\u2192${targetUtilPct}% \u533A\u95F4\u5B9E\u9645\u70E7\u4E0D\u5230\u3002\u60F3\u771F\u6B63\u7528\u5230 targetUtil\uFF0C` + "\u9700\u81EA\u884C\u8C03\u9AD8 quota-guard \u7684 BUDGET_HARD\uFF08\u672C\u4ED3\u5E93\u4E0D\u4EE3\u6539\u5916\u5C42\u914D\u7F6E\uFF09\uFF1B\u5C55\u793A\u4FA7\u5DF2\u6309 guard \u7EBF\u6536\u53E3\u3002"
|
|
5941
|
+
};
|
|
5942
|
+
}
|
|
5943
|
+
function budgetStrategyGuardCheck(cwd) {
|
|
5944
|
+
const config = new ConfigService(cwd).loadOrDefault();
|
|
5945
|
+
const budget = applyBudgetEnvOverrides(config.budget);
|
|
5946
|
+
return evaluateBudgetStrategyGuard(budget.strategy, resolveGuardHardHint());
|
|
5947
|
+
}
|
|
5583
5948
|
function logCheck(name, path, cli) {
|
|
5584
5949
|
if (!existsSync15(path)) {
|
|
5585
5950
|
return {
|
|
@@ -5629,12 +5994,13 @@ function printDoctorReport(report) {
|
|
|
5629
5994
|
console.log(line);
|
|
5630
5995
|
}
|
|
5631
5996
|
}
|
|
5632
|
-
var LARGE_LOG_WARN_BYTES;
|
|
5997
|
+
var LARGE_LOG_WARN_BYTES, V3_DEFAULT_TARGET_UTIL = 97;
|
|
5633
5998
|
var init_doctor = __esm(() => {
|
|
5634
5999
|
init_plugin_cache();
|
|
5635
6000
|
init_build_info();
|
|
5636
6001
|
init_cli_invocation();
|
|
5637
6002
|
init_config_service();
|
|
6003
|
+
init_render();
|
|
5638
6004
|
init_env_guard();
|
|
5639
6005
|
init_pair_resolver();
|
|
5640
6006
|
init_thread_state();
|
|
@@ -5643,91 +6009,6 @@ var init_doctor = __esm(() => {
|
|
|
5643
6009
|
LARGE_LOG_WARN_BYTES = 100 * 1024 * 1024;
|
|
5644
6010
|
});
|
|
5645
6011
|
|
|
5646
|
-
// src/budget/render.ts
|
|
5647
|
-
function formatEpoch(epochSeconds) {
|
|
5648
|
-
if (!epochSeconds || epochSeconds <= 0)
|
|
5649
|
-
return "\u672A\u77E5";
|
|
5650
|
-
return new Date(epochSeconds * 1000).toISOString().replace("T", " ").replace(/\.\d+Z$/, "Z");
|
|
5651
|
-
}
|
|
5652
|
-
function formatWindow(window, label) {
|
|
5653
|
-
if (!window)
|
|
5654
|
-
return `${label} \u672A\u77E5`;
|
|
5655
|
-
return `${label} ${window.util}%\uFF08\u91CD\u7F6E ${formatEpoch(window.resetEpoch)}\uFF09`;
|
|
5656
|
-
}
|
|
5657
|
-
function formatAgent(name, usage, snapshotAt) {
|
|
5658
|
-
if (!usage)
|
|
5659
|
-
return `${name}\uFF1A\u672A\u77E5\uFF08\u63A2\u6D4B\u4E0D\u53EF\u7528\uFF09`;
|
|
5660
|
-
const parts = [
|
|
5661
|
-
formatWindow(usage.fiveHour, "5h"),
|
|
5662
|
-
formatWindow(usage.weekly, "\u5468"),
|
|
5663
|
-
`\u95E8\u63A7 ${usage.gateUtil}%`,
|
|
5664
|
-
`\u9884\u8B66 ${usage.warnUtil}%`
|
|
5665
|
-
];
|
|
5666
|
-
if (usage.rateLimitedUntil > 0) {
|
|
5667
|
-
parts.push(`\u9650\u6D41\u81F3 ${formatEpoch(usage.rateLimitedUntil)}`);
|
|
5668
|
-
}
|
|
5669
|
-
if (usage.parsedVia === "positional") {
|
|
5670
|
-
parts.push("\u26A0\uFE0F \u7A97\u53E3\u8BC6\u522B\u4F7F\u7528\u4F4D\u7F6E\u515C\u5E95");
|
|
5671
|
-
}
|
|
5672
|
-
const ageSec = usage.fetchedAt > 0 ? snapshotAt - usage.fetchedAt : 0;
|
|
5673
|
-
if (ageSec > 300) {
|
|
5674
|
-
parts.push(`\u26A0\uFE0F \u6570\u636E\u91C7\u96C6\u4E8E ${Math.round(ageSec / 60)} \u5206\u949F\u524D`);
|
|
5675
|
-
} else if (usage.stale) {
|
|
5676
|
-
parts.push("\uFF08\u7F13\u5B58\u6570\u636E\uFF09");
|
|
5677
|
-
}
|
|
5678
|
-
return `${name}\uFF1A${parts.join(" \xB7 ")}`;
|
|
5679
|
-
}
|
|
5680
|
-
function renderBudgetSnapshot(snapshot) {
|
|
5681
|
-
const lines = [];
|
|
5682
|
-
lines.push(`\u3010\u9884\u7B97\u5FEB\u7167 \xB7 \u8D26\u53F7\u7EA7\u3011\u9636\u6BB5\uFF1A${PHASE_LABELS[snapshot.phase]} \xB7 \u66F4\u65B0\u4E8E ${formatEpoch(snapshot.updatedAt)}`);
|
|
5683
|
-
lines.push(formatAgent("Claude", snapshot.claude, snapshot.updatedAt));
|
|
5684
|
-
lines.push(formatAgent("Codex", snapshot.codex, snapshot.updatedAt));
|
|
5685
|
-
if (snapshot.claude && snapshot.codex) {
|
|
5686
|
-
const abs = Math.abs(snapshot.driftPct);
|
|
5687
|
-
if (abs > 0) {
|
|
5688
|
-
const heavier = snapshot.driftPct > 0 ? "Claude" : "Codex";
|
|
5689
|
-
const lighter = snapshot.driftPct > 0 ? "Codex" : "Claude";
|
|
5690
|
-
lines.push(`\u6F02\u79FB\uFF1A${heavier} \u6BD4 ${lighter} \u9AD8 ${abs} \u4E2A\u767E\u5206\u70B9`);
|
|
5691
|
-
} else {
|
|
5692
|
-
lines.push("\u6F02\u79FB\uFF1A\u53CC\u65B9\u6301\u5E73");
|
|
5693
|
-
}
|
|
5694
|
-
}
|
|
5695
|
-
if (snapshot.paused) {
|
|
5696
|
-
const resume = snapshot.resumeAfterEpoch ? `\uFF1B\u9884\u8BA1\u6062\u590D ${formatEpoch(snapshot.resumeAfterEpoch)}\uFF08\u4EE5\u5B9E\u6D4B\u4E3A\u51C6\uFF1B\u63D0\u524D\u5237\u65B0\u4F1A\u66F4\u65E9\u89E3\u9664\uFF09` : "";
|
|
5697
|
-
const reason = snapshot.pauseReason ?? "\u989D\u5EA6\u63A5\u8FD1\u8017\u5C3D";
|
|
5698
|
-
if (snapshot.pauseSide === "claude" && !snapshot.gateClosed) {
|
|
5699
|
-
lines.push(`\u63A5\u529B\u4E2D\uFF1AClaude \u4FA7\u989D\u5EA6\u8017\u5C3D\uFF0C\u5DF2\u4EA4\u63A5 Codex \u7EE7\u7EED\u63A8\u8FDB\uFF08\u95F8\u95E8\u5F00\u653E\uFF09 \u2014 ${reason}${resume}`);
|
|
5700
|
-
} else if (snapshot.pauseSide === "codex") {
|
|
5701
|
-
lines.push(`\u6682\u505C\uFF1ACodex \u4FA7\u989D\u5EA6\u8017\u5C3D\uFF08\u95F8\u95E8\u5173\u95ED\uFF0CClaude \u53EF solo \u63A8\u8FDB\u72EC\u7ACB\u90E8\u5206\uFF09 \u2014 ${reason}${resume}`);
|
|
5702
|
-
} else {
|
|
5703
|
-
lines.push(`\u6682\u505C\uFF1A\u53CC\u4FA7\u8054\u5408\u6682\u505C\uFF08\u95F8\u95E8\u5173\u95ED\uFF09 \u2014 ${reason}${resume}`);
|
|
5704
|
-
}
|
|
5705
|
-
} else {
|
|
5706
|
-
lines.push("\u6682\u505C\uFF1A\u5426");
|
|
5707
|
-
}
|
|
5708
|
-
if (snapshot.parallelRecommended) {
|
|
5709
|
-
lines.push("\u5E76\u884C\u5EFA\u8BAE\uFF1A\u989D\u5EA6\u5BCC\u4F59\u4E14\u4E34\u8FD1\u7ED3\u7B97\uFF0C\u5EFA\u8BAE\u62C6\u5206\u66F4\u591A\u5E76\u884C\u5B50\u4EFB\u52A1");
|
|
5710
|
-
}
|
|
5711
|
-
if (snapshot.codexTier !== "full") {
|
|
5712
|
-
lines.push(`Codex \u6863\u4F4D\uFF1A${snapshot.codexTier}`);
|
|
5713
|
-
}
|
|
5714
|
-
if (snapshot.claudeAdvice) {
|
|
5715
|
-
lines.push(`Claude \u5EFA\u8BAE\uFF1A${snapshot.claudeAdvice}`);
|
|
5716
|
-
}
|
|
5717
|
-
lines.push("\u6CE8\uFF1A\u767E\u5206\u6BD4\u4E3A\u8BA2\u9605\u8D26\u53F7\u7EA7\u7528\u91CF\uFF08\u540C\u673A\u5176\u4ED6\u4F1A\u8BDD\u5171\u4EAB\u540C\u4E00\u989D\u5EA6\u6C60\uFF09\u3002");
|
|
5718
|
-
return lines.join(`
|
|
5719
|
-
`);
|
|
5720
|
-
}
|
|
5721
|
-
var PHASE_LABELS, BUDGET_UNAVAILABLE_TEXT = "\u9884\u7B97\u611F\u77E5\u4E0D\u53EF\u7528\uFF1A\u672A\u68C0\u6D4B\u5230 agent-quota-guard \u63A2\u9488\uFF08~/.budget-guard/bin/budget-probe\uFF09\u6216 budget \u529F\u80FD\u5DF2\u7981\u7528\u3002\u534F\u4F5C\u4E0D\u53D7\u5F71\u54CD\u3002";
|
|
5722
|
-
var init_render = __esm(() => {
|
|
5723
|
-
PHASE_LABELS = {
|
|
5724
|
-
normal: "normal\uFF08\u6B63\u5E38\uFF09",
|
|
5725
|
-
balance: "balance\uFF08\u9700\u5747\u8861\uFF09",
|
|
5726
|
-
parallel: "parallel\uFF08\u5EFA\u8BAE\u5E76\u884C\u63D0\u901F\uFF09",
|
|
5727
|
-
paused: "paused\uFF08\u9884\u7B97\u5E72\u9884\u4E2D\uFF09"
|
|
5728
|
-
};
|
|
5729
|
-
});
|
|
5730
|
-
|
|
5731
6012
|
// src/cli/budget.ts
|
|
5732
6013
|
var exports_budget = {};
|
|
5733
6014
|
__export(exports_budget, {
|
|
@@ -5968,7 +6249,9 @@ async function main(command, restArgs) {
|
|
|
5968
6249
|
if (command && NOTIFY_COMMANDS.has(command)) {
|
|
5969
6250
|
try {
|
|
5970
6251
|
const { maybeNotifyUpdate: maybeNotifyUpdate2 } = await Promise.resolve().then(() => (init_update_notifier(), exports_update_notifier));
|
|
5971
|
-
maybeNotifyUpdate2({ refresh: REFRESH_COMMANDS.has(command) });
|
|
6252
|
+
const decision = await maybeNotifyUpdate2({ refresh: REFRESH_COMMANDS.has(command) });
|
|
6253
|
+
if (decision === "updated")
|
|
6254
|
+
process.exit(0);
|
|
5972
6255
|
} catch {}
|
|
5973
6256
|
}
|
|
5974
6257
|
switch (command) {
|