@sma1lboy/kobe 0.5.9 → 0.5.10
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/bin/kobed.js +91 -1
- package/dist/cli/index.js +300 -168
- package/package.json +1 -1
package/dist/bin/kobed.js
CHANGED
|
@@ -2506,6 +2506,86 @@ var init_claude_settings = __esm(() => {
|
|
|
2506
2506
|
SETTINGS_PATH = join4(homedir6(), ".claude", "settings.json");
|
|
2507
2507
|
});
|
|
2508
2508
|
|
|
2509
|
+
// src/session/usage-metrics.ts
|
|
2510
|
+
function totalContextTokens(u) {
|
|
2511
|
+
return u.input_tokens + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0);
|
|
2512
|
+
}
|
|
2513
|
+
function parseTimestampMs(value) {
|
|
2514
|
+
const ms = new Date(value).getTime();
|
|
2515
|
+
return Number.isFinite(ms) ? ms : null;
|
|
2516
|
+
}
|
|
2517
|
+
function mergeIntervals(intervals) {
|
|
2518
|
+
if (intervals.length === 0)
|
|
2519
|
+
return [];
|
|
2520
|
+
const sorted = [...intervals].sort((a, b) => a.startMs - b.startMs);
|
|
2521
|
+
const first = sorted[0];
|
|
2522
|
+
if (!first)
|
|
2523
|
+
return [];
|
|
2524
|
+
const merged = [{ startMs: first.startMs, endMs: first.endMs }];
|
|
2525
|
+
for (let i = 1;i < sorted.length; i++) {
|
|
2526
|
+
const current = sorted[i];
|
|
2527
|
+
const last = merged[merged.length - 1];
|
|
2528
|
+
if (!current || !last)
|
|
2529
|
+
continue;
|
|
2530
|
+
if (current.startMs <= last.endMs) {
|
|
2531
|
+
last.endMs = Math.max(last.endMs, current.endMs);
|
|
2532
|
+
} else {
|
|
2533
|
+
merged.push({ startMs: current.startMs, endMs: current.endMs });
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
return merged;
|
|
2537
|
+
}
|
|
2538
|
+
function durationMs(intervals) {
|
|
2539
|
+
return intervals.reduce((total, interval) => total + (interval.endMs - interval.startMs), 0);
|
|
2540
|
+
}
|
|
2541
|
+
function deriveSessionUsageMetrics(past) {
|
|
2542
|
+
let latestUsage;
|
|
2543
|
+
let latestUsageTimestampMs = null;
|
|
2544
|
+
let lastUserTimestampMs = null;
|
|
2545
|
+
let inputTokens = 0;
|
|
2546
|
+
let outputTokens = 0;
|
|
2547
|
+
const intervals = [];
|
|
2548
|
+
for (const message of past) {
|
|
2549
|
+
const timestampMs = parseTimestampMs(message.timestamp);
|
|
2550
|
+
if (message.role === "user" && timestampMs !== null) {
|
|
2551
|
+
lastUserTimestampMs = timestampMs;
|
|
2552
|
+
continue;
|
|
2553
|
+
}
|
|
2554
|
+
if (message.role !== "assistant" || !message.usage)
|
|
2555
|
+
continue;
|
|
2556
|
+
if (timestampMs !== null && (latestUsageTimestampMs === null || timestampMs > latestUsageTimestampMs)) {
|
|
2557
|
+
latestUsageTimestampMs = timestampMs;
|
|
2558
|
+
latestUsage = message.usage;
|
|
2559
|
+
} else if (latestUsage === undefined) {
|
|
2560
|
+
latestUsage = message.usage;
|
|
2561
|
+
}
|
|
2562
|
+
inputTokens += message.usage.input_tokens;
|
|
2563
|
+
outputTokens += message.usage.output_tokens;
|
|
2564
|
+
if (timestampMs !== null && lastUserTimestampMs !== null && timestampMs > lastUserTimestampMs) {
|
|
2565
|
+
intervals.push({ startMs: lastUserTimestampMs, endMs: timestampMs });
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
if (!latestUsage)
|
|
2569
|
+
return;
|
|
2570
|
+
const totalDurationMs = durationMs(mergeIntervals(intervals));
|
|
2571
|
+
if (totalDurationMs <= 0)
|
|
2572
|
+
return latestUsage;
|
|
2573
|
+
return {
|
|
2574
|
+
...latestUsage,
|
|
2575
|
+
total_speed_tokens_per_second: (inputTokens + outputTokens) / (totalDurationMs / 1000)
|
|
2576
|
+
};
|
|
2577
|
+
}
|
|
2578
|
+
function withTotalSpeedForTurn(usage, startedAtIso, endedAtIso) {
|
|
2579
|
+
const startMs = startedAtIso ? parseTimestampMs(startedAtIso) : null;
|
|
2580
|
+
const endMs = parseTimestampMs(endedAtIso);
|
|
2581
|
+
if (startMs === null || endMs === null || endMs <= startMs)
|
|
2582
|
+
return usage;
|
|
2583
|
+
return {
|
|
2584
|
+
...usage,
|
|
2585
|
+
total_speed_tokens_per_second: (usage.input_tokens + usage.output_tokens) / ((endMs - startMs) / 1000)
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2509
2589
|
// src/env.ts
|
|
2510
2590
|
import { homedir as homedir7 } from "os";
|
|
2511
2591
|
import { join as join5 } from "path";
|
|
@@ -3588,6 +3668,14 @@ class Orchestrator {
|
|
|
3588
3668
|
return [];
|
|
3589
3669
|
}
|
|
3590
3670
|
}
|
|
3671
|
+
async readHistoryWithMetrics(sessionId) {
|
|
3672
|
+
const messages = await this.readHistory(sessionId);
|
|
3673
|
+
const usageMetrics = deriveSessionUsageMetrics(messages);
|
|
3674
|
+
return {
|
|
3675
|
+
messages,
|
|
3676
|
+
...usageMetrics ? { usageMetrics } : {}
|
|
3677
|
+
};
|
|
3678
|
+
}
|
|
3591
3679
|
async listSessions(id) {
|
|
3592
3680
|
const task = this.requireTask(id);
|
|
3593
3681
|
if (!task.worktreePath)
|
|
@@ -5123,6 +5211,7 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
5123
5211
|
const result = await readTaskHistory(orch, taskId, sessionId, limit, before);
|
|
5124
5212
|
return {
|
|
5125
5213
|
messages: serializeMessages(result.messages),
|
|
5214
|
+
...result.usageMetrics ? { usageMetrics: result.usageMetrics } : {},
|
|
5126
5215
|
nextBefore: result.nextBefore,
|
|
5127
5216
|
hasMore: result.hasMore
|
|
5128
5217
|
};
|
|
@@ -5270,6 +5359,7 @@ async function readTaskHistory(orch, taskId, requestedSessionId, limit, before)
|
|
|
5270
5359
|
if (!sessionId)
|
|
5271
5360
|
return { messages: [], nextBefore: null, hasMore: false };
|
|
5272
5361
|
const messages = await orch.readHistory(sessionId);
|
|
5362
|
+
const usageMetrics = deriveSessionUsageMetrics(messages);
|
|
5273
5363
|
const beforeIdx = before ? messages.findIndex((m) => `${m.timestamp}:${m.sessionId}` === before) : -1;
|
|
5274
5364
|
const end = beforeIdx >= 0 ? beforeIdx : messages.length;
|
|
5275
5365
|
const start = Math.max(0, end - limit);
|
|
@@ -5277,7 +5367,7 @@ async function readTaskHistory(orch, taskId, requestedSessionId, limit, before)
|
|
|
5277
5367
|
const hasMore = start > 0;
|
|
5278
5368
|
const first = page[0];
|
|
5279
5369
|
const nextBefore = hasMore && first ? `${first.timestamp}:${first.sessionId}` : null;
|
|
5280
|
-
return { messages: page, nextBefore, hasMore };
|
|
5370
|
+
return { messages: page, ...usageMetrics ? { usageMetrics } : {}, nextBefore, hasMore };
|
|
5281
5371
|
}
|
|
5282
5372
|
function writeFrame(client, frame) {
|
|
5283
5373
|
client.socket.write(frameToLine(frame));
|
package/dist/cli/index.js
CHANGED
|
@@ -8857,7 +8857,7 @@ var init_package = __esm(() => {
|
|
|
8857
8857
|
package_default = {
|
|
8858
8858
|
$schema: "https://json.schemastore.org/package.json",
|
|
8859
8859
|
name: "@sma1lboy/kobe",
|
|
8860
|
-
version: "0.5.
|
|
8860
|
+
version: "0.5.10",
|
|
8861
8861
|
description: "TUI orchestrator for Claude Code (codename)",
|
|
8862
8862
|
type: "module",
|
|
8863
8863
|
packageManager: "bun@1.3.13",
|
|
@@ -8922,6 +8922,9 @@ function repoSlug() {
|
|
|
8922
8922
|
return null;
|
|
8923
8923
|
return `${m[1]}/${m[2]}`;
|
|
8924
8924
|
}
|
|
8925
|
+
function recommendedGlobalInstallCommand() {
|
|
8926
|
+
return `npm install -g ${PACKAGE_NAME}@latest`;
|
|
8927
|
+
}
|
|
8925
8928
|
function cachePath() {
|
|
8926
8929
|
return join3(kobeStateDir(), "version-check.json");
|
|
8927
8930
|
}
|
|
@@ -9037,13 +9040,13 @@ function releasePageUrl(version) {
|
|
|
9037
9040
|
return null;
|
|
9038
9041
|
return `https://github.com/${slug}/releases/tag/v${version}`;
|
|
9039
9042
|
}
|
|
9040
|
-
var CURRENT_VERSION, PACKAGE_NAME,
|
|
9043
|
+
var CURRENT_VERSION, PACKAGE_NAME, UPDATE_SCRIPT_URL = "https://raw.githubusercontent.com/Sma1lboy/kobe/main/scripts/update.sh", UPDATE_COMMAND, CACHE_TTL_MS, FETCH_TIMEOUT_MS = 3000;
|
|
9041
9044
|
var init_version = __esm(() => {
|
|
9042
9045
|
init_package();
|
|
9043
9046
|
init_env();
|
|
9044
9047
|
CURRENT_VERSION = package_default.version;
|
|
9045
9048
|
PACKAGE_NAME = package_default.name;
|
|
9046
|
-
|
|
9049
|
+
UPDATE_COMMAND = `curl -fsSL ${UPDATE_SCRIPT_URL} | sh`;
|
|
9047
9050
|
CACHE_TTL_MS = 6 * 60 * 60 * 1000;
|
|
9048
9051
|
});
|
|
9049
9052
|
|
|
@@ -9375,6 +9378,93 @@ var init_diagnose = __esm(() => {
|
|
|
9375
9378
|
STATUS_ORDER = ["backlog", "in_progress", "in_review", "done", "canceled", "error"];
|
|
9376
9379
|
});
|
|
9377
9380
|
|
|
9381
|
+
// src/cli/update.ts
|
|
9382
|
+
var exports_update = {};
|
|
9383
|
+
__export(exports_update, {
|
|
9384
|
+
updatePlan: () => updatePlan,
|
|
9385
|
+
runUpdateSubcommand: () => runUpdateSubcommand,
|
|
9386
|
+
parseUpdateArgs: () => parseUpdateArgs
|
|
9387
|
+
});
|
|
9388
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
9389
|
+
function fail(message) {
|
|
9390
|
+
process.stderr.write(`kobe update: ${message}
|
|
9391
|
+
`);
|
|
9392
|
+
process.exit(1);
|
|
9393
|
+
}
|
|
9394
|
+
function updatePlan() {
|
|
9395
|
+
return {
|
|
9396
|
+
command: "sh",
|
|
9397
|
+
args: ["-c", UPDATE_COMMAND],
|
|
9398
|
+
display: UPDATE_COMMAND
|
|
9399
|
+
};
|
|
9400
|
+
}
|
|
9401
|
+
function parseUpdateArgs(args) {
|
|
9402
|
+
let dryRun = false;
|
|
9403
|
+
for (let i = 0;i < args.length; i += 1) {
|
|
9404
|
+
const arg = args[i];
|
|
9405
|
+
if (arg === "--help" || arg === "-h" || arg === "help")
|
|
9406
|
+
return { help: true, dryRun };
|
|
9407
|
+
if (arg === "--dry-run") {
|
|
9408
|
+
dryRun = true;
|
|
9409
|
+
continue;
|
|
9410
|
+
}
|
|
9411
|
+
fail(`unknown argument "${arg}"`);
|
|
9412
|
+
}
|
|
9413
|
+
return { help: false, dryRun };
|
|
9414
|
+
}
|
|
9415
|
+
function printUsage(out) {
|
|
9416
|
+
out.write([
|
|
9417
|
+
"Usage: kobe update [--dry-run]",
|
|
9418
|
+
"",
|
|
9419
|
+
"Runs kobe's GitHub-hosted update script.",
|
|
9420
|
+
"",
|
|
9421
|
+
"Default command:",
|
|
9422
|
+
` ${UPDATE_COMMAND}`,
|
|
9423
|
+
"",
|
|
9424
|
+
"Script URL:",
|
|
9425
|
+
` ${UPDATE_SCRIPT_URL}`,
|
|
9426
|
+
"",
|
|
9427
|
+
"Manual fallback:",
|
|
9428
|
+
` ${recommendedGlobalInstallCommand()}`,
|
|
9429
|
+
"",
|
|
9430
|
+
"Examples:",
|
|
9431
|
+
" kobe update",
|
|
9432
|
+
" kobe update --dry-run",
|
|
9433
|
+
""
|
|
9434
|
+
].join(`
|
|
9435
|
+
`));
|
|
9436
|
+
}
|
|
9437
|
+
async function runUpdateSubcommand(args, deps) {
|
|
9438
|
+
const io = {
|
|
9439
|
+
spawn: deps?.spawn ?? spawnSync6,
|
|
9440
|
+
stdout: deps?.stdout ?? process.stdout,
|
|
9441
|
+
stderr: deps?.stderr ?? process.stderr,
|
|
9442
|
+
exit: deps?.exit ?? ((code) => process.exit(code))
|
|
9443
|
+
};
|
|
9444
|
+
const parsed = parseUpdateArgs(args);
|
|
9445
|
+
if (parsed.help) {
|
|
9446
|
+
printUsage(io.stdout);
|
|
9447
|
+
return;
|
|
9448
|
+
}
|
|
9449
|
+
const plan = updatePlan();
|
|
9450
|
+
io.stdout.write(`kobe ${CURRENT_VERSION} -> latest
|
|
9451
|
+
`);
|
|
9452
|
+
io.stdout.write(`running: ${plan.display}
|
|
9453
|
+
`);
|
|
9454
|
+
if (parsed.dryRun)
|
|
9455
|
+
return;
|
|
9456
|
+
const result = io.spawn(plan.command, plan.args, { stdio: "inherit" });
|
|
9457
|
+
if (result.error) {
|
|
9458
|
+
io.stderr.write(`kobe update: failed to run ${plan.command}: ${result.error.message}
|
|
9459
|
+
`);
|
|
9460
|
+
io.exit(1);
|
|
9461
|
+
}
|
|
9462
|
+
io.exit(result.status ?? 1);
|
|
9463
|
+
}
|
|
9464
|
+
var init_update = __esm(() => {
|
|
9465
|
+
init_version();
|
|
9466
|
+
});
|
|
9467
|
+
|
|
9378
9468
|
// src/tui/context/theme/schema.ts
|
|
9379
9469
|
function isPlainObject(v) {
|
|
9380
9470
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -9475,7 +9565,7 @@ __export(exports_theme, {
|
|
|
9475
9565
|
});
|
|
9476
9566
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync as readdirSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
9477
9567
|
import { basename as basename2, join as join6, resolve } from "path";
|
|
9478
|
-
function
|
|
9568
|
+
function fail2(message) {
|
|
9479
9569
|
process.stderr.write(`kobe theme: ${message}
|
|
9480
9570
|
`);
|
|
9481
9571
|
process.exit(1);
|
|
@@ -9513,10 +9603,10 @@ async function readSource(source) {
|
|
|
9513
9603
|
try {
|
|
9514
9604
|
res = await fetch(source);
|
|
9515
9605
|
} catch (err) {
|
|
9516
|
-
|
|
9606
|
+
fail2(`failed to fetch ${source}: ${err instanceof Error ? err.message : String(err)}`);
|
|
9517
9607
|
}
|
|
9518
9608
|
if (!res.ok) {
|
|
9519
|
-
|
|
9609
|
+
fail2(`failed to fetch ${source}: HTTP ${res.status} ${res.statusText}`);
|
|
9520
9610
|
}
|
|
9521
9611
|
const text2 = await res.text();
|
|
9522
9612
|
const cleanPath = source.split(/[?#]/)[0] ?? source;
|
|
@@ -9529,7 +9619,7 @@ async function readSource(source) {
|
|
|
9529
9619
|
try {
|
|
9530
9620
|
text = readFileSync3(abs, "utf8");
|
|
9531
9621
|
} catch (err) {
|
|
9532
|
-
|
|
9622
|
+
fail2(`failed to read ${abs}: ${err instanceof Error ? err.message : String(err)}`);
|
|
9533
9623
|
}
|
|
9534
9624
|
const file = basename2(abs);
|
|
9535
9625
|
const defaultName = file.endsWith(".json") ? file.slice(0, -".json".length) : file;
|
|
@@ -9548,7 +9638,7 @@ function parseAddArgs(args) {
|
|
|
9548
9638
|
if (a === "--name" || a === "-n") {
|
|
9549
9639
|
const next = args[i + 1];
|
|
9550
9640
|
if (next === undefined)
|
|
9551
|
-
|
|
9641
|
+
fail2("--name requires a value");
|
|
9552
9642
|
name = next;
|
|
9553
9643
|
i += 1;
|
|
9554
9644
|
continue;
|
|
@@ -9558,15 +9648,15 @@ function parseAddArgs(args) {
|
|
|
9558
9648
|
continue;
|
|
9559
9649
|
}
|
|
9560
9650
|
if (a.startsWith("--"))
|
|
9561
|
-
|
|
9651
|
+
fail2(`unknown flag: ${a}`);
|
|
9562
9652
|
if (source === null) {
|
|
9563
9653
|
source = a;
|
|
9564
9654
|
continue;
|
|
9565
9655
|
}
|
|
9566
|
-
|
|
9656
|
+
fail2(`unexpected positional argument: ${a}`);
|
|
9567
9657
|
}
|
|
9568
9658
|
if (source === null)
|
|
9569
|
-
|
|
9659
|
+
fail2("missing <source> (URL or path to theme JSON)");
|
|
9570
9660
|
return { source, opts: { name, force } };
|
|
9571
9661
|
}
|
|
9572
9662
|
async function addTheme2(args) {
|
|
@@ -9576,21 +9666,21 @@ async function addTheme2(args) {
|
|
|
9576
9666
|
try {
|
|
9577
9667
|
parsed = JSON.parse(text);
|
|
9578
9668
|
} catch (err) {
|
|
9579
|
-
|
|
9669
|
+
fail2(`source is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
9580
9670
|
}
|
|
9581
9671
|
const result = validateTheme(parsed);
|
|
9582
9672
|
if (!result.ok) {
|
|
9583
|
-
|
|
9673
|
+
fail2(`source is not a valid kobe theme: ${result.reason}`);
|
|
9584
9674
|
}
|
|
9585
9675
|
const name = opts.name ?? defaultName;
|
|
9586
9676
|
if (!name || !/^[a-zA-Z0-9._-]+$/.test(name)) {
|
|
9587
|
-
|
|
9677
|
+
fail2(`invalid theme name "${name}" (use letters, digits, '.', '_', '-')`);
|
|
9588
9678
|
}
|
|
9589
9679
|
const dir = userThemesDir();
|
|
9590
9680
|
mkdirSync2(dir, { recursive: true });
|
|
9591
9681
|
const dest = join6(dir, `${name}.json`);
|
|
9592
9682
|
if (existsSync3(dest) && !opts.force) {
|
|
9593
|
-
|
|
9683
|
+
fail2(`${dest} already exists (pass --force to overwrite)`);
|
|
9594
9684
|
}
|
|
9595
9685
|
writeFileSync2(dest, `${JSON.stringify(result.theme, null, 2)}
|
|
9596
9686
|
`, "utf8");
|
|
@@ -9600,21 +9690,21 @@ async function addTheme2(args) {
|
|
|
9600
9690
|
function removeTheme(args) {
|
|
9601
9691
|
const name = args[0];
|
|
9602
9692
|
if (!name)
|
|
9603
|
-
|
|
9693
|
+
fail2("missing <name>");
|
|
9604
9694
|
if (args.length > 1)
|
|
9605
|
-
|
|
9695
|
+
fail2(`unexpected extra arguments after "${name}"`);
|
|
9606
9696
|
if (BUNDLED_NAMES.includes(name)) {
|
|
9607
|
-
|
|
9697
|
+
fail2(`"${name}" is a built-in theme and cannot be removed`);
|
|
9608
9698
|
}
|
|
9609
9699
|
const dest = join6(userThemesDir(), `${name}.json`);
|
|
9610
9700
|
if (!existsSync3(dest)) {
|
|
9611
|
-
|
|
9701
|
+
fail2(`no user theme named "${name}" (looked for ${dest})`);
|
|
9612
9702
|
}
|
|
9613
9703
|
unlinkSync(dest);
|
|
9614
9704
|
process.stdout.write(`removed theme "${name}" (${dest})
|
|
9615
9705
|
`);
|
|
9616
9706
|
}
|
|
9617
|
-
function
|
|
9707
|
+
function printUsage2() {
|
|
9618
9708
|
process.stderr.write([
|
|
9619
9709
|
"Usage: kobe theme <command> [args]",
|
|
9620
9710
|
"",
|
|
@@ -9633,14 +9723,14 @@ function printUsage() {
|
|
|
9633
9723
|
async function runThemeSubcommand(args) {
|
|
9634
9724
|
const [action, ...rest] = args;
|
|
9635
9725
|
if (!action || action === "--help" || action === "-h" || action === "help") {
|
|
9636
|
-
|
|
9726
|
+
printUsage2();
|
|
9637
9727
|
if (!action)
|
|
9638
9728
|
process.exit(1);
|
|
9639
9729
|
return;
|
|
9640
9730
|
}
|
|
9641
9731
|
if (action === "list" || action === "ls") {
|
|
9642
9732
|
if (rest.length > 0)
|
|
9643
|
-
|
|
9733
|
+
fail2(`"${action}" takes no arguments`);
|
|
9644
9734
|
listThemes2();
|
|
9645
9735
|
return;
|
|
9646
9736
|
}
|
|
@@ -9652,7 +9742,7 @@ async function runThemeSubcommand(args) {
|
|
|
9652
9742
|
removeTheme(rest);
|
|
9653
9743
|
return;
|
|
9654
9744
|
}
|
|
9655
|
-
|
|
9745
|
+
fail2(`unknown action "${action}" (try "list", "add", or "remove")`);
|
|
9656
9746
|
}
|
|
9657
9747
|
var BUNDLED_NAMES;
|
|
9658
9748
|
var init_theme2 = __esm(() => {
|
|
@@ -9775,7 +9865,7 @@ async function handleMcpFrame(client, line) {
|
|
|
9775
9865
|
process.stdout.write(`${JSON.stringify(out)}
|
|
9776
9866
|
`);
|
|
9777
9867
|
};
|
|
9778
|
-
const
|
|
9868
|
+
const fail3 = (code, message) => {
|
|
9779
9869
|
const out = { jsonrpc: "2.0", id: msg.id, error: { code, message } };
|
|
9780
9870
|
process.stdout.write(`${JSON.stringify(out)}
|
|
9781
9871
|
`);
|
|
@@ -9797,7 +9887,7 @@ async function handleMcpFrame(client, line) {
|
|
|
9797
9887
|
const name = params.name;
|
|
9798
9888
|
const args = params.arguments ?? {};
|
|
9799
9889
|
if (!name) {
|
|
9800
|
-
|
|
9890
|
+
fail3(-32602, "missing tool name");
|
|
9801
9891
|
return;
|
|
9802
9892
|
}
|
|
9803
9893
|
const result = await invokeTool(client, name, args);
|
|
@@ -9807,11 +9897,11 @@ async function handleMcpFrame(client, line) {
|
|
|
9807
9897
|
return;
|
|
9808
9898
|
}
|
|
9809
9899
|
default:
|
|
9810
|
-
|
|
9900
|
+
fail3(-32601, `method not found: ${msg.method}`);
|
|
9811
9901
|
return;
|
|
9812
9902
|
}
|
|
9813
9903
|
} catch (err) {
|
|
9814
|
-
|
|
9904
|
+
fail3(-32000, err instanceof Error ? err.message : String(err));
|
|
9815
9905
|
}
|
|
9816
9906
|
}
|
|
9817
9907
|
async function invokeTool(client, name, args) {
|
|
@@ -10174,6 +10264,86 @@ var init_claude_settings = __esm(() => {
|
|
|
10174
10264
|
SETTINGS_PATH = join9(homedir6(), ".claude", "settings.json");
|
|
10175
10265
|
});
|
|
10176
10266
|
|
|
10267
|
+
// src/session/usage-metrics.ts
|
|
10268
|
+
function totalContextTokens(u) {
|
|
10269
|
+
return u.input_tokens + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0);
|
|
10270
|
+
}
|
|
10271
|
+
function parseTimestampMs(value) {
|
|
10272
|
+
const ms = new Date(value).getTime();
|
|
10273
|
+
return Number.isFinite(ms) ? ms : null;
|
|
10274
|
+
}
|
|
10275
|
+
function mergeIntervals(intervals) {
|
|
10276
|
+
if (intervals.length === 0)
|
|
10277
|
+
return [];
|
|
10278
|
+
const sorted = [...intervals].sort((a, b) => a.startMs - b.startMs);
|
|
10279
|
+
const first = sorted[0];
|
|
10280
|
+
if (!first)
|
|
10281
|
+
return [];
|
|
10282
|
+
const merged = [{ startMs: first.startMs, endMs: first.endMs }];
|
|
10283
|
+
for (let i = 1;i < sorted.length; i++) {
|
|
10284
|
+
const current = sorted[i];
|
|
10285
|
+
const last = merged[merged.length - 1];
|
|
10286
|
+
if (!current || !last)
|
|
10287
|
+
continue;
|
|
10288
|
+
if (current.startMs <= last.endMs) {
|
|
10289
|
+
last.endMs = Math.max(last.endMs, current.endMs);
|
|
10290
|
+
} else {
|
|
10291
|
+
merged.push({ startMs: current.startMs, endMs: current.endMs });
|
|
10292
|
+
}
|
|
10293
|
+
}
|
|
10294
|
+
return merged;
|
|
10295
|
+
}
|
|
10296
|
+
function durationMs(intervals) {
|
|
10297
|
+
return intervals.reduce((total, interval) => total + (interval.endMs - interval.startMs), 0);
|
|
10298
|
+
}
|
|
10299
|
+
function deriveSessionUsageMetrics(past) {
|
|
10300
|
+
let latestUsage;
|
|
10301
|
+
let latestUsageTimestampMs = null;
|
|
10302
|
+
let lastUserTimestampMs = null;
|
|
10303
|
+
let inputTokens = 0;
|
|
10304
|
+
let outputTokens = 0;
|
|
10305
|
+
const intervals = [];
|
|
10306
|
+
for (const message of past) {
|
|
10307
|
+
const timestampMs = parseTimestampMs(message.timestamp);
|
|
10308
|
+
if (message.role === "user" && timestampMs !== null) {
|
|
10309
|
+
lastUserTimestampMs = timestampMs;
|
|
10310
|
+
continue;
|
|
10311
|
+
}
|
|
10312
|
+
if (message.role !== "assistant" || !message.usage)
|
|
10313
|
+
continue;
|
|
10314
|
+
if (timestampMs !== null && (latestUsageTimestampMs === null || timestampMs > latestUsageTimestampMs)) {
|
|
10315
|
+
latestUsageTimestampMs = timestampMs;
|
|
10316
|
+
latestUsage = message.usage;
|
|
10317
|
+
} else if (latestUsage === undefined) {
|
|
10318
|
+
latestUsage = message.usage;
|
|
10319
|
+
}
|
|
10320
|
+
inputTokens += message.usage.input_tokens;
|
|
10321
|
+
outputTokens += message.usage.output_tokens;
|
|
10322
|
+
if (timestampMs !== null && lastUserTimestampMs !== null && timestampMs > lastUserTimestampMs) {
|
|
10323
|
+
intervals.push({ startMs: lastUserTimestampMs, endMs: timestampMs });
|
|
10324
|
+
}
|
|
10325
|
+
}
|
|
10326
|
+
if (!latestUsage)
|
|
10327
|
+
return;
|
|
10328
|
+
const totalDurationMs = durationMs(mergeIntervals(intervals));
|
|
10329
|
+
if (totalDurationMs <= 0)
|
|
10330
|
+
return latestUsage;
|
|
10331
|
+
return {
|
|
10332
|
+
...latestUsage,
|
|
10333
|
+
total_speed_tokens_per_second: (inputTokens + outputTokens) / (totalDurationMs / 1000)
|
|
10334
|
+
};
|
|
10335
|
+
}
|
|
10336
|
+
function withTotalSpeedForTurn(usage, startedAtIso, endedAtIso) {
|
|
10337
|
+
const startMs = startedAtIso ? parseTimestampMs(startedAtIso) : null;
|
|
10338
|
+
const endMs = parseTimestampMs(endedAtIso);
|
|
10339
|
+
if (startMs === null || endMs === null || endMs <= startMs)
|
|
10340
|
+
return usage;
|
|
10341
|
+
return {
|
|
10342
|
+
...usage,
|
|
10343
|
+
total_speed_tokens_per_second: (usage.input_tokens + usage.output_tokens) / ((endMs - startMs) / 1000)
|
|
10344
|
+
};
|
|
10345
|
+
}
|
|
10346
|
+
|
|
10177
10347
|
// src/orchestrator/metadata-suggester.ts
|
|
10178
10348
|
import { spawn as spawn3 } from "child_process";
|
|
10179
10349
|
|
|
@@ -10353,10 +10523,10 @@ class InMemoryPendingInputBroker {
|
|
|
10353
10523
|
}
|
|
10354
10524
|
|
|
10355
10525
|
// src/orchestrator/pr/build.ts
|
|
10356
|
-
import { spawnSync as
|
|
10526
|
+
import { spawnSync as spawnSync7 } from "child_process";
|
|
10357
10527
|
function git(cwd, args) {
|
|
10358
10528
|
try {
|
|
10359
|
-
const out =
|
|
10529
|
+
const out = spawnSync7("git", args.slice(), {
|
|
10360
10530
|
cwd,
|
|
10361
10531
|
encoding: "utf8",
|
|
10362
10532
|
timeout: GIT_TIMEOUT_MS
|
|
@@ -11049,6 +11219,14 @@ class Orchestrator {
|
|
|
11049
11219
|
return [];
|
|
11050
11220
|
}
|
|
11051
11221
|
}
|
|
11222
|
+
async readHistoryWithMetrics(sessionId) {
|
|
11223
|
+
const messages = await this.readHistory(sessionId);
|
|
11224
|
+
const usageMetrics = deriveSessionUsageMetrics(messages);
|
|
11225
|
+
return {
|
|
11226
|
+
messages,
|
|
11227
|
+
...usageMetrics ? { usageMetrics } : {}
|
|
11228
|
+
};
|
|
11229
|
+
}
|
|
11052
11230
|
async listSessions(id) {
|
|
11053
11231
|
const task = this.requireTask(id);
|
|
11054
11232
|
if (!task.worktreePath)
|
|
@@ -11524,15 +11702,21 @@ class RemoteOrchestrator {
|
|
|
11524
11702
|
await this.client.request("chat.tab.activate", { taskId, tabId });
|
|
11525
11703
|
}
|
|
11526
11704
|
async readHistory(sessionId) {
|
|
11705
|
+
return (await this.readHistoryWithMetrics(sessionId)).messages;
|
|
11706
|
+
}
|
|
11707
|
+
async readHistoryWithMetrics(sessionId) {
|
|
11527
11708
|
const task = this.tasksAcc().find((t) => t.sessionId === sessionId || t.tabs.some((tab) => tab.sessionId === sessionId));
|
|
11528
11709
|
if (!task)
|
|
11529
|
-
return [];
|
|
11710
|
+
return { messages: [] };
|
|
11530
11711
|
const res = await this.client.request("chat.history", {
|
|
11531
11712
|
taskId: task.id,
|
|
11532
11713
|
sessionId,
|
|
11533
11714
|
limit: 500
|
|
11534
11715
|
});
|
|
11535
|
-
return
|
|
11716
|
+
return {
|
|
11717
|
+
messages: res.messages,
|
|
11718
|
+
...res.usageMetrics ? { usageMetrics: res.usageMetrics } : {}
|
|
11719
|
+
};
|
|
11536
11720
|
}
|
|
11537
11721
|
async listSessions(taskId) {
|
|
11538
11722
|
const res = await this.client.request("chat.sessions", { taskId });
|
|
@@ -11685,12 +11869,12 @@ var init_remote_orchestrator = __esm(() => {
|
|
|
11685
11869
|
});
|
|
11686
11870
|
|
|
11687
11871
|
// src/orchestrator/worktree/git.ts
|
|
11688
|
-
import { spawnSync as
|
|
11872
|
+
import { spawnSync as spawnSync8 } from "child_process";
|
|
11689
11873
|
function git2(args, opts) {
|
|
11690
11874
|
if (!opts.cwd) {
|
|
11691
11875
|
throw new Error("git(): cwd is required; refusing to inherit from process.cwd()");
|
|
11692
11876
|
}
|
|
11693
|
-
const proc =
|
|
11877
|
+
const proc = spawnSync8("git", [...args], {
|
|
11694
11878
|
cwd: opts.cwd,
|
|
11695
11879
|
env: opts.env ? { ...process.env, ...opts.env } : process.env,
|
|
11696
11880
|
encoding: "utf8",
|
|
@@ -15243,11 +15427,11 @@ function UpdateDialog(props) {
|
|
|
15243
15427
|
const [notes] = createResource(() => fetchReleaseNotes(props.info.latest));
|
|
15244
15428
|
const fallbackUrl = () => releasePageUrl(props.info.latest);
|
|
15245
15429
|
return (() => {
|
|
15246
|
-
var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$7 = createElement("box"), _el$8 = createElement("text"), _el$9 = createTextNode(`v`), _el$0 = createElement("text"), _el$10 = createElement("text"), _el$11 = createTextNode(`v`), _el$12 = createElement("box"), _el$13 = createElement("text"), _el$15 = createElement("box"), _el$16 = createElement("text"), _el$17 = createElement("box"), _el$18 = createElement("text"), _el$20 = createElement("box");
|
|
15430
|
+
var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$7 = createElement("box"), _el$8 = createElement("text"), _el$9 = createTextNode(`v`), _el$0 = createElement("text"), _el$10 = createElement("text"), _el$11 = createTextNode(`v`), _el$12 = createElement("box"), _el$13 = createElement("text"), _el$15 = createElement("box"), _el$16 = createElement("text"), _el$17 = createElement("box"), _el$18 = createElement("text"), _el$19 = createTextNode(`Manual fallback: `), _el$20 = createElement("box"), _el$21 = createElement("text"), _el$23 = createElement("box");
|
|
15247
15431
|
insertNode(_el$, _el$2);
|
|
15248
15432
|
insertNode(_el$, _el$7);
|
|
15249
15433
|
insertNode(_el$, _el$12);
|
|
15250
|
-
insertNode(_el$, _el$
|
|
15434
|
+
insertNode(_el$, _el$20);
|
|
15251
15435
|
setProp(_el$, "paddingLeft", 2);
|
|
15252
15436
|
setProp(_el$, "paddingRight", 2);
|
|
15253
15437
|
setProp(_el$, "gap", 1);
|
|
@@ -15270,86 +15454,91 @@ function UpdateDialog(props) {
|
|
|
15270
15454
|
insert(_el$10, () => props.info.latest, null);
|
|
15271
15455
|
insertNode(_el$12, _el$13);
|
|
15272
15456
|
insertNode(_el$12, _el$15);
|
|
15457
|
+
insertNode(_el$12, _el$17);
|
|
15273
15458
|
setProp(_el$12, "gap", 0);
|
|
15274
15459
|
insertNode(_el$13, createTextNode(`Run this to update:`));
|
|
15275
15460
|
insertNode(_el$15, _el$16);
|
|
15276
15461
|
setProp(_el$15, "paddingLeft", 2);
|
|
15277
|
-
insert(_el$16,
|
|
15462
|
+
insert(_el$16, UPDATE_COMMAND);
|
|
15278
15463
|
insertNode(_el$17, _el$18);
|
|
15279
|
-
|
|
15280
|
-
|
|
15281
|
-
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
|
|
15464
|
+
setProp(_el$17, "paddingLeft", 2);
|
|
15465
|
+
insertNode(_el$18, _el$19);
|
|
15466
|
+
insert(_el$18, recommendedGlobalInstallCommand, null);
|
|
15467
|
+
insertNode(_el$20, _el$21);
|
|
15468
|
+
insertNode(_el$20, _el$23);
|
|
15469
|
+
setProp(_el$20, "gap", 0);
|
|
15470
|
+
insertNode(_el$21, createTextNode(`What's new:`));
|
|
15471
|
+
setProp(_el$23, "paddingLeft", 2);
|
|
15472
|
+
setProp(_el$23, "paddingTop", 1);
|
|
15473
|
+
insert(_el$23, createComponent2(Switch, {
|
|
15285
15474
|
get children() {
|
|
15286
15475
|
return [createComponent2(Match, {
|
|
15287
15476
|
get when() {
|
|
15288
15477
|
return notes.loading;
|
|
15289
15478
|
},
|
|
15290
15479
|
get children() {
|
|
15291
|
-
var _el$
|
|
15292
|
-
insertNode(_el$
|
|
15293
|
-
effect((_$p) => setProp(_el$
|
|
15294
|
-
return _el$
|
|
15480
|
+
var _el$24 = createElement("text");
|
|
15481
|
+
insertNode(_el$24, createTextNode(`Loading release notes\u2026`));
|
|
15482
|
+
effect((_$p) => setProp(_el$24, "fg", theme.textMuted, _$p));
|
|
15483
|
+
return _el$24;
|
|
15295
15484
|
}
|
|
15296
15485
|
}), createComponent2(Match, {
|
|
15297
15486
|
get when() {
|
|
15298
15487
|
return notes() === null;
|
|
15299
15488
|
},
|
|
15300
15489
|
get children() {
|
|
15301
|
-
var _el$
|
|
15302
|
-
insertNode(_el$
|
|
15303
|
-
setProp(_el$
|
|
15304
|
-
insertNode(_el$
|
|
15305
|
-
insert(_el$
|
|
15490
|
+
var _el$26 = createElement("box"), _el$27 = createElement("text");
|
|
15491
|
+
insertNode(_el$26, _el$27);
|
|
15492
|
+
setProp(_el$26, "gap", 0);
|
|
15493
|
+
insertNode(_el$27, createTextNode(`(couldn't reach GitHub \u2014 see the release page directly)`));
|
|
15494
|
+
insert(_el$26, createComponent2(Show, {
|
|
15306
15495
|
get when() {
|
|
15307
15496
|
return fallbackUrl();
|
|
15308
15497
|
},
|
|
15309
15498
|
get children() {
|
|
15310
|
-
var _el$
|
|
15311
|
-
insert(_el$
|
|
15312
|
-
effect((_$p) => setProp(_el$
|
|
15313
|
-
return _el$
|
|
15499
|
+
var _el$29 = createElement("text");
|
|
15500
|
+
insert(_el$29, fallbackUrl);
|
|
15501
|
+
effect((_$p) => setProp(_el$29, "fg", theme.accent, _$p));
|
|
15502
|
+
return _el$29;
|
|
15314
15503
|
}
|
|
15315
15504
|
}), null);
|
|
15316
|
-
effect((_$p) => setProp(_el$
|
|
15317
|
-
return _el$
|
|
15505
|
+
effect((_$p) => setProp(_el$27, "fg", theme.textMuted, _$p));
|
|
15506
|
+
return _el$26;
|
|
15318
15507
|
}
|
|
15319
15508
|
}), createComponent2(Match, {
|
|
15320
15509
|
get when() {
|
|
15321
15510
|
return notes();
|
|
15322
15511
|
},
|
|
15323
15512
|
get children() {
|
|
15324
|
-
var _el$
|
|
15325
|
-
setProp(_el$
|
|
15326
|
-
setProp(_el$
|
|
15327
|
-
insert(_el$
|
|
15513
|
+
var _el$30 = createElement("box");
|
|
15514
|
+
setProp(_el$30, "flexDirection", "column");
|
|
15515
|
+
setProp(_el$30, "gap", 0);
|
|
15516
|
+
insert(_el$30, createComponent2(Markdown, {
|
|
15328
15517
|
get source() {
|
|
15329
15518
|
return notes()?.body ?? "";
|
|
15330
15519
|
}
|
|
15331
15520
|
}), null);
|
|
15332
|
-
insert(_el$
|
|
15521
|
+
insert(_el$30, createComponent2(Show, {
|
|
15333
15522
|
get when() {
|
|
15334
15523
|
return notes()?.url;
|
|
15335
15524
|
},
|
|
15336
15525
|
get children() {
|
|
15337
|
-
var _el$
|
|
15338
|
-
insertNode(_el$
|
|
15339
|
-
setProp(_el$
|
|
15340
|
-
insertNode(_el$
|
|
15341
|
-
insert(_el$
|
|
15342
|
-
effect((_$p) => setProp(_el$
|
|
15343
|
-
return _el$
|
|
15526
|
+
var _el$31 = createElement("box"), _el$32 = createElement("text"), _el$33 = createTextNode(`Full release: `);
|
|
15527
|
+
insertNode(_el$31, _el$32);
|
|
15528
|
+
setProp(_el$31, "paddingTop", 1);
|
|
15529
|
+
insertNode(_el$32, _el$33);
|
|
15530
|
+
insert(_el$32, () => notes()?.url, null);
|
|
15531
|
+
effect((_$p) => setProp(_el$32, "fg", theme.textMuted, _$p));
|
|
15532
|
+
return _el$31;
|
|
15344
15533
|
}
|
|
15345
15534
|
}), null);
|
|
15346
|
-
return _el$
|
|
15535
|
+
return _el$30;
|
|
15347
15536
|
}
|
|
15348
15537
|
})];
|
|
15349
15538
|
}
|
|
15350
15539
|
}));
|
|
15351
15540
|
effect((_p$) => {
|
|
15352
|
-
var _v$ = TextAttributes17.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted, _v$5 = theme.textMuted, _v$6 = theme.warning, _v$7 = TextAttributes17.BOLD, _v$8 = theme.textMuted, _v$9 = theme.accent, _v$0 = TextAttributes17.BOLD, _v$1 = theme.textMuted;
|
|
15541
|
+
var _v$ = TextAttributes17.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted, _v$5 = theme.textMuted, _v$6 = theme.warning, _v$7 = TextAttributes17.BOLD, _v$8 = theme.textMuted, _v$9 = theme.accent, _v$0 = TextAttributes17.BOLD, _v$1 = theme.textMuted, _v$10 = theme.textMuted;
|
|
15353
15542
|
_v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
|
|
15354
15543
|
_v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
|
|
15355
15544
|
_v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
|
|
@@ -15361,6 +15550,7 @@ function UpdateDialog(props) {
|
|
|
15361
15550
|
_v$9 !== _p$.r && (_p$.r = setProp(_el$16, "fg", _v$9, _p$.r));
|
|
15362
15551
|
_v$0 !== _p$.d && (_p$.d = setProp(_el$16, "attributes", _v$0, _p$.d));
|
|
15363
15552
|
_v$1 !== _p$.l && (_p$.l = setProp(_el$18, "fg", _v$1, _p$.l));
|
|
15553
|
+
_v$10 !== _p$.u && (_p$.u = setProp(_el$21, "fg", _v$10, _p$.u));
|
|
15364
15554
|
return _p$;
|
|
15365
15555
|
}, {
|
|
15366
15556
|
e: undefined,
|
|
@@ -15373,7 +15563,8 @@ function UpdateDialog(props) {
|
|
|
15373
15563
|
h: undefined,
|
|
15374
15564
|
r: undefined,
|
|
15375
15565
|
d: undefined,
|
|
15376
|
-
l: undefined
|
|
15566
|
+
l: undefined,
|
|
15567
|
+
u: undefined
|
|
15377
15568
|
});
|
|
15378
15569
|
return _el$;
|
|
15379
15570
|
})();
|
|
@@ -16903,8 +17094,8 @@ function validateRepoPath(repo) {
|
|
|
16903
17094
|
if (!stat3.isDirectory())
|
|
16904
17095
|
return `not a directory: ${trimmed}`;
|
|
16905
17096
|
try {
|
|
16906
|
-
const { spawnSync:
|
|
16907
|
-
const out =
|
|
17097
|
+
const { spawnSync: spawnSync9 } = __require("child_process");
|
|
17098
|
+
const out = spawnSync9("git", ["rev-parse", "--git-dir"], {
|
|
16908
17099
|
cwd: trimmed,
|
|
16909
17100
|
encoding: "utf-8",
|
|
16910
17101
|
timeout: 2000,
|
|
@@ -16921,8 +17112,8 @@ function getCurrentBranch(repo) {
|
|
|
16921
17112
|
if (!repo)
|
|
16922
17113
|
return null;
|
|
16923
17114
|
try {
|
|
16924
|
-
const { spawnSync:
|
|
16925
|
-
const out =
|
|
17115
|
+
const { spawnSync: spawnSync9 } = __require("child_process");
|
|
17116
|
+
const out = spawnSync9("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
16926
17117
|
cwd: repo,
|
|
16927
17118
|
encoding: "utf-8",
|
|
16928
17119
|
timeout: 2000,
|
|
@@ -16942,8 +17133,8 @@ function listLocalBranches(repo) {
|
|
|
16942
17133
|
if (!repo)
|
|
16943
17134
|
return [];
|
|
16944
17135
|
try {
|
|
16945
|
-
const { spawnSync:
|
|
16946
|
-
const out =
|
|
17136
|
+
const { spawnSync: spawnSync9 } = __require("child_process");
|
|
17137
|
+
const out = spawnSync9("git", ["for-each-ref", "--format=%(refname:short)", "refs/heads/"], {
|
|
16947
17138
|
cwd: repo,
|
|
16948
17139
|
encoding: "utf-8",
|
|
16949
17140
|
timeout: 2000
|
|
@@ -18062,7 +18253,7 @@ var init_resume_dialog = __esm(() => {
|
|
|
18062
18253
|
});
|
|
18063
18254
|
|
|
18064
18255
|
// src/tui/panes/chat/composer/clipboard-image.ts
|
|
18065
|
-
import { spawnSync as
|
|
18256
|
+
import { spawnSync as spawnSync9 } from "child_process";
|
|
18066
18257
|
import { statSync as statSync4 } from "fs";
|
|
18067
18258
|
function clipboardImageSupported() {
|
|
18068
18259
|
return process.platform === "darwin";
|
|
@@ -18087,7 +18278,7 @@ function readClipboardImageMacOS(destPath) {
|
|
|
18087
18278
|
"end try"
|
|
18088
18279
|
].join(`
|
|
18089
18280
|
`);
|
|
18090
|
-
const result =
|
|
18281
|
+
const result = spawnSync9("osascript", ["-e", script], {
|
|
18091
18282
|
timeout: 5000,
|
|
18092
18283
|
stdio: ["ignore", "ignore", "ignore"]
|
|
18093
18284
|
});
|
|
@@ -21986,93 +22177,30 @@ async function loadUserSlashes(worktreePath) {
|
|
|
21986
22177
|
var init_user_slashes = () => {};
|
|
21987
22178
|
|
|
21988
22179
|
// src/tui/panes/chat/context-meter.ts
|
|
21989
|
-
function
|
|
21990
|
-
|
|
21991
|
-
|
|
21992
|
-
|
|
21993
|
-
|
|
21994
|
-
|
|
21995
|
-
}
|
|
21996
|
-
function mergeIntervals(intervals) {
|
|
21997
|
-
if (intervals.length === 0)
|
|
21998
|
-
return [];
|
|
21999
|
-
const sorted = [...intervals].sort((a, b) => a.startMs - b.startMs);
|
|
22000
|
-
const first = sorted[0];
|
|
22001
|
-
if (!first)
|
|
22002
|
-
return [];
|
|
22003
|
-
const merged = [{ startMs: first.startMs, endMs: first.endMs }];
|
|
22004
|
-
for (let i = 1;i < sorted.length; i++) {
|
|
22005
|
-
const current = sorted[i];
|
|
22006
|
-
const last = merged[merged.length - 1];
|
|
22007
|
-
if (!current || !last)
|
|
22008
|
-
continue;
|
|
22009
|
-
if (current.startMs <= last.endMs) {
|
|
22010
|
-
last.endMs = Math.max(last.endMs, current.endMs);
|
|
22011
|
-
} else {
|
|
22012
|
-
merged.push({ startMs: current.startMs, endMs: current.endMs });
|
|
22180
|
+
function parseContextWindowSize(modelIdentifier) {
|
|
22181
|
+
const delimitedMatch = /(?:\(|\[)\s*(\d+(?:[,_]\d+)*(?:\.\d+)?)\s*([km])\s*(?:\)|\])/i.exec(modelIdentifier);
|
|
22182
|
+
if (delimitedMatch?.[1] && delimitedMatch[2]) {
|
|
22183
|
+
const parsed2 = Number.parseFloat(delimitedMatch[1].replace(/[,_]/g, ""));
|
|
22184
|
+
if (Number.isFinite(parsed2) && parsed2 > 0) {
|
|
22185
|
+
return Math.round(parsed2 * (delimitedMatch[2].toLowerCase() === "m" ? 1e6 : 1000));
|
|
22013
22186
|
}
|
|
22014
22187
|
}
|
|
22015
|
-
|
|
22016
|
-
|
|
22017
|
-
|
|
22018
|
-
|
|
22019
|
-
|
|
22020
|
-
|
|
22021
|
-
|
|
22022
|
-
let latestUsageTimestampMs = null;
|
|
22023
|
-
let lastUserTimestampMs = null;
|
|
22024
|
-
let inputTokens = 0;
|
|
22025
|
-
let outputTokens = 0;
|
|
22026
|
-
const intervals = [];
|
|
22027
|
-
for (const message of past) {
|
|
22028
|
-
const timestampMs = parseTimestampMs(message.timestamp);
|
|
22029
|
-
if (message.role === "user" && timestampMs !== null) {
|
|
22030
|
-
lastUserTimestampMs = timestampMs;
|
|
22031
|
-
continue;
|
|
22032
|
-
}
|
|
22033
|
-
if (message.role !== "assistant" || !message.usage)
|
|
22034
|
-
continue;
|
|
22035
|
-
if (timestampMs !== null && (latestUsageTimestampMs === null || timestampMs > latestUsageTimestampMs)) {
|
|
22036
|
-
latestUsageTimestampMs = timestampMs;
|
|
22037
|
-
latestUsage = message.usage;
|
|
22038
|
-
} else if (latestUsage === undefined) {
|
|
22039
|
-
latestUsage = message.usage;
|
|
22040
|
-
}
|
|
22041
|
-
inputTokens += message.usage.input_tokens;
|
|
22042
|
-
outputTokens += message.usage.output_tokens;
|
|
22043
|
-
if (timestampMs !== null && lastUserTimestampMs !== null && timestampMs > lastUserTimestampMs) {
|
|
22044
|
-
intervals.push({ startMs: lastUserTimestampMs, endMs: timestampMs });
|
|
22045
|
-
}
|
|
22046
|
-
}
|
|
22047
|
-
if (!latestUsage)
|
|
22048
|
-
return;
|
|
22049
|
-
const totalDurationMs = durationMs(mergeIntervals(intervals));
|
|
22050
|
-
if (totalDurationMs <= 0)
|
|
22051
|
-
return latestUsage;
|
|
22052
|
-
return {
|
|
22053
|
-
...latestUsage,
|
|
22054
|
-
total_speed_tokens_per_second: (inputTokens + outputTokens) / (totalDurationMs / 1000)
|
|
22055
|
-
};
|
|
22056
|
-
}
|
|
22057
|
-
function withTotalSpeedForTurn(usage, startedAtIso, endedAtIso) {
|
|
22058
|
-
const startMs = startedAtIso ? parseTimestampMs(startedAtIso) : null;
|
|
22059
|
-
const endMs = parseTimestampMs(endedAtIso);
|
|
22060
|
-
if (startMs === null || endMs === null || endMs <= startMs)
|
|
22061
|
-
return usage;
|
|
22062
|
-
return {
|
|
22063
|
-
...usage,
|
|
22064
|
-
total_speed_tokens_per_second: (usage.input_tokens + usage.output_tokens) / ((endMs - startMs) / 1000)
|
|
22065
|
-
};
|
|
22188
|
+
const contextMatch = /\b(\d+(?:[,_]\d+)*(?:\.\d+)?)\s*([km])(?:\s*(?:token\s*)?context)?\b/i.exec(modelIdentifier);
|
|
22189
|
+
if (!contextMatch?.[1] || !contextMatch[2])
|
|
22190
|
+
return null;
|
|
22191
|
+
const parsed = Number.parseFloat(contextMatch[1].replace(/[,_]/g, ""));
|
|
22192
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
22193
|
+
return null;
|
|
22194
|
+
return Math.round(parsed * (contextMatch[2].toLowerCase() === "m" ? 1e6 : 1000));
|
|
22066
22195
|
}
|
|
22067
22196
|
function contextWindowTokensForModel(modelId) {
|
|
22068
22197
|
const id = modelId ?? resolveDefaultModelId();
|
|
22069
|
-
|
|
22070
|
-
|
|
22198
|
+
const parsedWindow = parseContextWindowSize(id);
|
|
22199
|
+
if (parsedWindow !== null)
|
|
22200
|
+
return parsedWindow;
|
|
22071
22201
|
const inPicker = MODEL_CHOICES.some((m) => m.id === id);
|
|
22072
22202
|
if (inPicker)
|
|
22073
22203
|
return STD_CTX;
|
|
22074
|
-
if (id.includes("1m") || id.includes("[1M]"))
|
|
22075
|
-
return LONG_CTX;
|
|
22076
22204
|
return STD_CTX;
|
|
22077
22205
|
}
|
|
22078
22206
|
function formatTokShort(n) {
|
|
@@ -22102,7 +22230,7 @@ function formatContextUsageCompact(u, modelId) {
|
|
|
22102
22230
|
const speed = formatTotalSpeed(u.total_speed_tokens_per_second);
|
|
22103
22231
|
return [`${pct2}% \xB7 ${formatTokShort(total)}/${formatTokShort(window)}`, speed].filter(Boolean).join(" \xB7 ");
|
|
22104
22232
|
}
|
|
22105
|
-
var
|
|
22233
|
+
var STD_CTX = 200000;
|
|
22106
22234
|
var init_context_meter = __esm(() => {
|
|
22107
22235
|
init_claude_settings2();
|
|
22108
22236
|
init_models();
|
|
@@ -22146,13 +22274,13 @@ function createInitialState() {
|
|
|
22146
22274
|
queue: []
|
|
22147
22275
|
};
|
|
22148
22276
|
}
|
|
22149
|
-
function setMessagesFromHistory(state, past) {
|
|
22277
|
+
function setMessagesFromHistory(state, past, usageMetrics) {
|
|
22150
22278
|
const rows = [];
|
|
22151
22279
|
const toolIndexById = new Map;
|
|
22152
22280
|
for (const m of past) {
|
|
22153
22281
|
appendRowsFromMessage(rows, toolIndexById, m);
|
|
22154
22282
|
}
|
|
22155
|
-
const latestUsage =
|
|
22283
|
+
const latestUsage = usageMetrics ?? deriveSessionUsageMetrics(past);
|
|
22156
22284
|
return {
|
|
22157
22285
|
...state,
|
|
22158
22286
|
messages: capMessages(rows, new Date().toISOString()),
|
|
@@ -22422,7 +22550,6 @@ function findLastIndex(arr, pred) {
|
|
|
22422
22550
|
}
|
|
22423
22551
|
var SCROLLBACK_CAP = 1000, SENTINEL_PREFIX = "(scrollback truncated \u2014 ", SENTINEL_SUFFIX = " rows dropped)", CLAUDE_NOISE_TAGS, NOISE_TAG_PATTERN, QUEUE_SOFT_CAP = 50;
|
|
22424
22552
|
var init_store2 = __esm(() => {
|
|
22425
|
-
init_context_meter();
|
|
22426
22553
|
CLAUDE_NOISE_TAGS = [
|
|
22427
22554
|
"local-command-caveat",
|
|
22428
22555
|
"command-message",
|
|
@@ -22533,10 +22660,10 @@ function useChatSession(opts) {
|
|
|
22533
22660
|
};
|
|
22534
22661
|
if (tab.sessionId) {
|
|
22535
22662
|
const sid = tab.sessionId;
|
|
22536
|
-
orchestrator.
|
|
22663
|
+
orchestrator.readHistoryWithMetrics(sid).then(({ messages, usageMetrics }) => {
|
|
22537
22664
|
if (opts.taskId() !== taskId)
|
|
22538
22665
|
return;
|
|
22539
|
-
patchStateForTab(tabId, (s) => setMessagesFromHistory(s,
|
|
22666
|
+
patchStateForTab(tabId, (s) => setMessagesFromHistory(s, messages, usageMetrics));
|
|
22540
22667
|
replayPending();
|
|
22541
22668
|
}).catch((err) => {
|
|
22542
22669
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -23421,12 +23548,12 @@ var init_sidebar = __esm(() => {
|
|
|
23421
23548
|
});
|
|
23422
23549
|
|
|
23423
23550
|
// src/tui/panes/sidebar/git-head.ts
|
|
23424
|
-
import { spawnSync as
|
|
23551
|
+
import { spawnSync as spawnSync10 } from "child_process";
|
|
23425
23552
|
function readCurrentBranch(repo) {
|
|
23426
23553
|
if (!repo)
|
|
23427
23554
|
return "";
|
|
23428
23555
|
try {
|
|
23429
|
-
const out =
|
|
23556
|
+
const out = spawnSync10("git", ["symbolic-ref", "--short", "HEAD"], {
|
|
23430
23557
|
cwd: repo,
|
|
23431
23558
|
encoding: "utf8",
|
|
23432
23559
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -23436,7 +23563,7 @@ function readCurrentBranch(repo) {
|
|
|
23436
23563
|
if (name && name !== "HEAD")
|
|
23437
23564
|
return name;
|
|
23438
23565
|
}
|
|
23439
|
-
const head =
|
|
23566
|
+
const head = spawnSync10("git", ["rev-parse", "--verify", "HEAD"], {
|
|
23440
23567
|
cwd: repo,
|
|
23441
23568
|
encoding: "utf8",
|
|
23442
23569
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -24824,6 +24951,11 @@ async function main() {
|
|
|
24824
24951
|
await runDiagnoseSubcommand2();
|
|
24825
24952
|
return;
|
|
24826
24953
|
}
|
|
24954
|
+
if (subcommand === "update") {
|
|
24955
|
+
const { runUpdateSubcommand: runUpdateSubcommand2 } = await Promise.resolve().then(() => (init_update(), exports_update));
|
|
24956
|
+
await runUpdateSubcommand2(rest);
|
|
24957
|
+
return;
|
|
24958
|
+
}
|
|
24827
24959
|
if (subcommand === "theme") {
|
|
24828
24960
|
const { runThemeSubcommand: runThemeSubcommand2 } = await Promise.resolve().then(() => (init_theme2(), exports_theme));
|
|
24829
24961
|
await runThemeSubcommand2(rest);
|
package/package.json
CHANGED