@sma1lboy/kobe 0.5.0 → 0.5.1
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 +187 -4
- package/dist/cli/index.js +85 -7
- package/package.json +1 -1
package/dist/bin/kobed.js
CHANGED
|
@@ -353,7 +353,24 @@ function extractMessage(record, fallbackSessionId) {
|
|
|
353
353
|
const content = inner.content;
|
|
354
354
|
const ts = typeof record.timestamp === "string" ? record.timestamp : new Date().toISOString();
|
|
355
355
|
const sid = typeof record.sessionId === "string" ? record.sessionId : fallbackSessionId;
|
|
356
|
-
|
|
356
|
+
const usage = extractUsage(inner.usage);
|
|
357
|
+
return usage ? { role, content, timestamp: ts, sessionId: sid, usage } : { role, content, timestamp: ts, sessionId: sid };
|
|
358
|
+
}
|
|
359
|
+
function extractUsage(v) {
|
|
360
|
+
if (!isObject(v))
|
|
361
|
+
return;
|
|
362
|
+
const inTok = typeof v.input_tokens === "number" ? v.input_tokens : undefined;
|
|
363
|
+
const outTok = typeof v.output_tokens === "number" ? v.output_tokens : undefined;
|
|
364
|
+
if (inTok === undefined || outTok === undefined)
|
|
365
|
+
return;
|
|
366
|
+
const cacheRead = typeof v.cache_read_input_tokens === "number" ? v.cache_read_input_tokens : undefined;
|
|
367
|
+
const cacheCreate = typeof v.cache_creation_input_tokens === "number" ? v.cache_creation_input_tokens : undefined;
|
|
368
|
+
return {
|
|
369
|
+
input_tokens: inTok,
|
|
370
|
+
output_tokens: outTok,
|
|
371
|
+
...cacheRead !== undefined ? { cache_read_input_tokens: cacheRead } : {},
|
|
372
|
+
...cacheCreate !== undefined ? { cache_creation_input_tokens: cacheCreate } : {}
|
|
373
|
+
};
|
|
357
374
|
}
|
|
358
375
|
function isObject(v) {
|
|
359
376
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -2961,6 +2978,9 @@ class Orchestrator {
|
|
|
2961
2978
|
tasksSignal() {
|
|
2962
2979
|
return this.tasksAcc;
|
|
2963
2980
|
}
|
|
2981
|
+
planUsageSignal() {
|
|
2982
|
+
return () => null;
|
|
2983
|
+
}
|
|
2964
2984
|
subscribeTasks(listener) {
|
|
2965
2985
|
return this.store.subscribe(listener);
|
|
2966
2986
|
}
|
|
@@ -4294,9 +4314,166 @@ init_paths2();
|
|
|
4294
4314
|
|
|
4295
4315
|
// src/daemon/server.ts
|
|
4296
4316
|
init_paths2();
|
|
4297
|
-
import { mkdir as mkdir3, readFile as
|
|
4317
|
+
import { mkdir as mkdir3, readFile as readFile5, unlink as unlink4, writeFile as writeFile3 } from "fs/promises";
|
|
4298
4318
|
import { createServer as createServer2 } from "net";
|
|
4299
4319
|
import { dirname as dirname4 } from "path";
|
|
4320
|
+
|
|
4321
|
+
// src/engine/claude-code-local/plan-usage.ts
|
|
4322
|
+
import { execFile } from "child_process";
|
|
4323
|
+
import { createHash } from "crypto";
|
|
4324
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
4325
|
+
import { homedir as homedir10, userInfo } from "os";
|
|
4326
|
+
import { join as join6 } from "path";
|
|
4327
|
+
import { promisify } from "util";
|
|
4328
|
+
var execFileAsync = promisify(execFile);
|
|
4329
|
+
var USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
4330
|
+
var FETCH_TIMEOUT_MS = 5000;
|
|
4331
|
+
var KEYCHAIN_BASE = "Claude Code";
|
|
4332
|
+
var KEYCHAIN_SUFFIX = "-credentials";
|
|
4333
|
+
function keychainServiceName() {
|
|
4334
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
4335
|
+
if (!configDir)
|
|
4336
|
+
return `${KEYCHAIN_BASE}${KEYCHAIN_SUFFIX}`;
|
|
4337
|
+
const hash = createHash("sha256").update(configDir).digest("hex").slice(0, 8);
|
|
4338
|
+
return `${KEYCHAIN_BASE}${KEYCHAIN_SUFFIX}-${hash}`;
|
|
4339
|
+
}
|
|
4340
|
+
function keychainAccount() {
|
|
4341
|
+
return process.env.USER || userInfo().username || "claude-code-user";
|
|
4342
|
+
}
|
|
4343
|
+
async function readKeychainToken() {
|
|
4344
|
+
if (process.platform !== "darwin")
|
|
4345
|
+
return null;
|
|
4346
|
+
try {
|
|
4347
|
+
const { stdout } = await execFileAsync("security", [
|
|
4348
|
+
"find-generic-password",
|
|
4349
|
+
"-a",
|
|
4350
|
+
keychainAccount(),
|
|
4351
|
+
"-w",
|
|
4352
|
+
"-s",
|
|
4353
|
+
keychainServiceName()
|
|
4354
|
+
]);
|
|
4355
|
+
return parseStoredOAuth(stdout);
|
|
4356
|
+
} catch {
|
|
4357
|
+
return null;
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
async function readPlainTextToken() {
|
|
4361
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR ?? join6(homedir10(), ".claude");
|
|
4362
|
+
const path7 = join6(configDir, ".credentials.json");
|
|
4363
|
+
try {
|
|
4364
|
+
const raw = await readFile4(path7, "utf8");
|
|
4365
|
+
return parseStoredOAuth(raw);
|
|
4366
|
+
} catch {
|
|
4367
|
+
return null;
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
function parseStoredOAuth(raw) {
|
|
4371
|
+
const trimmed = raw.trim();
|
|
4372
|
+
if (!trimmed)
|
|
4373
|
+
return null;
|
|
4374
|
+
try {
|
|
4375
|
+
const parsed = JSON.parse(trimmed);
|
|
4376
|
+
const tok = parsed.claudeAiOauth;
|
|
4377
|
+
if (!tok || typeof tok.accessToken !== "string" || tok.accessToken.length === 0)
|
|
4378
|
+
return null;
|
|
4379
|
+
return tok;
|
|
4380
|
+
} catch {
|
|
4381
|
+
return null;
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
async function loadToken() {
|
|
4385
|
+
return await readKeychainToken() ?? await readPlainTextToken();
|
|
4386
|
+
}
|
|
4387
|
+
function normalizeBucket(b) {
|
|
4388
|
+
if (!b)
|
|
4389
|
+
return null;
|
|
4390
|
+
return {
|
|
4391
|
+
utilization: typeof b.utilization === "number" && Number.isFinite(b.utilization) ? b.utilization : null,
|
|
4392
|
+
resetsAt: typeof b.resets_at === "string" && b.resets_at.length > 0 ? b.resets_at : null
|
|
4393
|
+
};
|
|
4394
|
+
}
|
|
4395
|
+
async function fetchPlanUsage(now = Date.now()) {
|
|
4396
|
+
const token = await loadToken();
|
|
4397
|
+
if (!token)
|
|
4398
|
+
return null;
|
|
4399
|
+
if (typeof token.expiresAt === "number" && token.expiresAt > 0 && token.expiresAt < now)
|
|
4400
|
+
return null;
|
|
4401
|
+
const ctrl = new AbortController;
|
|
4402
|
+
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
4403
|
+
try {
|
|
4404
|
+
const res = await fetch(USAGE_URL, {
|
|
4405
|
+
signal: ctrl.signal,
|
|
4406
|
+
headers: {
|
|
4407
|
+
accept: "application/json",
|
|
4408
|
+
"content-type": "application/json",
|
|
4409
|
+
"user-agent": "kobe-plan-usage",
|
|
4410
|
+
"anthropic-beta": "oauth-2025-04-20",
|
|
4411
|
+
authorization: `Bearer ${token.accessToken}`
|
|
4412
|
+
}
|
|
4413
|
+
});
|
|
4414
|
+
if (!res.ok)
|
|
4415
|
+
return null;
|
|
4416
|
+
const body = await res.json();
|
|
4417
|
+
return {
|
|
4418
|
+
fiveHour: normalizeBucket(body.five_hour),
|
|
4419
|
+
sevenDay: normalizeBucket(body.seven_day),
|
|
4420
|
+
sevenDayOpus: normalizeBucket(body.seven_day_opus),
|
|
4421
|
+
sevenDaySonnet: normalizeBucket(body.seven_day_sonnet),
|
|
4422
|
+
fetchedAt: new Date(now).toISOString()
|
|
4423
|
+
};
|
|
4424
|
+
} catch {
|
|
4425
|
+
return null;
|
|
4426
|
+
} finally {
|
|
4427
|
+
clearTimeout(timer);
|
|
4428
|
+
}
|
|
4429
|
+
}
|
|
4430
|
+
|
|
4431
|
+
// src/daemon/plan-usage-poller.ts
|
|
4432
|
+
var DEFAULT_INTERVAL_MS = 60000;
|
|
4433
|
+
function createPlanUsagePoller(options) {
|
|
4434
|
+
const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
4435
|
+
const fetcher = options.fetcher ?? fetchPlanUsage;
|
|
4436
|
+
let timer = null;
|
|
4437
|
+
let last = null;
|
|
4438
|
+
let inflight = false;
|
|
4439
|
+
async function tick() {
|
|
4440
|
+
if (inflight)
|
|
4441
|
+
return;
|
|
4442
|
+
inflight = true;
|
|
4443
|
+
try {
|
|
4444
|
+
const usage = await fetcher();
|
|
4445
|
+
if (usage) {
|
|
4446
|
+
last = usage;
|
|
4447
|
+
options.onUpdate(usage);
|
|
4448
|
+
}
|
|
4449
|
+
} finally {
|
|
4450
|
+
inflight = false;
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
return {
|
|
4454
|
+
start() {
|
|
4455
|
+
if (timer)
|
|
4456
|
+
return;
|
|
4457
|
+
tick();
|
|
4458
|
+
timer = setInterval(() => void tick(), intervalMs);
|
|
4459
|
+
timer.unref?.();
|
|
4460
|
+
},
|
|
4461
|
+
stop() {
|
|
4462
|
+
if (timer) {
|
|
4463
|
+
clearInterval(timer);
|
|
4464
|
+
timer = null;
|
|
4465
|
+
}
|
|
4466
|
+
},
|
|
4467
|
+
current() {
|
|
4468
|
+
return last;
|
|
4469
|
+
},
|
|
4470
|
+
async refresh() {
|
|
4471
|
+
await tick();
|
|
4472
|
+
}
|
|
4473
|
+
};
|
|
4474
|
+
}
|
|
4475
|
+
|
|
4476
|
+
// src/daemon/server.ts
|
|
4300
4477
|
async function startDaemonServer(orch, options = {}) {
|
|
4301
4478
|
const socketPath = options.socketPath ?? defaultDaemonSocketPath(options.homeDir);
|
|
4302
4479
|
const pidPath = options.pidPath ?? defaultDaemonPidPath(options.homeDir);
|
|
@@ -4327,12 +4504,16 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
4327
4504
|
clients.delete(client);
|
|
4328
4505
|
});
|
|
4329
4506
|
});
|
|
4507
|
+
const planUsagePoller = options.planUsagePoller ?? createPlanUsagePoller({
|
|
4508
|
+
onUpdate: (usage) => broadcast(clients, { type: "event", name: "plan.usage", payload: { usage } })
|
|
4509
|
+
});
|
|
4330
4510
|
const serverApi = {
|
|
4331
4511
|
socketPath,
|
|
4332
4512
|
pidPath,
|
|
4333
4513
|
startedAt,
|
|
4334
4514
|
clients,
|
|
4335
4515
|
async close() {
|
|
4516
|
+
planUsagePoller.stop();
|
|
4336
4517
|
broadcast(clients, { type: "event", name: "daemon.stopping", payload: {} });
|
|
4337
4518
|
await new Promise((resolve) => server.close(() => resolve()));
|
|
4338
4519
|
for (const client of Array.from(clients)) {
|
|
@@ -4345,6 +4526,7 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
4345
4526
|
await unlink4(pidPath).catch(() => {});
|
|
4346
4527
|
}
|
|
4347
4528
|
};
|
|
4529
|
+
planUsagePoller.start();
|
|
4348
4530
|
await new Promise((resolve, reject) => {
|
|
4349
4531
|
server.once("error", reject);
|
|
4350
4532
|
server.listen(socketPath, () => {
|
|
@@ -4380,7 +4562,8 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
4380
4562
|
clientId: client.id,
|
|
4381
4563
|
tasks: tasks.map(serializeTask),
|
|
4382
4564
|
pending,
|
|
4383
|
-
runState
|
|
4565
|
+
runState,
|
|
4566
|
+
planUsage: planUsagePoller.current()
|
|
4384
4567
|
};
|
|
4385
4568
|
}
|
|
4386
4569
|
case "daemon.status":
|
|
@@ -4606,7 +4789,7 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
4606
4789
|
}
|
|
4607
4790
|
async function readPidFile(pidPath) {
|
|
4608
4791
|
try {
|
|
4609
|
-
const raw = await
|
|
4792
|
+
const raw = await readFile5(pidPath, "utf8");
|
|
4610
4793
|
const pid = Number(raw.trim());
|
|
4611
4794
|
return Number.isFinite(pid) ? pid : null;
|
|
4612
4795
|
} catch {
|
package/dist/cli/index.js
CHANGED
|
@@ -8825,7 +8825,7 @@ var init_package = __esm(() => {
|
|
|
8825
8825
|
package_default = {
|
|
8826
8826
|
$schema: "https://json.schemastore.org/package.json",
|
|
8827
8827
|
name: "@sma1lboy/kobe",
|
|
8828
|
-
version: "0.5.
|
|
8828
|
+
version: "0.5.1",
|
|
8829
8829
|
description: "TUI orchestrator for Claude Code (codename)",
|
|
8830
8830
|
type: "module",
|
|
8831
8831
|
packageManager: "bun@1.3.13",
|
|
@@ -10584,6 +10584,9 @@ class Orchestrator {
|
|
|
10584
10584
|
tasksSignal() {
|
|
10585
10585
|
return this.tasksAcc;
|
|
10586
10586
|
}
|
|
10587
|
+
planUsageSignal() {
|
|
10588
|
+
return () => null;
|
|
10589
|
+
}
|
|
10587
10590
|
subscribeTasks(listener2) {
|
|
10588
10591
|
return this.store.subscribe(listener2);
|
|
10589
10592
|
}
|
|
@@ -11287,16 +11290,21 @@ class RemoteOrchestrator {
|
|
|
11287
11290
|
setTasks;
|
|
11288
11291
|
runStateAcc;
|
|
11289
11292
|
setRunState;
|
|
11293
|
+
planUsageAcc;
|
|
11294
|
+
setPlanUsage;
|
|
11290
11295
|
subscribers = new Map;
|
|
11291
11296
|
pendingInputBroker = new InMemoryPendingInputBroker;
|
|
11292
11297
|
constructor(client) {
|
|
11293
11298
|
this.client = client;
|
|
11294
11299
|
const [tasks, setTasks] = createSignal([]);
|
|
11295
11300
|
const [runState, setRunState] = createSignal(new Map);
|
|
11301
|
+
const [planUsage, setPlanUsage] = createSignal(null);
|
|
11296
11302
|
this.tasksAcc = tasks;
|
|
11297
11303
|
this.setTasks = (next) => setTasks(() => next);
|
|
11298
11304
|
this.runStateAcc = runState;
|
|
11299
11305
|
this.setRunState = (next) => setRunState(() => next);
|
|
11306
|
+
this.planUsageAcc = planUsage;
|
|
11307
|
+
this.setPlanUsage = (next) => setPlanUsage(() => next);
|
|
11300
11308
|
this.client.on("*", (frame) => this.handleEvent(frame.name, frame.payload));
|
|
11301
11309
|
}
|
|
11302
11310
|
async init() {
|
|
@@ -11316,6 +11324,8 @@ class RemoteOrchestrator {
|
|
|
11316
11324
|
if (seed.size > 0)
|
|
11317
11325
|
this.setRunState(seed);
|
|
11318
11326
|
}
|
|
11327
|
+
if (hello.planUsage)
|
|
11328
|
+
this.setPlanUsage(hello.planUsage);
|
|
11319
11329
|
await this.client.request("subscribe", { taskIds: "all" });
|
|
11320
11330
|
if (hello.pending) {
|
|
11321
11331
|
for (const [taskId, entries] of Object.entries(hello.pending)) {
|
|
@@ -11345,6 +11355,9 @@ class RemoteOrchestrator {
|
|
|
11345
11355
|
chatRunStateSignal() {
|
|
11346
11356
|
return this.runStateAcc;
|
|
11347
11357
|
}
|
|
11358
|
+
planUsageSignal() {
|
|
11359
|
+
return this.planUsageAcc;
|
|
11360
|
+
}
|
|
11348
11361
|
listTasks() {
|
|
11349
11362
|
return this.tasksAcc().slice();
|
|
11350
11363
|
}
|
|
@@ -11477,6 +11490,11 @@ class RemoteOrchestrator {
|
|
|
11477
11490
|
}
|
|
11478
11491
|
return;
|
|
11479
11492
|
}
|
|
11493
|
+
if (name === "plan.usage") {
|
|
11494
|
+
const usage = obj.usage;
|
|
11495
|
+
this.setPlanUsage(usage ?? null);
|
|
11496
|
+
return;
|
|
11497
|
+
}
|
|
11480
11498
|
const taskId = obj.taskId;
|
|
11481
11499
|
const tabId = obj.tabId;
|
|
11482
11500
|
if (!taskId || !tabId)
|
|
@@ -14704,7 +14722,24 @@ function extractMessage(record, fallbackSessionId) {
|
|
|
14704
14722
|
const content = inner.content;
|
|
14705
14723
|
const ts = typeof record.timestamp === "string" ? record.timestamp : new Date().toISOString();
|
|
14706
14724
|
const sid = typeof record.sessionId === "string" ? record.sessionId : fallbackSessionId;
|
|
14707
|
-
|
|
14725
|
+
const usage = extractUsage(inner.usage);
|
|
14726
|
+
return usage ? { role, content, timestamp: ts, sessionId: sid, usage } : { role, content, timestamp: ts, sessionId: sid };
|
|
14727
|
+
}
|
|
14728
|
+
function extractUsage(v) {
|
|
14729
|
+
if (!isObject(v))
|
|
14730
|
+
return;
|
|
14731
|
+
const inTok = typeof v.input_tokens === "number" ? v.input_tokens : undefined;
|
|
14732
|
+
const outTok = typeof v.output_tokens === "number" ? v.output_tokens : undefined;
|
|
14733
|
+
if (inTok === undefined || outTok === undefined)
|
|
14734
|
+
return;
|
|
14735
|
+
const cacheRead = typeof v.cache_read_input_tokens === "number" ? v.cache_read_input_tokens : undefined;
|
|
14736
|
+
const cacheCreate = typeof v.cache_creation_input_tokens === "number" ? v.cache_creation_input_tokens : undefined;
|
|
14737
|
+
return {
|
|
14738
|
+
input_tokens: inTok,
|
|
14739
|
+
output_tokens: outTok,
|
|
14740
|
+
...cacheRead !== undefined ? { cache_read_input_tokens: cacheRead } : {},
|
|
14741
|
+
...cacheCreate !== undefined ? { cache_creation_input_tokens: cacheCreate } : {}
|
|
14742
|
+
};
|
|
14708
14743
|
}
|
|
14709
14744
|
function isObject(v) {
|
|
14710
14745
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -15598,6 +15633,27 @@ var init_engine_bootstrap = __esm(() => {
|
|
|
15598
15633
|
init_claude_code_local();
|
|
15599
15634
|
});
|
|
15600
15635
|
|
|
15636
|
+
// src/tui/lib/format-plan-usage.ts
|
|
15637
|
+
function pct(value) {
|
|
15638
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
15639
|
+
return null;
|
|
15640
|
+
return `${Math.round(value)}%`;
|
|
15641
|
+
}
|
|
15642
|
+
function formatPlanUsageCompact(usage) {
|
|
15643
|
+
if (!usage)
|
|
15644
|
+
return null;
|
|
15645
|
+
const fiveHour = pct(usage.fiveHour?.utilization);
|
|
15646
|
+
const sevenDay = pct(usage.sevenDay?.utilization);
|
|
15647
|
+
const parts = [];
|
|
15648
|
+
if (fiveHour)
|
|
15649
|
+
parts.push(`5h ${fiveHour}`);
|
|
15650
|
+
if (sevenDay)
|
|
15651
|
+
parts.push(`7d ${sevenDay}`);
|
|
15652
|
+
if (parts.length === 0)
|
|
15653
|
+
return null;
|
|
15654
|
+
return `Plan ${parts.join(" \xB7 ")}`;
|
|
15655
|
+
}
|
|
15656
|
+
|
|
15601
15657
|
// src/tui/lib/use-pane-sizes.ts
|
|
15602
15658
|
function usePaneSizes(kv) {
|
|
15603
15659
|
const dims = useTerminalDimensions();
|
|
@@ -20349,7 +20405,7 @@ var init_user_slashes = () => {};
|
|
|
20349
20405
|
|
|
20350
20406
|
// src/tui/panes/chat/context-meter.ts
|
|
20351
20407
|
function totalContextTokens(u) {
|
|
20352
|
-
return u.input_tokens +
|
|
20408
|
+
return u.input_tokens + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0);
|
|
20353
20409
|
}
|
|
20354
20410
|
function contextWindowTokensForModel(modelId) {
|
|
20355
20411
|
const id = modelId ?? resolveDefaultModelId();
|
|
@@ -20378,8 +20434,8 @@ function formatContextUsageCompact(u, modelId) {
|
|
|
20378
20434
|
const total = totalContextTokens(u);
|
|
20379
20435
|
if (total <= 0 || window <= 0)
|
|
20380
20436
|
return null;
|
|
20381
|
-
const
|
|
20382
|
-
return `${
|
|
20437
|
+
const pct2 = Math.min(100, Math.max(0, Math.round(total / window * 100)));
|
|
20438
|
+
return `${pct2}% \xB7 ${formatTokShort(total)}/${formatTokShort(window)}`;
|
|
20383
20439
|
}
|
|
20384
20440
|
var LONG_CTX = 1e6, STD_CTX = 200000;
|
|
20385
20441
|
var init_context_meter = __esm(() => {
|
|
@@ -20431,7 +20487,19 @@ function setMessagesFromHistory(state, past) {
|
|
|
20431
20487
|
for (const m of past) {
|
|
20432
20488
|
appendRowsFromMessage(rows, toolIndexById, m);
|
|
20433
20489
|
}
|
|
20434
|
-
|
|
20490
|
+
let latestUsage;
|
|
20491
|
+
for (let i = past.length - 1;i >= 0; i--) {
|
|
20492
|
+
const u = past[i]?.usage;
|
|
20493
|
+
if (u) {
|
|
20494
|
+
latestUsage = u;
|
|
20495
|
+
break;
|
|
20496
|
+
}
|
|
20497
|
+
}
|
|
20498
|
+
return {
|
|
20499
|
+
...state,
|
|
20500
|
+
messages: capMessages(rows, new Date().toISOString()),
|
|
20501
|
+
...latestUsage ? { lastUsage: latestUsage } : {}
|
|
20502
|
+
};
|
|
20435
20503
|
}
|
|
20436
20504
|
function enqueuePrompt(state, prompt, nowIso = new Date().toISOString()) {
|
|
20437
20505
|
if (state.queue.length >= QUEUE_SOFT_CAP)
|
|
@@ -22351,6 +22419,8 @@ function Shell(props) {
|
|
|
22351
22419
|
const [selectedId, setSelectedId] = createSignal(null);
|
|
22352
22420
|
const [pendingPrompt, setPendingPrompt] = createSignal(null);
|
|
22353
22421
|
const [workspaceContextAside, setWorkspaceContextAside] = createSignal(null);
|
|
22422
|
+
const planUsageAcc = props.orchestrator.planUsageSignal();
|
|
22423
|
+
const workspacePlanAside = createMemo(() => formatPlanUsageCompact(planUsageAcc()));
|
|
22354
22424
|
const [updateInfo, setUpdateInfo] = createSignal(null);
|
|
22355
22425
|
onMount(() => {
|
|
22356
22426
|
checkLatestVersion().then((info) => {
|
|
@@ -22433,6 +22503,14 @@ function Shell(props) {
|
|
|
22433
22503
|
selectFileTab,
|
|
22434
22504
|
closeFileTab
|
|
22435
22505
|
} = workspaceTabs;
|
|
22506
|
+
const workspaceAsideRight = createMemo(() => {
|
|
22507
|
+
const plan = workspacePlanAside();
|
|
22508
|
+
const ctx3 = isChatTabActive() ? workspaceContextAside() : null;
|
|
22509
|
+
const parts = [plan, ctx3].filter((v) => Boolean(v));
|
|
22510
|
+
if (parts.length === 0)
|
|
22511
|
+
return;
|
|
22512
|
+
return parts.join(" \u2022 ");
|
|
22513
|
+
});
|
|
22436
22514
|
let pendingPersistedId = persistedSelectedId ?? null;
|
|
22437
22515
|
createEffect(() => {
|
|
22438
22516
|
const tasks = tasksAcc();
|
|
@@ -22565,7 +22643,7 @@ function Shell(props) {
|
|
|
22565
22643
|
return activeTask()?.title ?? "no task";
|
|
22566
22644
|
},
|
|
22567
22645
|
get asideRight() {
|
|
22568
|
-
return
|
|
22646
|
+
return workspaceAsideRight();
|
|
22569
22647
|
},
|
|
22570
22648
|
get focused() {
|
|
22571
22649
|
return focusedPane() === "workspace";
|
package/package.json
CHANGED