@sma1lboy/kobe 0.5.8 → 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/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.8",
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, INSTALL_COMMAND, CACHE_TTL_MS, FETCH_TIMEOUT_MS = 3000;
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
- INSTALL_COMMAND = `bun install -g ${PACKAGE_NAME}@latest`;
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 fail(message) {
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
- fail(`failed to fetch ${source}: ${err instanceof Error ? err.message : String(err)}`);
9606
+ fail2(`failed to fetch ${source}: ${err instanceof Error ? err.message : String(err)}`);
9517
9607
  }
9518
9608
  if (!res.ok) {
9519
- fail(`failed to fetch ${source}: HTTP ${res.status} ${res.statusText}`);
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
- fail(`failed to read ${abs}: ${err instanceof Error ? err.message : String(err)}`);
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
- fail("--name requires a value");
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
- fail(`unknown flag: ${a}`);
9651
+ fail2(`unknown flag: ${a}`);
9562
9652
  if (source === null) {
9563
9653
  source = a;
9564
9654
  continue;
9565
9655
  }
9566
- fail(`unexpected positional argument: ${a}`);
9656
+ fail2(`unexpected positional argument: ${a}`);
9567
9657
  }
9568
9658
  if (source === null)
9569
- fail("missing <source> (URL or path to theme JSON)");
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
- fail(`source is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
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
- fail(`source is not a valid kobe theme: ${result.reason}`);
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
- fail(`invalid theme name "${name}" (use letters, digits, '.', '_', '-')`);
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
- fail(`${dest} already exists (pass --force to overwrite)`);
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
- fail("missing <name>");
9693
+ fail2("missing <name>");
9604
9694
  if (args.length > 1)
9605
- fail(`unexpected extra arguments after "${name}"`);
9695
+ fail2(`unexpected extra arguments after "${name}"`);
9606
9696
  if (BUNDLED_NAMES.includes(name)) {
9607
- fail(`"${name}" is a built-in theme and cannot be removed`);
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
- fail(`no user theme named "${name}" (looked for ${dest})`);
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 printUsage() {
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
- printUsage();
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
- fail(`"${action}" takes no arguments`);
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
- fail(`unknown action "${action}" (try "list", "add", or "remove")`);
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 fail2 = (code, message) => {
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
- fail2(-32602, "missing tool name");
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
- fail2(-32601, `method not found: ${msg.method}`);
9900
+ fail3(-32601, `method not found: ${msg.method}`);
9811
9901
  return;
9812
9902
  }
9813
9903
  } catch (err) {
9814
- fail2(-32000, err instanceof Error ? err.message : String(err));
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 spawnSync6 } from "child_process";
10526
+ import { spawnSync as spawnSync7 } from "child_process";
10357
10527
  function git(cwd, args) {
10358
10528
  try {
10359
- const out = spawnSync6("git", args.slice(), {
10529
+ const out = spawnSync7("git", args.slice(), {
10360
10530
  cwd,
10361
10531
  encoding: "utf8",
10362
10532
  timeout: GIT_TIMEOUT_MS
@@ -10580,6 +10750,7 @@ class Orchestrator {
10580
10750
  worktrees;
10581
10751
  metadataSuggester;
10582
10752
  handles = new Map;
10753
+ firstSpawnLatches = new Map;
10583
10754
  subscribers = new Map;
10584
10755
  pumps = new Map;
10585
10756
  pendingInputBroker = new InMemoryPendingInputBroker;
@@ -10812,8 +10983,16 @@ class Orchestrator {
10812
10983
  const renameTabId = this.resolveTab(task, tabId).id;
10813
10984
  this.maybeRenameTempBranch(task.id, renameTabId, prompt);
10814
10985
  }
10815
- const targetTab = this.resolveTab(task, tabId);
10986
+ let targetTab = this.resolveTab(task, tabId);
10816
10987
  const key = tabKey(task.id, targetTab.id);
10988
+ if (!targetTab.sessionId) {
10989
+ const inflight = this.firstSpawnLatches.get(key);
10990
+ if (inflight) {
10991
+ await inflight.catch(() => {});
10992
+ task = this.requireTask(id);
10993
+ targetTab = this.resolveTab(task, tabId);
10994
+ }
10995
+ }
10817
10996
  if (this.handles.has(key) === false) {
10818
10997
  const running = this.countRunning();
10819
10998
  if (running >= CONCURRENCY_CAP) {
@@ -10834,18 +11013,28 @@ class Orchestrator {
10834
11013
  model: modelToUse
10835
11014
  });
10836
11015
  } else {
10837
- handle = await this.engine.spawn(task.worktreePath, promptToSend, {
10838
- permissionMode: task.permissionMode,
10839
- model: modelToUse
11016
+ let releaseLatch = () => {};
11017
+ const latch = new Promise((resolve3) => {
11018
+ releaseLatch = resolve3;
10840
11019
  });
10841
- await this.updateTab(task.id, targetTab.id, { sessionId: handle.sessionId });
10842
- if (task.title === PLACEHOLDER_TASK_TITLE && prompt && prompt.trim().length > 0) {
10843
- const derived = deriveTitleFromPrompt(prompt);
10844
- if (derived)
10845
- await this.store.update(task.id, { title: derived });
10846
- }
10847
- if (prompt && prompt.trim().length > 0) {
10848
- this.maybeUpgradeTitle(task.id, prompt);
11020
+ this.firstSpawnLatches.set(key, latch);
11021
+ try {
11022
+ handle = await this.engine.spawn(task.worktreePath, promptToSend, {
11023
+ permissionMode: task.permissionMode,
11024
+ model: modelToUse
11025
+ });
11026
+ await this.updateTab(task.id, targetTab.id, { sessionId: handle.sessionId });
11027
+ if (task.title === PLACEHOLDER_TASK_TITLE && prompt && prompt.trim().length > 0) {
11028
+ const derived = deriveTitleFromPrompt(prompt);
11029
+ if (derived)
11030
+ await this.store.update(task.id, { title: derived });
11031
+ }
11032
+ if (prompt && prompt.trim().length > 0) {
11033
+ this.maybeUpgradeTitle(task.id, prompt);
11034
+ }
11035
+ } finally {
11036
+ releaseLatch();
11037
+ this.firstSpawnLatches.delete(key);
10849
11038
  }
10850
11039
  }
10851
11040
  this.handles.set(key, handle);
@@ -10912,6 +11101,12 @@ class Orchestrator {
10912
11101
  }
10913
11102
  this.dispatchEvent(task.id, targetTab.id, { type: "done" });
10914
11103
  }
11104
+ async steerTask(id, prompt, tabId) {
11105
+ const task = this.requireTask(id);
11106
+ const targetTab = this.resolveTab(task, tabId);
11107
+ await this.interruptTask(task.id, targetTab.id);
11108
+ await this.runTask(task.id, prompt, targetTab.id);
11109
+ }
10915
11110
  async pauseTask(id) {
10916
11111
  const task = this.requireTask(id);
10917
11112
  if (task.status !== "in_progress") {
@@ -11024,6 +11219,14 @@ class Orchestrator {
11024
11219
  return [];
11025
11220
  }
11026
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
+ }
11027
11230
  async listSessions(id) {
11028
11231
  const task = this.requireTask(id);
11029
11232
  if (!task.worktreePath)
@@ -11459,6 +11662,10 @@ class RemoteOrchestrator {
11459
11662
  async interruptTask(taskId, tabId) {
11460
11663
  await this.client.request("chat.interrupt", { taskId, tabId });
11461
11664
  }
11665
+ async steerTask(taskId, text, tabId) {
11666
+ await this.client.request("chat.steer", { taskId, text, tabId });
11667
+ this.markRunState(taskId, tabId ?? this.getTask(taskId)?.activeTabId, "running");
11668
+ }
11462
11669
  async setArchived(taskId, archived) {
11463
11670
  await this.client.request("task.archive", { taskId, archived });
11464
11671
  }
@@ -11495,15 +11702,21 @@ class RemoteOrchestrator {
11495
11702
  await this.client.request("chat.tab.activate", { taskId, tabId });
11496
11703
  }
11497
11704
  async readHistory(sessionId) {
11705
+ return (await this.readHistoryWithMetrics(sessionId)).messages;
11706
+ }
11707
+ async readHistoryWithMetrics(sessionId) {
11498
11708
  const task = this.tasksAcc().find((t) => t.sessionId === sessionId || t.tabs.some((tab) => tab.sessionId === sessionId));
11499
11709
  if (!task)
11500
- return [];
11710
+ return { messages: [] };
11501
11711
  const res = await this.client.request("chat.history", {
11502
11712
  taskId: task.id,
11503
11713
  sessionId,
11504
11714
  limit: 500
11505
11715
  });
11506
- return res.messages;
11716
+ return {
11717
+ messages: res.messages,
11718
+ ...res.usageMetrics ? { usageMetrics: res.usageMetrics } : {}
11719
+ };
11507
11720
  }
11508
11721
  async listSessions(taskId) {
11509
11722
  const res = await this.client.request("chat.sessions", { taskId });
@@ -11656,12 +11869,12 @@ var init_remote_orchestrator = __esm(() => {
11656
11869
  });
11657
11870
 
11658
11871
  // src/orchestrator/worktree/git.ts
11659
- import { spawnSync as spawnSync7 } from "child_process";
11872
+ import { spawnSync as spawnSync8 } from "child_process";
11660
11873
  function git2(args, opts) {
11661
11874
  if (!opts.cwd) {
11662
11875
  throw new Error("git(): cwd is required; refusing to inherit from process.cwd()");
11663
11876
  }
11664
- const proc = spawnSync7("git", [...args], {
11877
+ const proc = spawnSync8("git", [...args], {
11665
11878
  cwd: opts.cwd,
11666
11879
  env: opts.env ? { ...process.env, ...opts.env } : process.env,
11667
11880
  encoding: "utf8",
@@ -15214,11 +15427,11 @@ function UpdateDialog(props) {
15214
15427
  const [notes] = createResource(() => fetchReleaseNotes(props.info.latest));
15215
15428
  const fallbackUrl = () => releasePageUrl(props.info.latest);
15216
15429
  return (() => {
15217
- 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");
15218
15431
  insertNode(_el$, _el$2);
15219
15432
  insertNode(_el$, _el$7);
15220
15433
  insertNode(_el$, _el$12);
15221
- insertNode(_el$, _el$17);
15434
+ insertNode(_el$, _el$20);
15222
15435
  setProp(_el$, "paddingLeft", 2);
15223
15436
  setProp(_el$, "paddingRight", 2);
15224
15437
  setProp(_el$, "gap", 1);
@@ -15241,86 +15454,91 @@ function UpdateDialog(props) {
15241
15454
  insert(_el$10, () => props.info.latest, null);
15242
15455
  insertNode(_el$12, _el$13);
15243
15456
  insertNode(_el$12, _el$15);
15457
+ insertNode(_el$12, _el$17);
15244
15458
  setProp(_el$12, "gap", 0);
15245
15459
  insertNode(_el$13, createTextNode(`Run this to update:`));
15246
15460
  insertNode(_el$15, _el$16);
15247
15461
  setProp(_el$15, "paddingLeft", 2);
15248
- insert(_el$16, INSTALL_COMMAND);
15462
+ insert(_el$16, UPDATE_COMMAND);
15249
15463
  insertNode(_el$17, _el$18);
15250
- insertNode(_el$17, _el$20);
15251
- setProp(_el$17, "gap", 0);
15252
- insertNode(_el$18, createTextNode(`What's new:`));
15253
- setProp(_el$20, "paddingLeft", 2);
15254
- setProp(_el$20, "paddingTop", 1);
15255
- insert(_el$20, createComponent2(Switch, {
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, {
15256
15474
  get children() {
15257
15475
  return [createComponent2(Match, {
15258
15476
  get when() {
15259
15477
  return notes.loading;
15260
15478
  },
15261
15479
  get children() {
15262
- var _el$21 = createElement("text");
15263
- insertNode(_el$21, createTextNode(`Loading release notes\u2026`));
15264
- effect((_$p) => setProp(_el$21, "fg", theme.textMuted, _$p));
15265
- return _el$21;
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;
15266
15484
  }
15267
15485
  }), createComponent2(Match, {
15268
15486
  get when() {
15269
15487
  return notes() === null;
15270
15488
  },
15271
15489
  get children() {
15272
- var _el$23 = createElement("box"), _el$24 = createElement("text");
15273
- insertNode(_el$23, _el$24);
15274
- setProp(_el$23, "gap", 0);
15275
- insertNode(_el$24, createTextNode(`(couldn't reach GitHub \u2014 see the release page directly)`));
15276
- insert(_el$23, createComponent2(Show, {
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, {
15277
15495
  get when() {
15278
15496
  return fallbackUrl();
15279
15497
  },
15280
15498
  get children() {
15281
- var _el$26 = createElement("text");
15282
- insert(_el$26, fallbackUrl);
15283
- effect((_$p) => setProp(_el$26, "fg", theme.accent, _$p));
15284
- return _el$26;
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;
15285
15503
  }
15286
15504
  }), null);
15287
- effect((_$p) => setProp(_el$24, "fg", theme.textMuted, _$p));
15288
- return _el$23;
15505
+ effect((_$p) => setProp(_el$27, "fg", theme.textMuted, _$p));
15506
+ return _el$26;
15289
15507
  }
15290
15508
  }), createComponent2(Match, {
15291
15509
  get when() {
15292
15510
  return notes();
15293
15511
  },
15294
15512
  get children() {
15295
- var _el$27 = createElement("box");
15296
- setProp(_el$27, "flexDirection", "column");
15297
- setProp(_el$27, "gap", 0);
15298
- insert(_el$27, createComponent2(Markdown, {
15513
+ var _el$30 = createElement("box");
15514
+ setProp(_el$30, "flexDirection", "column");
15515
+ setProp(_el$30, "gap", 0);
15516
+ insert(_el$30, createComponent2(Markdown, {
15299
15517
  get source() {
15300
15518
  return notes()?.body ?? "";
15301
15519
  }
15302
15520
  }), null);
15303
- insert(_el$27, createComponent2(Show, {
15521
+ insert(_el$30, createComponent2(Show, {
15304
15522
  get when() {
15305
15523
  return notes()?.url;
15306
15524
  },
15307
15525
  get children() {
15308
- var _el$28 = createElement("box"), _el$29 = createElement("text"), _el$30 = createTextNode(`Full release: `);
15309
- insertNode(_el$28, _el$29);
15310
- setProp(_el$28, "paddingTop", 1);
15311
- insertNode(_el$29, _el$30);
15312
- insert(_el$29, () => notes()?.url, null);
15313
- effect((_$p) => setProp(_el$29, "fg", theme.textMuted, _$p));
15314
- return _el$28;
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;
15315
15533
  }
15316
15534
  }), null);
15317
- return _el$27;
15535
+ return _el$30;
15318
15536
  }
15319
15537
  })];
15320
15538
  }
15321
15539
  }));
15322
15540
  effect((_p$) => {
15323
- 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;
15324
15542
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
15325
15543
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
15326
15544
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -15332,6 +15550,7 @@ function UpdateDialog(props) {
15332
15550
  _v$9 !== _p$.r && (_p$.r = setProp(_el$16, "fg", _v$9, _p$.r));
15333
15551
  _v$0 !== _p$.d && (_p$.d = setProp(_el$16, "attributes", _v$0, _p$.d));
15334
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));
15335
15554
  return _p$;
15336
15555
  }, {
15337
15556
  e: undefined,
@@ -15344,7 +15563,8 @@ function UpdateDialog(props) {
15344
15563
  h: undefined,
15345
15564
  r: undefined,
15346
15565
  d: undefined,
15347
- l: undefined
15566
+ l: undefined,
15567
+ u: undefined
15348
15568
  });
15349
15569
  return _el$;
15350
15570
  })();
@@ -15571,7 +15791,8 @@ var init_sync = __esm(() => {
15571
15791
  });
15572
15792
 
15573
15793
  // src/engine/claude-code-local/history.ts
15574
- import { readFile as readFile4, readdir, unlink as unlink2 } from "fs/promises";
15794
+ import { randomUUID } from "crypto";
15795
+ import { appendFile, mkdir as mkdir3, readFile as readFile4, readdir, unlink as unlink2, writeFile as writeFile3 } from "fs/promises";
15575
15796
  import { homedir as homedir8 } from "os";
15576
15797
  import path6 from "path";
15577
15798
  function encodeCwd(cwd) {
@@ -15668,6 +15889,76 @@ function extractUsage(v) {
15668
15889
  function isObject(v) {
15669
15890
  return typeof v === "object" && v !== null && !Array.isArray(v);
15670
15891
  }
15892
+ async function appendInterruptedUserPrompt(sessionId, cwd, prompt, deps = defaultDeps2) {
15893
+ if (!prompt || prompt.trim().length === 0)
15894
+ return;
15895
+ const projectDir = path6.join(deps.projectsDir(), encodeCwd(cwd));
15896
+ const filePath = path6.join(projectDir, `${sessionId}.jsonl`);
15897
+ let lines = [];
15898
+ try {
15899
+ const raw = await readFile4(filePath, "utf8");
15900
+ lines = raw.split(`
15901
+ `).filter((l) => l.length > 0);
15902
+ } catch (err) {
15903
+ if (err.code !== "ENOENT")
15904
+ throw err;
15905
+ await mkdir3(projectDir, { recursive: true });
15906
+ }
15907
+ let lastConvIdx = -1;
15908
+ let lastConvRecord = null;
15909
+ let lastConvRole = null;
15910
+ for (let i = lines.length - 1;i >= 0; i--) {
15911
+ let parsed;
15912
+ try {
15913
+ parsed = JSON.parse(lines[i]);
15914
+ } catch {
15915
+ continue;
15916
+ }
15917
+ if (!isObject(parsed))
15918
+ continue;
15919
+ const inner = isObject(parsed.message) ? parsed.message : parsed;
15920
+ const role = inner.role;
15921
+ if (role === "user" || role === "assistant") {
15922
+ lastConvIdx = i;
15923
+ lastConvRecord = parsed;
15924
+ lastConvRole = role;
15925
+ break;
15926
+ }
15927
+ }
15928
+ const now = new Date().toISOString();
15929
+ if (lastConvRole === "user" && lastConvRecord && lastConvIdx >= 0) {
15930
+ const inner = isObject(lastConvRecord.message) ? lastConvRecord.message : lastConvRecord;
15931
+ const existing = typeof inner.content === "string" ? inner.content : "";
15932
+ if (existing === prompt || existing.endsWith(`
15933
+
15934
+ ${prompt}`))
15935
+ return;
15936
+ inner.content = existing.length > 0 ? `${existing}
15937
+
15938
+ ${prompt}` : prompt;
15939
+ lastConvRecord.timestamp = now;
15940
+ lines[lastConvIdx] = JSON.stringify(lastConvRecord);
15941
+ await writeFile3(filePath, `${lines.join(`
15942
+ `)}
15943
+ `);
15944
+ return;
15945
+ }
15946
+ const parentUuid = lastConvRecord && typeof lastConvRecord.uuid === "string" ? lastConvRecord.uuid : null;
15947
+ const record = {
15948
+ type: "user",
15949
+ message: { role: "user", content: prompt },
15950
+ uuid: randomUUID(),
15951
+ parentUuid,
15952
+ sessionId,
15953
+ cwd,
15954
+ timestamp: now,
15955
+ isSidechain: false,
15956
+ userType: "external",
15957
+ version: "1.0.0"
15958
+ };
15959
+ await appendFile(filePath, `${JSON.stringify(record)}
15960
+ `);
15961
+ }
15671
15962
  var defaultDeps2;
15672
15963
  var init_history = __esm(() => {
15673
15964
  defaultDeps2 = {
@@ -16075,13 +16366,21 @@ class ClaudeCodeLocal {
16075
16366
  }
16076
16367
  async stop(handle) {
16077
16368
  const sid = handle.sessionId;
16078
- await this.registry.kill(sid, this.stopGraceMs);
16079
16369
  const session = this.running.get(sid);
16370
+ const shouldRescue = !!session && !session.completedNaturally && session.prompt.trim().length > 0;
16371
+ const rescuePrompt = session?.prompt ?? "";
16372
+ const rescueCwd = session?.cwd ?? handle.cwd;
16373
+ await this.registry.kill(sid, this.stopGraceMs);
16080
16374
  if (session) {
16081
16375
  session.closed = true;
16082
16376
  this.notify(session);
16083
16377
  this.running.delete(sid);
16084
16378
  }
16379
+ if (shouldRescue) {
16380
+ try {
16381
+ await appendInterruptedUserPrompt(sid, rescueCwd, rescuePrompt);
16382
+ } catch {}
16383
+ }
16085
16384
  }
16086
16385
  async start(args2) {
16087
16386
  const binaryPath = await this.binaryPathResolver();
@@ -16114,14 +16413,17 @@ class ClaudeCodeLocal {
16114
16413
  spawned,
16115
16414
  queue,
16116
16415
  waiters: [],
16117
- closed: false
16416
+ closed: false,
16417
+ completedNaturally: false,
16418
+ prompt: args2.prompt
16118
16419
  };
16119
16420
  this.running.set(sessionId, session);
16120
16421
  this.registry.register({
16121
16422
  sessionId,
16122
16423
  cwd: args2.cwd,
16123
16424
  proc: spawned.proc,
16124
- startedAt: Date.now()
16425
+ startedAt: Date.now(),
16426
+ prompt: args2.prompt
16125
16427
  });
16126
16428
  resolveHandle({ sessionId, cwd: args2.cwd });
16127
16429
  };
@@ -16143,6 +16445,9 @@ class ClaudeCodeLocal {
16143
16445
  try {
16144
16446
  for await (const ev of events) {
16145
16447
  queue.push(ev);
16448
+ if (ev.type === "done" && session) {
16449
+ session.completedNaturally = true;
16450
+ }
16146
16451
  if (session)
16147
16452
  this.notify(session);
16148
16453
  }
@@ -16731,7 +17036,11 @@ function stripNewlines(v) {
16731
17036
  return v.replace(/[\r\n]+/g, "");
16732
17037
  }
16733
17038
  function nextField(field) {
16734
- return field === "repo" ? "baseRef" : "repo";
17039
+ if (field === "repo")
17040
+ return "baseRef";
17041
+ if (field === "baseRef")
17042
+ return "confirm";
17043
+ return "repo";
16735
17044
  }
16736
17045
  function computeRepoOptions(defaultRepo, savedRepos) {
16737
17046
  const seen = new Set;
@@ -16785,8 +17094,8 @@ function validateRepoPath(repo) {
16785
17094
  if (!stat3.isDirectory())
16786
17095
  return `not a directory: ${trimmed}`;
16787
17096
  try {
16788
- const { spawnSync: spawnSync8 } = __require("child_process");
16789
- const out = spawnSync8("git", ["rev-parse", "--git-dir"], {
17097
+ const { spawnSync: spawnSync9 } = __require("child_process");
17098
+ const out = spawnSync9("git", ["rev-parse", "--git-dir"], {
16790
17099
  cwd: trimmed,
16791
17100
  encoding: "utf-8",
16792
17101
  timeout: 2000,
@@ -16799,12 +17108,33 @@ function validateRepoPath(repo) {
16799
17108
  }
16800
17109
  return null;
16801
17110
  }
17111
+ function getCurrentBranch(repo) {
17112
+ if (!repo)
17113
+ return null;
17114
+ try {
17115
+ const { spawnSync: spawnSync9 } = __require("child_process");
17116
+ const out = spawnSync9("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
17117
+ cwd: repo,
17118
+ encoding: "utf-8",
17119
+ timeout: 2000,
17120
+ stdio: ["ignore", "pipe", "ignore"]
17121
+ });
17122
+ if (out.status !== 0)
17123
+ return null;
17124
+ const name = out.stdout.trim();
17125
+ if (!name || name === "HEAD")
17126
+ return null;
17127
+ return name;
17128
+ } catch {
17129
+ return null;
17130
+ }
17131
+ }
16802
17132
  function listLocalBranches(repo) {
16803
17133
  if (!repo)
16804
17134
  return [];
16805
17135
  try {
16806
- const { spawnSync: spawnSync8 } = __require("child_process");
16807
- const out = spawnSync8("git", ["for-each-ref", "--format=%(refname:short)", "refs/heads/"], {
17136
+ const { spawnSync: spawnSync9 } = __require("child_process");
17137
+ const out = spawnSync9("git", ["for-each-ref", "--format=%(refname:short)", "refs/heads/"], {
16808
17138
  cwd: repo,
16809
17139
  encoding: "utf-8",
16810
17140
  timeout: 2000
@@ -16896,7 +17226,8 @@ function NewTaskDialogView(props) {
16896
17226
  } = useTheme();
16897
17227
  const [field, setField] = createSignal("repo");
16898
17228
  const [repo, setRepo] = createSignal(props.defaultRepo);
16899
- const [baseRef, setBaseRef] = createSignal(DEFAULT_BASE_REF);
17229
+ const [baseRef, setBaseRef] = createSignal(getCurrentBranch(expandHome(props.defaultRepo.trim())) ?? DEFAULT_BASE_REF);
17230
+ const [baseRefTouched, setBaseRefTouched] = createSignal(false);
16900
17231
  const repoOptions = createMemo(() => computeRepoOptions(props.defaultRepo, props.savedRepos));
16901
17232
  const mode = createMemo(() => pickerModeFor(repo(), repoOptions()));
16902
17233
  const subdirSplit = createMemo(() => splitPathForDirSuggest(repo()));
@@ -16914,6 +17245,16 @@ function NewTaskDialogView(props) {
16914
17245
  branchFiltered();
16915
17246
  setBranchCursor(0);
16916
17247
  });
17248
+ createEffect(() => {
17249
+ const r = expandHome(repo().trim());
17250
+ if (!r)
17251
+ return;
17252
+ if (baseRefTouched())
17253
+ return;
17254
+ const current = getCurrentBranch(r);
17255
+ if (current)
17256
+ setBaseRef(current);
17257
+ });
16917
17258
  createEffect(() => {
16918
17259
  activeList();
16919
17260
  setRepoCursor(0);
@@ -16945,7 +17286,7 @@ function NewTaskDialogView(props) {
16945
17286
  const picked2 = activeList()[0];
16946
17287
  if (picked2) {
16947
17288
  setRepo(picked2);
16948
- commit();
17289
+ setField("baseRef");
16949
17290
  return;
16950
17291
  }
16951
17292
  }
@@ -16964,16 +17305,16 @@ function NewTaskDialogView(props) {
16964
17305
  return;
16965
17306
  }
16966
17307
  }
16967
- commit();
17308
+ setField("baseRef");
16968
17309
  return;
16969
17310
  }
16970
17311
  const picked = activeList()[repoCursor()];
16971
17312
  if (picked) {
16972
17313
  setRepo(picked);
16973
- commit();
17314
+ setField("baseRef");
16974
17315
  return;
16975
17316
  }
16976
- commit();
17317
+ setField("baseRef");
16977
17318
  }
16978
17319
  function selectRepoAtMouse(absoluteIndex) {
16979
17320
  const list = activeList();
@@ -17030,8 +17371,15 @@ function NewTaskDialogView(props) {
17030
17371
  }
17031
17372
  }]
17032
17373
  }));
17374
+ useBindings(() => ({
17375
+ enabled: field() === "confirm",
17376
+ bindings: [{
17377
+ key: "return",
17378
+ cmd: () => commit()
17379
+ }]
17380
+ }));
17033
17381
  return (() => {
17034
- 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$0 = createElement("input"), _el$18 = createElement("box"), _el$19 = createElement("text"), _el$21 = createElement("input"), _el$31 = createElement("box"), _el$32 = createElement("text");
17382
+ 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$0 = createElement("input"), _el$18 = createElement("box"), _el$19 = createElement("text"), _el$21 = createElement("input"), _el$31 = createElement("box"), _el$32 = createElement("text"), _el$34 = createElement("text");
17035
17383
  insertNode(_el$, _el$2);
17036
17384
  insertNode(_el$, _el$7);
17037
17385
  insertNode(_el$, _el$18);
@@ -17090,23 +17438,23 @@ function NewTaskDialogView(props) {
17090
17438
  const suffix = () => mode() === "browse" ? "/" : "";
17091
17439
  const tag = () => isCurrentDir() ? " (current dir)" : "";
17092
17440
  return (() => {
17093
- var _el$34 = createElement("text");
17094
- setProp(_el$34, "wrapMode", "none");
17095
- setProp(_el$34, "onMouseUp", () => selectRepoAtMouse(absoluteIndex()));
17096
- insert(_el$34, () => isCursor() ? "\u25B8 " : " ", null);
17097
- insert(_el$34, name, null);
17098
- insert(_el$34, suffix, null);
17099
- insert(_el$34, tag, null);
17441
+ var _el$35 = createElement("text");
17442
+ setProp(_el$35, "wrapMode", "none");
17443
+ setProp(_el$35, "onMouseUp", () => selectRepoAtMouse(absoluteIndex()));
17444
+ insert(_el$35, () => isCursor() ? "\u25B8 " : " ", null);
17445
+ insert(_el$35, name, null);
17446
+ insert(_el$35, suffix, null);
17447
+ insert(_el$35, tag, null);
17100
17448
  effect((_p$) => {
17101
- var _v$10 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$11 = isCursor() ? TextAttributes19.BOLD : undefined;
17102
- _v$10 !== _p$.e && (_p$.e = setProp(_el$34, "fg", _v$10, _p$.e));
17103
- _v$11 !== _p$.t && (_p$.t = setProp(_el$34, "attributes", _v$11, _p$.t));
17449
+ var _v$12 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$13 = isCursor() ? TextAttributes19.BOLD : undefined;
17450
+ _v$12 !== _p$.e && (_p$.e = setProp(_el$35, "fg", _v$12, _p$.e));
17451
+ _v$13 !== _p$.t && (_p$.t = setProp(_el$35, "attributes", _v$13, _p$.t));
17104
17452
  return _p$;
17105
17453
  }, {
17106
17454
  e: undefined,
17107
17455
  t: undefined
17108
17456
  });
17109
- return _el$34;
17457
+ return _el$35;
17110
17458
  })();
17111
17459
  }
17112
17460
  }), null);
@@ -17144,10 +17492,14 @@ function NewTaskDialogView(props) {
17144
17492
  setProp(_el$18, "gap", 0);
17145
17493
  insertNode(_el$19, createTextNode(`from branch`));
17146
17494
  setProp(_el$21, "placeholder", DEFAULT_BASE_REF);
17147
- setProp(_el$21, "onInput", (v) => setBaseRef(stripNewlines(v)));
17495
+ setProp(_el$21, "onInput", (v) => {
17496
+ setBaseRefTouched(true);
17497
+ setBaseRef(stripNewlines(v));
17498
+ });
17148
17499
  setProp(_el$21, "onSubmit", () => {
17149
17500
  setBaseRef(resolveBaseRef(baseRef(), branchFiltered(), branchCursor()));
17150
- commit();
17501
+ setBaseRefTouched(true);
17502
+ setField("confirm");
17151
17503
  });
17152
17504
  insert(_el$, createComponent2(Show, {
17153
17505
  get when() {
@@ -17197,25 +17549,26 @@ function NewTaskDialogView(props) {
17197
17549
  const isCursor = () => absoluteIndex() === branchCursor();
17198
17550
  const isSelected = () => baseRef().trim() === name;
17199
17551
  return (() => {
17200
- var _el$35 = createElement("text");
17201
- setProp(_el$35, "wrapMode", "none");
17202
- setProp(_el$35, "onMouseUp", () => {
17552
+ var _el$36 = createElement("text");
17553
+ setProp(_el$36, "wrapMode", "none");
17554
+ setProp(_el$36, "onMouseUp", () => {
17203
17555
  setBaseRef(name);
17556
+ setBaseRefTouched(true);
17204
17557
  setBranchCursor(absoluteIndex());
17205
- commit();
17558
+ setField("confirm");
17206
17559
  });
17207
- insert(_el$35, () => isCursor() ? "\u25B8 " : " ", null);
17208
- insert(_el$35, name, null);
17560
+ insert(_el$36, () => isCursor() ? "\u25B8 " : " ", null);
17561
+ insert(_el$36, name, null);
17209
17562
  effect((_p$) => {
17210
- var _v$12 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$13 = isCursor() ? TextAttributes19.BOLD : undefined;
17211
- _v$12 !== _p$.e && (_p$.e = setProp(_el$35, "fg", _v$12, _p$.e));
17212
- _v$13 !== _p$.t && (_p$.t = setProp(_el$35, "attributes", _v$13, _p$.t));
17563
+ var _v$14 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$15 = isCursor() ? TextAttributes19.BOLD : undefined;
17564
+ _v$14 !== _p$.e && (_p$.e = setProp(_el$36, "fg", _v$14, _p$.e));
17565
+ _v$15 !== _p$.t && (_p$.t = setProp(_el$36, "attributes", _v$15, _p$.t));
17213
17566
  return _p$;
17214
17567
  }, {
17215
17568
  e: undefined,
17216
17569
  t: undefined
17217
17570
  });
17218
- return _el$35;
17571
+ return _el$36;
17219
17572
  })();
17220
17573
  }
17221
17574
  }), null);
@@ -17237,10 +17590,15 @@ function NewTaskDialogView(props) {
17237
17590
  }
17238
17591
  }), _el$31);
17239
17592
  insertNode(_el$31, _el$32);
17593
+ insertNode(_el$31, _el$34);
17594
+ setProp(_el$31, "flexDirection", "row");
17595
+ setProp(_el$31, "justifyContent", "space-between");
17240
17596
  setProp(_el$31, "paddingBottom", 1);
17241
17597
  insertNode(_el$32, createTextNode(`\u2191\u2193 pick \xB7 enter select \xB7 tab next field \xB7 esc cancel`));
17598
+ setProp(_el$34, "onMouseUp", () => commit());
17599
+ insert(_el$34, () => field() === "confirm" ? "\u25B8 [ Create ]" : " [ Create ]");
17242
17600
  effect((_p$) => {
17243
- var _v$ = TextAttributes19.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = field() === "repo" ? theme.accent : theme.textMuted, _v$5 = repo(), _v$6 = props.defaultRepo, _v$7 = field() === "repo", _v$8 = field() === "baseRef" ? theme.accent : theme.textMuted, _v$9 = baseRef(), _v$0 = field() === "baseRef", _v$1 = theme.textMuted;
17601
+ var _v$ = TextAttributes19.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = field() === "repo" ? theme.accent : theme.textMuted, _v$5 = repo(), _v$6 = props.defaultRepo, _v$7 = field() === "repo", _v$8 = field() === "baseRef" ? theme.accent : theme.textMuted, _v$9 = baseRef(), _v$0 = field() === "baseRef", _v$1 = theme.textMuted, _v$10 = field() === "confirm" ? theme.primary : theme.text, _v$11 = field() === "confirm" ? TextAttributes19.BOLD : undefined;
17244
17602
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
17245
17603
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
17246
17604
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -17252,6 +17610,8 @@ function NewTaskDialogView(props) {
17252
17610
  _v$9 !== _p$.r && (_p$.r = setProp(_el$21, "value", _v$9, _p$.r));
17253
17611
  _v$0 !== _p$.d && (_p$.d = setProp(_el$21, "focused", _v$0, _p$.d));
17254
17612
  _v$1 !== _p$.l && (_p$.l = setProp(_el$32, "fg", _v$1, _p$.l));
17613
+ _v$10 !== _p$.u && (_p$.u = setProp(_el$34, "fg", _v$10, _p$.u));
17614
+ _v$11 !== _p$.c && (_p$.c = setProp(_el$34, "attributes", _v$11, _p$.c));
17255
17615
  return _p$;
17256
17616
  }, {
17257
17617
  e: undefined,
@@ -17264,7 +17624,9 @@ function NewTaskDialogView(props) {
17264
17624
  h: undefined,
17265
17625
  r: undefined,
17266
17626
  d: undefined,
17267
- l: undefined
17627
+ l: undefined,
17628
+ u: undefined,
17629
+ c: undefined
17268
17630
  });
17269
17631
  return _el$;
17270
17632
  })();
@@ -17409,11 +17771,17 @@ var init_rename_task_dialog = __esm(() => {
17409
17771
  function useTaskActions(deps) {
17410
17772
  const { orchestrator, dialog, kv, selectedId, setSelectedId, setFocusedPane, savedRepos } = deps;
17411
17773
  async function openNewTaskFlow() {
17412
- const lastRepo = (() => {
17774
+ const defaultRepo = (() => {
17775
+ const sid = selectedId();
17776
+ if (sid) {
17777
+ const task = orchestrator.getTask(sid);
17778
+ if (task?.repo?.trim())
17779
+ return task.repo;
17780
+ }
17413
17781
  const raw = kv.get("lastNewTaskRepo");
17414
17782
  return typeof raw === "string" && raw.trim() ? raw : process.cwd();
17415
17783
  })();
17416
- const result = await NewTaskDialog.show(dialog, lastRepo, savedRepos());
17784
+ const result = await NewTaskDialog.show(dialog, defaultRepo, savedRepos());
17417
17785
  if (!result)
17418
17786
  return;
17419
17787
  try {
@@ -17885,7 +18253,7 @@ var init_resume_dialog = __esm(() => {
17885
18253
  });
17886
18254
 
17887
18255
  // src/tui/panes/chat/composer/clipboard-image.ts
17888
- import { spawnSync as spawnSync8 } from "child_process";
18256
+ import { spawnSync as spawnSync9 } from "child_process";
17889
18257
  import { statSync as statSync4 } from "fs";
17890
18258
  function clipboardImageSupported() {
17891
18259
  return process.platform === "darwin";
@@ -17910,7 +18278,7 @@ function readClipboardImageMacOS(destPath) {
17910
18278
  "end try"
17911
18279
  ].join(`
17912
18280
  `);
17913
- const result = spawnSync8("osascript", ["-e", script], {
18281
+ const result = spawnSync9("osascript", ["-e", script], {
17914
18282
  timeout: 5000,
17915
18283
  stdio: ["ignore", "ignore", "ignore"]
17916
18284
  });
@@ -17956,7 +18324,7 @@ var init_history2 = __esm(() => {
17956
18324
  });
17957
18325
 
17958
18326
  // src/tui/panes/chat/composer/image-paste.ts
17959
- import { randomUUID } from "crypto";
18327
+ import { randomUUID as randomUUID2 } from "crypto";
17960
18328
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "fs";
17961
18329
  import { join as join13 } from "path";
17962
18330
  function pastedImagesDir() {
@@ -18040,7 +18408,7 @@ function mimeTypeToExt(mimeType) {
18040
18408
  return ".png";
18041
18409
  }
18042
18410
  function mintPath(ext) {
18043
- return join13(pastedImagesDir(), `${randomUUID()}${ext}`);
18411
+ return join13(pastedImagesDir(), `${randomUUID2()}${ext}`);
18044
18412
  }
18045
18413
  var IMAGE_TOKEN_RE;
18046
18414
  var init_image_paste = __esm(() => {
@@ -18642,9 +19010,9 @@ function Composer(props) {
18642
19010
  return theme.border;
18643
19011
  };
18644
19012
  return (() => {
18645
- var _el$ = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("box"), _el$16 = createElement("box"), _el$17 = createElement("text"), _el$18 = createElement("box"), _el$25 = createElement("box"), _el$26 = createElement("box");
19013
+ var _el$ = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("box"), _el$21 = createElement("box"), _el$22 = createElement("text"), _el$23 = createElement("box"), _el$30 = createElement("box"), _el$31 = createElement("box");
18646
19014
  insertNode(_el$, _el$14);
18647
- insertNode(_el$, _el$25);
19015
+ insertNode(_el$, _el$30);
18648
19016
  setProp(_el$, "flexShrink", 0);
18649
19017
  setProp(_el$, "flexDirection", "column");
18650
19018
  setProp(_el$, "paddingTop", 1);
@@ -18691,35 +19059,35 @@ function Composer(props) {
18691
19059
  return idx >= 0 ? match.displayPath.slice(0, idx) : "";
18692
19060
  };
18693
19061
  return (() => {
18694
- var _el$27 = createElement("box"), _el$28 = createElement("text");
18695
- insertNode(_el$27, _el$28);
18696
- setProp(_el$27, "flexDirection", "row");
18697
- setProp(_el$27, "gap", 2);
18698
- setProp(_el$28, "wrapMode", "none");
18699
- insert(_el$28, () => active() ? "\u25B8 " : " ", null);
18700
- insert(_el$28, filename, null);
18701
- insert(_el$27, createComponent2(Show, {
19062
+ var _el$32 = createElement("box"), _el$33 = createElement("text");
19063
+ insertNode(_el$32, _el$33);
19064
+ setProp(_el$32, "flexDirection", "row");
19065
+ setProp(_el$32, "gap", 2);
19066
+ setProp(_el$33, "wrapMode", "none");
19067
+ insert(_el$33, () => active() ? "\u25B8 " : " ", null);
19068
+ insert(_el$33, filename, null);
19069
+ insert(_el$32, createComponent2(Show, {
18702
19070
  get when() {
18703
19071
  return directory().length > 0;
18704
19072
  },
18705
19073
  get children() {
18706
- var _el$29 = createElement("text");
18707
- setProp(_el$29, "wrapMode", "none");
18708
- insert(_el$29, directory);
18709
- effect((_$p) => setProp(_el$29, "fg", theme.textMuted, _$p));
18710
- return _el$29;
19074
+ var _el$34 = createElement("text");
19075
+ setProp(_el$34, "wrapMode", "none");
19076
+ insert(_el$34, directory);
19077
+ effect((_$p) => setProp(_el$34, "fg", theme.textMuted, _$p));
19078
+ return _el$34;
18711
19079
  }
18712
19080
  }), null);
18713
19081
  effect((_p$) => {
18714
- var _v$20 = active() ? theme.primary : theme.text, _v$21 = active() ? TextAttributes22.BOLD : undefined;
18715
- _v$20 !== _p$.e && (_p$.e = setProp(_el$28, "fg", _v$20, _p$.e));
18716
- _v$21 !== _p$.t && (_p$.t = setProp(_el$28, "attributes", _v$21, _p$.t));
19082
+ var _v$23 = active() ? theme.primary : theme.text, _v$24 = active() ? TextAttributes22.BOLD : undefined;
19083
+ _v$23 !== _p$.e && (_p$.e = setProp(_el$33, "fg", _v$23, _p$.e));
19084
+ _v$24 !== _p$.t && (_p$.t = setProp(_el$33, "attributes", _v$24, _p$.t));
18717
19085
  return _p$;
18718
19086
  }, {
18719
19087
  e: undefined,
18720
19088
  t: undefined
18721
19089
  });
18722
- return _el$27;
19090
+ return _el$32;
18723
19091
  })();
18724
19092
  }
18725
19093
  }), null);
@@ -18786,47 +19154,47 @@ function Composer(props) {
18786
19154
  const absoluteIndex = () => slashWindow().start + i();
18787
19155
  const active = () => absoluteIndex() === slashCursor();
18788
19156
  return (() => {
18789
- var _el$30 = createElement("box"), _el$31 = createElement("text");
18790
- insertNode(_el$30, _el$31);
18791
- setProp(_el$30, "flexDirection", "row");
18792
- setProp(_el$30, "gap", 2);
18793
- setProp(_el$31, "wrapMode", "none");
18794
- insert(_el$31, () => active() ? "\u25B8 " : " ", null);
18795
- insert(_el$31, () => entry.display, null);
18796
- insert(_el$30, createComponent2(Show, {
19157
+ var _el$35 = createElement("box"), _el$36 = createElement("text");
19158
+ insertNode(_el$35, _el$36);
19159
+ setProp(_el$35, "flexDirection", "row");
19160
+ setProp(_el$35, "gap", 2);
19161
+ setProp(_el$36, "wrapMode", "none");
19162
+ insert(_el$36, () => active() ? "\u25B8 " : " ", null);
19163
+ insert(_el$36, () => entry.display, null);
19164
+ insert(_el$35, createComponent2(Show, {
18797
19165
  get when() {
18798
19166
  return entry.source === "user";
18799
19167
  },
18800
19168
  get children() {
18801
- var _el$32 = createElement("text");
18802
- insertNode(_el$32, createTextNode(`user`));
18803
- setProp(_el$32, "wrapMode", "none");
18804
- effect((_$p) => setProp(_el$32, "fg", theme.textMuted, _$p));
18805
- return _el$32;
19169
+ var _el$37 = createElement("text");
19170
+ insertNode(_el$37, createTextNode(`user`));
19171
+ setProp(_el$37, "wrapMode", "none");
19172
+ effect((_$p) => setProp(_el$37, "fg", theme.textMuted, _$p));
19173
+ return _el$37;
18806
19174
  }
18807
19175
  }), null);
18808
- insert(_el$30, createComponent2(Show, {
19176
+ insert(_el$35, createComponent2(Show, {
18809
19177
  get when() {
18810
19178
  return entry.description;
18811
19179
  },
18812
19180
  get children() {
18813
- var _el$34 = createElement("text");
18814
- setProp(_el$34, "wrapMode", "none");
18815
- insert(_el$34, () => entry.description);
18816
- effect((_$p) => setProp(_el$34, "fg", theme.textMuted, _$p));
18817
- return _el$34;
19181
+ var _el$39 = createElement("text");
19182
+ setProp(_el$39, "wrapMode", "none");
19183
+ insert(_el$39, () => entry.description);
19184
+ effect((_$p) => setProp(_el$39, "fg", theme.textMuted, _$p));
19185
+ return _el$39;
18818
19186
  }
18819
19187
  }), null);
18820
19188
  effect((_p$) => {
18821
- var _v$22 = active() ? theme.primary : theme.text, _v$23 = active() ? TextAttributes22.BOLD : undefined;
18822
- _v$22 !== _p$.e && (_p$.e = setProp(_el$31, "fg", _v$22, _p$.e));
18823
- _v$23 !== _p$.t && (_p$.t = setProp(_el$31, "attributes", _v$23, _p$.t));
19189
+ var _v$25 = active() ? theme.primary : theme.text, _v$26 = active() ? TextAttributes22.BOLD : undefined;
19190
+ _v$25 !== _p$.e && (_p$.e = setProp(_el$36, "fg", _v$25, _p$.e));
19191
+ _v$26 !== _p$.t && (_p$.t = setProp(_el$36, "attributes", _v$26, _p$.t));
18824
19192
  return _p$;
18825
19193
  }, {
18826
19194
  e: undefined,
18827
19195
  t: undefined
18828
19196
  });
18829
- return _el$30;
19197
+ return _el$35;
18830
19198
  })();
18831
19199
  }
18832
19200
  }), null);
@@ -18860,37 +19228,125 @@ function Composer(props) {
18860
19228
  }), _el$14);
18861
19229
  insertNode(_el$14, _el$15);
18862
19230
  setProp(_el$14, "border", ["left"]);
18863
- insertNode(_el$15, _el$16);
19231
+ insertNode(_el$15, _el$21);
18864
19232
  setProp(_el$15, "paddingLeft", 2);
18865
19233
  setProp(_el$15, "paddingRight", 2);
18866
19234
  setProp(_el$15, "paddingTop", 1);
18867
19235
  setProp(_el$15, "paddingBottom", 0);
18868
19236
  setProp(_el$15, "flexDirection", "column");
18869
19237
  setProp(_el$15, "flexGrow", 1);
18870
- insertNode(_el$16, _el$17);
18871
- insertNode(_el$16, _el$18);
18872
- setProp(_el$16, "flexDirection", "row");
18873
- setProp(_el$16, "gap", 1);
18874
- setProp(_el$16, "alignItems", "flex-start");
18875
- insert(_el$17, () => props.isStreaming ? "\u2026" : ">");
18876
- setProp(_el$18, "flexGrow", 1);
18877
- setProp(_el$18, "flexShrink", 1);
18878
- setProp(_el$18, "maxHeight", 8);
18879
- setProp(_el$18, "minHeight", 1);
18880
- insert(_el$18, createComponent2(Show, {
19238
+ insert(_el$15, createComponent2(Show, {
19239
+ get when() {
19240
+ return (props.queue?.() ?? []).length > 0;
19241
+ },
19242
+ get children() {
19243
+ var _el$16 = createElement("box");
19244
+ setProp(_el$16, "flexDirection", "column");
19245
+ setProp(_el$16, "paddingBottom", 1);
19246
+ insert(_el$16, createComponent2(For, {
19247
+ get each() {
19248
+ return (props.queue?.() ?? []).slice(0, QUEUE_VISIBLE_CAP);
19249
+ },
19250
+ children: (entry, idx) => (() => {
19251
+ var _el$40 = createElement("box"), _el$41 = createElement("text"), _el$43 = createElement("text"), _el$44 = createTextNode(`queued`), _el$45 = createTextNode(`:`), _el$46 = createElement("box"), _el$47 = createElement("text"), _el$48 = createElement("text"), _el$50 = createElement("text");
19252
+ insertNode(_el$40, _el$41);
19253
+ insertNode(_el$40, _el$43);
19254
+ insertNode(_el$40, _el$46);
19255
+ insertNode(_el$40, _el$48);
19256
+ insertNode(_el$40, _el$50);
19257
+ setProp(_el$40, "flexDirection", "row");
19258
+ setProp(_el$40, "gap", 1);
19259
+ setProp(_el$40, "alignItems", "flex-start");
19260
+ insertNode(_el$41, createTextNode(`+`));
19261
+ insertNode(_el$43, _el$44);
19262
+ insertNode(_el$43, _el$45);
19263
+ setProp(_el$43, "wrapMode", "none");
19264
+ insert(_el$43, () => idx() === 0 ? " (next)" : "", _el$45);
19265
+ insertNode(_el$46, _el$47);
19266
+ setProp(_el$46, "flexGrow", 1);
19267
+ insert(_el$47, () => entry.text);
19268
+ insertNode(_el$48, createTextNode(`[\u25B6]`));
19269
+ setProp(_el$48, "onMouseUp", () => props.onSendQueuedNow?.(entry.id));
19270
+ insertNode(_el$50, createTextNode(`[x]`));
19271
+ setProp(_el$50, "onMouseUp", () => props.onCancelQueued?.(entry.id));
19272
+ effect((_p$) => {
19273
+ var _v$27 = theme.textMuted, _v$28 = TextAttributes22.BOLD, _v$29 = theme.textMuted, _v$30 = theme.text, _v$31 = theme.primary, _v$32 = TextAttributes22.BOLD, _v$33 = theme.error, _v$34 = TextAttributes22.BOLD;
19274
+ _v$27 !== _p$.e && (_p$.e = setProp(_el$41, "fg", _v$27, _p$.e));
19275
+ _v$28 !== _p$.t && (_p$.t = setProp(_el$41, "attributes", _v$28, _p$.t));
19276
+ _v$29 !== _p$.a && (_p$.a = setProp(_el$43, "fg", _v$29, _p$.a));
19277
+ _v$30 !== _p$.o && (_p$.o = setProp(_el$47, "fg", _v$30, _p$.o));
19278
+ _v$31 !== _p$.i && (_p$.i = setProp(_el$48, "fg", _v$31, _p$.i));
19279
+ _v$32 !== _p$.n && (_p$.n = setProp(_el$48, "attributes", _v$32, _p$.n));
19280
+ _v$33 !== _p$.s && (_p$.s = setProp(_el$50, "fg", _v$33, _p$.s));
19281
+ _v$34 !== _p$.h && (_p$.h = setProp(_el$50, "attributes", _v$34, _p$.h));
19282
+ return _p$;
19283
+ }, {
19284
+ e: undefined,
19285
+ t: undefined,
19286
+ a: undefined,
19287
+ o: undefined,
19288
+ i: undefined,
19289
+ n: undefined,
19290
+ s: undefined,
19291
+ h: undefined
19292
+ });
19293
+ return _el$40;
19294
+ })()
19295
+ }), null);
19296
+ insert(_el$16, createComponent2(Show, {
19297
+ get when() {
19298
+ return (props.queue?.() ?? []).length > QUEUE_VISIBLE_CAP;
19299
+ },
19300
+ get children() {
19301
+ var _el$17 = createElement("box"), _el$18 = createElement("text"), _el$20 = createElement("text");
19302
+ insertNode(_el$17, _el$18);
19303
+ insertNode(_el$17, _el$20);
19304
+ setProp(_el$17, "flexDirection", "row");
19305
+ setProp(_el$17, "gap", 1);
19306
+ setProp(_el$17, "alignItems", "flex-start");
19307
+ insertNode(_el$18, createTextNode(`+`));
19308
+ insert(_el$20, () => `\u2026 ${(props.queue?.() ?? []).length - QUEUE_VISIBLE_CAP} more queued`);
19309
+ effect((_p$) => {
19310
+ var _v$7 = theme.textMuted, _v$8 = TextAttributes22.BOLD, _v$9 = theme.textMuted;
19311
+ _v$7 !== _p$.e && (_p$.e = setProp(_el$18, "fg", _v$7, _p$.e));
19312
+ _v$8 !== _p$.t && (_p$.t = setProp(_el$18, "attributes", _v$8, _p$.t));
19313
+ _v$9 !== _p$.a && (_p$.a = setProp(_el$20, "fg", _v$9, _p$.a));
19314
+ return _p$;
19315
+ }, {
19316
+ e: undefined,
19317
+ t: undefined,
19318
+ a: undefined
19319
+ });
19320
+ return _el$17;
19321
+ }
19322
+ }), null);
19323
+ return _el$16;
19324
+ }
19325
+ }), _el$21);
19326
+ insertNode(_el$21, _el$22);
19327
+ insertNode(_el$21, _el$23);
19328
+ setProp(_el$21, "flexDirection", "row");
19329
+ setProp(_el$21, "gap", 1);
19330
+ setProp(_el$21, "alignItems", "flex-start");
19331
+ insert(_el$22, () => props.isStreaming ? "\u2026" : ">");
19332
+ setProp(_el$23, "flexGrow", 1);
19333
+ setProp(_el$23, "flexShrink", 1);
19334
+ setProp(_el$23, "maxHeight", 8);
19335
+ setProp(_el$23, "minHeight", 1);
19336
+ insert(_el$23, createComponent2(Show, {
18881
19337
  get when() {
18882
19338
  return props.hasTask;
18883
19339
  },
18884
19340
  get fallback() {
18885
19341
  return (() => {
18886
- var _el$35 = createElement("text");
18887
- insert(_el$35, () => props.noTaskMessage ?? "(no task \u2014 press n to create)");
18888
- effect((_$p) => setProp(_el$35, "fg", theme.textMuted, _$p));
18889
- return _el$35;
19342
+ var _el$52 = createElement("text");
19343
+ insert(_el$52, () => props.noTaskMessage ?? "(no task \u2014 press n to create)");
19344
+ effect((_$p) => setProp(_el$52, "fg", theme.textMuted, _$p));
19345
+ return _el$52;
18890
19346
  })();
18891
19347
  },
18892
19348
  get children() {
18893
- var _el$19 = createElement("textarea");
19349
+ var _el$24 = createElement("textarea");
18894
19350
  use((r) => {
18895
19351
  textareaRef = r;
18896
19352
  if (props.draft)
@@ -18898,23 +19354,23 @@ function Composer(props) {
18898
19354
  r.onPaste = handlePaste;
18899
19355
  if (props.focused?.())
18900
19356
  r.focus();
18901
- }, _el$19);
18902
- setProp(_el$19, "wrapMode", "word");
18903
- setProp(_el$19, "keyBindings", composerKeyBindings);
18904
- setProp(_el$19, "onContentChange", handleContentChange);
18905
- setProp(_el$19, "onKeyDown", handleKeyDown);
18906
- setProp(_el$19, "onSubmit", () => handleSubmit("auto"));
19357
+ }, _el$24);
19358
+ setProp(_el$24, "wrapMode", "word");
19359
+ setProp(_el$24, "keyBindings", composerKeyBindings);
19360
+ setProp(_el$24, "onContentChange", handleContentChange);
19361
+ setProp(_el$24, "onKeyDown", handleKeyDown);
19362
+ setProp(_el$24, "onSubmit", () => handleSubmit("auto"));
18907
19363
  effect((_p$) => {
18908
- var _v$7 = resolvePlaceholder({
19364
+ var _v$0 = resolvePlaceholder({
18909
19365
  isStreaming: props.isStreaming,
18910
19366
  hasTask: props.hasTask,
18911
19367
  noTaskMessage: props.noTaskMessage
18912
- }), _v$8 = theme.textMuted, _v$9 = theme.text, _v$0 = theme.backgroundElement, _v$1 = theme.backgroundElement;
18913
- _v$7 !== _p$.e && (_p$.e = setProp(_el$19, "placeholder", _v$7, _p$.e));
18914
- _v$8 !== _p$.t && (_p$.t = setProp(_el$19, "placeholderColor", _v$8, _p$.t));
18915
- _v$9 !== _p$.a && (_p$.a = setProp(_el$19, "textColor", _v$9, _p$.a));
18916
- _v$0 !== _p$.o && (_p$.o = setProp(_el$19, "backgroundColor", _v$0, _p$.o));
18917
- _v$1 !== _p$.i && (_p$.i = setProp(_el$19, "focusedBackgroundColor", _v$1, _p$.i));
19368
+ }), _v$1 = theme.textMuted, _v$10 = theme.text, _v$11 = theme.backgroundElement, _v$12 = theme.backgroundElement;
19369
+ _v$0 !== _p$.e && (_p$.e = setProp(_el$24, "placeholder", _v$0, _p$.e));
19370
+ _v$1 !== _p$.t && (_p$.t = setProp(_el$24, "placeholderColor", _v$1, _p$.t));
19371
+ _v$10 !== _p$.a && (_p$.a = setProp(_el$24, "textColor", _v$10, _p$.a));
19372
+ _v$11 !== _p$.o && (_p$.o = setProp(_el$24, "backgroundColor", _v$11, _p$.o));
19373
+ _v$12 !== _p$.i && (_p$.i = setProp(_el$24, "focusedBackgroundColor", _v$12, _p$.i));
18918
19374
  return _p$;
18919
19375
  }, {
18920
19376
  e: undefined,
@@ -18923,7 +19379,7 @@ function Composer(props) {
18923
19379
  o: undefined,
18924
19380
  i: undefined
18925
19381
  });
18926
- return _el$19;
19382
+ return _el$24;
18927
19383
  }
18928
19384
  }));
18929
19385
  insert(_el$15, createComponent2(Show, {
@@ -18931,74 +19387,74 @@ function Composer(props) {
18931
19387
  return props.hasTask;
18932
19388
  },
18933
19389
  get children() {
18934
- var _el$20 = createElement("box"), _el$21 = createElement("text"), _el$22 = createElement("box"), _el$23 = createElement("box"), _el$24 = createElement("text");
18935
- insertNode(_el$20, _el$21);
18936
- insertNode(_el$20, _el$22);
18937
- setProp(_el$20, "flexDirection", "row");
18938
- setProp(_el$20, "justifyContent", "space-between");
18939
- setProp(_el$20, "paddingTop", 1);
18940
- setProp(_el$20, "flexShrink", 0);
18941
- setProp(_el$21, "wrapMode", "none");
18942
- insert(_el$21, footerHint);
18943
- insertNode(_el$22, _el$23);
18944
- setProp(_el$22, "flexDirection", "row");
18945
- setProp(_el$22, "gap", 2);
18946
- setProp(_el$22, "flexShrink", 0);
18947
- insert(_el$22, createComponent2(Show, {
19390
+ var _el$25 = createElement("box"), _el$26 = createElement("text"), _el$27 = createElement("box"), _el$28 = createElement("box"), _el$29 = createElement("text");
19391
+ insertNode(_el$25, _el$26);
19392
+ insertNode(_el$25, _el$27);
19393
+ setProp(_el$25, "flexDirection", "row");
19394
+ setProp(_el$25, "justifyContent", "space-between");
19395
+ setProp(_el$25, "paddingTop", 1);
19396
+ setProp(_el$25, "flexShrink", 0);
19397
+ setProp(_el$26, "wrapMode", "none");
19398
+ insert(_el$26, footerHint);
19399
+ insertNode(_el$27, _el$28);
19400
+ setProp(_el$27, "flexDirection", "row");
19401
+ setProp(_el$27, "gap", 2);
19402
+ setProp(_el$27, "flexShrink", 0);
19403
+ insert(_el$27, createComponent2(Show, {
18948
19404
  get when() {
18949
19405
  return modeBadge();
18950
19406
  },
18951
19407
  children: (badge) => (() => {
18952
- var _el$36 = createElement("text");
18953
- setProp(_el$36, "wrapMode", "none");
18954
- insert(_el$36, () => badge().label);
18955
- effect((_$p) => setProp(_el$36, "fg", toneColor(badge().tone), _$p));
18956
- return _el$36;
19408
+ var _el$53 = createElement("text");
19409
+ setProp(_el$53, "wrapMode", "none");
19410
+ insert(_el$53, () => badge().label);
19411
+ effect((_$p) => setProp(_el$53, "fg", toneColor(badge().tone), _$p));
19412
+ return _el$53;
18957
19413
  })()
18958
- }), _el$23);
18959
- insertNode(_el$23, _el$24);
18960
- setProp(_el$23, "flexDirection", "row");
18961
- setProp(_el$23, "flexShrink", 0);
18962
- setProp(_el$23, "onMouseUp", () => props.onChooseModel?.());
18963
- setProp(_el$24, "wrapMode", "none");
18964
- insert(_el$24, modelLabel, null);
18965
- insert(_el$24, () => props.onChooseModel ? " \u25BE" : "", null);
19414
+ }), _el$28);
19415
+ insertNode(_el$28, _el$29);
19416
+ setProp(_el$28, "flexDirection", "row");
19417
+ setProp(_el$28, "flexShrink", 0);
19418
+ setProp(_el$28, "onMouseUp", () => props.onChooseModel?.());
19419
+ setProp(_el$29, "wrapMode", "none");
19420
+ insert(_el$29, modelLabel, null);
19421
+ insert(_el$29, () => props.onChooseModel ? " \u25BE" : "", null);
18966
19422
  effect((_p$) => {
18967
- var _v$10 = props.isStreaming ? theme.accent : theme.textMuted, _v$11 = theme.textMuted;
18968
- _v$10 !== _p$.e && (_p$.e = setProp(_el$21, "fg", _v$10, _p$.e));
18969
- _v$11 !== _p$.t && (_p$.t = setProp(_el$24, "fg", _v$11, _p$.t));
19423
+ var _v$13 = props.isStreaming ? theme.accent : theme.textMuted, _v$14 = theme.textMuted;
19424
+ _v$13 !== _p$.e && (_p$.e = setProp(_el$26, "fg", _v$13, _p$.e));
19425
+ _v$14 !== _p$.t && (_p$.t = setProp(_el$29, "fg", _v$14, _p$.t));
18970
19426
  return _p$;
18971
19427
  }, {
18972
19428
  e: undefined,
18973
19429
  t: undefined
18974
19430
  });
18975
- return _el$20;
19431
+ return _el$25;
18976
19432
  }
18977
19433
  }), null);
18978
- insertNode(_el$25, _el$26);
18979
- setProp(_el$25, "height", 1);
18980
- setProp(_el$25, "border", ["left"]);
18981
- setProp(_el$26, "height", 1);
18982
- setProp(_el$26, "border", ["bottom"]);
19434
+ insertNode(_el$30, _el$31);
19435
+ setProp(_el$30, "height", 1);
19436
+ setProp(_el$30, "border", ["left"]);
19437
+ setProp(_el$31, "height", 1);
19438
+ setProp(_el$31, "border", ["bottom"]);
18983
19439
  effect((_p$) => {
18984
- var _v$12 = railColor(), _v$13 = {
19440
+ var _v$15 = railColor(), _v$16 = {
18985
19441
  ...SplitBorder.customBorderChars,
18986
19442
  bottomLeft: "\u2579"
18987
- }, _v$14 = theme.backgroundElement, _v$15 = props.isStreaming ? theme.accent : theme.primary, _v$16 = railColor(), _v$17 = {
19443
+ }, _v$17 = theme.backgroundElement, _v$18 = props.isStreaming ? theme.accent : theme.primary, _v$19 = railColor(), _v$20 = {
18988
19444
  ...EmptyBorder,
18989
19445
  vertical: theme.backgroundElement.a !== 0 ? "\u2579" : " "
18990
- }, _v$18 = theme.backgroundElement, _v$19 = {
19446
+ }, _v$21 = theme.backgroundElement, _v$22 = {
18991
19447
  ...EmptyBorder,
18992
19448
  horizontal: theme.backgroundElement.a !== 0 ? "\u2580" : " "
18993
19449
  };
18994
- _v$12 !== _p$.e && (_p$.e = setProp(_el$14, "borderColor", _v$12, _p$.e));
18995
- _v$13 !== _p$.t && (_p$.t = setProp(_el$14, "customBorderChars", _v$13, _p$.t));
18996
- _v$14 !== _p$.a && (_p$.a = setProp(_el$15, "backgroundColor", _v$14, _p$.a));
18997
- _v$15 !== _p$.o && (_p$.o = setProp(_el$17, "fg", _v$15, _p$.o));
18998
- _v$16 !== _p$.i && (_p$.i = setProp(_el$25, "borderColor", _v$16, _p$.i));
18999
- _v$17 !== _p$.n && (_p$.n = setProp(_el$25, "customBorderChars", _v$17, _p$.n));
19000
- _v$18 !== _p$.s && (_p$.s = setProp(_el$26, "borderColor", _v$18, _p$.s));
19001
- _v$19 !== _p$.h && (_p$.h = setProp(_el$26, "customBorderChars", _v$19, _p$.h));
19450
+ _v$15 !== _p$.e && (_p$.e = setProp(_el$14, "borderColor", _v$15, _p$.e));
19451
+ _v$16 !== _p$.t && (_p$.t = setProp(_el$14, "customBorderChars", _v$16, _p$.t));
19452
+ _v$17 !== _p$.a && (_p$.a = setProp(_el$15, "backgroundColor", _v$17, _p$.a));
19453
+ _v$18 !== _p$.o && (_p$.o = setProp(_el$22, "fg", _v$18, _p$.o));
19454
+ _v$19 !== _p$.i && (_p$.i = setProp(_el$30, "borderColor", _v$19, _p$.i));
19455
+ _v$20 !== _p$.n && (_p$.n = setProp(_el$30, "customBorderChars", _v$20, _p$.n));
19456
+ _v$21 !== _p$.s && (_p$.s = setProp(_el$31, "borderColor", _v$21, _p$.s));
19457
+ _v$22 !== _p$.h && (_p$.h = setProp(_el$31, "customBorderChars", _v$22, _p$.h));
19002
19458
  return _p$;
19003
19459
  }, {
19004
19460
  e: undefined,
@@ -19013,6 +19469,7 @@ function Composer(props) {
19013
19469
  return _el$;
19014
19470
  })();
19015
19471
  }
19472
+ var QUEUE_VISIBLE_CAP = 4;
19016
19473
  var init_Composer = __esm(() => {
19017
19474
  init_solid();
19018
19475
  init_solid();
@@ -21720,18 +22177,30 @@ async function loadUserSlashes(worktreePath) {
21720
22177
  var init_user_slashes = () => {};
21721
22178
 
21722
22179
  // src/tui/panes/chat/context-meter.ts
21723
- function totalContextTokens(u) {
21724
- return u.input_tokens + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0);
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));
22186
+ }
22187
+ }
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));
21725
22195
  }
21726
22196
  function contextWindowTokensForModel(modelId) {
21727
22197
  const id = modelId ?? resolveDefaultModelId();
21728
- if (id.includes("[1m]"))
21729
- return LONG_CTX;
22198
+ const parsedWindow = parseContextWindowSize(id);
22199
+ if (parsedWindow !== null)
22200
+ return parsedWindow;
21730
22201
  const inPicker = MODEL_CHOICES.some((m) => m.id === id);
21731
22202
  if (inPicker)
21732
22203
  return STD_CTX;
21733
- if (id.includes("1m") || id.includes("[1M]"))
21734
- return LONG_CTX;
21735
22204
  return STD_CTX;
21736
22205
  }
21737
22206
  function formatTokShort(n) {
@@ -21745,15 +22214,23 @@ function formatTokShort(n) {
21745
22214
  return `${(n / 1000).toFixed(1)}k`;
21746
22215
  return String(n);
21747
22216
  }
22217
+ function formatTotalSpeed(tokensPerSecond) {
22218
+ if (typeof tokensPerSecond !== "number" || !Number.isFinite(tokensPerSecond))
22219
+ return null;
22220
+ if (tokensPerSecond >= 1000)
22221
+ return `${(tokensPerSecond / 1000).toFixed(1)}k t/s`;
22222
+ return `${tokensPerSecond.toFixed(1)} t/s`;
22223
+ }
21748
22224
  function formatContextUsageCompact(u, modelId) {
21749
22225
  const window = contextWindowTokensForModel(modelId);
21750
22226
  const total = totalContextTokens(u);
21751
22227
  if (total <= 0 || window <= 0)
21752
22228
  return null;
21753
22229
  const pct2 = Math.min(100, Math.max(0, Math.round(total / window * 100)));
21754
- return `${pct2}% \xB7 ${formatTokShort(total)}/${formatTokShort(window)}`;
22230
+ const speed = formatTotalSpeed(u.total_speed_tokens_per_second);
22231
+ return [`${pct2}% \xB7 ${formatTokShort(total)}/${formatTokShort(window)}`, speed].filter(Boolean).join(" \xB7 ");
21755
22232
  }
21756
- var LONG_CTX = 1e6, STD_CTX = 200000;
22233
+ var STD_CTX = 200000;
21757
22234
  var init_context_meter = __esm(() => {
21758
22235
  init_claude_settings2();
21759
22236
  init_models();
@@ -21797,20 +22274,13 @@ function createInitialState() {
21797
22274
  queue: []
21798
22275
  };
21799
22276
  }
21800
- function setMessagesFromHistory(state, past) {
22277
+ function setMessagesFromHistory(state, past, usageMetrics) {
21801
22278
  const rows = [];
21802
22279
  const toolIndexById = new Map;
21803
22280
  for (const m of past) {
21804
22281
  appendRowsFromMessage(rows, toolIndexById, m);
21805
22282
  }
21806
- let latestUsage;
21807
- for (let i = past.length - 1;i >= 0; i--) {
21808
- const u = past[i]?.usage;
21809
- if (u) {
21810
- latestUsage = u;
21811
- break;
21812
- }
21813
- }
22283
+ const latestUsage = usageMetrics ?? deriveSessionUsageMetrics(past);
21814
22284
  return {
21815
22285
  ...state,
21816
22286
  messages: capMessages(rows, new Date().toISOString()),
@@ -21888,19 +22358,20 @@ function applyEvent(state, ev, nowIso = new Date().toISOString()) {
21888
22358
  case "usage":
21889
22359
  return {
21890
22360
  ...state,
21891
- lastUsage: {
22361
+ lastUsage: withTotalSpeedForTurn({
21892
22362
  input_tokens: ev.input_tokens,
21893
22363
  output_tokens: ev.output_tokens,
21894
22364
  cache_read_input_tokens: ev.cache_read_input_tokens,
21895
22365
  cache_creation_input_tokens: ev.cache_creation_input_tokens
21896
- }
22366
+ }, state.activeTurnStartedAt, nowIso)
21897
22367
  };
21898
22368
  case "done":
21899
- return { ...state, isStreaming: false };
22369
+ return { ...state, isStreaming: false, activeTurnStartedAt: undefined };
21900
22370
  case "error":
21901
22371
  return {
21902
22372
  ...state,
21903
22373
  isStreaming: false,
22374
+ activeTurnStartedAt: undefined,
21904
22375
  error: ev.message,
21905
22376
  messages: capMessages([...state.messages, { kind: "system", text: `error: ${ev.message}`, ts: nowIso }], nowIso)
21906
22377
  };
@@ -21910,6 +22381,7 @@ function applyEvent(state, ev, nowIso = new Date().toISOString()) {
21910
22381
  isStreaming: true,
21911
22382
  error: null,
21912
22383
  lastUsage: undefined,
22384
+ activeTurnStartedAt: nowIso,
21913
22385
  messages: capMessages([...state.messages, { kind: "user", text: ev.text, ts: nowIso }], nowIso)
21914
22386
  };
21915
22387
  case "system.info":
@@ -22188,10 +22660,10 @@ function useChatSession(opts) {
22188
22660
  };
22189
22661
  if (tab.sessionId) {
22190
22662
  const sid = tab.sessionId;
22191
- orchestrator.readHistory(sid).then((past) => {
22663
+ orchestrator.readHistoryWithMetrics(sid).then(({ messages, usageMetrics }) => {
22192
22664
  if (opts.taskId() !== taskId)
22193
22665
  return;
22194
- patchStateForTab(tabId, (s) => setMessagesFromHistory(s, past));
22666
+ patchStateForTab(tabId, (s) => setMessagesFromHistory(s, messages, usageMetrics));
22195
22667
  replayPending();
22196
22668
  }).catch((err) => {
22197
22669
  const msg = err instanceof Error ? err.message : String(err);
@@ -22278,7 +22750,6 @@ var init_use_chat_session = __esm(() => {
22278
22750
  });
22279
22751
 
22280
22752
  // src/tui/panes/chat/Chat.tsx
22281
- import { TextAttributes as TextAttributes25 } from "@opentui/core";
22282
22753
  function Chat(props) {
22283
22754
  const {
22284
22755
  theme
@@ -22483,7 +22954,7 @@ function Chat(props) {
22483
22954
  send(pp);
22484
22955
  });
22485
22956
  });
22486
- let draining = false;
22957
+ let dispatching = false;
22487
22958
  createEffect(() => {
22488
22959
  const taskId = props.taskId();
22489
22960
  const tabId = activeTabId();
@@ -22496,15 +22967,15 @@ function Chat(props) {
22496
22967
  return;
22497
22968
  if (hasPendingInput())
22498
22969
  return;
22499
- if (draining)
22970
+ if (dispatching)
22500
22971
  return;
22501
22972
  queueMicrotask(async () => {
22502
- if (draining)
22973
+ if (dispatching)
22503
22974
  return;
22504
22975
  const cur = activeState();
22505
22976
  if (cur.isStreaming || cur.queue.length === 0)
22506
22977
  return;
22507
- draining = true;
22978
+ dispatching = true;
22508
22979
  try {
22509
22980
  let head = null;
22510
22981
  patchActiveState((s) => {
@@ -22521,7 +22992,7 @@ function Chat(props) {
22521
22992
  patchActiveState((s) => pushSystemError(s, `queued runTask failed: ${stringifyErr2(err)}`));
22522
22993
  }
22523
22994
  } finally {
22524
- draining = false;
22995
+ dispatching = false;
22525
22996
  }
22526
22997
  });
22527
22998
  });
@@ -22547,16 +23018,17 @@ function Chat(props) {
22547
23018
  const streaming = activeState().isStreaming;
22548
23019
  if (streaming && mode === "steer") {
22549
23020
  setDraft("");
22550
- try {
22551
- await props.orchestrator.interruptTask(taskId, tabId);
22552
- } catch (err) {
22553
- patchActiveState((s) => pushSystemError(s, `interrupt failed: ${stringifyErr2(err)}`));
23021
+ if (dispatching)
22554
23022
  return;
22555
- }
23023
+ dispatching = true;
22556
23024
  try {
22557
- await props.orchestrator.runTask(taskId, text, tabId);
22558
- } catch (err) {
22559
- patchActiveState((s) => pushSystemError(s, `runTask failed: ${stringifyErr2(err)}`));
23025
+ try {
23026
+ await props.orchestrator.steerTask(taskId, text, tabId);
23027
+ } catch (err) {
23028
+ patchActiveState((s) => pushSystemError(s, `steer failed: ${stringifyErr2(err)}`));
23029
+ }
23030
+ } finally {
23031
+ dispatching = false;
22560
23032
  }
22561
23033
  return;
22562
23034
  }
@@ -22579,6 +23051,13 @@ function Chat(props) {
22579
23051
  function cancelQueued(id) {
22580
23052
  patchActiveState((s) => removeFromQueue(s, id));
22581
23053
  }
23054
+ function sendQueuedNow(id) {
23055
+ const entry = activeState().queue.find((q) => q.id === id);
23056
+ if (!entry)
23057
+ return;
23058
+ patchActiveState((s) => removeFromQueue(s, id));
23059
+ send(entry.text, "steer");
23060
+ }
22582
23061
  async function newTab() {
22583
23062
  const taskId = props.taskId();
22584
23063
  if (!taskId)
@@ -22832,19 +23311,6 @@ function Chat(props) {
22832
23311
  return _el$5;
22833
23312
  }
22834
23313
  }), null);
22835
- insert(_el$, createComponent2(Show, {
22836
- get when() {
22837
- return memo2(() => !!props.taskId())() && activeState().queue.length > 0;
22838
- },
22839
- get children() {
22840
- return createComponent2(QueuedPromptList, {
22841
- get queue() {
22842
- return activeState().queue;
22843
- },
22844
- onCancel: cancelQueued
22845
- });
22846
- }
22847
- }), null);
22848
23314
  insert(_el$, createComponent2(Show, {
22849
23315
  get when() {
22850
23316
  return memo2(() => !!showThinking())() && props.taskId();
@@ -22889,7 +23355,10 @@ function Chat(props) {
22889
23355
  onCyclePermissionMode: cyclePermissionMode,
22890
23356
  modelLabel,
22891
23357
  onChooseModel: () => void chooseModel(),
22892
- worktreePath
23358
+ worktreePath,
23359
+ queue: () => activeState().queue,
23360
+ onCancelQueued: cancelQueued,
23361
+ onSendQueuedNow: sendQueuedNow
22893
23362
  });
22894
23363
  }
22895
23364
  }), null);
@@ -22905,97 +23374,6 @@ function stringifyErr2(err) {
22905
23374
  return String(err);
22906
23375
  }
22907
23376
  }
22908
- function QueuedPromptList(props) {
22909
- const {
22910
- theme
22911
- } = useTheme();
22912
- const visible = () => props.queue.slice(0, QUEUE_VISIBLE_CAP);
22913
- const hidden = () => Math.max(0, props.queue.length - QUEUE_VISIBLE_CAP);
22914
- return (() => {
22915
- var _el$7 = createElement("box");
22916
- setProp(_el$7, "flexDirection", "column");
22917
- setProp(_el$7, "gap", 0);
22918
- setProp(_el$7, "paddingTop", 1);
22919
- setProp(_el$7, "paddingLeft", 1);
22920
- setProp(_el$7, "paddingRight", 1);
22921
- insert(_el$7, createComponent2(For, {
22922
- get each() {
22923
- return visible();
22924
- },
22925
- children: (entry, idx) => (() => {
22926
- var _el$10 = createElement("box"), _el$11 = createElement("text"), _el$13 = createElement("box"), _el$14 = createElement("text"), _el$15 = createTextNode(`queued`), _el$16 = createTextNode(`:`), _el$17 = createElement("box"), _el$18 = createElement("text"), _el$19 = createElement("text");
22927
- insertNode(_el$10, _el$11);
22928
- insertNode(_el$10, _el$13);
22929
- setProp(_el$10, "flexDirection", "row");
22930
- setProp(_el$10, "gap", 1);
22931
- setProp(_el$10, "alignItems", "flex-start");
22932
- insertNode(_el$11, createTextNode(`+`));
22933
- insertNode(_el$13, _el$14);
22934
- insertNode(_el$13, _el$17);
22935
- insertNode(_el$13, _el$19);
22936
- setProp(_el$13, "flexGrow", 1);
22937
- setProp(_el$13, "flexDirection", "row");
22938
- setProp(_el$13, "gap", 1);
22939
- insertNode(_el$14, _el$15);
22940
- insertNode(_el$14, _el$16);
22941
- setProp(_el$14, "wrapMode", "none");
22942
- insert(_el$14, () => idx() === 0 ? " (next)" : "", _el$16);
22943
- insertNode(_el$17, _el$18);
22944
- setProp(_el$17, "flexGrow", 1);
22945
- insert(_el$18, () => entry.text);
22946
- insertNode(_el$19, createTextNode(`[x]`));
22947
- setProp(_el$19, "onMouseUp", () => props.onCancel(entry.id));
22948
- effect((_p$) => {
22949
- var _v$4 = theme.textMuted, _v$5 = TextAttributes25.BOLD, _v$6 = theme.textMuted, _v$7 = theme.text, _v$8 = theme.error, _v$9 = TextAttributes25.BOLD;
22950
- _v$4 !== _p$.e && (_p$.e = setProp(_el$11, "fg", _v$4, _p$.e));
22951
- _v$5 !== _p$.t && (_p$.t = setProp(_el$11, "attributes", _v$5, _p$.t));
22952
- _v$6 !== _p$.a && (_p$.a = setProp(_el$14, "fg", _v$6, _p$.a));
22953
- _v$7 !== _p$.o && (_p$.o = setProp(_el$18, "fg", _v$7, _p$.o));
22954
- _v$8 !== _p$.i && (_p$.i = setProp(_el$19, "fg", _v$8, _p$.i));
22955
- _v$9 !== _p$.n && (_p$.n = setProp(_el$19, "attributes", _v$9, _p$.n));
22956
- return _p$;
22957
- }, {
22958
- e: undefined,
22959
- t: undefined,
22960
- a: undefined,
22961
- o: undefined,
22962
- i: undefined,
22963
- n: undefined
22964
- });
22965
- return _el$10;
22966
- })()
22967
- }), null);
22968
- insert(_el$7, createComponent2(Show, {
22969
- get when() {
22970
- return hidden() > 0;
22971
- },
22972
- get children() {
22973
- var _el$8 = createElement("box"), _el$9 = createElement("text"), _el$1 = createElement("text");
22974
- insertNode(_el$8, _el$9);
22975
- insertNode(_el$8, _el$1);
22976
- setProp(_el$8, "flexDirection", "row");
22977
- setProp(_el$8, "gap", 1);
22978
- setProp(_el$8, "alignItems", "flex-start");
22979
- insertNode(_el$9, createTextNode(`+`));
22980
- insert(_el$1, () => `\u2026 ${hidden()} more queued`);
22981
- effect((_p$) => {
22982
- var _v$ = theme.textMuted, _v$2 = TextAttributes25.BOLD, _v$3 = theme.textMuted;
22983
- _v$ !== _p$.e && (_p$.e = setProp(_el$9, "fg", _v$, _p$.e));
22984
- _v$2 !== _p$.t && (_p$.t = setProp(_el$9, "attributes", _v$2, _p$.t));
22985
- _v$3 !== _p$.a && (_p$.a = setProp(_el$1, "fg", _v$3, _p$.a));
22986
- return _p$;
22987
- }, {
22988
- e: undefined,
22989
- t: undefined,
22990
- a: undefined
22991
- });
22992
- return _el$8;
22993
- }
22994
- }), null);
22995
- return _el$7;
22996
- })();
22997
- }
22998
- var QUEUE_VISIBLE_CAP = 4;
22999
23377
  var init_Chat = __esm(() => {
23000
23378
  init_solid();
23001
23379
  init_solid();
@@ -23025,7 +23403,7 @@ var init_Chat = __esm(() => {
23025
23403
  });
23026
23404
 
23027
23405
  // src/tui/component/sidebar.tsx
23028
- import { TextAttributes as TextAttributes26 } from "@opentui/core";
23406
+ import { TextAttributes as TextAttributes25 } from "@opentui/core";
23029
23407
  function Sidebar(props) {
23030
23408
  const {
23031
23409
  theme
@@ -23051,7 +23429,7 @@ function Sidebar(props) {
23051
23429
  setProp(_el$2, "paddingBottom", 1);
23052
23430
  insert(_el$3, () => props.title);
23053
23431
  effect((_p$) => {
23054
- var _v$ = theme.text, _v$2 = TextAttributes26.BOLD;
23432
+ var _v$ = theme.text, _v$2 = TextAttributes25.BOLD;
23055
23433
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "fg", _v$, _p$.e));
23056
23434
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "attributes", _v$2, _p$.t));
23057
23435
  return _p$;
@@ -23170,12 +23548,12 @@ var init_sidebar = __esm(() => {
23170
23548
  });
23171
23549
 
23172
23550
  // src/tui/panes/sidebar/git-head.ts
23173
- import { spawnSync as spawnSync9 } from "child_process";
23551
+ import { spawnSync as spawnSync10 } from "child_process";
23174
23552
  function readCurrentBranch(repo) {
23175
23553
  if (!repo)
23176
23554
  return "";
23177
23555
  try {
23178
- const out = spawnSync9("git", ["symbolic-ref", "--short", "HEAD"], {
23556
+ const out = spawnSync10("git", ["symbolic-ref", "--short", "HEAD"], {
23179
23557
  cwd: repo,
23180
23558
  encoding: "utf8",
23181
23559
  stdio: ["ignore", "pipe", "pipe"]
@@ -23185,7 +23563,7 @@ function readCurrentBranch(repo) {
23185
23563
  if (name && name !== "HEAD")
23186
23564
  return name;
23187
23565
  }
23188
- const head = spawnSync9("git", ["rev-parse", "--verify", "HEAD"], {
23566
+ const head = spawnSync10("git", ["rev-parse", "--verify", "HEAD"], {
23189
23567
  cwd: repo,
23190
23568
  encoding: "utf8",
23191
23569
  stdio: ["ignore", "pipe", "pipe"]
@@ -23310,7 +23688,7 @@ var init_keys4 = __esm(() => {
23310
23688
  });
23311
23689
 
23312
23690
  // src/tui/panes/sidebar/Sidebar.tsx
23313
- import { TextAttributes as TextAttributes27 } from "@opentui/core";
23691
+ import { TextAttributes as TextAttributes26 } from "@opentui/core";
23314
23692
  function Sidebar2(props) {
23315
23693
  const {
23316
23694
  theme
@@ -23402,7 +23780,7 @@ function Sidebar2(props) {
23402
23780
  return () => _c$() ? `[ ${tab.label} ]` : tab.label;
23403
23781
  })());
23404
23782
  effect((_p$) => {
23405
- var _v$7 = active() ? theme.primary : theme.textMuted, _v$8 = active() ? TextAttributes27.BOLD : undefined;
23783
+ var _v$7 = active() ? theme.primary : theme.textMuted, _v$8 = active() ? TextAttributes26.BOLD : undefined;
23406
23784
  _v$7 !== _p$.e && (_p$.e = setProp(_el$13, "fg", _v$7, _p$.e));
23407
23785
  _v$8 !== _p$.t && (_p$.t = setProp(_el$13, "attributes", _v$8, _p$.t));
23408
23786
  return _p$;
@@ -23497,7 +23875,7 @@ function Sidebar2(props) {
23497
23875
  }
23498
23876
  }), null);
23499
23877
  effect((_p$) => {
23500
- var _v$9 = isCursor() ? theme.primary : isSelected() ? theme.backgroundElement : undefined, _v$0 = isCursor() ? theme.selectedListItemText : badgeColor(), _v$1 = isCursor() ? theme.selectedListItemText : theme.text, _v$10 = (isMain || isSelected() && !isCursor()) && !isCursor() ? TextAttributes27.BOLD : undefined;
23878
+ var _v$9 = isCursor() ? theme.primary : isSelected() ? theme.backgroundElement : undefined, _v$0 = isCursor() ? theme.selectedListItemText : badgeColor(), _v$1 = isCursor() ? theme.selectedListItemText : theme.text, _v$10 = (isMain || isSelected() && !isCursor()) && !isCursor() ? TextAttributes26.BOLD : undefined;
23501
23879
  _v$9 !== _p$.e && (_p$.e = setProp(_el$14, "backgroundColor", _v$9, _p$.e));
23502
23880
  _v$0 !== _p$.t && (_p$.t = setProp(_el$15, "fg", _v$0, _p$.t));
23503
23881
  _v$1 !== _p$.a && (_p$.a = setProp(_el$16, "fg", _v$1, _p$.a));
@@ -23535,7 +23913,7 @@ function Sidebar2(props) {
23535
23913
  setProp(_el$11, "wrapMode", "none");
23536
23914
  setProp(_el$11, "onMouseUp", () => props.onAddTask?.());
23537
23915
  effect((_p$) => {
23538
- var _v$ = props.width ? props.width() : SIDEBAR_WIDTH, _v$2 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$3 = TextAttributes27.BOLD, _v$4 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$5 = TextAttributes27.BOLD, _v$6 = theme.textMuted;
23916
+ var _v$ = props.width ? props.width() : SIDEBAR_WIDTH, _v$2 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$3 = TextAttributes26.BOLD, _v$4 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$5 = TextAttributes26.BOLD, _v$6 = theme.textMuted;
23539
23917
  _v$ !== _p$.e && (_p$.e = setProp(_el$, "width", _v$, _p$.e));
23540
23918
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
23541
23919
  _v$3 !== _p$.a && (_p$.a = setProp(_el$3, "attributes", _v$3, _p$.a));
@@ -23605,11 +23983,11 @@ var init_Sidebar = __esm(() => {
23605
23983
  });
23606
23984
 
23607
23985
  // src/orchestrator/bridge/server.ts
23608
- import { mkdir as mkdir3, unlink as unlink3 } from "fs/promises";
23986
+ import { mkdir as mkdir4, unlink as unlink3 } from "fs/promises";
23609
23987
  import { createServer } from "net";
23610
23988
  import { dirname as dirname6 } from "path";
23611
23989
  async function startBridgeServer(orch, socketPath) {
23612
- await mkdir3(dirname6(socketPath), { recursive: true });
23990
+ await mkdir4(dirname6(socketPath), { recursive: true });
23613
23991
  await unlink3(socketPath).catch(() => {});
23614
23992
  const conns = new Set;
23615
23993
  const server = createServer((conn) => {
@@ -23742,7 +24120,7 @@ var exports_bridge = {};
23742
24120
  __export(exports_bridge, {
23743
24121
  startBridge: () => startBridge
23744
24122
  });
23745
- import { writeFile as writeFile3 } from "fs/promises";
24123
+ import { writeFile as writeFile4 } from "fs/promises";
23746
24124
  import { homedir as homedir12 } from "os";
23747
24125
  import { join as join15 } from "path";
23748
24126
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -23762,7 +24140,7 @@ async function startBridge(orch, opts = {}) {
23762
24140
  }
23763
24141
  }
23764
24142
  };
23765
- await writeFile3(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf8");
24143
+ await writeFile4(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf8");
23766
24144
  process.env.KOBE_MCP_CONFIG = mcpConfigPath;
23767
24145
  return {
23768
24146
  socketPath,
@@ -24345,7 +24723,7 @@ var exports_tui = {};
24345
24723
  __export(exports_tui, {
24346
24724
  startTui: () => startTui
24347
24725
  });
24348
- import { TextAttributes as TextAttributes28 } from "@opentui/core";
24726
+ import { TextAttributes as TextAttributes27 } from "@opentui/core";
24349
24727
  function HelpHint() {
24350
24728
  const {
24351
24729
  theme
@@ -24419,7 +24797,7 @@ function Banner() {
24419
24797
  insert(_el$20, selected);
24420
24798
  insert(_el$12, createComponent2(HelpHint, {}), null);
24421
24799
  effect((_p$) => {
24422
- var _v$7 = theme.primary, _v$8 = TextAttributes28.BOLD, _v$9 = theme.borderActive, _v$0 = theme.text, _v$1 = theme.textMuted, _v$10 = {
24800
+ var _v$7 = theme.primary, _v$8 = TextAttributes27.BOLD, _v$9 = theme.borderActive, _v$0 = theme.text, _v$1 = theme.textMuted, _v$10 = {
24423
24801
  fg: theme.accent
24424
24802
  };
24425
24803
  _v$7 !== _p$.e && (_p$.e = setProp(_el$13, "fg", _v$7, _p$.e));
@@ -24573,6 +24951,11 @@ async function main() {
24573
24951
  await runDiagnoseSubcommand2();
24574
24952
  return;
24575
24953
  }
24954
+ if (subcommand === "update") {
24955
+ const { runUpdateSubcommand: runUpdateSubcommand2 } = await Promise.resolve().then(() => (init_update(), exports_update));
24956
+ await runUpdateSubcommand2(rest);
24957
+ return;
24958
+ }
24576
24959
  if (subcommand === "theme") {
24577
24960
  const { runThemeSubcommand: runThemeSubcommand2 } = await Promise.resolve().then(() => (init_theme2(), exports_theme));
24578
24961
  await runThemeSubcommand2(rest);