@cofy-x/dsh-console 0.1.0-alpha.4 → 0.1.0-alpha.5

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.
@@ -1,3 +1,7 @@
1
+ import {
2
+ POKEMON_NUMBER_ENV,
3
+ resolvePokemonNumber
4
+ } from "./chunk-WTD7XY24.js";
1
5
  import {
2
6
  CoreEvent,
3
7
  DEFAULT_FILE_FILTERING_OPTIONS,
@@ -71,7 +75,7 @@ import {
71
75
  } from "@deepseek-ai/dsh-agent";
72
76
  import { createUserMessage as createUserMessage2 } from "@deepseek-ai/dsh-llm";
73
77
  import {
74
- SessionId as SessionId3
78
+ SessionId as SessionId4
75
79
  } from "@deepseek-ai/dsh-session";
76
80
 
77
81
  // src/utils/exit-codes.ts
@@ -208,6 +212,7 @@ function isLoadableSettingScope(scope) {
208
212
  }
209
213
 
210
214
  // src/config/settings-schema.ts
215
+ var EMPTY_CUSTOM_THEMES = {};
211
216
  var SETTINGS_SCHEMA = {
212
217
  general: {
213
218
  type: "object",
@@ -279,7 +284,7 @@ var SETTINGS_SCHEMA = {
279
284
  label: "Custom Themes",
280
285
  category: "UI",
281
286
  requiresRestart: false,
282
- default: {},
287
+ default: EMPTY_CUSTOM_THEMES,
283
288
  description: "Custom theme definitions.",
284
289
  showInDialog: false,
285
290
  additionalProperties: {
@@ -1464,10 +1469,6 @@ function loadEnvironment(settings) {
1464
1469
  }
1465
1470
  }
1466
1471
  function loadSettings(workspaceDir = process.cwd()) {
1467
- let systemSettings = {};
1468
- let systemDefaultSettings = {};
1469
- let userSettings = {};
1470
- let workspaceSettings = {};
1471
1472
  const settingsErrors = [];
1472
1473
  const systemSettingsPath = getSystemSettingsPath();
1473
1474
  const systemDefaultsPath = getSystemDefaultsPath();
@@ -1535,10 +1536,10 @@ function loadSettings(workspaceDir = process.cwd()) {
1535
1536
  );
1536
1537
  const userOriginalSettings = structuredClone(userResult.settings);
1537
1538
  const workspaceOriginalSettings = structuredClone(workspaceResult.settings);
1538
- systemSettings = resolveEnvVarsInObject(systemResult.settings);
1539
- systemDefaultSettings = resolveEnvVarsInObject(systemDefaultsResult.settings);
1540
- userSettings = resolveEnvVarsInObject(userResult.settings);
1541
- workspaceSettings = resolveEnvVarsInObject(workspaceResult.settings);
1539
+ const systemSettings = resolveEnvVarsInObject(systemResult.settings);
1540
+ const systemDefaultSettings = resolveEnvVarsInObject(systemDefaultsResult.settings);
1541
+ const userSettings = resolveEnvVarsInObject(userResult.settings);
1542
+ const workspaceSettings = resolveEnvVarsInObject(workspaceResult.settings);
1542
1543
  const isTrusted = true;
1543
1544
  const tempMergedSettings = mergeSettings(
1544
1545
  systemSettings,
@@ -1610,6 +1611,100 @@ function saveSettings(settingsFile) {
1610
1611
  // src/config/cli-args.ts
1611
1612
  import yargs from "yargs/yargs";
1612
1613
  import { hideBin } from "yargs/helpers";
1614
+
1615
+ // src/utils/header-loader.ts
1616
+ import fs3 from "node:fs";
1617
+ import path2 from "node:path";
1618
+ var packageRoot = findPackageRoot(import.meta.url);
1619
+ var builtResources = path2.join(
1620
+ packageRoot,
1621
+ "dist/ui/components/layout/resources"
1622
+ );
1623
+ var sourceResources = path2.join(
1624
+ packageRoot,
1625
+ "src/ui/components/layout/resources"
1626
+ );
1627
+ var PokemonHeaderArtNotFoundError = class extends Error {
1628
+ constructor(pokemonNumber) {
1629
+ super(`Bundled Pokemon #${pokemonNumber} is not available.`);
1630
+ this.name = "PokemonHeaderArtNotFoundError";
1631
+ }
1632
+ };
1633
+ function resolveResourcesDir(resourceType, customPath) {
1634
+ if (resourceType === "custom") {
1635
+ if (!customPath) {
1636
+ return null;
1637
+ }
1638
+ return path2.resolve(process.cwd(), customPath);
1639
+ }
1640
+ if (resourceType === "pokemon" && customPath) {
1641
+ return path2.resolve(process.cwd(), customPath);
1642
+ }
1643
+ const builtResourceDir = path2.join(builtResources, resourceType);
1644
+ return fs3.existsSync(builtResourceDir) ? builtResourceDir : path2.join(sourceResources, resourceType);
1645
+ }
1646
+ function loadHeaderArt(resourceType = "pokemon", customPath, pokemonNumber) {
1647
+ try {
1648
+ const resourcesDir = resolveResourcesDir(resourceType, customPath);
1649
+ if (!resourcesDir) {
1650
+ if (pokemonNumber !== void 0) {
1651
+ throw new PokemonHeaderArtNotFoundError(pokemonNumber);
1652
+ }
1653
+ debugLogger.warn("Custom header art requires an art resources path.");
1654
+ return null;
1655
+ }
1656
+ if (!fs3.existsSync(resourcesDir)) {
1657
+ if (pokemonNumber !== void 0) {
1658
+ throw new PokemonHeaderArtNotFoundError(pokemonNumber);
1659
+ }
1660
+ debugLogger.warn(`Header art resources path not found: ${resourcesDir}`);
1661
+ return null;
1662
+ }
1663
+ const files = fs3.readdirSync(resourcesDir).filter((file) => file.endsWith(".txt")).sort();
1664
+ if (files.length === 0) {
1665
+ if (pokemonNumber !== void 0) {
1666
+ throw new PokemonHeaderArtNotFoundError(pokemonNumber);
1667
+ }
1668
+ return null;
1669
+ }
1670
+ const selectedFile = pokemonNumber === void 0 ? files[Math.floor(Math.random() * files.length)] : files.find((file) => {
1671
+ const match = /^(\d+)(?:-|\.txt$)/.exec(file);
1672
+ return match?.[1] !== void 0 && Number(match[1]) === pokemonNumber;
1673
+ });
1674
+ if (!selectedFile) {
1675
+ if (pokemonNumber !== void 0) {
1676
+ throw new PokemonHeaderArtNotFoundError(pokemonNumber);
1677
+ }
1678
+ return null;
1679
+ }
1680
+ const filePath = path2.join(resourcesDir, selectedFile);
1681
+ const content = fs3.readFileSync(filePath, "utf-8");
1682
+ const id = selectedFile.replace(".txt", "");
1683
+ return {
1684
+ id,
1685
+ art: content
1686
+ };
1687
+ } catch (error) {
1688
+ if (error instanceof PokemonHeaderArtNotFoundError) throw error;
1689
+ debugLogger.warn("Error loading header art:", error);
1690
+ return null;
1691
+ }
1692
+ }
1693
+ function loadCustomAsciiArt(filePath) {
1694
+ try {
1695
+ const resolvedPath = path2.resolve(process.cwd(), filePath);
1696
+ if (!fs3.existsSync(resolvedPath)) {
1697
+ debugLogger.warn(`Custom ASCII art file not found: ${resolvedPath}`);
1698
+ return void 0;
1699
+ }
1700
+ return fs3.readFileSync(resolvedPath, "utf-8");
1701
+ } catch (error) {
1702
+ debugLogger.warn("Error loading custom ASCII art:", error);
1703
+ return void 0;
1704
+ }
1705
+ }
1706
+
1707
+ // src/config/cli-args.ts
1613
1708
  async function parseArguments(settings, args = hideBin(process.argv)) {
1614
1709
  const startupMessages = [];
1615
1710
  const yargsInstance = yargs(args).locale("en").scriptName("dsh-console").usage(
@@ -1619,6 +1714,10 @@ async function parseArguments(settings, args = hideBin(process.argv)) {
1619
1714
  type: "boolean",
1620
1715
  description: "Enable DSH Console diagnostics",
1621
1716
  default: false
1717
+ }).option("pokemon", {
1718
+ type: "string",
1719
+ nargs: 1,
1720
+ description: "Use a bundled Pokemon number for this launch"
1622
1721
  }).command(
1623
1722
  "$0 [query..]",
1624
1723
  "Launch DSH Console",
@@ -1657,6 +1756,14 @@ async function parseArguments(settings, args = hideBin(process.argv)) {
1657
1756
  let result;
1658
1757
  try {
1659
1758
  result = await yargsInstance.parse();
1759
+ const pokemonNumber = resolvePokemonNumber(
1760
+ result["pokemon"],
1761
+ process.env[POKEMON_NUMBER_ENV]
1762
+ );
1763
+ if (pokemonNumber !== void 0) {
1764
+ loadHeaderArt("pokemon", void 0, pokemonNumber);
1765
+ result["pokemon"] = pokemonNumber;
1766
+ }
1660
1767
  } catch (e) {
1661
1768
  const msg = e instanceof Error ? e.message : String(e);
1662
1769
  debugLogger.error(msg);
@@ -1727,7 +1834,7 @@ var ConsolePatcher = class {
1727
1834
  };
1728
1835
 
1729
1836
  // src/config/config.ts
1730
- import path2 from "node:path";
1837
+ import path3 from "node:path";
1731
1838
  var DEFAULT_SHELL_TERMINAL_WIDTH = 80;
1732
1839
  var DEFAULT_SHELL_TERMINAL_HEIGHT = 24;
1733
1840
  var Config = class {
@@ -1736,6 +1843,7 @@ var Config = class {
1736
1843
  targetDir;
1737
1844
  debugMode;
1738
1845
  question;
1846
+ pokemonNumber;
1739
1847
  // Environment sanitization
1740
1848
  allowedEnvironmentVariables;
1741
1849
  blockedEnvironmentVariables;
@@ -1756,9 +1864,10 @@ var Config = class {
1756
1864
  // Storage
1757
1865
  storage;
1758
1866
  constructor(params) {
1759
- this.targetDir = path2.resolve(params.targetDir);
1867
+ this.targetDir = path3.resolve(params.targetDir);
1760
1868
  this.debugMode = params.debugMode;
1761
1869
  this.question = params.question;
1870
+ this.pokemonNumber = params.pokemonNumber;
1762
1871
  this.allowedEnvironmentVariables = params.allowedEnvironmentVariables ?? [];
1763
1872
  this.blockedEnvironmentVariables = params.blockedEnvironmentVariables ?? [];
1764
1873
  this.enableEnvironmentVariableRedaction = params.enableEnvironmentVariableRedaction ?? true;
@@ -1815,6 +1924,9 @@ var Config = class {
1815
1924
  getQuestion() {
1816
1925
  return this.question;
1817
1926
  }
1927
+ getPokemonNumber() {
1928
+ return this.pokemonNumber;
1929
+ }
1818
1930
  get sanitizationConfig() {
1819
1931
  return {
1820
1932
  allowedEnvironmentVariables: this.allowedEnvironmentVariables,
@@ -1887,6 +1999,7 @@ async function loadCliConfig(settings, argv, options = {}) {
1887
1999
  targetDir: cwd,
1888
2000
  debugMode,
1889
2001
  question,
2002
+ pokemonNumber: argv.pokemon,
1890
2003
  blockedEnvironmentVariables: settings.security?.environmentVariableRedaction?.blocked,
1891
2004
  enableEnvironmentVariableRedaction: settings.security?.environmentVariableRedaction?.enabled,
1892
2005
  accessibility: {
@@ -1924,7 +2037,7 @@ var useAlternateBuffer = () => {
1924
2037
  };
1925
2038
 
1926
2039
  // src/terminal/capabilities.ts
1927
- import * as fs3 from "node:fs";
2040
+ import * as fs4 from "node:fs";
1928
2041
  var TerminalCapabilityManager = class _TerminalCapabilityManager {
1929
2042
  static instance;
1930
2043
  static KITTY_QUERY = "\x1B[?u";
@@ -2078,7 +2191,7 @@ var TerminalCapabilityManager = class _TerminalCapabilityManager {
2078
2191
  };
2079
2192
  process.stdin.on("data", onData);
2080
2193
  try {
2081
- fs3.writeSync(
2194
+ fs4.writeSync(
2082
2195
  process.stdout.fd,
2083
2196
  _TerminalCapabilityManager.KITTY_QUERY + _TerminalCapabilityManager.OSC_11_QUERY + _TerminalCapabilityManager.TERMINAL_NAME_QUERY + _TerminalCapabilityManager.MODIFY_OTHER_KEYS_QUERY + _TerminalCapabilityManager.DEVICE_ATTRIBUTES_QUERY
2084
2197
  );
@@ -2168,21 +2281,21 @@ async function setupTerminalAndTheme(config, settings) {
2168
2281
  }
2169
2282
 
2170
2283
  // src/bootstrap/startup-warnings.ts
2171
- import * as fs4 from "node:fs/promises";
2284
+ import * as fs5 from "node:fs/promises";
2172
2285
  import os from "node:os";
2173
2286
  import process2 from "node:process";
2174
- import path3, { join as pathJoin } from "node:path";
2287
+ import path4, { join as pathJoin } from "node:path";
2175
2288
  var WARNINGS_FILE_PATH = pathJoin(
2176
2289
  os.tmpdir(),
2177
2290
  "dsh-console-warnings.txt"
2178
2291
  );
2179
2292
  async function getStoredStartupWarnings() {
2180
2293
  try {
2181
- await fs4.access(WARNINGS_FILE_PATH);
2182
- const warningsContent = await fs4.readFile(WARNINGS_FILE_PATH, "utf-8");
2294
+ await fs5.access(WARNINGS_FILE_PATH);
2295
+ const warningsContent = await fs5.readFile(WARNINGS_FILE_PATH, "utf-8");
2183
2296
  const warnings = warningsContent.split("\n").filter((line) => line.trim() !== "");
2184
2297
  try {
2185
- await fs4.unlink(WARNINGS_FILE_PATH);
2298
+ await fs5.unlink(WARNINGS_FILE_PATH);
2186
2299
  } catch {
2187
2300
  warnings.push("Warning: Could not delete temporary warnings file.");
2188
2301
  }
@@ -2202,8 +2315,8 @@ var homeDirectoryCheck = {
2202
2315
  }
2203
2316
  try {
2204
2317
  const [workspaceRealPath, homeRealPath] = await Promise.all([
2205
- fs4.realpath(workspaceRoot),
2206
- fs4.realpath(homedir())
2318
+ fs5.realpath(workspaceRoot),
2319
+ fs5.realpath(homedir())
2207
2320
  ]);
2208
2321
  if (workspaceRealPath === homeRealPath) {
2209
2322
  return "Warning you are running DSH Console in your home directory.\nThis warning can be disabled in /settings";
@@ -2218,9 +2331,9 @@ var rootDirectoryCheck = {
2218
2331
  id: "root-directory",
2219
2332
  check: async (workspaceRoot, _settings) => {
2220
2333
  try {
2221
- const workspaceRealPath = await fs4.realpath(workspaceRoot);
2334
+ const workspaceRealPath = await fs5.realpath(workspaceRoot);
2222
2335
  const errorMessage = "Warning: You are running DSH Console in the root directory. Your entire folder structure will be used for context. It is strongly recommended to run in a project-specific directory.";
2223
- if (path3.dirname(workspaceRealPath) === workspaceRealPath) {
2336
+ if (path4.dirname(workspaceRealPath) === workspaceRealPath) {
2224
2337
  return errorMessage;
2225
2338
  }
2226
2339
  return null;
@@ -2248,7 +2361,7 @@ async function getStartupWarnings(settings, workspaceRoot = process2.cwd()) {
2248
2361
  }
2249
2362
 
2250
2363
  // src/ui/root.tsx
2251
- import { basename as basename3 } from "node:path";
2364
+ import { basename as basename4 } from "node:path";
2252
2365
 
2253
2366
  // src/ui/types.ts
2254
2367
  import "react";
@@ -2319,13 +2432,13 @@ function computeTerminalTitle({
2319
2432
 
2320
2433
  // src/ui/app-container.tsx
2321
2434
  import {
2322
- useMemo as useMemo34,
2323
- useState as useState53,
2324
- useCallback as useCallback45,
2325
- useEffect as useEffect54,
2326
- useRef as useRef30,
2435
+ useMemo as useMemo36,
2436
+ useState as useState54,
2437
+ useCallback as useCallback46,
2438
+ useEffect as useEffect55,
2439
+ useRef as useRef31,
2327
2440
  useLayoutEffect as useLayoutEffect3,
2328
- useSyncExternalStore as useSyncExternalStore5
2441
+ useSyncExternalStore as useSyncExternalStore6
2329
2442
  } from "react";
2330
2443
  import { measureElement as measureElement3, useApp } from "ink";
2331
2444
 
@@ -3214,7 +3327,7 @@ var MarkdownDisplayInternal = ({
3214
3327
  } else if (headerMatch) {
3215
3328
  const level = headerMatch[1].length;
3216
3329
  const headerText = headerMatch[2];
3217
- let headerNode = null;
3330
+ let headerNode;
3218
3331
  switch (level) {
3219
3332
  case 1:
3220
3333
  headerNode = /* @__PURE__ */ jsx9(Text8, { bold: true, color: theme.text.link, children: /* @__PURE__ */ jsx9(RenderInline, { text: headerText, defaultColor: theme.text.link }) });
@@ -4210,8 +4323,8 @@ var renderDiffContent = (parsedLines, filename, tabWidth = DEFAULT_TAB_WIDTH, av
4210
4323
  );
4211
4324
  }
4212
4325
  const lineKey = `diff-line-${index}`;
4213
- let gutterNumStr = "";
4214
- let prefixSymbol = " ";
4326
+ let gutterNumStr;
4327
+ let prefixSymbol;
4215
4328
  switch (line.type) {
4216
4329
  case "add":
4217
4330
  gutterNumStr = (line.newLine ?? "").toString();
@@ -5190,7 +5303,7 @@ function* emitKeys(keypressHandler) {
5190
5303
  let alt = false;
5191
5304
  let ctrl = false;
5192
5305
  let cmd = false;
5193
- let code = void 0;
5306
+ let code;
5194
5307
  let insertable = false;
5195
5308
  if (ch === ESC) {
5196
5309
  escaped = true;
@@ -5323,8 +5436,8 @@ function* emitKeys(keypressHandler) {
5323
5436
  name2 = "undefined";
5324
5437
  if ((ctrl || cmd || alt) && (code.endsWith("u") || code.endsWith("~"))) {
5325
5438
  const codeNumber = parseInt(code.slice(1, -1), 10);
5326
- if (codeNumber >= "a".charCodeAt(0) && codeNumber <= "z".charCodeAt(0)) {
5327
- name2 = String.fromCharCode(codeNumber);
5439
+ if (codeNumber >= 32 && codeNumber <= 126) {
5440
+ name2 = String.fromCharCode(codeNumber).toLowerCase();
5328
5441
  }
5329
5442
  }
5330
5443
  }
@@ -5486,6 +5599,9 @@ function useKeypress(onKeypress, { isActive }) {
5486
5599
  }
5487
5600
 
5488
5601
  // src/terminal/keys.ts
5602
+ function isConversationSwitchKey(key) {
5603
+ return key.sequence === "" || key.ctrl && (key.name === "/" || key.name === "_");
5604
+ }
5489
5605
  function keyToAnsi(key) {
5490
5606
  if (key.ctrl) {
5491
5607
  if (key.name >= "a" && key.name <= "z") {
@@ -6039,7 +6155,7 @@ import { Box as Box25 } from "ink";
6039
6155
  import { Box as Box21, Text as Text20 } from "ink";
6040
6156
 
6041
6157
  // src/generated/git-commit.ts
6042
- var GIT_COMMIT_INFO = "1318436";
6158
+ var GIT_COMMIT_INFO = "7fa332d";
6043
6159
 
6044
6160
  // src/ui/components/dialogs/about-box.tsx
6045
6161
  import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
@@ -6680,18 +6796,18 @@ var useAppContext = () => {
6680
6796
  };
6681
6797
 
6682
6798
  // src/ui/components/indicators/notifications.tsx
6683
- import path5 from "node:path";
6799
+ import path6 from "node:path";
6684
6800
 
6685
6801
  // src/ui/state/persistent.ts
6686
- import * as fs5 from "node:fs";
6687
- import * as path4 from "node:path";
6802
+ import * as fs6 from "node:fs";
6803
+ import * as path5 from "node:path";
6688
6804
  var STATE_FILENAME = "state.json";
6689
6805
  var PersistentState = class {
6690
6806
  cache = null;
6691
6807
  filePath = null;
6692
6808
  getPath() {
6693
6809
  if (!this.filePath) {
6694
- this.filePath = path4.join(
6810
+ this.filePath = path5.join(
6695
6811
  Storage.getGlobalDshConsoleDir(),
6696
6812
  STATE_FILENAME
6697
6813
  );
@@ -6704,8 +6820,8 @@ var PersistentState = class {
6704
6820
  }
6705
6821
  try {
6706
6822
  const filePath = this.getPath();
6707
- if (fs5.existsSync(filePath)) {
6708
- const content = fs5.readFileSync(filePath, "utf-8");
6823
+ if (fs6.existsSync(filePath)) {
6824
+ const content = fs6.readFileSync(filePath, "utf-8");
6709
6825
  this.cache = JSON.parse(content);
6710
6826
  } else {
6711
6827
  this.cache = {};
@@ -6720,11 +6836,11 @@ var PersistentState = class {
6720
6836
  if (!this.cache) return;
6721
6837
  try {
6722
6838
  const filePath = this.getPath();
6723
- const dir = path4.dirname(filePath);
6724
- if (!fs5.existsSync(dir)) {
6725
- fs5.mkdirSync(dir, { recursive: true });
6839
+ const dir = path5.dirname(filePath);
6840
+ if (!fs6.existsSync(dir)) {
6841
+ fs6.mkdirSync(dir, { recursive: true });
6726
6842
  }
6727
- fs5.writeFileSync(filePath, JSON.stringify(this.cache, null, 2));
6843
+ fs6.writeFileSync(filePath, JSON.stringify(this.cache, null, 2));
6728
6844
  } catch (error) {
6729
6845
  debugLogger.warn("Failed to save persistent state:", error);
6730
6846
  }
@@ -6742,7 +6858,7 @@ var persistentState = new PersistentState();
6742
6858
 
6743
6859
  // src/ui/components/indicators/notifications.tsx
6744
6860
  import { Fragment as Fragment8, jsx as jsx36, jsxs as jsxs26 } from "react/jsx-runtime";
6745
- var settingsPath = path5.join(homedir(), DSH_CONSOLE_DIR, "settings.json");
6861
+ var settingsPath = path6.join(homedir(), DSH_CONSOLE_DIR, "settings.json");
6746
6862
  var Notifications = () => {
6747
6863
  const { startupWarnings } = useAppContext();
6748
6864
  const { initError, streamingState } = useUIState();
@@ -7273,76 +7389,6 @@ var Header = ({
7273
7389
  return /* @__PURE__ */ jsx41(HorizontalHeader, { version, art: headerArt.art });
7274
7390
  };
7275
7391
 
7276
- // src/utils/header-loader.ts
7277
- import fs6 from "node:fs";
7278
- import path6 from "node:path";
7279
- var packageRoot = findPackageRoot(import.meta.url);
7280
- var builtResources = path6.join(
7281
- packageRoot,
7282
- "dist/ui/components/layout/resources"
7283
- );
7284
- var sourceResources = path6.join(
7285
- packageRoot,
7286
- "src/ui/components/layout/resources"
7287
- );
7288
- function resolveResourcesDir(resourceType, customPath) {
7289
- if (resourceType === "custom") {
7290
- if (!customPath) {
7291
- return null;
7292
- }
7293
- return path6.resolve(process.cwd(), customPath);
7294
- }
7295
- if (resourceType === "pokemon" && customPath) {
7296
- return path6.resolve(process.cwd(), customPath);
7297
- }
7298
- const builtResourceDir = path6.join(builtResources, resourceType);
7299
- return fs6.existsSync(builtResourceDir) ? builtResourceDir : path6.join(sourceResources, resourceType);
7300
- }
7301
- function loadHeaderArt(resourceType = "pokemon", customPath) {
7302
- try {
7303
- const resourcesDir = resolveResourcesDir(resourceType, customPath);
7304
- if (!resourcesDir) {
7305
- debugLogger.warn("Custom header art requires an art resources path.");
7306
- return null;
7307
- }
7308
- if (!fs6.existsSync(resourcesDir)) {
7309
- debugLogger.warn(`Header art resources path not found: ${resourcesDir}`);
7310
- return null;
7311
- }
7312
- const files = fs6.readdirSync(resourcesDir).filter((file) => file.endsWith(".txt")).sort();
7313
- if (files.length === 0) {
7314
- return null;
7315
- }
7316
- const selectedFile = files[Math.floor(Math.random() * files.length)];
7317
- if (!selectedFile) {
7318
- return null;
7319
- }
7320
- const filePath = path6.join(resourcesDir, selectedFile);
7321
- const content = fs6.readFileSync(filePath, "utf-8");
7322
- const id = selectedFile.replace(".txt", "");
7323
- return {
7324
- id,
7325
- art: content
7326
- };
7327
- } catch (error) {
7328
- debugLogger.warn("Error loading header art:", error);
7329
- return null;
7330
- }
7331
- }
7332
- function loadCustomAsciiArt(filePath) {
7333
- try {
7334
- const resolvedPath = path6.resolve(process.cwd(), filePath);
7335
- if (!fs6.existsSync(resolvedPath)) {
7336
- debugLogger.warn(`Custom ASCII art file not found: ${resolvedPath}`);
7337
- return void 0;
7338
- }
7339
- return fs6.readFileSync(resolvedPath, "utf-8");
7340
- } catch (error) {
7341
- debugLogger.warn("Error loading custom ASCII art:", error);
7342
- return void 0;
7343
- }
7344
- }
7345
-
7346
7392
  // src/ui/components/layout/app-header.tsx
7347
7393
  import { useMemo as useMemo9 } from "react";
7348
7394
  import { jsx as jsx42 } from "react/jsx-runtime";
@@ -7354,18 +7400,22 @@ var AppHeader = ({ version }) => {
7354
7400
  const artResourceType = settings.merged.ui.header.artResourceType ?? "pokemon";
7355
7401
  const artResourcesPath = settings.merged.ui.header.artResourcesPath;
7356
7402
  const customAsciiArtPath = settings.merged.ui.header.customAsciiArtPath;
7403
+ const pokemonNumber = config.getPokemonNumber();
7357
7404
  const customAsciiArt = useMemo9(() => {
7358
- if (customAsciiArtPath) {
7405
+ if (pokemonNumber === void 0 && customAsciiArtPath) {
7359
7406
  return loadCustomAsciiArt(customAsciiArtPath);
7360
7407
  }
7361
7408
  return void 0;
7362
- }, [customAsciiArtPath]);
7409
+ }, [customAsciiArtPath, pokemonNumber]);
7363
7410
  const headerArt = useMemo9(() => {
7364
7411
  if (customAsciiArt) {
7365
7412
  return null;
7366
7413
  }
7414
+ if (pokemonNumber !== void 0) {
7415
+ return loadHeaderArt("pokemon", void 0, pokemonNumber);
7416
+ }
7367
7417
  return loadHeaderArt(artResourceType, artResourcesPath);
7368
- }, [artResourceType, artResourcesPath, customAsciiArt]);
7418
+ }, [artResourceType, artResourcesPath, customAsciiArt, pokemonNumber]);
7369
7419
  if (config.getScreenReader()) {
7370
7420
  return null;
7371
7421
  }
@@ -7915,7 +7965,7 @@ var ScrollProvider = ({
7915
7965
  const hitTop = isTop ? absoluteThumbTop : absoluteThumbTop - 1;
7916
7966
  const hitBottom = isBottom ? absoluteThumbBottom : absoluteThumbBottom + 1;
7917
7967
  const isThumbClick = mouseEvent.row >= hitTop && mouseEvent.row < hitBottom;
7918
- let offset = 0;
7968
+ let offset;
7919
7969
  const relativeMouseY = mouseEvent.row - y;
7920
7970
  if (isThumbClick) {
7921
7971
  offset = relativeMouseY - currentThumbY;
@@ -9780,11 +9830,9 @@ function getUserLinuxClipboardTool() {
9780
9830
  if (linuxClipboardTool !== null) {
9781
9831
  return linuxClipboardTool;
9782
9832
  }
9783
- let toolName = null;
9784
9833
  const displayServer = process.env["XDG_SESSION_TYPE"];
9785
- if (displayServer === "wayland") toolName = "wl-paste";
9786
- else if (displayServer === "x11") toolName = "xclip";
9787
- else return null;
9834
+ const toolName = displayServer === "wayland" ? "wl-paste" : displayServer === "x11" ? "xclip" : null;
9835
+ if (toolName === null) return null;
9788
9836
  try {
9789
9837
  execSync(`command -v ${toolName}`, { stdio: "ignore" });
9790
9838
  linuxClipboardTool = toolName;
@@ -10340,8 +10388,8 @@ function calculateInitialCursorPosition(initialLines, offset) {
10340
10388
  return [0, 0];
10341
10389
  }
10342
10390
  function offsetToLogicalPos(text, offset) {
10343
- let row = 0;
10344
- let col = 0;
10391
+ let row;
10392
+ let col;
10345
10393
  let currentOffset = 0;
10346
10394
  if (offset === 0) return [0, 0];
10347
10395
  const lines = text.split("\n");
@@ -11752,7 +11800,7 @@ function textBufferReducerLogic(state, action, options = {}) {
11752
11800
  case "wordLeft": {
11753
11801
  if (cursorCol === 0 && cursorRow === 0) return state;
11754
11802
  let newCursorRow = cursorRow;
11755
- let newCursorCol = cursorCol;
11803
+ let newCursorCol;
11756
11804
  if (cursorCol === 0) {
11757
11805
  newCursorRow--;
11758
11806
  newCursorCol = cpLen(lines[newCursorRow] ?? "");
@@ -11773,7 +11821,7 @@ function textBufferReducerLogic(state, action, options = {}) {
11773
11821
  return state;
11774
11822
  }
11775
11823
  let newCursorRow = cursorRow;
11776
- let newCursorCol = cursorCol;
11824
+ let newCursorCol;
11777
11825
  const lineLen = cpLen(lineContent);
11778
11826
  if (cursorCol >= lineLen) {
11779
11827
  newCursorRow++;
@@ -13176,7 +13224,7 @@ function BaseSettingsDialog({
13176
13224
  return;
13177
13225
  }
13178
13226
  let ch = key.sequence;
13179
- let isValidChar = false;
13227
+ let isValidChar;
13180
13228
  if (type === "number") {
13181
13229
  isValidChar = /[0-9\-+.]/.test(ch);
13182
13230
  } else {
@@ -14393,7 +14441,7 @@ var _ExpandableText = ({
14393
14441
  }
14394
14442
  const matchLength = userInput.length;
14395
14443
  let before = "";
14396
- let match = "";
14444
+ let match;
14397
14445
  let after = "";
14398
14446
  if (isExpanded || label.length <= maxWidth) {
14399
14447
  before = label.slice(0, matchedIndex);
@@ -14595,7 +14643,7 @@ function useInputHistory({
14595
14643
  const navigateUp = useCallback23(() => {
14596
14644
  if (!isActive) return false;
14597
14645
  if (userMessages.length === 0) return false;
14598
- let nextIndex = historyIndex;
14646
+ let nextIndex;
14599
14647
  if (historyIndex === -1) {
14600
14648
  setOriginalQueryBeforeNav(currentQuery);
14601
14649
  nextIndex = 0;
@@ -15257,7 +15305,7 @@ function useCommandSuggestions(query, parserResult, commandContext, getFzfForCom
15257
15305
  if (commandsToSearch.length > 0) {
15258
15306
  const performFuzzySearch = async () => {
15259
15307
  if (signal.aborted) return;
15260
- let potentialSuggestions = [];
15308
+ let potentialSuggestions;
15261
15309
  if (partial === "") {
15262
15310
  potentialSuggestions = commandsToSearch.filter(
15263
15311
  (cmd) => cmd.description && !cmd.hidden
@@ -15983,6 +16031,39 @@ import { createContext as createContext11, useContext as useContext12 } from "re
15983
16031
  var ShellFocusContext = createContext11(true);
15984
16032
  var useShellFocusState = () => useContext12(ShellFocusContext);
15985
16033
 
16034
+ // src/ui/commands/parser.ts
16035
+ var parseSlashCommand = (query, commands) => {
16036
+ const trimmed = query.trim();
16037
+ const parts = trimmed.substring(1).trim().split(/\s+/);
16038
+ const commandPath = parts.filter((p) => p);
16039
+ let currentCommands = commands;
16040
+ let commandToExecute;
16041
+ let pathIndex = 0;
16042
+ const canonicalPath = [];
16043
+ for (const part of commandPath) {
16044
+ let foundCommand = currentCommands.find((cmd) => cmd.name === part);
16045
+ if (!foundCommand) {
16046
+ foundCommand = currentCommands.find(
16047
+ (cmd) => cmd.altNames?.includes(part)
16048
+ );
16049
+ }
16050
+ if (foundCommand) {
16051
+ commandToExecute = foundCommand;
16052
+ canonicalPath.push(foundCommand.name);
16053
+ pathIndex++;
16054
+ if (foundCommand.subCommands) {
16055
+ currentCommands = foundCommand.subCommands;
16056
+ } else {
16057
+ break;
16058
+ }
16059
+ } else {
16060
+ break;
16061
+ }
16062
+ }
16063
+ const args = parts.slice(pathIndex).join(" ");
16064
+ return { commandToExecute, args, canonicalPath };
16065
+ };
16066
+
15986
16067
  // src/ui/components/input/input-prompt.tsx
15987
16068
  import { Fragment as Fragment12, jsx as jsx64, jsxs as jsxs48 } from "react/jsx-runtime";
15988
16069
  function isTerminalPasteTrusted(kittyProtocolSupported) {
@@ -16125,8 +16206,10 @@ var InputPrompt = ({
16125
16206
  (submittedValue) => {
16126
16207
  const trimmedMessage = submittedValue.trim();
16127
16208
  const isSlash = isSlashCommand(trimmedMessage);
16209
+ const command = isSlash ? parseSlashCommand(trimmedMessage, slashCommands).commandToExecute : void 0;
16210
+ const canRunWhileBusy = command?.allowWhileBusy === true;
16128
16211
  const isShell = shellModeActive;
16129
- if ((isSlash || isShell) && streamingState === "responding" /* Responding */) {
16212
+ if ((isShell || isSlash && !canRunWhileBusy) && streamingState === "responding" /* Responding */) {
16130
16213
  setQueueErrorMessage(
16131
16214
  `${isShell ? "Shell" : "Slash"} commands cannot be queued`
16132
16215
  );
@@ -16136,6 +16219,7 @@ var InputPrompt = ({
16136
16219
  },
16137
16220
  [
16138
16221
  handleSubmitAndClear,
16222
+ slashCommands,
16139
16223
  shellModeActive,
16140
16224
  streamingState,
16141
16225
  setQueueErrorMessage
@@ -16587,6 +16671,9 @@ var InputPrompt = ({
16587
16671
  }
16588
16672
  return;
16589
16673
  }
16674
+ if (isConversationSwitchKey(key)) {
16675
+ return;
16676
+ }
16590
16677
  buffer.handleInput(key);
16591
16678
  if (completion.promptCompletion.text && key.sequence && key.sequence.length === 1 && !key.alt && !key.ctrl && !key.cmd) {
16592
16679
  completion.promptCompletion.clear();
@@ -16643,7 +16730,7 @@ var InputPrompt = ({
16643
16730
  const remainingWidth = Math.max(0, inputWidth - usedWidth);
16644
16731
  const ghostTextLinesRaw = ghostSuffix.split("\n");
16645
16732
  const firstLineRaw = ghostTextLinesRaw.shift() || "";
16646
- let inlineGhost2 = "";
16733
+ let inlineGhost2;
16647
16734
  let remainingFirstLine = "";
16648
16735
  if (stringWidth3(firstLineRaw) <= remainingWidth) {
16649
16736
  inlineGhost2 = firstLineRaw;
@@ -16940,6 +17027,7 @@ var InputPrompt = ({
16940
17027
  };
16941
17028
 
16942
17029
  // src/ui/components/layout/footer.tsx
17030
+ import { basename as basename2 } from "node:path";
16943
17031
  import { Box as Box54, Text as Text49 } from "ink";
16944
17032
 
16945
17033
  // src/ui/components/layout/console-summary-display.tsx
@@ -16995,7 +17083,7 @@ var MemoryUsageDisplay = () => {
16995
17083
  import { Text as Text47 } from "ink";
16996
17084
  import { useEffect as useEffect35, useState as useState32 } from "react";
16997
17085
  import { FixedDeque } from "mnemonist";
16998
- import { jsx as jsx67, jsxs as jsxs51 } from "react/jsx-runtime";
17086
+ import { Fragment as Fragment13, jsx as jsx67, jsxs as jsxs51 } from "react/jsx-runtime";
16999
17087
  var MIN_TIME_FROM_ACTION_TO_BE_IDLE = 500;
17000
17088
  var ACTION_TIMESTAMP_CAPACITY = 2048;
17001
17089
  var FRAME_TIMESTAMP_CAPACITY = 2048;
@@ -17147,12 +17235,14 @@ var DebugProfiler = ({ compact = false }) => {
17147
17235
  }
17148
17236
  if (compact) {
17149
17237
  return /* @__PURE__ */ jsxs51(Text47, { color: theme.status.warning, wrap: "truncate-end", children: [
17150
- "R:",
17238
+ "R",
17151
17239
  profiler.numFrames,
17152
- " I:",
17240
+ " I",
17153
17241
  /* @__PURE__ */ jsx67(Text47, { color: theme.status.error, children: profiler.totalIdleFrames }),
17154
- " F:",
17155
- /* @__PURE__ */ jsx67(Text47, { color: theme.status.error, children: profiler.totalFlickerFrames })
17242
+ profiler.totalFlickerFrames > 0 && /* @__PURE__ */ jsxs51(Fragment13, { children: [
17243
+ " F",
17244
+ /* @__PURE__ */ jsx67(Text47, { color: theme.status.error, children: profiler.totalFlickerFrames })
17245
+ ] })
17156
17246
  ] }, forceRefresh);
17157
17247
  }
17158
17248
  return /* @__PURE__ */ jsxs51(Text47, { color: theme.status.warning, wrap: "truncate-end", children: [
@@ -17227,14 +17317,26 @@ var Footer = () => {
17227
17317
  nightly: uiState.nightly,
17228
17318
  terminalWidth: uiState.terminalWidth
17229
17319
  };
17230
- const showMemoryUsage = config.getDebugMode() || settings.merged.ui.showMemoryUsage;
17320
+ const isNarrow = terminalWidth < 120;
17321
+ const isCompact = terminalWidth < 160;
17322
+ const showMemoryUsage = !isCompact && (config.getDebugMode() || settings.merged.ui.showMemoryUsage);
17231
17323
  const hideCWD = settings.merged.ui.footer.hideCWD;
17232
17324
  const hideModelInfo = settings.merged.ui.footer.hideModelInfo;
17233
17325
  const pathLength = Math.max(20, Math.floor(terminalWidth * 0.25));
17234
- const displayPath = shortenPath(tildeifyPath(targetDir), pathLength);
17235
- const justifyContent = hideCWD && hideModelInfo ? "center" : "space-between";
17326
+ const displayPath = isCompact ? basename2(targetDir) || targetDir : shortenPath(tildeifyPath(targetDir), pathLength);
17236
17327
  const displayVimMode = vimEnabled ? vimMode : void 0;
17237
- const showRenderDiagnostics = debugMode || isDevelopment;
17328
+ const sideConversation = uiState.sideConversation ?? {
17329
+ activeSurface: "main",
17330
+ mainBusy: false,
17331
+ sideBusy: false
17332
+ };
17333
+ const showRenderDiagnostics = (debugMode || isDevelopment) && (!isNarrow || sideConversation.activeSurface !== "side");
17334
+ const showCwd = !hideCWD;
17335
+ const showLeft = Boolean(
17336
+ displayVimMode || showCwd || debugMode && isNarrow
17337
+ );
17338
+ const justifyContent = hideModelInfo ? showLeft ? "flex-start" : "center" : showLeft ? "space-between" : "flex-end";
17339
+ const displayModel = isCompact ? model.split("/").at(-1) ?? model : model;
17238
17340
  return /* @__PURE__ */ jsxs53(
17239
17341
  Box54,
17240
17342
  {
@@ -17244,28 +17346,29 @@ var Footer = () => {
17244
17346
  alignItems: "center",
17245
17347
  paddingX: 1,
17246
17348
  children: [
17247
- (displayVimMode || !hideCWD) && /* @__PURE__ */ jsxs53(Box54, { children: [
17349
+ (displayVimMode || showCwd || debugMode && isNarrow) && /* @__PURE__ */ jsxs53(Box54, { flexShrink: 1, children: [
17248
17350
  displayVimMode && /* @__PURE__ */ jsxs53(Text49, { color: theme.text.secondary, children: [
17249
17351
  "[",
17250
17352
  displayVimMode,
17251
17353
  "] "
17252
17354
  ] }),
17253
- !hideCWD && (nightly ? /* @__PURE__ */ jsxs53(ThemedGradient, { children: [
17355
+ showCwd && (nightly ? /* @__PURE__ */ jsxs53(ThemedGradient, { children: [
17254
17356
  displayPath,
17255
- branchName && /* @__PURE__ */ jsxs53(Text49, { children: [
17357
+ branchName && !isNarrow && /* @__PURE__ */ jsxs53(Text49, { children: [
17256
17358
  " (",
17257
17359
  branchName,
17258
17360
  "*)"
17259
17361
  ] })
17260
17362
  ] }) : /* @__PURE__ */ jsxs53(Text49, { color: theme.text.link, children: [
17261
17363
  displayPath,
17262
- branchName && /* @__PURE__ */ jsxs53(Text49, { color: theme.text.secondary, children: [
17364
+ branchName && !isNarrow && /* @__PURE__ */ jsxs53(Text49, { color: theme.text.secondary, children: [
17263
17365
  " (",
17264
17366
  branchName,
17265
17367
  "*)"
17266
17368
  ] })
17267
17369
  ] })),
17268
- debugMode && /* @__PURE__ */ jsx69(Text49, { color: theme.status.error, children: " " + (debugMessage || "--debug") })
17370
+ debugMode && !isNarrow && /* @__PURE__ */ jsx69(Text49, { color: theme.status.error, children: " " + (debugMessage || "--debug") }),
17371
+ debugMode && isNarrow && /* @__PURE__ */ jsx69(Text49, { color: theme.status.error, children: showCwd ? " --debug" : "--debug" })
17269
17372
  ] }),
17270
17373
  showRenderDiagnostics && /* @__PURE__ */ jsx69(
17271
17374
  Box54,
@@ -17274,12 +17377,30 @@ var Footer = () => {
17274
17377
  flexShrink: 1,
17275
17378
  justifyContent: "center",
17276
17379
  marginX: terminalWidth >= 120 ? 1 : 0,
17277
- children: /* @__PURE__ */ jsx69(DebugProfiler, { compact: terminalWidth < 120 })
17380
+ children: /* @__PURE__ */ jsx69(DebugProfiler, { compact: isCompact })
17278
17381
  }
17279
17382
  ),
17280
- !hideModelInfo && /* @__PURE__ */ jsxs53(Box54, { alignItems: "center", justifyContent: "flex-end", children: [
17281
- /* @__PURE__ */ jsxs53(Box54, { alignItems: "center", justifyContent: "flex-end", children: [
17282
- /* @__PURE__ */ jsx69(Text49, { color: theme.text.accent, children: model }),
17383
+ !hideModelInfo && /* @__PURE__ */ jsxs53(Box54, { alignItems: "center", justifyContent: "flex-end", flexShrink: 1, children: [
17384
+ (uiState.subagentCatalog?.runningCount ?? 0) > 0 && /* @__PURE__ */ jsxs53(Box54, { flexShrink: 0, children: [
17385
+ /* @__PURE__ */ jsx69(Text49, { color: theme.status.success, children: isCompact ? `A${uiState.subagentCatalog?.runningCount}` : `${uiState.subagentCatalog?.runningCount} agent${uiState.subagentCatalog?.runningCount === 1 ? "" : "s"} working` }),
17386
+ /* @__PURE__ */ jsx69(Text49, { color: theme.text.secondary, children: " | " })
17387
+ ] }),
17388
+ sideConversation.activeSurface === "side" && /* @__PURE__ */ jsxs53(Box54, { flexShrink: 1, children: [
17389
+ /* @__PURE__ */ jsx69(Text49, { color: theme.text.accent, children: "Side" }),
17390
+ /* @__PURE__ */ jsx69(Text49, { color: theme.text.secondary, children: " \xB7 Main " }),
17391
+ /* @__PURE__ */ jsx69(
17392
+ Text49,
17393
+ {
17394
+ color: sideConversation.mainBusy ? theme.status.warning : theme.status.success,
17395
+ children: sideConversation.mainBusy ? "working" : "idle"
17396
+ }
17397
+ ),
17398
+ /* @__PURE__ */ jsx69(Text49, { color: theme.text.secondary, children: " \xB7 " }),
17399
+ /* @__PURE__ */ jsx69(Text49, { color: theme.text.accent, wrap: "truncate-end", children: isCompact ? "Ctrl+/" : "Ctrl+/ switch" }),
17400
+ /* @__PURE__ */ jsx69(Text49, { color: theme.text.secondary, children: " | " })
17401
+ ] }),
17402
+ /* @__PURE__ */ jsxs53(Box54, { alignItems: "center", justifyContent: "flex-end", flexShrink: 1, children: [
17403
+ /* @__PURE__ */ jsx69(Text49, { color: theme.text.accent, wrap: "truncate-end", children: displayModel }),
17283
17404
  uiState.currentReasoningEffort && /* @__PURE__ */ jsxs53(Text49, { color: theme.text.link, children: [
17284
17405
  " ",
17285
17406
  uiState.currentReasoningEffort
@@ -17289,7 +17410,7 @@ var Footer = () => {
17289
17410
  {
17290
17411
  promptTokens: uiState.sessionStats.lastPromptTokenCount,
17291
17412
  contextWindow: uiState.sessionStats.contextWindow,
17292
- compact: terminalWidth < 100
17413
+ compact: isCompact
17293
17414
  }
17294
17415
  ),
17295
17416
  showMemoryUsage && /* @__PURE__ */ jsx69(MemoryUsageDisplay, {})
@@ -17343,33 +17464,42 @@ var CommandInitDisplay = ({
17343
17464
  import { Box as Box57, Text as Text52 } from "ink";
17344
17465
  import { useMemo as useMemo21 } from "react";
17345
17466
  import { jsx as jsx72, jsxs as jsxs56 } from "react/jsx-runtime";
17346
- var TodoTitleDisplay = ({ todos }) => {
17467
+ var TodoTitleDisplay = ({ todos, isWorking, compact = false }) => {
17347
17468
  const score = useMemo21(() => {
17348
17469
  let total = 0;
17349
17470
  let completed = 0;
17471
+ let unfinished = 0;
17350
17472
  for (const todo of todos.todos) {
17351
17473
  if (todo.status !== "cancelled") {
17352
17474
  total += 1;
17353
17475
  if (todo.status === "completed") {
17354
17476
  completed += 1;
17477
+ } else {
17478
+ unfinished += 1;
17355
17479
  }
17356
17480
  }
17357
17481
  }
17358
- return `${completed}/${total} completed`;
17359
- }, [todos]);
17482
+ const idleRemainder = !isWorking && unfinished > 0 ? ` \xB7 ${unfinished} unfinished` : "";
17483
+ const completion = compact ? `${completed}/${total}` : `${completed}/${total} completed`;
17484
+ return `${completion}${idleRemainder}`;
17485
+ }, [compact, isWorking, todos]);
17360
17486
  return /* @__PURE__ */ jsxs56(Box57, { flexDirection: "row", columnGap: 2, height: 1, children: [
17361
17487
  /* @__PURE__ */ jsx72(Text52, { color: theme.text.primary, bold: true, "aria-label": "Todo list", children: "Todo" }),
17362
- /* @__PURE__ */ jsxs56(Text52, { color: theme.text.secondary, children: [
17488
+ /* @__PURE__ */ jsxs56(Text52, { color: theme.text.secondary, wrap: "truncate", children: [
17363
17489
  score,
17364
- " (ctrl+t to toggle)"
17490
+ " ",
17491
+ compact ? "(ctrl+t)" : "(ctrl+t to toggle)"
17365
17492
  ] })
17366
17493
  ] });
17367
17494
  };
17368
- var TodoStatusDisplay = ({ status }) => {
17495
+ var TodoStatusDisplay = ({ status, isWorking }) => {
17369
17496
  switch (status) {
17370
17497
  case "completed":
17371
17498
  return /* @__PURE__ */ jsx72(Text52, { color: theme.status.success, "aria-label": "Completed", children: "\u2713" });
17372
17499
  case "in_progress":
17500
+ if (!isWorking) {
17501
+ return /* @__PURE__ */ jsx72(Text52, { color: theme.text.secondary, "aria-label": "Unfinished", children: "\u25CB" });
17502
+ }
17373
17503
  return /* @__PURE__ */ jsx72(Text52, { color: theme.text.accent, "aria-label": "In Progress", children: "\xBB" });
17374
17504
  case "pending":
17375
17505
  return /* @__PURE__ */ jsx72(Text52, { color: theme.text.secondary, "aria-label": "Pending", children: "\u2610" });
@@ -17378,11 +17508,11 @@ var TodoStatusDisplay = ({ status }) => {
17378
17508
  return /* @__PURE__ */ jsx72(Text52, { color: theme.status.error, "aria-label": "Cancelled", children: "\u2717" });
17379
17509
  }
17380
17510
  };
17381
- var TodoItemDisplay = ({ todo, wrap, role: ariaRole }) => {
17511
+ var TodoItemDisplay = ({ todo, wrap, role: ariaRole, isWorking }) => {
17382
17512
  const textColor = (() => {
17383
17513
  switch (todo.status) {
17384
17514
  case "in_progress":
17385
- return theme.text.accent;
17515
+ return isWorking ? theme.text.accent : theme.text.primary;
17386
17516
  case "completed":
17387
17517
  case "cancelled":
17388
17518
  return theme.text.secondary;
@@ -17392,13 +17522,14 @@ var TodoItemDisplay = ({ todo, wrap, role: ariaRole }) => {
17392
17522
  })();
17393
17523
  const strikethrough = todo.status === "cancelled";
17394
17524
  return /* @__PURE__ */ jsxs56(Box57, { flexDirection: "row", columnGap: 1, "aria-role": ariaRole, children: [
17395
- /* @__PURE__ */ jsx72(TodoStatusDisplay, { status: todo.status }),
17525
+ /* @__PURE__ */ jsx72(TodoStatusDisplay, { status: todo.status, isWorking }),
17396
17526
  /* @__PURE__ */ jsx72(Box57, { flexShrink: 1, children: /* @__PURE__ */ jsx72(Text52, { color: textColor, wrap, strikethrough, children: todo.description }) })
17397
17527
  ] });
17398
17528
  };
17399
17529
  var TodoTray = () => {
17400
17530
  const uiState = useUIState();
17401
17531
  const todos = uiState.todos ?? null;
17532
+ const isWorking = uiState.streamingState === "responding" /* Responding */;
17402
17533
  const inProgress = useMemo21(() => {
17403
17534
  if (todos === null) {
17404
17535
  return null;
@@ -17425,16 +17556,31 @@ var TodoTray = () => {
17425
17556
  paddingLeft: 1,
17426
17557
  paddingRight: 1,
17427
17558
  children: uiState.showFullTodos ? /* @__PURE__ */ jsxs56(Box57, { flexDirection: "column", rowGap: 1, children: [
17428
- /* @__PURE__ */ jsx72(TodoTitleDisplay, { todos }),
17429
- /* @__PURE__ */ jsx72(TodoListDisplay, { todos })
17559
+ /* @__PURE__ */ jsx72(TodoTitleDisplay, { todos, isWorking }),
17560
+ /* @__PURE__ */ jsx72(TodoListDisplay, { todos, isWorking })
17430
17561
  ] }) : /* @__PURE__ */ jsxs56(Box57, { flexDirection: "row", columnGap: 1, height: 1, children: [
17431
- /* @__PURE__ */ jsx72(Box57, { flexShrink: 0, flexGrow: 0, children: /* @__PURE__ */ jsx72(TodoTitleDisplay, { todos }) }),
17432
- inProgress && /* @__PURE__ */ jsx72(Box57, { flexShrink: 1, flexGrow: 1, children: /* @__PURE__ */ jsx72(TodoItemDisplay, { todo: inProgress, wrap: "truncate" }) })
17562
+ /* @__PURE__ */ jsx72(Box57, { flexShrink: 1, flexGrow: 0, children: /* @__PURE__ */ jsx72(TodoTitleDisplay, { todos, isWorking, compact: true }) }),
17563
+ inProgress && /* @__PURE__ */ jsx72(Box57, { flexShrink: 1, flexGrow: 1, children: /* @__PURE__ */ jsx72(
17564
+ TodoItemDisplay,
17565
+ {
17566
+ todo: inProgress,
17567
+ wrap: "truncate",
17568
+ isWorking
17569
+ }
17570
+ ) })
17433
17571
  ] })
17434
17572
  }
17435
17573
  );
17436
17574
  };
17437
- var TodoListDisplay = ({ todos }) => /* @__PURE__ */ jsx72(Box57, { flexDirection: "column", "aria-role": "list", children: todos.todos.map((todo, index) => /* @__PURE__ */ jsx72(TodoItemDisplay, { todo, role: "listitem" }, index)) });
17575
+ var TodoListDisplay = ({ todos, isWorking }) => /* @__PURE__ */ jsx72(Box57, { flexDirection: "column", "aria-role": "list", children: todos.todos.map((todo, index) => /* @__PURE__ */ jsx72(
17576
+ TodoItemDisplay,
17577
+ {
17578
+ todo,
17579
+ role: "listitem",
17580
+ isWorking
17581
+ },
17582
+ index
17583
+ )) });
17438
17584
 
17439
17585
  // src/ui/components/layout/status-display.tsx
17440
17586
  import { Text as Text53 } from "ink";
@@ -17560,10 +17706,10 @@ var Composer = ({ isFocused = true }) => {
17560
17706
 
17561
17707
  // src/ui/components/dialogs/exit-warning.tsx
17562
17708
  import { Box as Box59, Text as Text54 } from "ink";
17563
- import { Fragment as Fragment13, jsx as jsx75, jsxs as jsxs58 } from "react/jsx-runtime";
17709
+ import { Fragment as Fragment14, jsx as jsx75, jsxs as jsxs58 } from "react/jsx-runtime";
17564
17710
  var ExitWarning = () => {
17565
17711
  const uiState = useUIState();
17566
- return /* @__PURE__ */ jsxs58(Fragment13, { children: [
17712
+ return /* @__PURE__ */ jsxs58(Fragment14, { children: [
17567
17713
  uiState.dialogsVisible && uiState.ctrlCPressedOnce && /* @__PURE__ */ jsx75(Box59, { marginTop: 1, children: /* @__PURE__ */ jsx75(Text54, { color: theme.status.warning, children: "Press Ctrl+C again to exit." }) }),
17568
17714
  uiState.dialogsVisible && uiState.ctrlDPressedOnce && /* @__PURE__ */ jsx75(Box59, { marginTop: 1, children: /* @__PURE__ */ jsx75(Text54, { color: theme.status.warning, children: "Press Ctrl+D again to exit." }) })
17569
17715
  ] });
@@ -18706,7 +18852,7 @@ var CopyModeWarning = () => {
18706
18852
  };
18707
18853
 
18708
18854
  // src/ui/components/layout/default-app-layout.tsx
18709
- import { Fragment as Fragment14, jsx as jsx85, jsxs as jsxs64 } from "react/jsx-runtime";
18855
+ import { Fragment as Fragment15, jsx as jsx85, jsxs as jsxs64 } from "react/jsx-runtime";
18710
18856
  var DefaultAppLayout = () => {
18711
18857
  const uiState = useUIState();
18712
18858
  const isAlternateBuffer = useAlternateBuffer();
@@ -18740,7 +18886,7 @@ var DefaultAppLayout = () => {
18740
18886
  children: [
18741
18887
  /* @__PURE__ */ jsx85(Notifications, {}),
18742
18888
  /* @__PURE__ */ jsx85(CopyModeWarning, {}),
18743
- pendingApproval !== void 0 ? /* @__PURE__ */ jsxs64(Fragment14, { children: [
18889
+ pendingApproval !== void 0 ? /* @__PURE__ */ jsxs64(Fragment15, { children: [
18744
18890
  /* @__PURE__ */ jsx85(
18745
18891
  ToolConfirmationQueue,
18746
18892
  {
@@ -18899,7 +19045,7 @@ function useHistory() {
18899
19045
  }
18900
19046
 
18901
19047
  // src/ui/hooks/commands/use-slash-command-processor.ts
18902
- import { useCallback as useCallback35, useMemo as useMemo33, useEffect as useEffect43, useRef as useRef21, useState as useState41 } from "react";
19048
+ import { useCallback as useCallback36, useMemo as useMemo34, useEffect as useEffect44, useRef as useRef22, useState as useState42 } from "react";
18903
19049
 
18904
19050
  // src/services/command-service.ts
18905
19051
  var CommandService = class _CommandService {
@@ -19276,7 +19422,7 @@ function ProviderSetupDialog({
19276
19422
  }
19277
19423
 
19278
19424
  // src/ui/components/dialogs/model-dialog.tsx
19279
- import { Fragment as Fragment15, jsx as jsx89, jsxs as jsxs67 } from "react/jsx-runtime";
19425
+ import { Fragment as Fragment16, jsx as jsx89, jsxs as jsxs67 } from "react/jsx-runtime";
19280
19426
  function capabilityLabel(model) {
19281
19427
  return model.inputModalities.includes("image") ? "Text + Vision" : "Text";
19282
19428
  }
@@ -19572,7 +19718,7 @@ function ModelDialog({
19572
19718
  },
19573
19719
  items.map((item) => item.key).join("|")
19574
19720
  ) }),
19575
- /* @__PURE__ */ jsx89(Box69, { width: "45%", paddingLeft: 2, flexDirection: "column", children: pending ? /* @__PURE__ */ jsxs67(Fragment15, { children: [
19721
+ /* @__PURE__ */ jsx89(Box69, { width: "45%", paddingLeft: 2, flexDirection: "column", children: pending ? /* @__PURE__ */ jsxs67(Fragment16, { children: [
19576
19722
  /* @__PURE__ */ jsx89(Text62, { bold: true, color: theme.status.warning, children: "Start a new Session?" }),
19577
19723
  /* @__PURE__ */ jsxs67(Box69, { marginTop: 1, flexDirection: "column", children: [
19578
19724
  /* @__PURE__ */ jsxs67(Text62, { children: [
@@ -19597,7 +19743,7 @@ function ModelDialog({
19597
19743
  showNumbers: false
19598
19744
  }
19599
19745
  ) })
19600
- ] }) : /* @__PURE__ */ jsxs67(Fragment15, { children: [
19746
+ ] }) : /* @__PURE__ */ jsxs67(Fragment16, { children: [
19601
19747
  /* @__PURE__ */ jsx89(Text62, { bold: true, color: theme.text.primary, children: highlighted.name }),
19602
19748
  /* @__PURE__ */ jsxs67(Box69, { marginTop: 1, flexDirection: "column", children: [
19603
19749
  /* @__PURE__ */ jsx89(Text62, { color: theme.text.secondary, children: "Provider" }),
@@ -19633,6 +19779,13 @@ var modelCommand = {
19633
19779
  content: "Usage: /model"
19634
19780
  };
19635
19781
  }
19782
+ if (context.services.sideConversation?.getWorkspaceSnapshot().sideSessionId !== void 0) {
19783
+ return {
19784
+ type: "message",
19785
+ messageType: "error",
19786
+ content: "Close the Side conversation before changing the Main model. Use /side, then Ctrl+C."
19787
+ };
19788
+ }
19636
19789
  const runtime = context.services.modelSelection;
19637
19790
  if (!runtime) {
19638
19791
  return { type: "message", messageType: "error", content: "DSH model selection is unavailable." };
@@ -19661,7 +19814,7 @@ import React17 from "react";
19661
19814
  // src/ui/components/dialogs/provider-dialog.tsx
19662
19815
  import { useEffect as useEffect40, useMemo as useMemo29, useState as useState37 } from "react";
19663
19816
  import { Box as Box70, Text as Text63 } from "ink";
19664
- import { Fragment as Fragment16, jsx as jsx90, jsxs as jsxs68 } from "react/jsx-runtime";
19817
+ import { Fragment as Fragment17, jsx as jsx90, jsxs as jsxs68 } from "react/jsx-runtime";
19665
19818
  function statusLabel(status) {
19666
19819
  switch (status) {
19667
19820
  case "configured":
@@ -19819,11 +19972,11 @@ function ProviderDialog({
19819
19972
  /* @__PURE__ */ jsx90(Text63, { children: highlighted.provider }),
19820
19973
  /* @__PURE__ */ jsx90(Text63, { color: theme.text.secondary, children: "Status" }),
19821
19974
  /* @__PURE__ */ jsx90(Text63, { color: statusColor(highlighted.status), children: statusLabel(highlighted.status) }),
19822
- highlighted.credentialLabel && /* @__PURE__ */ jsxs68(Fragment16, { children: [
19975
+ highlighted.credentialLabel && /* @__PURE__ */ jsxs68(Fragment17, { children: [
19823
19976
  /* @__PURE__ */ jsx90(Text63, { color: theme.text.secondary, children: "Credential" }),
19824
19977
  /* @__PURE__ */ jsx90(Text63, { children: highlighted.credentialLabel })
19825
19978
  ] }),
19826
- highlighted.source && /* @__PURE__ */ jsxs68(Fragment16, { children: [
19979
+ highlighted.source && /* @__PURE__ */ jsxs68(Fragment17, { children: [
19827
19980
  /* @__PURE__ */ jsx90(Text63, { color: theme.text.secondary, children: "Source" }),
19828
19981
  /* @__PURE__ */ jsx90(Text63, { children: highlighted.source })
19829
19982
  ] }),
@@ -19832,7 +19985,7 @@ function ProviderDialog({
19832
19985
  ] })
19833
19986
  ] })
19834
19987
  ] }),
19835
- providers.length > 0 && highlighted && /* @__PURE__ */ jsx90(Box70, { marginTop: 1, children: highlighted.writable && highlighted.status !== "unsupported" ? /* @__PURE__ */ jsxs68(Fragment16, { children: [
19988
+ providers.length > 0 && highlighted && /* @__PURE__ */ jsx90(Box70, { marginTop: 1, children: highlighted.writable && highlighted.status !== "unsupported" ? /* @__PURE__ */ jsxs68(Fragment17, { children: [
19836
19989
  /* @__PURE__ */ jsx90(Text63, { bold: true, color: theme.text.accent, children: "Enter" }),
19837
19990
  /* @__PURE__ */ jsxs68(Text63, { color: theme.text.primary, children: [
19838
19991
  " ",
@@ -19896,7 +20049,7 @@ import React18 from "react";
19896
20049
  // src/ui/components/dialogs/session-dialog.tsx
19897
20050
  import { useCallback as useCallback33, useEffect as useEffect41, useMemo as useMemo30, useRef as useRef20, useState as useState38 } from "react";
19898
20051
  import { Box as Box71, Text as Text64 } from "ink";
19899
- import { Fragment as Fragment17, jsx as jsx91, jsxs as jsxs69 } from "react/jsx-runtime";
20052
+ import { Fragment as Fragment18, jsx as jsx91, jsxs as jsxs69 } from "react/jsx-runtime";
19900
20053
  function shortId(id) {
19901
20054
  const start2 = id.startsWith("dsh-console-") ? "dsh-console-".length : 0;
19902
20055
  return id.slice(start2, start2 + 12);
@@ -19912,24 +20065,64 @@ function SessionDialog({ runtime, onClose }) {
19912
20065
  const [switching, setSwitching] = useState38(false);
19913
20066
  const [error, setError] = useState38();
19914
20067
  const switchingRef = useRef20(false);
20068
+ const titleRequestsRef = useRef20(/* @__PURE__ */ new Map());
20069
+ const resolveTitles = useCallback33((candidates) => {
20070
+ const sessionsToResolve = candidates.filter((session) => !session.title && !titleRequestsRef.current.has(session.id));
20071
+ if (sessionsToResolve.length === 0) return;
20072
+ const controller = new AbortController();
20073
+ for (const session of sessionsToResolve) {
20074
+ titleRequestsRef.current.set(session.id, controller);
20075
+ }
20076
+ void runtime.resolveSessionTitles(
20077
+ sessionsToResolve.map((session) => session.id),
20078
+ controller.signal
20079
+ ).then((titles) => {
20080
+ if (controller.signal.aborted || titles.length === 0) return;
20081
+ const titleById = new Map(titles.map(({ id, title }) => [id, title]));
20082
+ const withResolvedTitle = (item) => {
20083
+ const title = titleById.get(item.id);
20084
+ return title === void 0 ? item : { ...item, title };
20085
+ };
20086
+ setSessions((current) => current.map(withResolvedTitle));
20087
+ setHighlighted((current) => current ? withResolvedTitle(current) : current);
20088
+ setPending((current) => current ? withResolvedTitle(current) : current);
20089
+ }).catch(() => {
20090
+ }).finally(() => {
20091
+ for (const session of sessionsToResolve) {
20092
+ if (titleRequestsRef.current.get(session.id) === controller) {
20093
+ titleRequestsRef.current.delete(session.id);
20094
+ }
20095
+ }
20096
+ });
20097
+ }, [runtime]);
19915
20098
  useEffect41(() => {
19916
20099
  const controller = new AbortController();
20100
+ const titleRequests = titleRequestsRef.current;
19917
20101
  void runtime.listSessions(controller.signal).then((listed) => {
19918
20102
  setSessions(listed);
19919
20103
  setHighlighted(listed.find((session) => session.current) ?? listed[0]);
20104
+ resolveTitles(listed.slice(0, 12));
19920
20105
  }).catch((cause) => {
19921
20106
  if (!controller.signal.aborted) setError(cause instanceof Error ? cause.message : String(cause));
19922
20107
  }).finally(() => {
19923
20108
  if (!controller.signal.aborted) setLoading(false);
19924
20109
  });
19925
- return () => controller.abort();
19926
- }, [runtime]);
20110
+ return () => {
20111
+ controller.abort();
20112
+ for (const titleController of titleRequests.values()) titleController.abort();
20113
+ titleRequests.clear();
20114
+ };
20115
+ }, [resolveTitles, runtime]);
19927
20116
  const items = useMemo30(() => sessions.map((session) => ({
19928
20117
  key: session.id,
19929
20118
  value: session,
19930
20119
  label: sessionLabel(session)
19931
20120
  })), [sessions]);
19932
20121
  const initialIndex = Math.max(0, sessions.findIndex((session) => session.current));
20122
+ const highlight = useCallback33((session) => {
20123
+ setHighlighted(session);
20124
+ resolveTitles([session]);
20125
+ }, [resolveTitles]);
19933
20126
  const resume = useCallback33(async (session) => {
19934
20127
  if (switchingRef.current) return;
19935
20128
  switchingRef.current = true;
@@ -19975,7 +20168,7 @@ function SessionDialog({ runtime, onClose }) {
19975
20168
  {
19976
20169
  items,
19977
20170
  initialIndex,
19978
- onHighlight: setHighlighted,
20171
+ onHighlight: highlight,
19979
20172
  onSelect: select,
19980
20173
  isFocused: !pending && !switching,
19981
20174
  showScrollArrows: true,
@@ -19987,7 +20180,7 @@ function SessionDialog({ runtime, onClose }) {
19987
20180
  ] })
19988
20181
  }
19989
20182
  ) }),
19990
- /* @__PURE__ */ jsx91(Box71, { width: "45%", paddingLeft: 2, flexDirection: "column", children: pending ? /* @__PURE__ */ jsxs69(Fragment17, { children: [
20183
+ /* @__PURE__ */ jsx91(Box71, { width: "45%", paddingLeft: 2, flexDirection: "column", children: pending ? /* @__PURE__ */ jsxs69(Fragment18, { children: [
19991
20184
  /* @__PURE__ */ jsx91(Text64, { bold: true, color: theme.status.warning, children: "Resume this Session?" }),
19992
20185
  /* @__PURE__ */ jsxs69(Box71, { marginTop: 1, flexDirection: "column", children: [
19993
20186
  /* @__PURE__ */ jsx91(Text64, { children: sessionLabel(pending) }),
@@ -20005,12 +20198,12 @@ function SessionDialog({ runtime, onClose }) {
20005
20198
  showNumbers: false
20006
20199
  }
20007
20200
  ) })
20008
- ] }) : highlighted ? /* @__PURE__ */ jsxs69(Fragment17, { children: [
20201
+ ] }) : highlighted ? /* @__PURE__ */ jsxs69(Fragment18, { children: [
20009
20202
  /* @__PURE__ */ jsx91(Text64, { bold: true, children: sessionLabel(highlighted) }),
20010
20203
  /* @__PURE__ */ jsxs69(Box71, { marginTop: 1, flexDirection: "column", children: [
20011
20204
  /* @__PURE__ */ jsx91(Text64, { color: theme.text.secondary, children: "Created" }),
20012
20205
  /* @__PURE__ */ jsx91(Text64, { children: new Date(highlighted.createdAt).toLocaleString() }),
20013
- !highlighted.resumable && highlighted.resumeUnavailableReason && /* @__PURE__ */ jsxs69(Fragment17, { children: [
20206
+ !highlighted.resumable && highlighted.resumeUnavailableReason && /* @__PURE__ */ jsxs69(Fragment18, { children: [
20014
20207
  /* @__PURE__ */ jsx91(Text64, { color: theme.text.secondary, children: "Resume status" }),
20015
20208
  /* @__PURE__ */ jsx91(Text64, { color: theme.status.warning, children: highlighted.resumeUnavailableReason })
20016
20209
  ] }),
@@ -20027,6 +20220,13 @@ function SessionDialog({ runtime, onClose }) {
20027
20220
  function unavailable() {
20028
20221
  return { type: "message", messageType: "error", content: "DSH Session management is unavailable." };
20029
20222
  }
20223
+ function requireStableMain(context) {
20224
+ return context.services.sideConversation?.getWorkspaceSnapshot().sideSessionId !== void 0 ? {
20225
+ type: "message",
20226
+ messageType: "error",
20227
+ content: "Close the Side conversation before managing Main Sessions. Use /side, then Ctrl+C."
20228
+ } : void 0;
20229
+ }
20030
20230
  function openDialog(context) {
20031
20231
  const runtime = context.services.sessionManagement;
20032
20232
  if (!runtime) return unavailable();
@@ -20044,6 +20244,8 @@ var newCommand = {
20044
20244
  kind: "built-in" /* BUILT_IN */,
20045
20245
  autoExecute: true,
20046
20246
  action: async (context, args) => {
20247
+ const mainRequired = requireStableMain(context);
20248
+ if (mainRequired) return mainRequired;
20047
20249
  if (args.trim() !== "") return { type: "message", messageType: "error", content: "Usage: /new" };
20048
20250
  const runtime = context.services.sessionManagement;
20049
20251
  if (!runtime) return unavailable();
@@ -20065,7 +20267,11 @@ var sessionsCommand = {
20065
20267
  description: "Browse dsh-console Sessions in this workspace",
20066
20268
  kind: "built-in" /* BUILT_IN */,
20067
20269
  autoExecute: true,
20068
- action: async (context, args) => args.trim() === "" ? openDialog(context) : { type: "message", messageType: "error", content: "Usage: /sessions" }
20270
+ action: async (context, args) => {
20271
+ const mainRequired = requireStableMain(context);
20272
+ if (mainRequired) return mainRequired;
20273
+ return args.trim() === "" ? openDialog(context) : { type: "message", messageType: "error", content: "Usage: /sessions" };
20274
+ }
20069
20275
  };
20070
20276
  var resumeCommand = {
20071
20277
  name: "resume",
@@ -20073,6 +20279,8 @@ var resumeCommand = {
20073
20279
  kind: "built-in" /* BUILT_IN */,
20074
20280
  autoExecute: true,
20075
20281
  action: async (context, args) => {
20282
+ const mainRequired = requireStableMain(context);
20283
+ if (mainRequired) return mainRequired;
20076
20284
  const runtime = context.services.sessionManagement;
20077
20285
  if (!runtime) return unavailable();
20078
20286
  const sessionId = args.trim();
@@ -20146,7 +20354,7 @@ function DescriptiveRadioButtonSelect({
20146
20354
  }
20147
20355
 
20148
20356
  // src/ui/components/dialogs/tools-dialog.tsx
20149
- import { Fragment as Fragment18, jsx as jsx93, jsxs as jsxs71 } from "react/jsx-runtime";
20357
+ import { Fragment as Fragment19, jsx as jsx93, jsxs as jsxs71 } from "react/jsx-runtime";
20150
20358
  function summary(description) {
20151
20359
  const line = description.replace(/\s+/g, " ").trim();
20152
20360
  return line.length > 90 ? `${line.slice(0, 89)}...` : line;
@@ -20207,7 +20415,7 @@ function ToolsDialog({ runtime, onClose }) {
20207
20415
  maxItemsToShow: 10
20208
20416
  }
20209
20417
  ) }),
20210
- /* @__PURE__ */ jsx93(Box73, { width: "45%", paddingLeft: 2, flexDirection: "column", children: selected && /* @__PURE__ */ jsxs71(Fragment18, { children: [
20418
+ /* @__PURE__ */ jsx93(Box73, { width: "45%", paddingLeft: 2, flexDirection: "column", children: selected && /* @__PURE__ */ jsxs71(Fragment19, { children: [
20211
20419
  /* @__PURE__ */ jsx93(Text66, { bold: true, color: theme.text.accent, children: selected.name }),
20212
20420
  /* @__PURE__ */ jsx93(Box73, { marginTop: 1, children: /* @__PURE__ */ jsx93(Text66, { wrap: "wrap", children: selected.description }) }),
20213
20421
  /* @__PURE__ */ jsxs71(Box73, { marginTop: 1, flexDirection: "column", children: [
@@ -20270,7 +20478,7 @@ import React20 from "react";
20270
20478
  // src/ui/components/dialogs/permission-dialog.tsx
20271
20479
  import { useCallback as useCallback34, useMemo as useMemo32, useState as useState40, useSyncExternalStore as useSyncExternalStore4 } from "react";
20272
20480
  import { Box as Box74, Text as Text67 } from "ink";
20273
- import { Fragment as Fragment19, jsx as jsx94, jsxs as jsxs72 } from "react/jsx-runtime";
20481
+ import { Fragment as Fragment20, jsx as jsx94, jsxs as jsxs72 } from "react/jsx-runtime";
20274
20482
  function PermissionDialog({
20275
20483
  runtime,
20276
20484
  onClose,
@@ -20364,7 +20572,7 @@ function PermissionDialog({
20364
20572
  },
20365
20573
  items.map((item) => item.key).join("|")
20366
20574
  ) }),
20367
- /* @__PURE__ */ jsx94(Box74, { width: "50%", paddingLeft: 2, flexDirection: "column", children: pending ? /* @__PURE__ */ jsxs72(Fragment19, { children: [
20575
+ /* @__PURE__ */ jsx94(Box74, { width: "50%", paddingLeft: 2, flexDirection: "column", children: pending ? /* @__PURE__ */ jsxs72(Fragment20, { children: [
20368
20576
  /* @__PURE__ */ jsx94(Text67, { bold: true, color: theme.status.warning, children: "Enable Full access?" }),
20369
20577
  /* @__PURE__ */ jsx94(Box74, { marginTop: 1, children: /* @__PURE__ */ jsx94(Text67, { children: "This allows commands to run without workspace sandbox restrictions or approval prompts." }) }),
20370
20578
  /* @__PURE__ */ jsx94(Box74, { marginTop: 1, children: /* @__PURE__ */ jsx94(
@@ -20382,7 +20590,7 @@ function PermissionDialog({
20382
20590
  showNumbers: false
20383
20591
  }
20384
20592
  ) })
20385
- ] }) : selected ? /* @__PURE__ */ jsxs72(Fragment19, { children: [
20593
+ ] }) : selected ? /* @__PURE__ */ jsxs72(Fragment20, { children: [
20386
20594
  /* @__PURE__ */ jsx94(Text67, { bold: true, color: theme.text.primary, children: selected.name }),
20387
20595
  /* @__PURE__ */ jsx94(Text67, { color: theme.text.secondary, children: selected.value }),
20388
20596
  /* @__PURE__ */ jsx94(Box74, { marginTop: 1, children: /* @__PURE__ */ jsx94(Text67, { children: selected.description ?? "No description is available for this preset." }) }),
@@ -20478,82 +20686,525 @@ var profilerCommand = {
20478
20686
  action: (context) => context.ui.toggleDebugProfiler()
20479
20687
  };
20480
20688
 
20481
- // src/services/builtin-command-loader.ts
20482
- var BuiltinCommandLoader = class {
20483
- constructor(enableProfiler = false) {
20484
- this.enableProfiler = enableProfiler;
20485
- }
20486
- isFirstLoad = true;
20487
- /**
20488
- * Gathers all raw built-in command definitions, injects dependencies where
20489
- * needed (e.g., config) and filters out any that are not available.
20490
- *
20491
- * @param _signal An AbortSignal (unused for this synchronous loader).
20492
- * @returns A promise that resolves to an array of `SlashCommand` objects.
20493
- */
20494
- async loadCommands(_signal) {
20495
- const startTime = performance.now();
20496
- const isInitialLoad = this.isFirstLoad;
20497
- this.isFirstLoad = false;
20498
- const commands = [
20499
- helpCommand,
20500
- aboutCommand,
20501
- statsCommand,
20502
- toolsCommand,
20503
- ...this.enableProfiler ? [profilerCommand] : [],
20504
- quitCommand,
20505
- themeCommand,
20506
- settingsCommand,
20507
- vimCommand,
20508
- modelCommand,
20509
- providerCommand,
20510
- permissionCommand,
20511
- newCommand,
20512
- sessionsCommand,
20513
- resumeCommand
20514
- ];
20515
- const duration = (performance.now() - startTime).toFixed(2);
20516
- const logMessage = `[BuiltinCommandLoader] ${isInitialLoad ? "Loaded" : "Reloaded"} ${commands.length} commands in ${duration}ms`;
20517
- if (isInitialLoad) {
20518
- debugLogger.log(logMessage);
20519
- } else {
20520
- debugLogger.debug(logMessage);
20689
+ // src/ui/commands/btw-command.ts
20690
+ var btwCommand = {
20691
+ name: "btw",
20692
+ description: "Ask an ephemeral side question without interrupting the main Agent",
20693
+ inputHint: "<question>",
20694
+ kind: "built-in" /* BUILT_IN */,
20695
+ autoExecute: false,
20696
+ recordInvocation: false,
20697
+ allowWhileBusy: true,
20698
+ action: async (context, args) => {
20699
+ const question = args.trim();
20700
+ const runtime = context.services.sideConversation;
20701
+ if (!runtime) {
20702
+ return {
20703
+ type: "message",
20704
+ messageType: "error",
20705
+ content: "DSH Side conversations are unavailable."
20706
+ };
20521
20707
  }
20522
- return commands;
20523
- }
20524
- };
20525
-
20526
- // src/ui/commands/parser.ts
20527
- var parseSlashCommand = (query, commands) => {
20528
- const trimmed = query.trim();
20529
- const parts = trimmed.substring(1).trim().split(/\s+/);
20530
- const commandPath = parts.filter((p) => p);
20531
- let currentCommands = commands;
20532
- let commandToExecute;
20533
- let pathIndex = 0;
20534
- const canonicalPath = [];
20535
- for (const part of commandPath) {
20536
- let foundCommand = currentCommands.find((cmd) => cmd.name === part);
20537
- if (!foundCommand) {
20538
- foundCommand = currentCommands.find(
20539
- (cmd) => cmd.altNames?.includes(part)
20540
- );
20708
+ if (!question && runtime.getWorkspaceSnapshot().sideSessionId === void 0) {
20709
+ return {
20710
+ type: "message",
20711
+ messageType: "error",
20712
+ content: "Usage: /btw <question>"
20713
+ };
20541
20714
  }
20542
- if (foundCommand) {
20543
- commandToExecute = foundCommand;
20544
- canonicalPath.push(foundCommand.name);
20545
- pathIndex++;
20546
- if (foundCommand.subCommands) {
20547
- currentCommands = foundCommand.subCommands;
20548
- } else {
20549
- break;
20715
+ await runtime.open(question || void 0, context.invocation.signal);
20716
+ return void 0;
20717
+ }
20718
+ };
20719
+ var mainCommand = {
20720
+ name: "main",
20721
+ description: "Switch to the main conversation",
20722
+ kind: "built-in" /* BUILT_IN */,
20723
+ autoExecute: true,
20724
+ recordInvocation: false,
20725
+ allowWhileBusy: true,
20726
+ action: (context, args) => {
20727
+ if (args.trim()) return { type: "message", messageType: "error", content: "Usage: /main" };
20728
+ const runtime = context.services.sideConversation;
20729
+ if (!runtime) return { type: "message", messageType: "error", content: "DSH Side conversations are unavailable." };
20730
+ runtime.switchToMain();
20731
+ return void 0;
20732
+ }
20733
+ };
20734
+ var sideCommand = {
20735
+ name: "side",
20736
+ description: "Switch to the active Side conversation",
20737
+ kind: "built-in" /* BUILT_IN */,
20738
+ autoExecute: true,
20739
+ recordInvocation: false,
20740
+ allowWhileBusy: true,
20741
+ action: (context, args) => {
20742
+ if (args.trim()) return { type: "message", messageType: "error", content: "Usage: /side" };
20743
+ const runtime = context.services.sideConversation;
20744
+ if (!runtime) return { type: "message", messageType: "error", content: "DSH Side conversations are unavailable." };
20745
+ runtime.switchToSide();
20746
+ return void 0;
20747
+ }
20748
+ };
20749
+
20750
+ // src/ui/commands/agents-command.ts
20751
+ import React21 from "react";
20752
+
20753
+ // src/ui/components/dialogs/agents-dialog.tsx
20754
+ import {
20755
+ useCallback as useCallback35,
20756
+ useEffect as useEffect43,
20757
+ useMemo as useMemo33,
20758
+ useRef as useRef21,
20759
+ useState as useState41,
20760
+ useSyncExternalStore as useSyncExternalStore5
20761
+ } from "react";
20762
+ import { Box as Box75, Text as Text68 } from "ink";
20763
+
20764
+ // src/ui/conversation-history-projector.ts
20765
+ function projectedToolCallIds(messages) {
20766
+ return new Set(
20767
+ messages.flatMap(
20768
+ (message) => message.role === "tool" ? [message.callId] : []
20769
+ )
20770
+ );
20771
+ }
20772
+ function conversationMessageToHistoryItem(message, visibleToolCallIds) {
20773
+ const assistantContent = message.role === "assistant" ? message.content.filter(
20774
+ (block) => block.type !== "tool-call" || !visibleToolCallIds.has(block.id)
20775
+ ) : void 0;
20776
+ if (message.role === "assistant" && assistantContent?.length === 0 && message.interrupted !== true) {
20777
+ return void 0;
20778
+ }
20779
+ if (message.role === "tool") {
20780
+ return {
20781
+ type: "tool_group",
20782
+ tools: [
20783
+ {
20784
+ callId: message.callId,
20785
+ name: message.presentation?.kind === "card" ? message.presentation.title ?? message.name : message.name,
20786
+ description: message.presentation?.kind === "compact" ? "" : message.presentation?.description ?? message.arguments,
20787
+ resultDisplay: message.presentation?.kind === "compact" ? void 0 : message.presentation?.resultDisplay ?? (message.result === void 0 ? void 0 : {
20788
+ type: "dsh-content",
20789
+ content: message.result.content,
20790
+ ...message.result.error === void 0 ? {} : { error: message.result.error }
20791
+ }),
20792
+ ...message.presentation?.kind === "compact" ? {
20793
+ presentation: {
20794
+ kind: "compact",
20795
+ label: message.presentation.label
20796
+ }
20797
+ } : {},
20798
+ status: message.status === "executing" ? "Executing" /* Executing */ : message.status === "success" ? "Success" /* Success */ : "Error" /* Error */
20799
+ }
20800
+ ]
20801
+ };
20802
+ }
20803
+ if (message.role === "assistant") {
20804
+ return {
20805
+ type: "dsh_assistant",
20806
+ content: assistantContent ?? message.content,
20807
+ interrupted: message.interrupted === true
20808
+ };
20809
+ }
20810
+ if (message.role === "user") {
20811
+ return {
20812
+ type: "dsh_user",
20813
+ content: message.displayContent ?? message.content
20814
+ };
20815
+ }
20816
+ return {
20817
+ type: message.status === "cancelled" ? "warning" /* WARNING */ : "error" /* ERROR */,
20818
+ text: conversationMessageText(message)
20819
+ };
20820
+ }
20821
+ function conversationMessageFingerprint(message, item) {
20822
+ if (message.role === "tool") {
20823
+ return JSON.stringify([
20824
+ message.status,
20825
+ message.result,
20826
+ message.presentation
20827
+ ]);
20828
+ }
20829
+ if (message.role === "assistant" && item.type === "dsh_assistant") {
20830
+ return JSON.stringify([item.content, item.interrupted]);
20831
+ }
20832
+ if (message.role === "user") {
20833
+ return JSON.stringify(message.displayContent ?? message.content);
20834
+ }
20835
+ return conversationMessageText(message);
20836
+ }
20837
+
20838
+ // src/ui/components/dialogs/agents-dialog.tsx
20839
+ import { Fragment as Fragment21, jsx as jsx95, jsxs as jsxs73 } from "react/jsx-runtime";
20840
+ function shortId2(id) {
20841
+ return id.slice(-8);
20842
+ }
20843
+ function itemTitle(item) {
20844
+ const branch = item.depth > 1 ? `${" ".repeat(item.depth - 1)}- ` : "";
20845
+ return `${branch}${item.kind === "agent" ? item.label : `Unavailable ${shortId2(item.id)}`}`;
20846
+ }
20847
+ function itemDescription(item) {
20848
+ if (item.kind === "diagnostic") return `diagnostic \xB7 ${item.reason}`;
20849
+ return `${item.activity} \xB7 ${item.mode}`;
20850
+ }
20851
+ function AgentsDialog({ runtime, onClose }) {
20852
+ const snapshot = useSyncExternalStore5(
20853
+ runtime.subscribe,
20854
+ runtime.getSnapshot,
20855
+ runtime.getSnapshot
20856
+ );
20857
+ const [selectedId, setSelectedId] = useState41(snapshot.items[0]?.id);
20858
+ const [transcript, setTranscript] = useState41();
20859
+ const [transcriptSessionId, setTranscriptSessionId] = useState41();
20860
+ const [opening, setOpening] = useState41(false);
20861
+ const [openError, setOpenError] = useState41();
20862
+ const openController = useRef21(void 0);
20863
+ const openingRef = useRef21(false);
20864
+ const transcriptRef = useRef21(void 0);
20865
+ const selected = snapshot.items.find((item) => item.id === selectedId) ?? snapshot.items[0];
20866
+ useEffect43(() => {
20867
+ const controller = new AbortController();
20868
+ void runtime.refresh(controller.signal);
20869
+ return () => controller.abort();
20870
+ }, [runtime]);
20871
+ useEffect43(
20872
+ () => () => {
20873
+ openController.current?.abort();
20874
+ transcriptRef.current?.dispose();
20875
+ transcriptRef.current = void 0;
20876
+ },
20877
+ []
20878
+ );
20879
+ useEffect43(() => {
20880
+ if (selected?.id !== selectedId) setSelectedId(selected?.id);
20881
+ }, [selected?.id, selectedId]);
20882
+ useKeypress(
20883
+ (key) => {
20884
+ if (transcript !== void 0) return;
20885
+ if (key.name === "escape") onClose();
20886
+ if (key.name === "r") void runtime.refresh();
20887
+ },
20888
+ { isActive: true }
20889
+ );
20890
+ const openTranscript = useCallback35(
20891
+ async (sessionId) => {
20892
+ const item = snapshot.items.find(
20893
+ (candidate) => candidate.id === sessionId && candidate.kind === "agent"
20894
+ );
20895
+ if (item === void 0 || openingRef.current) return;
20896
+ openingRef.current = true;
20897
+ openController.current?.abort();
20898
+ const controller = new AbortController();
20899
+ openController.current = controller;
20900
+ setOpening(true);
20901
+ setOpenError(void 0);
20902
+ try {
20903
+ const next = await runtime.openTranscript(sessionId, controller.signal);
20904
+ if (controller.signal.aborted) {
20905
+ next.dispose();
20906
+ return;
20907
+ }
20908
+ transcriptRef.current?.dispose();
20909
+ transcriptRef.current = next;
20910
+ setTranscriptSessionId(sessionId);
20911
+ setTranscript(next);
20912
+ } catch (error) {
20913
+ if (!controller.signal.aborted) {
20914
+ setOpenError(
20915
+ error instanceof Error ? error.message : "Unable to open the subagent transcript."
20916
+ );
20917
+ }
20918
+ } finally {
20919
+ if (openController.current === controller) {
20920
+ openController.current = void 0;
20921
+ openingRef.current = false;
20922
+ if (!controller.signal.aborted) setOpening(false);
20923
+ }
20924
+ }
20925
+ },
20926
+ [runtime, snapshot.items]
20927
+ );
20928
+ const closeTranscript = useCallback35(() => {
20929
+ openController.current?.abort();
20930
+ openController.current = void 0;
20931
+ openingRef.current = false;
20932
+ transcriptRef.current?.dispose();
20933
+ transcriptRef.current = void 0;
20934
+ setTranscript(void 0);
20935
+ setTranscriptSessionId(void 0);
20936
+ setOpenError(void 0);
20937
+ }, []);
20938
+ const items = useMemo33(
20939
+ () => snapshot.items.map((item) => ({
20940
+ key: item.id,
20941
+ value: item.id,
20942
+ title: itemTitle(item),
20943
+ description: itemDescription(item)
20944
+ })),
20945
+ [snapshot.items]
20946
+ );
20947
+ if (transcript !== void 0 && transcriptSessionId !== void 0) {
20948
+ const item = snapshot.items.find(
20949
+ (candidate) => candidate.id === transcriptSessionId
20950
+ );
20951
+ return /* @__PURE__ */ jsx95(
20952
+ AgentTranscriptView,
20953
+ {
20954
+ runtime: transcript,
20955
+ item,
20956
+ onBack: closeTranscript
20550
20957
  }
20958
+ );
20959
+ }
20960
+ return /* @__PURE__ */ jsxs73(
20961
+ Box75,
20962
+ {
20963
+ borderStyle: "round",
20964
+ borderColor: theme.border.default,
20965
+ flexDirection: "column",
20966
+ paddingX: 1,
20967
+ paddingY: 1,
20968
+ width: "100%",
20969
+ children: [
20970
+ /* @__PURE__ */ jsxs73(Box75, { justifyContent: "space-between", children: [
20971
+ /* @__PURE__ */ jsxs73(Text68, { bold: true, color: theme.text.primary, children: [
20972
+ "DSH Agents (",
20973
+ snapshot.items.length,
20974
+ ")"
20975
+ ] }),
20976
+ /* @__PURE__ */ jsx95(Text68, { color: theme.text.secondary, children: "R refresh \xB7 Esc close" })
20977
+ ] }),
20978
+ snapshot.status === "loading" && snapshot.items.length === 0 ? /* @__PURE__ */ jsx95(Box75, { marginTop: 1, children: /* @__PURE__ */ jsx95(Text68, { color: theme.text.secondary, children: "Loading delegated Agents..." }) }) : snapshot.status === "error" && snapshot.items.length === 0 ? /* @__PURE__ */ jsx95(Box75, { marginTop: 1, children: /* @__PURE__ */ jsx95(Text68, { color: theme.status.error, children: snapshot.error }) }) : snapshot.items.length === 0 ? /* @__PURE__ */ jsx95(Box75, { marginTop: 1, children: /* @__PURE__ */ jsx95(Text68, { color: theme.text.secondary, children: "The Main Agent has not delegated any subagents in this Session." }) }) : /* @__PURE__ */ jsxs73(Box75, { flexDirection: "row", marginTop: 1, children: [
20979
+ /* @__PURE__ */ jsx95(Box75, { width: "55%", paddingRight: 2, flexDirection: "column", children: /* @__PURE__ */ jsx95(
20980
+ DescriptiveRadioButtonSelect,
20981
+ {
20982
+ items,
20983
+ onHighlight: setSelectedId,
20984
+ onSelect: (sessionId) => void openTranscript(sessionId),
20985
+ showNumbers: false,
20986
+ showScrollArrows: true,
20987
+ maxItemsToShow: 10
20988
+ }
20989
+ ) }),
20990
+ /* @__PURE__ */ jsx95(Box75, { width: "45%", paddingLeft: 2, flexDirection: "column", children: selected?.kind === "agent" ? /* @__PURE__ */ jsxs73(Fragment21, { children: [
20991
+ /* @__PURE__ */ jsx95(Text68, { bold: true, color: theme.text.accent, children: selected.label }),
20992
+ /* @__PURE__ */ jsxs73(Box75, { marginTop: 1, flexDirection: "column", children: [
20993
+ /* @__PURE__ */ jsxs73(Text68, { color: theme.text.secondary, children: [
20994
+ "Status",
20995
+ " ",
20996
+ /* @__PURE__ */ jsx95(
20997
+ Text68,
20998
+ {
20999
+ color: selected.activity === "running" ? theme.status.success : theme.text.primary,
21000
+ children: selected.activity
21001
+ }
21002
+ )
21003
+ ] }),
21004
+ /* @__PURE__ */ jsxs73(Text68, { color: theme.text.secondary, children: [
21005
+ "Mode ",
21006
+ /* @__PURE__ */ jsx95(Text68, { color: theme.text.primary, children: selected.mode })
21007
+ ] }),
21008
+ /* @__PURE__ */ jsxs73(Text68, { color: theme.text.secondary, children: [
21009
+ "Depth ",
21010
+ /* @__PURE__ */ jsx95(Text68, { color: theme.text.primary, children: selected.depth })
21011
+ ] }),
21012
+ /* @__PURE__ */ jsxs73(Text68, { color: theme.text.secondary, children: [
21013
+ "Session ",
21014
+ /* @__PURE__ */ jsx95(Text68, { color: theme.text.primary, children: shortId2(selected.id) })
21015
+ ] })
21016
+ ] })
21017
+ ] }) : selected ? /* @__PURE__ */ jsxs73(Fragment21, { children: [
21018
+ /* @__PURE__ */ jsx95(Text68, { bold: true, color: theme.status.warning, children: "Unavailable Agent" }),
21019
+ /* @__PURE__ */ jsxs73(Box75, { marginTop: 1, flexDirection: "column", children: [
21020
+ /* @__PURE__ */ jsxs73(Text68, { color: theme.text.secondary, children: [
21021
+ "Reason ",
21022
+ /* @__PURE__ */ jsx95(Text68, { color: theme.text.primary, children: selected.reason })
21023
+ ] }),
21024
+ /* @__PURE__ */ jsxs73(Text68, { color: theme.text.secondary, children: [
21025
+ "Session ",
21026
+ /* @__PURE__ */ jsx95(Text68, { color: theme.text.primary, children: shortId2(selected.id) })
21027
+ ] })
21028
+ ] })
21029
+ ] }) : null })
21030
+ ] }),
21031
+ (opening || openError !== void 0) && /* @__PURE__ */ jsx95(Box75, { marginTop: 1, children: /* @__PURE__ */ jsx95(Text68, { color: openError === void 0 ? theme.text.secondary : theme.status.error, children: openError ?? "Opening canonical Agent history..." }) }),
21032
+ snapshot.items.length > 0 && /* @__PURE__ */ jsx95(Box75, { marginTop: 1, children: /* @__PURE__ */ jsx95(Text68, { color: theme.text.secondary, children: "Enter opens read-only history. Agent conversations remain DSH-owned." }) })
21033
+ ]
21034
+ }
21035
+ );
21036
+ }
21037
+ function AgentTranscriptView({
21038
+ runtime,
21039
+ item,
21040
+ onBack
21041
+ }) {
21042
+ const uiState = useUIState();
21043
+ const snapshot = useSyncExternalStore5(
21044
+ runtime.subscribe,
21045
+ runtime.getSnapshot,
21046
+ runtime.getSnapshot
21047
+ );
21048
+ const listRef = useRef21(null);
21049
+ const history = useMemo33(() => transcriptItems(snapshot.messages), [snapshot.messages]);
21050
+ const completed = snapshot.todos.filter((todo) => todo.status === "completed").length;
21051
+ useEffect43(() => {
21052
+ listRef.current?.scrollToEnd();
21053
+ }, [history.length]);
21054
+ useKeypress(
21055
+ (key) => {
21056
+ if (key.name === "escape") onBack();
21057
+ },
21058
+ { isActive: true }
21059
+ );
21060
+ const width = Math.max(40, uiState.terminalWidth - 4);
21061
+ const height = Math.max(8, uiState.terminalHeight - 6);
21062
+ const label = item?.kind === "agent" ? item.label : shortId2(item?.id ?? "agent");
21063
+ return /* @__PURE__ */ jsxs73(
21064
+ Box75,
21065
+ {
21066
+ borderStyle: "round",
21067
+ borderColor: theme.border.default,
21068
+ flexDirection: "column",
21069
+ paddingX: 1,
21070
+ height,
21071
+ width: "100%",
21072
+ children: [
21073
+ /* @__PURE__ */ jsxs73(Box75, { justifyContent: "space-between", children: [
21074
+ /* @__PURE__ */ jsxs73(Box75, { children: [
21075
+ /* @__PURE__ */ jsx95(Text68, { bold: true, color: theme.text.primary, children: label }),
21076
+ item?.kind === "agent" && /* @__PURE__ */ jsxs73(Text68, { color: theme.text.secondary, children: [
21077
+ " ",
21078
+ "\xB7 ",
21079
+ item.mode,
21080
+ " \xB7",
21081
+ " ",
21082
+ /* @__PURE__ */ jsx95(Text68, { color: item.activity === "running" ? theme.status.success : theme.text.secondary, children: item.activity })
21083
+ ] })
21084
+ ] }),
21085
+ /* @__PURE__ */ jsx95(Text68, { color: theme.text.secondary, children: "Read only \xB7 Esc back" })
21086
+ ] }),
21087
+ snapshot.todos.length > 0 && /* @__PURE__ */ jsx95(Box75, { marginTop: 1, children: /* @__PURE__ */ jsxs73(Text68, { color: theme.text.secondary, children: [
21088
+ "Todo ",
21089
+ completed,
21090
+ "/",
21091
+ snapshot.todos.length,
21092
+ " completed"
21093
+ ] }) }),
21094
+ /* @__PURE__ */ jsx95(Box75, { flexGrow: 1, marginTop: 1, overflow: "hidden", children: history.length === 0 ? /* @__PURE__ */ jsx95(Text68, { color: theme.text.secondary, children: "This Agent has no conversation events yet." }) : /* @__PURE__ */ jsx95(
21095
+ ScrollableListWithForwardRef,
21096
+ {
21097
+ ref: listRef,
21098
+ data: history,
21099
+ hasFocus: true,
21100
+ width: "100%",
21101
+ keyExtractor: (entry) => entry.key,
21102
+ estimatedItemHeight: () => 3,
21103
+ initialScrollIndex: history.length - 1,
21104
+ renderItem: ({ item: entry, index }) => /* @__PURE__ */ jsx95(
21105
+ HistoryItemDisplay,
21106
+ {
21107
+ item: { ...entry.item, id: index },
21108
+ terminalWidth: width,
21109
+ isPending: snapshot.busy && index === history.length - 1,
21110
+ isFocused: false
21111
+ }
21112
+ )
21113
+ }
21114
+ ) })
21115
+ ]
21116
+ }
21117
+ );
21118
+ }
21119
+ function transcriptItems(messages) {
21120
+ const toolCallIds = projectedToolCallIds(messages);
21121
+ return messages.flatMap((message) => {
21122
+ const item = conversationMessageToHistoryItem(message, toolCallIds);
21123
+ return item === void 0 ? [] : [{ key: message.id, item }];
21124
+ });
21125
+ }
21126
+
21127
+ // src/ui/commands/agents-command.ts
21128
+ var agentsCommand = {
21129
+ name: "agents",
21130
+ description: "Inspect subagents delegated by the Main Agent",
21131
+ kind: "built-in" /* BUILT_IN */,
21132
+ autoExecute: true,
21133
+ recordInvocation: false,
21134
+ allowWhileBusy: true,
21135
+ action: (context, args) => {
21136
+ if (args.trim().length > 0) {
21137
+ return {
21138
+ type: "message",
21139
+ messageType: "error",
21140
+ content: "Usage: /agents"
21141
+ };
21142
+ }
21143
+ const runtime = context.services.subagentCatalog;
21144
+ if (!runtime) {
21145
+ return {
21146
+ type: "message",
21147
+ messageType: "error",
21148
+ content: "DSH Agent catalog is unavailable."
21149
+ };
21150
+ }
21151
+ return {
21152
+ type: "custom_dialog",
21153
+ component: React21.createElement(AgentsDialog, {
21154
+ runtime,
21155
+ onClose: context.ui.removeComponent
21156
+ })
21157
+ };
21158
+ }
21159
+ };
21160
+
21161
+ // src/services/builtin-command-loader.ts
21162
+ var BuiltinCommandLoader = class {
21163
+ constructor(enableProfiler = false) {
21164
+ this.enableProfiler = enableProfiler;
21165
+ }
21166
+ isFirstLoad = true;
21167
+ /**
21168
+ * Gathers all raw built-in command definitions, injects dependencies where
21169
+ * needed (e.g., config) and filters out any that are not available.
21170
+ *
21171
+ * @param _signal An AbortSignal (unused for this synchronous loader).
21172
+ * @returns A promise that resolves to an array of `SlashCommand` objects.
21173
+ */
21174
+ async loadCommands(_signal) {
21175
+ const startTime = performance.now();
21176
+ const isInitialLoad = this.isFirstLoad;
21177
+ this.isFirstLoad = false;
21178
+ const commands = [
21179
+ helpCommand,
21180
+ aboutCommand,
21181
+ statsCommand,
21182
+ toolsCommand,
21183
+ agentsCommand,
21184
+ btwCommand,
21185
+ mainCommand,
21186
+ sideCommand,
21187
+ ...this.enableProfiler ? [profilerCommand] : [],
21188
+ quitCommand,
21189
+ themeCommand,
21190
+ settingsCommand,
21191
+ vimCommand,
21192
+ modelCommand,
21193
+ providerCommand,
21194
+ permissionCommand,
21195
+ newCommand,
21196
+ sessionsCommand,
21197
+ resumeCommand
21198
+ ];
21199
+ const duration = (performance.now() - startTime).toFixed(2);
21200
+ const logMessage = `[BuiltinCommandLoader] ${isInitialLoad ? "Loaded" : "Reloaded"} ${commands.length} commands in ${duration}ms`;
21201
+ if (isInitialLoad) {
21202
+ debugLogger.log(logMessage);
20551
21203
  } else {
20552
- break;
21204
+ debugLogger.debug(logMessage);
20553
21205
  }
21206
+ return commands;
20554
21207
  }
20555
- const args = parts.slice(pathIndex).join(" ");
20556
- return { commandToExecute, args, canonicalPath };
20557
21208
  };
20558
21209
 
20559
21210
  // src/services/dsh-command-loader.ts
@@ -20589,25 +21240,27 @@ var DshCommandLoader = class {
20589
21240
  };
20590
21241
 
20591
21242
  // src/ui/hooks/commands/use-slash-command-processor.ts
20592
- var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic, toggleVimEnabled, setIsProcessing, actions, setCustomDialog, modelSelection, permissionSelection, sessionManagement, toolCatalog, dshCommands, enableProfiler = false, providerSetup) => {
21243
+ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic, toggleVimEnabled, setIsProcessing, actions, setCustomDialog, modelSelection, permissionSelection, sessionManagement, toolCatalog, dshCommands, enableProfiler = false, providerSetup, sideConversation, subagentCatalog) => {
20593
21244
  const session = useSessionStats();
20594
- const [commands, setCommands] = useState41(
21245
+ const [commands, setCommands] = useState42(
20595
21246
  void 0
20596
21247
  );
20597
- const [reloadTrigger, setReloadTrigger] = useState41(0);
20598
- const commandAbortRef = useRef21(void 0);
20599
- const reloadCommands = useCallback35(() => {
21248
+ const [reloadTrigger, setReloadTrigger] = useState42(0);
21249
+ const commandAbortRef = useRef22(void 0);
21250
+ const reloadCommands = useCallback36(() => {
20600
21251
  setReloadTrigger((v) => v + 1);
20601
21252
  }, []);
20602
- const [confirmationRequest, setConfirmationRequest] = useState41(null);
20603
- const commandContext = useMemo33(
21253
+ const [confirmationRequest, setConfirmationRequest] = useState42(null);
21254
+ const commandContext = useMemo34(
20604
21255
  () => ({
20605
21256
  services: {
20606
21257
  modelSelection,
20607
21258
  providerSetup,
20608
21259
  permissionSelection,
20609
21260
  sessionManagement,
20610
- toolCatalog
21261
+ toolCatalog,
21262
+ sideConversation,
21263
+ subagentCatalog
20611
21264
  },
20612
21265
  ui: {
20613
21266
  addItem,
@@ -20636,6 +21289,8 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
20636
21289
  permissionSelection,
20637
21290
  sessionManagement,
20638
21291
  toolCatalog,
21292
+ sideConversation,
21293
+ subagentCatalog,
20639
21294
  loadHistory,
20640
21295
  addItem,
20641
21296
  clearItems,
@@ -20646,7 +21301,7 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
20646
21301
  setCustomDialog
20647
21302
  ]
20648
21303
  );
20649
- useEffect43(() => {
21304
+ useEffect44(() => {
20650
21305
  const controller = new AbortController();
20651
21306
  (async () => {
20652
21307
  const loaders = [
@@ -20660,15 +21315,15 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
20660
21315
  controller.abort();
20661
21316
  };
20662
21317
  }, [dshCommands, enableProfiler, reloadTrigger]);
20663
- useEffect43(
21318
+ useEffect44(
20664
21319
  () => dshCommands?.subscribe(reloadCommands),
20665
21320
  [dshCommands, reloadCommands]
20666
21321
  );
20667
- useEffect43(
21322
+ useEffect44(
20668
21323
  () => () => commandAbortRef.current?.abort(),
20669
21324
  []
20670
21325
  );
20671
- const handleSlashCommand = useCallback35(
21326
+ const handleSlashCommand = useCallback36(
20672
21327
  async (rawQuery, overwriteConfirmed, addToHistory = true) => {
20673
21328
  if (!commands) {
20674
21329
  return false;
@@ -20681,14 +21336,14 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
20681
21336
  const commandController = new AbortController();
20682
21337
  commandAbortRef.current?.abort();
20683
21338
  commandAbortRef.current = commandController;
20684
- if (addToHistory) {
21339
+ const { commandToExecute, args } = parseSlashCommand(trimmed, commands);
21340
+ if (addToHistory && commandToExecute?.recordInvocation !== false) {
20685
21341
  const userMessageTimestamp = Date.now();
20686
21342
  addItem(
20687
21343
  { type: "user" /* USER */, text: trimmed },
20688
21344
  userMessageTimestamp
20689
21345
  );
20690
21346
  }
20691
- const { commandToExecute, args } = parseSlashCommand(trimmed, commands);
20692
21347
  try {
20693
21348
  if (commandToExecute) {
20694
21349
  if (commandToExecute.action) {
@@ -20830,16 +21485,16 @@ ${commandToExecute.subCommands.map((sc) => ` - ${sc.name}: ${sc.description ||
20830
21485
  import { useStdout as useStdout4, useStdin as useStdin4 } from "ink";
20831
21486
  import ansiEscapes from "ansi-escapes";
20832
21487
  import * as fs12 from "node:fs";
20833
- import { basename as basename2, join as join5 } from "node:path";
21488
+ import { basename as basename3, join as join5 } from "node:path";
20834
21489
 
20835
21490
  // src/ui/hooks/commands/use-settings-command.ts
20836
- import { useState as useState42, useCallback as useCallback36 } from "react";
21491
+ import { useState as useState43, useCallback as useCallback37 } from "react";
20837
21492
  function useSettingsCommand() {
20838
- const [isSettingsDialogOpen, setIsSettingsDialogOpen] = useState42(false);
20839
- const openSettingsDialog = useCallback36(() => {
21493
+ const [isSettingsDialogOpen, setIsSettingsDialogOpen] = useState43(false);
21494
+ const openSettingsDialog = useCallback37(() => {
20840
21495
  setIsSettingsDialogOpen(true);
20841
21496
  }, []);
20842
- const closeSettingsDialog = useCallback36(() => {
21497
+ const closeSettingsDialog = useCallback37(() => {
20843
21498
  setIsSettingsDialogOpen(false);
20844
21499
  }, []);
20845
21500
  return {
@@ -20850,11 +21505,11 @@ function useSettingsCommand() {
20850
21505
  }
20851
21506
 
20852
21507
  // src/ui/hooks/commands/use-theme-command.ts
20853
- import { useState as useState43, useCallback as useCallback37 } from "react";
21508
+ import { useState as useState44, useCallback as useCallback38 } from "react";
20854
21509
  import process6 from "node:process";
20855
21510
  var useThemeCommand = (loadedSettings, setThemeError, addItem, initialThemeError) => {
20856
- const [isThemeDialogOpen, setIsThemeDialogOpen] = useState43(!!initialThemeError);
20857
- const openThemeDialog = useCallback37(() => {
21511
+ const [isThemeDialogOpen, setIsThemeDialogOpen] = useState44(!!initialThemeError);
21512
+ const openThemeDialog = useCallback38(() => {
20858
21513
  if (process6.env["NO_COLOR"]) {
20859
21514
  addItem(
20860
21515
  {
@@ -20867,7 +21522,7 @@ var useThemeCommand = (loadedSettings, setThemeError, addItem, initialThemeError
20867
21522
  }
20868
21523
  setIsThemeDialogOpen(true);
20869
21524
  }, [addItem]);
20870
- const applyTheme = useCallback37(
21525
+ const applyTheme = useCallback38(
20871
21526
  (themeName) => {
20872
21527
  if (!themeManager.setActiveTheme(themeName)) {
20873
21528
  setIsThemeDialogOpen(true);
@@ -20878,17 +21533,17 @@ var useThemeCommand = (loadedSettings, setThemeError, addItem, initialThemeError
20878
21533
  },
20879
21534
  [setThemeError]
20880
21535
  );
20881
- const handleThemeHighlight = useCallback37(
21536
+ const handleThemeHighlight = useCallback38(
20882
21537
  (themeName) => {
20883
21538
  applyTheme(themeName);
20884
21539
  },
20885
21540
  [applyTheme]
20886
21541
  );
20887
- const closeThemeDialog = useCallback37(() => {
21542
+ const closeThemeDialog = useCallback38(() => {
20888
21543
  applyTheme(loadedSettings.merged.ui.theme);
20889
21544
  setIsThemeDialogOpen(false);
20890
21545
  }, [applyTheme, loadedSettings]);
20891
- const handleThemeSelect = useCallback37(
21546
+ const handleThemeSelect = useCallback38(
20892
21547
  (themeName, scope) => {
20893
21548
  try {
20894
21549
  const mergedCustomThemes = {
@@ -20924,7 +21579,7 @@ var useThemeCommand = (loadedSettings, setThemeError, addItem, initialThemeError
20924
21579
  };
20925
21580
 
20926
21581
  // src/ui/hooks/input/use-vim.ts
20927
- import { useCallback as useCallback38, useReducer as useReducer5, useEffect as useEffect44, useRef as useRef22 } from "react";
21582
+ import { useCallback as useCallback39, useReducer as useReducer5, useEffect as useEffect45, useRef as useRef23 } from "react";
20928
21583
  var DIGIT_MULTIPLIER = 10;
20929
21584
  var DEFAULT_COUNT = 1;
20930
21585
  var DIGIT_1_TO_9 = /^[1-9]$/;
@@ -20989,22 +21644,22 @@ var vimReducer = (state, action) => {
20989
21644
  function useVim(buffer, onSubmit) {
20990
21645
  const { vimEnabled, vimMode, setVimMode } = useVimMode();
20991
21646
  const [state, dispatch] = useReducer5(vimReducer, initialVimState);
20992
- const lastEscapeTimestampRef = useRef22(0);
20993
- useEffect44(() => {
21647
+ const lastEscapeTimestampRef = useRef23(0);
21648
+ useEffect45(() => {
20994
21649
  dispatch({ type: "SET_MODE", mode: vimMode });
20995
21650
  }, [vimMode]);
20996
- const updateMode = useCallback38(
21651
+ const updateMode = useCallback39(
20997
21652
  (mode) => {
20998
21653
  setVimMode(mode);
20999
21654
  dispatch({ type: "SET_MODE", mode });
21000
21655
  },
21001
21656
  [setVimMode]
21002
21657
  );
21003
- const getCurrentCount = useCallback38(
21658
+ const getCurrentCount = useCallback39(
21004
21659
  () => state.count || DEFAULT_COUNT,
21005
21660
  [state.count]
21006
21661
  );
21007
- const checkDoubleEscape = useCallback38(() => {
21662
+ const checkDoubleEscape = useCallback39(() => {
21008
21663
  const now = Date.now();
21009
21664
  const lastEscape = lastEscapeTimestampRef.current;
21010
21665
  lastEscapeTimestampRef.current = now;
@@ -21014,7 +21669,7 @@ function useVim(buffer, onSubmit) {
21014
21669
  }
21015
21670
  return false;
21016
21671
  }, []);
21017
- const executeCommand = useCallback38(
21672
+ const executeCommand = useCallback39(
21018
21673
  (cmdType, count) => {
21019
21674
  switch (cmdType) {
21020
21675
  case CMD_TYPES.DELETE_WORD_FORWARD: {
@@ -21090,7 +21745,7 @@ function useVim(buffer, onSubmit) {
21090
21745
  },
21091
21746
  [buffer, updateMode]
21092
21747
  );
21093
- const handleInsertModeInput = useCallback38(
21748
+ const handleInsertModeInput = useCallback39(
21094
21749
  (normalizedKey) => {
21095
21750
  if (keyMatchers["basic.cancel" /* ESCAPE */](normalizedKey)) {
21096
21751
  checkDoubleEscape();
@@ -21122,7 +21777,7 @@ function useVim(buffer, onSubmit) {
21122
21777
  },
21123
21778
  [buffer, dispatch, updateMode, onSubmit, checkDoubleEscape]
21124
21779
  );
21125
- const normalizeKey = useCallback38(
21780
+ const normalizeKey = useCallback39(
21126
21781
  (key) => ({
21127
21782
  name: key.name || "",
21128
21783
  sequence: key.sequence || "",
@@ -21134,7 +21789,7 @@ function useVim(buffer, onSubmit) {
21134
21789
  }),
21135
21790
  []
21136
21791
  );
21137
- const handleChangeMovement = useCallback38(
21792
+ const handleChangeMovement = useCallback39(
21138
21793
  (movement) => {
21139
21794
  const count = getCurrentCount();
21140
21795
  dispatch({ type: "CLEAR_COUNT" });
@@ -21155,7 +21810,7 @@ function useVim(buffer, onSubmit) {
21155
21810
  },
21156
21811
  [getCurrentCount, dispatch, buffer, updateMode]
21157
21812
  );
21158
- const handleOperatorMotion = useCallback38(
21813
+ const handleOperatorMotion = useCallback39(
21159
21814
  (operator, motion) => {
21160
21815
  const count = getCurrentCount();
21161
21816
  const commandMap = {
@@ -21182,7 +21837,7 @@ function useVim(buffer, onSubmit) {
21182
21837
  },
21183
21838
  [getCurrentCount, executeCommand, dispatch]
21184
21839
  );
21185
- const handleInput = useCallback38(
21840
+ const handleInput = useCallback39(
21186
21841
  (key) => {
21187
21842
  if (!vimEnabled) {
21188
21843
  return false;
@@ -21489,13 +22144,13 @@ function useVim(buffer, onSubmit) {
21489
22144
  }
21490
22145
 
21491
22146
  // src/ui/hooks/session/use-git-branch-name.ts
21492
- import { useState as useState44, useEffect as useEffect45, useCallback as useCallback39 } from "react";
22147
+ import { useState as useState45, useEffect as useEffect46, useCallback as useCallback40 } from "react";
21493
22148
  import fs9 from "node:fs";
21494
22149
  import fsPromises2 from "node:fs/promises";
21495
22150
  import path11 from "node:path";
21496
22151
  function useGitBranchName(cwd) {
21497
- const [branchName, setBranchName] = useState44(void 0);
21498
- const fetchBranchName = useCallback39(async () => {
22152
+ const [branchName, setBranchName] = useState45(void 0);
22153
+ const fetchBranchName = useCallback40(async () => {
21499
22154
  try {
21500
22155
  const { stdout } = await spawnAsync(
21501
22156
  "git",
@@ -21517,15 +22172,15 @@ function useGitBranchName(cwd) {
21517
22172
  setBranchName(void 0);
21518
22173
  }
21519
22174
  }, [cwd, setBranchName]);
21520
- useEffect45(() => {
22175
+ useEffect46(() => {
21521
22176
  fetchBranchName();
21522
22177
  const gitLogsHeadPath = path11.join(cwd, ".git", "logs", "HEAD");
21523
22178
  let watcher;
21524
- let cancelled = false;
22179
+ let cancelled2 = false;
21525
22180
  const setupWatcher = async () => {
21526
22181
  try {
21527
22182
  await fsPromises2.access(gitLogsHeadPath, fs9.constants.F_OK);
21528
- if (cancelled) return;
22183
+ if (cancelled2) return;
21529
22184
  watcher = fs9.watch(gitLogsHeadPath, (eventType) => {
21530
22185
  if (eventType === "change" || eventType === "rename") {
21531
22186
  fetchBranchName();
@@ -21536,7 +22191,7 @@ function useGitBranchName(cwd) {
21536
22191
  };
21537
22192
  setupWatcher();
21538
22193
  return () => {
21539
- cancelled = true;
22194
+ cancelled2 = true;
21540
22195
  watcher?.close();
21541
22196
  };
21542
22197
  }, [cwd, fetchBranchName]);
@@ -21544,7 +22199,7 @@ function useGitBranchName(cwd) {
21544
22199
  }
21545
22200
 
21546
22201
  // src/ui/hooks/settings/use-editor-settings.ts
21547
- import { useState as useState45, useCallback as useCallback40 } from "react";
22202
+ import { useState as useState46, useCallback as useCallback41 } from "react";
21548
22203
 
21549
22204
  // src/config/setting-paths.ts
21550
22205
  var SettingPaths = {
@@ -21555,11 +22210,11 @@ var SettingPaths = {
21555
22210
 
21556
22211
  // src/ui/hooks/settings/use-editor-settings.ts
21557
22212
  var useEditorSettings = (loadedSettings, setEditorError, addItem) => {
21558
- const [isEditorDialogOpen, setIsEditorDialogOpen] = useState45(false);
21559
- const openEditorDialog = useCallback40(() => {
22213
+ const [isEditorDialogOpen, setIsEditorDialogOpen] = useState46(false);
22214
+ const openEditorDialog = useCallback41(() => {
21560
22215
  setIsEditorDialogOpen(true);
21561
22216
  }, []);
21562
- const handleEditorSelect = useCallback40(
22217
+ const handleEditorSelect = useCallback41(
21563
22218
  (editorType, scope) => {
21564
22219
  if (editorType && !checkHasEditorType(editorType)) {
21565
22220
  return;
@@ -21585,7 +22240,7 @@ var useEditorSettings = (loadedSettings, setEditorError, addItem) => {
21585
22240
  },
21586
22241
  [loadedSettings, setEditorError, addItem]
21587
22242
  );
21588
- const exitEditorDialog = useCallback40(() => {
22243
+ const exitEditorDialog = useCallback41(() => {
21589
22244
  setIsEditorDialogOpen(false);
21590
22245
  }, []);
21591
22246
  return {
@@ -21597,12 +22252,12 @@ var useEditorSettings = (loadedSettings, setEditorError, addItem) => {
21597
22252
  };
21598
22253
 
21599
22254
  // src/ui/hooks/terminal/use-memory-monitor.ts
21600
- import { useEffect as useEffect46 } from "react";
22255
+ import { useEffect as useEffect47 } from "react";
21601
22256
  import process7 from "node:process";
21602
22257
  var MEMORY_WARNING_THRESHOLD = 7 * 1024 * 1024 * 1024;
21603
22258
  var MEMORY_CHECK_INTERVAL = 60 * 1e3;
21604
22259
  var useMemoryMonitor = ({ addItem }) => {
21605
- useEffect46(() => {
22260
+ useEffect47(() => {
21606
22261
  const intervalId = setInterval(() => {
21607
22262
  const usage = process7.memoryUsage().rss;
21608
22263
  if (usage > MEMORY_WARNING_THRESHOLD) {
@@ -21622,10 +22277,10 @@ var useMemoryMonitor = ({ addItem }) => {
21622
22277
 
21623
22278
  // src/ui/hooks/visual/use-console-messages.ts
21624
22279
  import {
21625
- useCallback as useCallback41,
21626
- useEffect as useEffect47,
22280
+ useCallback as useCallback42,
22281
+ useEffect as useEffect48,
21627
22282
  useReducer as useReducer6,
21628
- useRef as useRef23,
22283
+ useRef as useRef24,
21629
22284
  useTransition
21630
22285
  } from "react";
21631
22286
  function consoleMessagesReducer(state, action) {
@@ -21653,10 +22308,10 @@ function consoleMessagesReducer(state, action) {
21653
22308
  }
21654
22309
  function useConsoleMessages() {
21655
22310
  const [consoleMessages, dispatch] = useReducer6(consoleMessagesReducer, []);
21656
- const messageQueueRef = useRef23([]);
21657
- const timeoutRef = useRef23(null);
22311
+ const messageQueueRef = useRef24([]);
22312
+ const timeoutRef = useRef24(null);
21658
22313
  const [, startTransition] = useTransition();
21659
- const processQueue = useCallback41(() => {
22314
+ const processQueue = useCallback42(() => {
21660
22315
  if (messageQueueRef.current.length > 0) {
21661
22316
  const messagesToProcess = messageQueueRef.current;
21662
22317
  messageQueueRef.current = [];
@@ -21666,7 +22321,7 @@ function useConsoleMessages() {
21666
22321
  }
21667
22322
  timeoutRef.current = null;
21668
22323
  }, []);
21669
- const handleNewMessage = useCallback41(
22324
+ const handleNewMessage = useCallback42(
21670
22325
  (message) => {
21671
22326
  messageQueueRef.current.push(message);
21672
22327
  if (!timeoutRef.current) {
@@ -21675,7 +22330,7 @@ function useConsoleMessages() {
21675
22330
  },
21676
22331
  [processQueue]
21677
22332
  );
21678
- useEffect47(() => {
22333
+ useEffect48(() => {
21679
22334
  const handleConsoleLog = (payload) => {
21680
22335
  handleNewMessage({
21681
22336
  type: payload.type,
@@ -21694,7 +22349,7 @@ function useConsoleMessages() {
21694
22349
  coreEvents.off(CoreEvent.Output, handleOutput);
21695
22350
  };
21696
22351
  }, [handleNewMessage]);
21697
- const clearConsoleMessages = useCallback41(() => {
22352
+ const clearConsoleMessages = useCallback42(() => {
21698
22353
  if (timeoutRef.current) {
21699
22354
  clearTimeout(timeoutRef.current);
21700
22355
  timeoutRef.current = null;
@@ -21704,7 +22359,7 @@ function useConsoleMessages() {
21704
22359
  dispatch({ type: "CLEAR" });
21705
22360
  });
21706
22361
  }, []);
21707
- useEffect47(
22362
+ useEffect48(
21708
22363
  () => () => {
21709
22364
  if (timeoutRef.current) {
21710
22365
  clearTimeout(timeoutRef.current);
@@ -21716,13 +22371,13 @@ function useConsoleMessages() {
21716
22371
  }
21717
22372
 
21718
22373
  // src/ui/hooks/visual/use-timer.ts
21719
- import { useState as useState46, useEffect as useEffect48, useRef as useRef24 } from "react";
22374
+ import { useState as useState47, useEffect as useEffect49, useRef as useRef25 } from "react";
21720
22375
  var useTimer = (isActive, resetKey) => {
21721
- const [elapsedTime, setElapsedTime] = useState46(0);
21722
- const timerRef = useRef24(null);
21723
- const prevResetKeyRef = useRef24(resetKey);
21724
- const prevIsActiveRef = useRef24(isActive);
21725
- useEffect48(() => {
22376
+ const [elapsedTime, setElapsedTime] = useState47(0);
22377
+ const timerRef = useRef25(null);
22378
+ const prevResetKeyRef = useRef25(resetKey);
22379
+ const prevIsActiveRef = useRef25(isActive);
22380
+ useEffect49(() => {
21726
22381
  let shouldResetTime = false;
21727
22382
  if (prevResetKeyRef.current !== resetKey) {
21728
22383
  shouldResetTime = true;
@@ -21759,7 +22414,7 @@ var useTimer = (isActive, resetKey) => {
21759
22414
  };
21760
22415
 
21761
22416
  // src/ui/hooks/visual/use-phrase-cycler.ts
21762
- import { useState as useState47, useEffect as useEffect49, useRef as useRef25 } from "react";
22417
+ import { useState as useState48, useEffect as useEffect50, useRef as useRef26 } from "react";
21763
22418
 
21764
22419
  // src/ui/components/indicators/loading-phrases.ts
21765
22420
  var WITTY_LOADING_PHRASES = [
@@ -21902,12 +22557,12 @@ var PHRASE_CHANGE_INTERVAL_MS = 15e3;
21902
22557
  var INTERACTIVE_SHELL_WAITING_PHRASE = "Interactive shell awaiting input... press tab to focus shell";
21903
22558
  var usePhraseCycler = (isActive, shouldShowFocusHint, customPhrases) => {
21904
22559
  const loadingPhrases = customPhrases && customPhrases.length > 0 ? customPhrases : WITTY_LOADING_PHRASES;
21905
- const [currentLoadingPhrase, setCurrentLoadingPhrase] = useState47(
22560
+ const [currentLoadingPhrase, setCurrentLoadingPhrase] = useState48(
21906
22561
  loadingPhrases[0]
21907
22562
  );
21908
- const phraseIntervalRef = useRef25(null);
21909
- const hasShownFirstRequestTipRef = useRef25(false);
21910
- useEffect49(() => {
22563
+ const phraseIntervalRef = useRef26(null);
22564
+ const hasShownFirstRequestTipRef = useRef26(false);
22565
+ useEffect50(() => {
21911
22566
  if (phraseIntervalRef.current) {
21912
22567
  clearInterval(phraseIntervalRef.current);
21913
22568
  phraseIntervalRef.current = null;
@@ -21952,13 +22607,13 @@ var usePhraseCycler = (isActive, shouldShowFocusHint, customPhrases) => {
21952
22607
  };
21953
22608
 
21954
22609
  // src/ui/hooks/visual/use-loading-indicator.ts
21955
- import { useState as useState48, useEffect as useEffect50, useRef as useRef26 } from "react";
22610
+ import { useState as useState49, useEffect as useEffect51, useRef as useRef27 } from "react";
21956
22611
  var useLoadingIndicator = ({
21957
22612
  streamingState,
21958
22613
  shouldShowFocusHint,
21959
22614
  customWittyPhrases
21960
22615
  }) => {
21961
- const [timerResetKey, setTimerResetKey] = useState48(0);
22616
+ const [timerResetKey, setTimerResetKey] = useState49(0);
21962
22617
  const isTimerActive = streamingState === "responding" /* Responding */;
21963
22618
  const elapsedTimeFromTimer = useTimer(isTimerActive, timerResetKey);
21964
22619
  const isPhraseCyclingActive = streamingState === "responding" /* Responding */;
@@ -21967,8 +22622,8 @@ var useLoadingIndicator = ({
21967
22622
  shouldShowFocusHint,
21968
22623
  customWittyPhrases
21969
22624
  );
21970
- const prevStreamingStateRef = useRef26(null);
21971
- useEffect50(() => {
22625
+ const prevStreamingStateRef = useRef27(null);
22626
+ useEffect51(() => {
21972
22627
  if (streamingState === "idle" /* Idle */ && prevStreamingStateRef.current === "responding" /* Responding */) {
21973
22628
  setTimerResetKey((prevKey) => prevKey + 1);
21974
22629
  }
@@ -21981,40 +22636,54 @@ var useLoadingIndicator = ({
21981
22636
  };
21982
22637
 
21983
22638
  // src/ui/hooks/session/use-message-queue.ts
21984
- import { useCallback as useCallback42, useEffect as useEffect51, useState as useState49 } from "react";
22639
+ import { useCallback as useCallback43, useEffect as useEffect52, useMemo as useMemo35, useState as useState50 } from "react";
21985
22640
  function useMessageQueue({
22641
+ queueKey,
21986
22642
  streamingState,
21987
22643
  submitQuery
21988
22644
  }) {
21989
- const [messageQueue, setMessageQueue] = useState49([]);
21990
- const addMessage = useCallback42((message) => {
22645
+ const [queuedMessages, setQueuedMessages] = useState50([]);
22646
+ const messageQueue = useMemo35(
22647
+ () => queuedMessages.filter((entry) => entry.key === queueKey).map((entry) => entry.message),
22648
+ [queueKey, queuedMessages]
22649
+ );
22650
+ const addMessage = useCallback43((message) => {
21991
22651
  const trimmedMessage = message.trim();
21992
22652
  if (trimmedMessage.length > 0) {
21993
- setMessageQueue((prev) => [...prev, trimmedMessage]);
22653
+ setQueuedMessages((previous) => [
22654
+ ...previous,
22655
+ { key: queueKey, message: trimmedMessage }
22656
+ ]);
21994
22657
  }
21995
- }, []);
21996
- const clearQueue = useCallback42(() => {
21997
- setMessageQueue([]);
21998
- }, []);
21999
- const getQueuedMessagesText = useCallback42(() => {
22658
+ }, [queueKey]);
22659
+ const clearQueue = useCallback43(() => {
22660
+ setQueuedMessages(
22661
+ (previous) => previous.filter((entry) => entry.key !== queueKey)
22662
+ );
22663
+ }, [queueKey]);
22664
+ const getQueuedMessagesText = useCallback43(() => {
22000
22665
  if (messageQueue.length === 0) return "";
22001
22666
  return messageQueue.join("\n\n");
22002
22667
  }, [messageQueue]);
22003
- const popAllMessages = useCallback42(() => {
22668
+ const popAllMessages = useCallback43(() => {
22004
22669
  if (messageQueue.length === 0) {
22005
22670
  return void 0;
22006
22671
  }
22007
22672
  const allMessages = messageQueue.join("\n\n");
22008
- setMessageQueue([]);
22673
+ setQueuedMessages(
22674
+ (previous) => previous.filter((entry) => entry.key !== queueKey)
22675
+ );
22009
22676
  return allMessages;
22010
- }, [messageQueue]);
22011
- useEffect51(() => {
22677
+ }, [messageQueue, queueKey]);
22678
+ useEffect52(() => {
22012
22679
  if (streamingState === "idle" /* Idle */ && messageQueue.length > 0) {
22013
22680
  const combinedMessage = messageQueue.join("\n\n");
22014
- setMessageQueue([]);
22681
+ setQueuedMessages(
22682
+ (previous) => previous.filter((entry) => entry.key !== queueKey)
22683
+ );
22015
22684
  submitQuery(combinedMessage);
22016
22685
  }
22017
- }, [streamingState, messageQueue, submitQuery]);
22686
+ }, [streamingState, messageQueue, queueKey, submitQuery]);
22018
22687
  return {
22019
22688
  messageQueue,
22020
22689
  addMessage,
@@ -22025,16 +22694,16 @@ function useMessageQueue({
22025
22694
  }
22026
22695
 
22027
22696
  // src/ui/hooks/input/use-input-history-store.ts
22028
- import { useCallback as useCallback43, useRef as useRef27, useState as useState50 } from "react";
22697
+ import { useCallback as useCallback44, useRef as useRef28, useState as useState51 } from "react";
22029
22698
  function deduplicateConsecutive(messages) {
22030
22699
  return messages.filter(
22031
22700
  (message, index) => index === 0 || message !== messages[index - 1]
22032
22701
  );
22033
22702
  }
22034
22703
  function useInputHistoryStore() {
22035
- const [inputHistory, setInputHistory] = useState50([]);
22036
- const initializationStarted = useRef27(false);
22037
- const initializeFromHistory = useCallback43(
22704
+ const [inputHistory, setInputHistory] = useState51([]);
22705
+ const initializationStarted = useRef28(false);
22706
+ const initializeFromHistory = useCallback44(
22038
22707
  async (history) => {
22039
22708
  if (initializationStarted.current) return;
22040
22709
  initializationStarted.current = true;
@@ -22055,7 +22724,7 @@ function useInputHistoryStore() {
22055
22724
  },
22056
22725
  []
22057
22726
  );
22058
- const addInput = useCallback43(
22727
+ const addInput = useCallback44(
22059
22728
  (input) => {
22060
22729
  const trimmedInput = input.trim();
22061
22730
  if (!trimmedInput) return;
@@ -22155,12 +22824,12 @@ var PromptHistoryStore = class {
22155
22824
  };
22156
22825
 
22157
22826
  // src/ui/hooks/ai/use-turn-activity-monitor.ts
22158
- import { useState as useState51, useEffect as useEffect52, useRef as useRef28 } from "react";
22827
+ import { useState as useState52, useEffect as useEffect53, useRef as useRef29 } from "react";
22159
22828
  var useTurnActivityMonitor = (streamingState, activePtyId) => {
22160
- const [operationStartTime, setOperationStartTime] = useState51(0);
22161
- const prevPtyIdRef = useRef28(void 0);
22162
- const prevStreamingStateRef = useRef28(void 0);
22163
- useEffect52(() => {
22829
+ const [operationStartTime, setOperationStartTime] = useState52(0);
22830
+ const prevPtyIdRef = useRef29(void 0);
22831
+ const prevStreamingStateRef = useRef29(void 0);
22832
+ useEffect53(() => {
22164
22833
  const isNowResponding = streamingState === "responding" /* Responding */;
22165
22834
  const wasResponding = prevStreamingStateRef.current === "responding" /* Responding */;
22166
22835
  const ptyChanged = activePtyId !== prevPtyIdRef.current;
@@ -22219,7 +22888,7 @@ var useShellInactivityStatus = ({
22219
22888
  };
22220
22889
 
22221
22890
  // src/ui/hooks/input/use-local-shell-command.ts
22222
- import { useCallback as useCallback44, useEffect as useEffect53, useRef as useRef29, useState as useState52 } from "react";
22891
+ import { useCallback as useCallback45, useEffect as useEffect54, useRef as useRef30, useState as useState53 } from "react";
22223
22892
  import crypto2 from "node:crypto";
22224
22893
  import fs11 from "node:fs";
22225
22894
  import os3 from "node:os";
@@ -22236,20 +22905,20 @@ function useLocalShellCommand({
22236
22905
  terminalWidth,
22237
22906
  terminalHeight
22238
22907
  }) {
22239
- const controllerRef = useRef29(void 0);
22240
- const mountedRef = useRef29(true);
22241
- const [isExecuting, setIsExecuting] = useState52(false);
22242
- const [activePtyId, setActivePtyId] = useState52(void 0);
22243
- const [lastOutputTime, setLastOutputTime] = useState52(0);
22244
- const cancel = useCallback44(() => controllerRef.current?.abort(), []);
22245
- useEffect53(() => {
22908
+ const controllerRef = useRef30(void 0);
22909
+ const mountedRef = useRef30(true);
22910
+ const [isExecuting, setIsExecuting] = useState53(false);
22911
+ const [activePtyId, setActivePtyId] = useState53(void 0);
22912
+ const [lastOutputTime, setLastOutputTime] = useState53(0);
22913
+ const cancel = useCallback45(() => controllerRef.current?.abort(), []);
22914
+ useEffect54(() => {
22246
22915
  mountedRef.current = true;
22247
22916
  return () => {
22248
22917
  mountedRef.current = false;
22249
22918
  controllerRef.current?.abort();
22250
22919
  };
22251
22920
  }, []);
22252
- const execute = useCallback44(
22921
+ const execute = useCallback45(
22253
22922
  (rawCommand) => {
22254
22923
  const command = rawCommand.trim();
22255
22924
  if (command.length === 0 || controllerRef.current !== void 0) {
@@ -22446,12 +23115,25 @@ ${output}`;
22446
23115
  }
22447
23116
 
22448
23117
  // src/ui/app-container.tsx
22449
- import { jsx as jsx95 } from "react/jsx-runtime";
23118
+ import { jsx as jsx96 } from "react/jsx-runtime";
22450
23119
  var SHELL_WIDTH_FRACTION = 0.89;
22451
23120
  var SHELL_HEIGHT_PADDING = 10;
22452
23121
  var noopExternalStoreSubscribe = () => () => {
22453
23122
  };
22454
23123
  var emptyProviderSetupSnapshot = () => void 0;
23124
+ var EMPTY_SIDE_CONVERSATION_SNAPSHOT = {
23125
+ activeSurface: "main",
23126
+ mainBusy: false,
23127
+ sideBusy: false
23128
+ };
23129
+ var emptySideConversationSnapshot = () => EMPTY_SIDE_CONVERSATION_SNAPSHOT;
23130
+ var EMPTY_SUBAGENT_CATALOG_SNAPSHOT = {
23131
+ rootSessionId: "",
23132
+ status: "idle",
23133
+ items: [],
23134
+ runningCount: 0
23135
+ };
23136
+ var emptySubagentCatalogSnapshot = () => EMPTY_SUBAGENT_CATALOG_SNAPSHOT;
22455
23137
  var AppContainer = (props) => {
22456
23138
  const {
22457
23139
  config,
@@ -22466,38 +23148,50 @@ var AppContainer = (props) => {
22466
23148
  userQuestionRuntime,
22467
23149
  commandRuntime,
22468
23150
  permissionSelectionRuntime,
22469
- toolCatalogRuntime
23151
+ toolCatalogRuntime,
23152
+ sideConversationRuntime,
23153
+ subagentCatalogRuntime
22470
23154
  } = props;
22471
23155
  const historyManager = useHistory();
22472
- const conversationSnapshot = useSyncExternalStore5(
23156
+ const conversationSnapshot = useSyncExternalStore6(
22473
23157
  conversationRuntime.subscribe,
22474
23158
  conversationRuntime.getSnapshot,
22475
23159
  conversationRuntime.getSnapshot
22476
23160
  );
22477
- const approvalSnapshot = useSyncExternalStore5(
23161
+ const sideConversationSnapshot = useSyncExternalStore6(
23162
+ sideConversationRuntime?.subscribeWorkspace ?? noopExternalStoreSubscribe,
23163
+ sideConversationRuntime?.getWorkspaceSnapshot ?? emptySideConversationSnapshot,
23164
+ sideConversationRuntime?.getWorkspaceSnapshot ?? emptySideConversationSnapshot
23165
+ );
23166
+ const subagentCatalogSnapshot = useSyncExternalStore6(
23167
+ subagentCatalogRuntime?.subscribe ?? noopExternalStoreSubscribe,
23168
+ subagentCatalogRuntime?.getSnapshot ?? emptySubagentCatalogSnapshot,
23169
+ subagentCatalogRuntime?.getSnapshot ?? emptySubagentCatalogSnapshot
23170
+ );
23171
+ const approvalSnapshot = useSyncExternalStore6(
22478
23172
  approvalRuntime.subscribe,
22479
23173
  approvalRuntime.getSnapshot,
22480
23174
  approvalRuntime.getSnapshot
22481
23175
  );
22482
23176
  const pendingApproval = approvalSnapshot.pending[0];
22483
- const userQuestionSnapshot = useSyncExternalStore5(
23177
+ const userQuestionSnapshot = useSyncExternalStore6(
22484
23178
  userQuestionRuntime.subscribe,
22485
23179
  userQuestionRuntime.getSnapshot,
22486
23180
  userQuestionRuntime.getSnapshot
22487
23181
  );
22488
23182
  const pendingUserQuestion = userQuestionSnapshot.pending[0];
22489
- const conversationHistoryIds = useRef30(/* @__PURE__ */ new Map());
22490
- const conversationHistoryTexts = useRef30(/* @__PURE__ */ new Map());
23183
+ const conversationHistoryIds = useRef31(/* @__PURE__ */ new Map());
23184
+ const conversationHistoryTexts = useRef31(/* @__PURE__ */ new Map());
22491
23185
  const conversationSessionId = conversationRuntime.getSessionStats().sessionId;
22492
- const [projectedSessionId, setProjectedSessionId] = useState53(
23186
+ const [projectedSessionId, setProjectedSessionId] = useState54(
22493
23187
  conversationSessionId
22494
23188
  );
22495
- const promptInputAbortRef = useRef30(void 0);
22496
- const [promptInputPreparing, setPromptInputPreparing] = useState53(false);
23189
+ const promptInputAbortRef = useRef31(void 0);
23190
+ const [promptInputPreparing, setPromptInputPreparing] = useState54(false);
22497
23191
  const addConversationHistoryItem = historyManager.addItem;
22498
23192
  const updateConversationHistoryItem = historyManager.updateItem;
22499
23193
  const clearConversationHistory = historyManager.clearItems;
22500
- useEffect54(() => {
23194
+ useEffect55(() => {
22501
23195
  if (projectedSessionId !== conversationSessionId) {
22502
23196
  conversationHistoryIds.current.clear();
22503
23197
  conversationHistoryTexts.current.clear();
@@ -22508,57 +23202,17 @@ var AppContainer = (props) => {
22508
23202
  const visibleHistoryIds = new Set(
22509
23203
  historyManager.history.map((item) => item.id)
22510
23204
  );
22511
- const projectedToolCallIds = new Set(
22512
- conversationSnapshot.messages.flatMap(
22513
- (message) => message.role === "tool" ? [message.callId] : []
22514
- )
23205
+ const visibleToolCallIds = projectedToolCallIds(
23206
+ conversationSnapshot.messages
22515
23207
  );
22516
23208
  for (const message of conversationSnapshot.messages) {
22517
23209
  const historyId = conversationHistoryIds.current.get(message.id);
22518
- const assistantContent = message.role === "assistant" ? message.content.filter(
22519
- (block) => block.type !== "tool-call" || !projectedToolCallIds.has(block.id)
22520
- ) : void 0;
22521
- if (message.role === "assistant" && assistantContent?.length === 0 && message.interrupted !== true) {
22522
- continue;
22523
- }
22524
- const messageText = message.role === "tool" ? void 0 : conversationMessageText(message);
22525
- const item = message.role === "tool" ? {
22526
- type: "tool_group",
22527
- tools: [
22528
- {
22529
- callId: message.callId,
22530
- name: message.presentation?.kind === "card" ? message.presentation.title ?? message.name : message.name,
22531
- description: message.presentation?.kind === "compact" ? "" : message.presentation?.description ?? message.arguments,
22532
- resultDisplay: message.presentation?.kind === "compact" ? void 0 : message.presentation?.resultDisplay ?? (message.result === void 0 ? void 0 : {
22533
- type: "dsh-content",
22534
- content: message.result.content,
22535
- ...message.result.error === void 0 ? {} : { error: message.result.error }
22536
- }),
22537
- ...message.presentation?.kind === "compact" ? {
22538
- presentation: {
22539
- kind: "compact",
22540
- label: message.presentation.label
22541
- }
22542
- } : {},
22543
- status: message.status === "executing" ? "Executing" /* Executing */ : message.status === "success" ? "Success" /* Success */ : "Error" /* Error */
22544
- }
22545
- ]
22546
- } : message.role === "assistant" ? {
22547
- type: "dsh_assistant",
22548
- content: assistantContent ?? message.content,
22549
- interrupted: message.interrupted === true
22550
- } : message.role === "user" ? {
22551
- type: "dsh_user",
22552
- content: message.displayContent ?? message.content
22553
- } : {
22554
- type: message.status === "cancelled" ? "warning" /* WARNING */ : "error" /* ERROR */,
22555
- text: messageText ?? ""
22556
- };
22557
- const fingerprint = message.role === "tool" ? JSON.stringify([
22558
- message.status,
22559
- message.result,
22560
- message.presentation
22561
- ]) : message.role === "assistant" ? JSON.stringify([assistantContent, message.interrupted]) : message.role === "user" ? JSON.stringify(message.displayContent ?? message.content) : messageText ?? "";
23210
+ const item = conversationMessageToHistoryItem(
23211
+ message,
23212
+ visibleToolCallIds
23213
+ );
23214
+ if (item === void 0) continue;
23215
+ const fingerprint = conversationMessageFingerprint(message, item);
22562
23216
  if (historyId === void 0 || !visibleHistoryIds.has(historyId)) {
22563
23217
  const nextHistoryId = addConversationHistoryItem(item);
22564
23218
  conversationHistoryIds.current.set(message.id, nextHistoryId);
@@ -22582,49 +23236,49 @@ var AppContainer = (props) => {
22582
23236
  useMemoryMonitor(historyManager);
22583
23237
  const settings = useSettings();
22584
23238
  const isAlternateBuffer = useAlternateBuffer();
22585
- const [debugMessage, setDebugMessage] = useState53("");
22586
- const [quittingMessages, setQuittingMessages] = useState53(null);
22587
- const [themeError, setThemeError] = useState53(
23239
+ const [debugMessage, setDebugMessage] = useState54("");
23240
+ const [quittingMessages, setQuittingMessages] = useState54(null);
23241
+ const [themeError, setThemeError] = useState54(
22588
23242
  initializationResult.themeError
22589
23243
  );
22590
- const [isProcessing, setIsProcessing] = useState53(false);
22591
- const [embeddedShellFocused, setEmbeddedShellFocused] = useState53(false);
23244
+ const [isProcessing, setIsProcessing] = useState54(false);
23245
+ const [embeddedShellFocused, setEmbeddedShellFocused] = useState54(false);
22592
23246
  const enableProfiler = config.getDebugMode() || process8.env["NODE_ENV"] === "development";
22593
- const [showDebugProfiler, setShowDebugProfiler] = useState53(enableProfiler);
22594
- const [customDialog, setCustomDialog] = useState53(
23247
+ const [showDebugProfiler, setShowDebugProfiler] = useState54(enableProfiler);
23248
+ const [customDialog, setCustomDialog] = useState54(
22595
23249
  null
22596
23250
  );
22597
- const [copyModeEnabled, setCopyModeEnabled] = useState53(false);
22598
- const [pendingRestorePrompt, setPendingRestorePrompt] = useState53(false);
22599
- const [shellModeActive, setShellModeActive] = useState53(false);
22600
- const [pendingShellHistoryItem, setPendingShellHistoryItem] = useState53(null);
22601
- const [historyRemountKey, setHistoryRemountKey] = useState53(0);
22602
- const [settingsNonce, setSettingsNonce] = useState53(0);
22603
- const [queueErrorMessage, setQueueErrorMessage] = useState53(
23251
+ const [copyModeEnabled, setCopyModeEnabled] = useState54(false);
23252
+ const [pendingRestorePrompt, setPendingRestorePrompt] = useState54(false);
23253
+ const [shellModeActive, setShellModeActive] = useState54(false);
23254
+ const [pendingShellHistoryItem, setPendingShellHistoryItem] = useState54(null);
23255
+ const [historyRemountKey, setHistoryRemountKey] = useState54(0);
23256
+ const [settingsNonce, setSettingsNonce] = useState54(0);
23257
+ const [queueErrorMessage, setQueueErrorMessage] = useState54(
22604
23258
  null
22605
23259
  );
22606
- const toggleDebugProfiler = useCallback45(
23260
+ const toggleDebugProfiler = useCallback46(
22607
23261
  () => setShowDebugProfiler((visible) => !visible),
22608
23262
  []
22609
23263
  );
22610
- const [modelSelectionSnapshot, setModelSelectionSnapshot] = useState53(
23264
+ const [modelSelectionSnapshot, setModelSelectionSnapshot] = useState54(
22611
23265
  () => modelSelectionRuntime?.getSnapshot()
22612
23266
  );
22613
- useEffect54(
23267
+ useEffect55(
22614
23268
  () => modelSelectionRuntime?.subscribe(
22615
23269
  () => setModelSelectionSnapshot(modelSelectionRuntime.getSnapshot())
22616
23270
  ),
22617
23271
  [modelSelectionRuntime]
22618
23272
  );
22619
- const currentModel = modelSelectionSnapshot ? modelSelectionLabel(modelSelectionSnapshot.current) : "DSH default";
22620
- const currentReasoningEffort = modelSelectionSnapshot ? modelReasoningEffortLabel(modelSelectionSnapshot.current) : void 0;
22621
- const providerSetupSnapshot = useSyncExternalStore5(
23273
+ const currentModel = sideConversationSnapshot.activeSurface === "side" && sideConversationSnapshot.sideModelLabel ? sideConversationSnapshot.sideModelLabel : modelSelectionSnapshot ? modelSelectionLabel(modelSelectionSnapshot.current) : "DSH default";
23274
+ const currentReasoningEffort = sideConversationSnapshot.activeSurface === "side" ? sideConversationSnapshot.sideReasoningEffortLabel : modelSelectionSnapshot ? modelReasoningEffortLabel(modelSelectionSnapshot.current) : void 0;
23275
+ const providerSetupSnapshot = useSyncExternalStore6(
22622
23276
  providerSetupRuntime?.subscribe ?? noopExternalStoreSubscribe,
22623
23277
  providerSetupRuntime?.getSnapshot ?? emptyProviderSetupSnapshot,
22624
23278
  providerSetupRuntime?.getSnapshot ?? emptyProviderSetupSnapshot
22625
23279
  );
22626
- const [providerSetupDismissed, setProviderSetupDismissed] = useState53(false);
22627
- const promptHistory = useMemo34(
23280
+ const [providerSetupDismissed, setProviderSetupDismissed] = useState54(false);
23281
+ const promptHistory = useMemo36(
22628
23282
  () => new PromptHistoryStore(
22629
23283
  join5(config.storage.getProjectTempDir(), "prompt_history.json")
22630
23284
  ),
@@ -22637,11 +23291,11 @@ var AppContainer = (props) => {
22637
23291
  const app = useApp();
22638
23292
  const { stats: sessionStats } = useSessionStats();
22639
23293
  const branchName = useGitBranchName(config.getTargetDir());
22640
- const mainControlsRef = useRef30(null);
22641
- const rootUiRef = useRef30(null);
22642
- const lastTitleRef = useRef30(null);
23294
+ const mainControlsRef = useRef31(null);
23295
+ const rootUiRef = useRef31(null);
23296
+ const lastTitleRef = useRef31(null);
22643
23297
  const staticExtraHeight = 3;
22644
- useEffect54(() => {
23298
+ useEffect55(() => {
22645
23299
  void (async () => {
22646
23300
  startupProfiler.flush();
22647
23301
  })();
@@ -22649,7 +23303,7 @@ var AppContainer = (props) => {
22649
23303
  disableMouseEvents();
22650
23304
  });
22651
23305
  }, [config]);
22652
- useEffect54(() => {
23306
+ useEffect55(() => {
22653
23307
  const handleSettingsChanged = () => {
22654
23308
  setSettingsNonce((prev) => prev + 1);
22655
23309
  };
@@ -22660,19 +23314,19 @@ var AppContainer = (props) => {
22660
23314
  }, []);
22661
23315
  const { consoleMessages, clearConsoleMessages: clearConsoleMessagesState } = useConsoleMessages();
22662
23316
  const mainAreaWidth = calculateMainAreaWidth(terminalWidth, settings);
22663
- const { inputWidth, suggestionsWidth } = useMemo34(() => {
23317
+ const { inputWidth, suggestionsWidth } = useMemo36(() => {
22664
23318
  const { inputWidth: inputWidth2, suggestionsWidth: suggestionsWidth2 } = calculatePromptWidths(mainAreaWidth);
22665
23319
  return { inputWidth: inputWidth2, suggestionsWidth: suggestionsWidth2 };
22666
23320
  }, [mainAreaWidth]);
22667
23321
  const staticAreaMaxItemHeight = Math.max(terminalHeight * 4, 100);
22668
- const isValidPath = useCallback45((filePath) => {
23322
+ const isValidPath = useCallback46((filePath) => {
22669
23323
  try {
22670
23324
  return fs12.existsSync(filePath) && fs12.statSync(filePath).isFile();
22671
23325
  } catch (_e) {
22672
23326
  return false;
22673
23327
  }
22674
23328
  }, []);
22675
- const getPreferredEditor = useCallback45(
23329
+ const getPreferredEditor = useCallback46(
22676
23330
  () => settings.merged.general.preferredEditor,
22677
23331
  [settings.merged.general.preferredEditor]
22678
23332
  );
@@ -22685,16 +23339,16 @@ var AppContainer = (props) => {
22685
23339
  shellModeActive,
22686
23340
  getPreferredEditor
22687
23341
  });
22688
- useEffect54(() => {
23342
+ useEffect55(() => {
22689
23343
  initializeFromHistory(promptHistory);
22690
23344
  }, [initializeFromHistory, promptHistory]);
22691
- const refreshStatic = useCallback45(() => {
23345
+ const refreshStatic = useCallback46(() => {
22692
23346
  if (!isAlternateBuffer) {
22693
23347
  stdout.write(ansiEscapes.clearTerminal);
22694
23348
  }
22695
23349
  setHistoryRemountKey((prev) => prev + 1);
22696
23350
  }, [setHistoryRemountKey, isAlternateBuffer, stdout]);
22697
- const handleEditorClose = useCallback45(() => {
23351
+ const handleEditorClose = useCallback46(() => {
22698
23352
  if (shouldEnterAlternateScreen(isAlternateBuffer, config.getScreenReader())) {
22699
23353
  enterAlternateScreen();
22700
23354
  enableMouseEvents();
@@ -22704,7 +23358,7 @@ var AppContainer = (props) => {
22704
23358
  terminalCapabilityManager.enableSupportedModes();
22705
23359
  refreshStatic();
22706
23360
  }, [refreshStatic, isAlternateBuffer, app, config]);
22707
- useEffect54(() => {
23361
+ useEffect55(() => {
22708
23362
  coreEvents.on(CoreEvent.ExternalEditorClosed, handleEditorClose);
22709
23363
  return () => {
22710
23364
  coreEvents.off(CoreEvent.ExternalEditorClosed, handleEditorClose);
@@ -22722,7 +23376,7 @@ var AppContainer = (props) => {
22722
23376
  historyManager.addItem,
22723
23377
  initializationResult.themeError
22724
23378
  );
22725
- const [editorError, setEditorError] = useState53(null);
23379
+ const [editorError, setEditorError] = useState54(null);
22726
23380
  const {
22727
23381
  isEditorDialogOpen,
22728
23382
  openEditorDialog,
@@ -22731,7 +23385,7 @@ var AppContainer = (props) => {
22731
23385
  } = useEditorSettings(settings, setEditorError, historyManager.addItem);
22732
23386
  const { isSettingsDialogOpen, openSettingsDialog, closeSettingsDialog } = useSettingsCommand();
22733
23387
  const { toggleVimEnabled } = useVimMode();
22734
- const slashCommandActions = useMemo34(
23388
+ const slashCommandActions = useMemo36(
22735
23389
  () => ({
22736
23390
  openThemeDialog,
22737
23391
  openEditorDialog,
@@ -22776,13 +23430,15 @@ var AppContainer = (props) => {
22776
23430
  toolCatalogRuntime,
22777
23431
  commandRuntime,
22778
23432
  enableProfiler,
22779
- providerSetupRuntime
23433
+ providerSetupRuntime,
23434
+ sideConversationRuntime,
23435
+ subagentCatalogRuntime
22780
23436
  );
22781
- const cancelHandlerRef = useRef30(
23437
+ const cancelHandlerRef = useRef31(
22782
23438
  () => {
22783
23439
  }
22784
23440
  );
22785
- useEffect54(() => {
23441
+ useEffect55(() => {
22786
23442
  if (pendingRestorePrompt) {
22787
23443
  const lastHistoryUserMsg = historyManager.history.findLast(
22788
23444
  (h) => h.type === "user"
@@ -22795,7 +23451,7 @@ var AppContainer = (props) => {
22795
23451
  }
22796
23452
  }, [pendingRestorePrompt, inputHistory, historyManager.history]);
22797
23453
  const initError = initializationResult.initError;
22798
- const todos = useMemo34(
23454
+ const todos = useMemo36(
22799
23455
  () => ({
22800
23456
  todos: conversationSnapshot.todos.map((todo) => ({
22801
23457
  description: todo.content,
@@ -22820,7 +23476,7 @@ var AppContainer = (props) => {
22820
23476
  terminalHeight
22821
23477
  });
22822
23478
  const streamingState = conversationSnapshot.busy || promptInputPreparing || localShellExecuting || isProcessing ? "responding" /* Responding */ : "idle" /* Idle */;
22823
- const submitQuery = useCallback45(
23479
+ const submitQuery = useCallback46(
22824
23480
  (query) => {
22825
23481
  if (isSlashCommand(query.trim())) {
22826
23482
  void handleSlashCommand(query);
@@ -22873,20 +23529,20 @@ var AppContainer = (props) => {
22873
23529
  buffer
22874
23530
  ]
22875
23531
  );
22876
- const cancelOngoingRequest = useCallback45(() => {
23532
+ const cancelOngoingRequest = useCallback46(() => {
22877
23533
  cancelCommand();
22878
23534
  cancelLocalShell();
22879
23535
  promptInputAbortRef.current?.abort();
22880
23536
  conversationRuntime.cancel();
22881
23537
  }, [cancelCommand, cancelLocalShell, conversationRuntime]);
22882
- useEffect54(
23538
+ useEffect55(
22883
23539
  () => () => {
22884
23540
  promptInputAbortRef.current?.abort();
22885
23541
  },
22886
23542
  []
22887
23543
  );
22888
- const lastOutputTimeRef = useRef30(0);
22889
- useEffect54(() => {
23544
+ const lastOutputTimeRef = useRef31(0);
23545
+ useEffect55(() => {
22890
23546
  lastOutputTimeRef.current = lastOutputTime;
22891
23547
  }, [lastOutputTime]);
22892
23548
  const { shouldShowFocusHint, inactivityStatus } = useShellInactivityStatus({
@@ -22905,10 +23561,11 @@ var AppContainer = (props) => {
22905
23561
  getQueuedMessagesText,
22906
23562
  popAllMessages
22907
23563
  } = useMessageQueue({
23564
+ queueKey: conversationSessionId,
22908
23565
  streamingState,
22909
23566
  submitQuery
22910
23567
  });
22911
- cancelHandlerRef.current = useCallback45(
23568
+ cancelHandlerRef.current = useCallback46(
22912
23569
  (shouldRestorePrompt = true) => {
22913
23570
  const lastUserMessage = inputHistory.at(-1);
22914
23571
  let textToSet = shouldRestorePrompt ? lastUserMessage || "" : "";
@@ -22923,14 +23580,9 @@ ${queuedText}` : queuedText;
22923
23580
  buffer.setText(textToSet);
22924
23581
  }
22925
23582
  },
22926
- [
22927
- buffer,
22928
- inputHistory,
22929
- getQueuedMessagesText,
22930
- clearQueue
22931
- ]
23583
+ [buffer, inputHistory, getQueuedMessagesText, clearQueue]
22932
23584
  );
22933
- const handleFinalSubmit = useCallback45(
23585
+ const handleFinalSubmit = useCallback46(
22934
23586
  (submittedValue) => {
22935
23587
  if (shellModeActive) {
22936
23588
  executeLocalShell(submittedValue);
@@ -22965,14 +23617,14 @@ ${queuedText}` : queuedText;
22965
23617
  streamingState
22966
23618
  ]
22967
23619
  );
22968
- const handleClearScreen = useCallback45(() => {
23620
+ const handleClearScreen = useCallback46(() => {
22969
23621
  historyManager.clearItems();
22970
23622
  clearConsoleMessagesState();
22971
23623
  refreshStatic();
22972
23624
  }, [historyManager, clearConsoleMessagesState, refreshStatic]);
22973
23625
  const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
22974
23626
  const isInputActive = !initError && !isProcessing && pendingApproval === void 0 && pendingUserQuestion === void 0 && !!slashCommands && (streamingState === "idle" /* Idle */ || streamingState === "responding" /* Responding */);
22975
- const [controlsHeight, setControlsHeight] = useState53(0);
23627
+ const [controlsHeight, setControlsHeight] = useState54(0);
22976
23628
  useLayoutEffect3(() => {
22977
23629
  if (mainControlsRef.current) {
22978
23630
  const fullFooterMeasurement = measureElement3(mainControlsRef.current);
@@ -22996,18 +23648,18 @@ ${queuedText}` : queuedText;
22996
23648
  sanitizationConfig: config.sanitizationConfig
22997
23649
  });
22998
23650
  const isFocused = useFocus();
22999
- const initialPrompt = useMemo34(
23651
+ const initialPrompt = useMemo36(
23000
23652
  () => props.initialPrompt ?? config.getQuestion(),
23001
23653
  [config, props.initialPrompt]
23002
23654
  );
23003
- const initialPromptSubmitted = useRef30(false);
23655
+ const initialPromptSubmitted = useRef31(false);
23004
23656
  const providerSetupRequired = providerSetupSnapshot?.current.status === "missing";
23005
- useEffect54(() => {
23657
+ useEffect55(() => {
23006
23658
  if (!providerSetupRuntime || !providerSetupRequired || providerSetupDismissed || customDialog) {
23007
23659
  return;
23008
23660
  }
23009
23661
  setCustomDialog(
23010
- /* @__PURE__ */ jsx95(
23662
+ /* @__PURE__ */ jsx96(
23011
23663
  ProviderSetupDialog,
23012
23664
  {
23013
23665
  runtime: providerSetupRuntime,
@@ -23034,7 +23686,7 @@ ${queuedText}` : queuedText;
23034
23686
  providerSetupRuntime,
23035
23687
  providerSetupSnapshot
23036
23688
  ]);
23037
- useEffect54(() => {
23689
+ useEffect55(() => {
23038
23690
  if (activePtyId) {
23039
23691
  try {
23040
23692
  ShellExecutionService.resizePty(
@@ -23052,7 +23704,7 @@ ${queuedText}` : queuedText;
23052
23704
  }
23053
23705
  }
23054
23706
  }, [terminalWidth, availableTerminalHeight, activePtyId]);
23055
- useEffect54(() => {
23707
+ useEffect55(() => {
23056
23708
  if (initialPrompt && !initialPromptSubmitted.current && !isThemeDialogOpen && !isEditorDialogOpen && !providerSetupRequired && !customDialog && conversationRuntime) {
23057
23709
  handleFinalSubmit(initialPrompt);
23058
23710
  initialPromptSubmitted.current = true;
@@ -23066,20 +23718,20 @@ ${queuedText}` : queuedText;
23066
23718
  customDialog,
23067
23719
  conversationRuntime
23068
23720
  ]);
23069
- const [showErrorDetails, setShowErrorDetails] = useState53(false);
23070
- const [showFullTodos, setShowFullTodos] = useState53(false);
23071
- const [renderMarkdown, setRenderMarkdown] = useState53(true);
23072
- const [ctrlCPressCount, setCtrlCPressCount] = useState53(0);
23073
- const ctrlCTimerRef = useRef30(null);
23074
- const [ctrlDPressCount, setCtrlDPressCount] = useState53(0);
23075
- const ctrlDTimerRef = useRef30(null);
23076
- const [constrainHeight, setConstrainHeight] = useState53(true);
23077
- const [showEscapePrompt, setShowEscapePrompt] = useState53(false);
23078
- const [warningMessage, setWarningMessage] = useState53(null);
23079
- const isInitialMount = useRef30(true);
23080
- const warningTimeoutRef = useRef30(null);
23081
- const tabFocusTimeoutRef = useRef30(null);
23082
- const handleWarning = useCallback45((message) => {
23721
+ const [showErrorDetails, setShowErrorDetails] = useState54(false);
23722
+ const [showFullTodos, setShowFullTodos] = useState54(false);
23723
+ const [renderMarkdown, setRenderMarkdown] = useState54(true);
23724
+ const [ctrlCPressCount, setCtrlCPressCount] = useState54(0);
23725
+ const ctrlCTimerRef = useRef31(null);
23726
+ const [ctrlDPressCount, setCtrlDPressCount] = useState54(0);
23727
+ const ctrlDTimerRef = useRef31(null);
23728
+ const [constrainHeight, setConstrainHeight] = useState54(true);
23729
+ const [showEscapePrompt, setShowEscapePrompt] = useState54(false);
23730
+ const [warningMessage, setWarningMessage] = useState54(null);
23731
+ const isInitialMount = useRef31(true);
23732
+ const warningTimeoutRef = useRef31(null);
23733
+ const tabFocusTimeoutRef = useRef31(null);
23734
+ const handleWarning = useCallback46((message) => {
23083
23735
  setWarningMessage(message);
23084
23736
  if (warningTimeoutRef.current) {
23085
23737
  clearTimeout(warningTimeoutRef.current);
@@ -23088,7 +23740,7 @@ ${queuedText}` : queuedText;
23088
23740
  setWarningMessage(null);
23089
23741
  }, WARNING_PROMPT_DURATION_MS);
23090
23742
  }, []);
23091
- useEffect54(() => {
23743
+ useEffect55(() => {
23092
23744
  const handleSelectionWarning = () => {
23093
23745
  handleWarning("Press Ctrl-S to enter selection mode to copy text.");
23094
23746
  };
@@ -23108,7 +23760,7 @@ ${queuedText}` : queuedText;
23108
23760
  }
23109
23761
  };
23110
23762
  }, [handleWarning]);
23111
- useEffect54(() => {
23763
+ useEffect55(() => {
23112
23764
  if (queueErrorMessage) {
23113
23765
  const timer = setTimeout(() => {
23114
23766
  setQueueErrorMessage(null);
@@ -23117,7 +23769,7 @@ ${queuedText}` : queuedText;
23117
23769
  }
23118
23770
  return void 0;
23119
23771
  }, [queueErrorMessage, setQueueErrorMessage]);
23120
- useEffect54(() => {
23772
+ useEffect55(() => {
23121
23773
  if (isInitialMount.current) {
23122
23774
  isInitialMount.current = false;
23123
23775
  return;
@@ -23129,7 +23781,7 @@ ${queuedText}` : queuedText;
23129
23781
  clearTimeout(handler);
23130
23782
  };
23131
23783
  }, [terminalWidth, refreshStatic]);
23132
- useEffect54(() => {
23784
+ useEffect55(() => {
23133
23785
  const openDebugConsole = () => {
23134
23786
  setShowErrorDetails(true);
23135
23787
  setConstrainHeight(false);
@@ -23139,7 +23791,7 @@ ${queuedText}` : queuedText;
23139
23791
  appEvents.off("open-debug-console" /* OpenDebugConsole */, openDebugConsole);
23140
23792
  };
23141
23793
  }, [config]);
23142
- useEffect54(() => {
23794
+ useEffect55(() => {
23143
23795
  if (ctrlCTimerRef.current) {
23144
23796
  clearTimeout(ctrlCTimerRef.current);
23145
23797
  ctrlCTimerRef.current = null;
@@ -23153,7 +23805,7 @@ ${queuedText}` : queuedText;
23153
23805
  }, WARNING_PROMPT_DURATION_MS);
23154
23806
  }
23155
23807
  }, [ctrlCPressCount, config, setCtrlCPressCount, handleSlashCommand]);
23156
- useEffect54(() => {
23808
+ useEffect55(() => {
23157
23809
  if (ctrlDTimerRef.current) {
23158
23810
  clearTimeout(ctrlDTimerRef.current);
23159
23811
  ctrlCTimerRef.current = null;
@@ -23167,7 +23819,7 @@ ${queuedText}` : queuedText;
23167
23819
  }, WARNING_PROMPT_DURATION_MS);
23168
23820
  }
23169
23821
  }, [ctrlDPressCount, config, setCtrlDPressCount, handleSlashCommand]);
23170
- const handleEscapePromptChange = useCallback45((showPrompt) => {
23822
+ const handleEscapePromptChange = useCallback46((showPrompt) => {
23171
23823
  setShowEscapePrompt(showPrompt);
23172
23824
  }, []);
23173
23825
  const { elapsedTime, currentLoadingPhrase } = useLoadingIndicator({
@@ -23175,13 +23827,21 @@ ${queuedText}` : queuedText;
23175
23827
  shouldShowFocusHint,
23176
23828
  customWittyPhrases: settings.merged.ui.customWittyPhrases
23177
23829
  });
23178
- const handleGlobalKeypress = useCallback45(
23830
+ const handleGlobalKeypress = useCallback46(
23179
23831
  (key) => {
23180
23832
  if (copyModeEnabled) {
23181
23833
  setCopyModeEnabled(false);
23182
23834
  enableMouseEvents();
23183
23835
  return;
23184
23836
  }
23837
+ if (sideConversationRuntime && !customDialog && pendingApproval === void 0 && pendingUserQuestion === void 0 && isConversationSwitchKey(key)) {
23838
+ if (sideConversationSnapshot.activeSurface === "side") {
23839
+ sideConversationRuntime.switchToMain();
23840
+ } else if (sideConversationSnapshot.sideSessionId !== void 0) {
23841
+ sideConversationRuntime.switchToSide();
23842
+ }
23843
+ return;
23844
+ }
23185
23845
  if (isAlternateBuffer && keyMatchers["app.toggleCopyMode" /* TOGGLE_COPY_MODE */](key)) {
23186
23846
  setCopyModeEnabled(true);
23187
23847
  disableMouseEvents();
@@ -23200,6 +23860,12 @@ ${queuedText}` : queuedText;
23200
23860
  return;
23201
23861
  }
23202
23862
  if (conversationRuntime) {
23863
+ if (sideConversationRuntime && sideConversationSnapshot.activeSurface === "side" && !conversationSnapshot.busy && !promptInputPreparing && !localShellExecuting && !isProcessing) {
23864
+ if (buffer.text.length > 0) return;
23865
+ clearQueue();
23866
+ void sideConversationRuntime.closeSide();
23867
+ return;
23868
+ }
23203
23869
  if (promptInputPreparing || localShellExecuting || isProcessing || conversationSnapshot.busy) {
23204
23870
  cancelOngoingRequest();
23205
23871
  } else {
@@ -23283,17 +23949,20 @@ ${queuedText}` : queuedText;
23283
23949
  setCopyModeEnabled,
23284
23950
  copyModeEnabled,
23285
23951
  isAlternateBuffer,
23286
- handleWarning
23952
+ handleWarning,
23953
+ clearQueue,
23954
+ sideConversationRuntime,
23955
+ sideConversationSnapshot
23287
23956
  ]
23288
23957
  );
23289
23958
  useKeypress(handleGlobalKeypress, { isActive: true });
23290
- useEffect54(() => {
23959
+ useEffect55(() => {
23291
23960
  if (settings.merged.ui.hideWindowTitle) return;
23292
23961
  const paddedTitle = computeTerminalTitle({
23293
23962
  streamingState,
23294
23963
  isConfirming: pendingApproval !== void 0 || !!confirmationRequest || shouldShowActionRequiredTitle,
23295
23964
  isSilentWorking: shouldShowSilentWorkingTitle,
23296
- folderName: basename2(config.getTargetDir()),
23965
+ folderName: basename3(config.getTargetDir()),
23297
23966
  useDynamicTitle: settings.merged.ui.dynamicWindowTitle
23298
23967
  });
23299
23968
  if (lastTitleRef.current !== paddedTitle) {
@@ -23311,7 +23980,7 @@ ${queuedText}` : queuedText;
23311
23980
  config,
23312
23981
  stdout
23313
23982
  ]);
23314
- useEffect54(() => {
23983
+ useEffect55(() => {
23315
23984
  const handleUserFeedback = (payload) => {
23316
23985
  let type;
23317
23986
  switch (payload.severity) {
@@ -23349,23 +24018,23 @@ ${queuedText}` : queuedText;
23349
24018
  coreEvents.off(CoreEvent.UserFeedback, handleUserFeedback);
23350
24019
  };
23351
24020
  }, [historyManager]);
23352
- const filteredConsoleMessages = useMemo34(() => {
24021
+ const filteredConsoleMessages = useMemo36(() => {
23353
24022
  if (config.getDebugMode()) {
23354
24023
  return consoleMessages;
23355
24024
  }
23356
24025
  return consoleMessages.filter((msg) => msg.type !== "debug");
23357
24026
  }, [consoleMessages, config]);
23358
- const errorCount = useMemo34(
24027
+ const errorCount = useMemo36(
23359
24028
  () => filteredConsoleMessages.filter((msg) => msg.type === "error").reduce((total, msg) => total + msg.count, 0),
23360
24029
  [filteredConsoleMessages]
23361
24030
  );
23362
24031
  const nightly = props.version.includes("nightly");
23363
24032
  const dialogsVisible = pendingUserQuestion !== void 0 || !!confirmationRequest || !!customDialog || isThemeDialogOpen || isSettingsDialogOpen || isEditorDialogOpen;
23364
- const pendingHistoryItems = useMemo34(
24033
+ const pendingHistoryItems = useMemo36(
23365
24034
  () => pendingShellHistoryItem ? [pendingShellHistoryItem] : [],
23366
24035
  [pendingShellHistoryItem]
23367
24036
  );
23368
- const uiState = useMemo34(
24037
+ const uiState = useMemo36(
23369
24038
  () => ({
23370
24039
  history: historyManager.history,
23371
24040
  isThemeDialogOpen,
@@ -23425,7 +24094,9 @@ ${queuedText}` : queuedText;
23425
24094
  copyModeEnabled,
23426
24095
  warningMessage,
23427
24096
  terminalBackgroundColor: config.getTerminalBackground(),
23428
- settingsNonce
24097
+ settingsNonce,
24098
+ sideConversation: sideConversationSnapshot,
24099
+ subagentCatalog: subagentCatalogSnapshot
23429
24100
  }),
23430
24101
  [
23431
24102
  isThemeDialogOpen,
@@ -23486,10 +24157,12 @@ ${queuedText}` : queuedText;
23486
24157
  copyModeEnabled,
23487
24158
  warningMessage,
23488
24159
  config,
23489
- settingsNonce
24160
+ settingsNonce,
24161
+ sideConversationSnapshot,
24162
+ subagentCatalogSnapshot
23490
24163
  ]
23491
24164
  );
23492
- const uiActions = useMemo34(
24165
+ const uiActions = useMemo36(
23493
24166
  () => ({
23494
24167
  handleThemeSelect,
23495
24168
  closeThemeDialog,
@@ -23531,22 +24204,22 @@ ${queuedText}` : queuedText;
23531
24204
  setEmbeddedShellFocused
23532
24205
  ]
23533
24206
  );
23534
- return /* @__PURE__ */ jsx95(UIStateContext.Provider, { value: uiState, children: /* @__PURE__ */ jsx95(UIActionsContext.Provider, { value: uiActions, children: /* @__PURE__ */ jsx95(ConfigContext.Provider, { value: config, children: /* @__PURE__ */ jsx95(
24207
+ return /* @__PURE__ */ jsx96(UIStateContext.Provider, { value: uiState, children: /* @__PURE__ */ jsx96(UIActionsContext.Provider, { value: uiActions, children: /* @__PURE__ */ jsx96(ConfigContext.Provider, { value: config, children: /* @__PURE__ */ jsx96(
23535
24208
  AppContext.Provider,
23536
24209
  {
23537
24210
  value: {
23538
24211
  version: props.version,
23539
24212
  startupWarnings: props.startupWarnings || []
23540
24213
  },
23541
- children: /* @__PURE__ */ jsx95(ApprovalRuntimeProvider, { runtime: approvalRuntime, children: /* @__PURE__ */ jsx95(UserQuestionRuntimeProvider, { runtime: userQuestionRuntime, children: /* @__PURE__ */ jsx95(ShellFocusContext.Provider, { value: isFocused, children: /* @__PURE__ */ jsx95(App, {}) }) }) })
24214
+ children: /* @__PURE__ */ jsx96(ApprovalRuntimeProvider, { runtime: approvalRuntime, children: /* @__PURE__ */ jsx96(UserQuestionRuntimeProvider, { runtime: userQuestionRuntime, children: /* @__PURE__ */ jsx96(ShellFocusContext.Provider, { value: isFocused, children: /* @__PURE__ */ jsx96(App, {}) }) }) })
23542
24215
  }
23543
24216
  ) }) }) });
23544
24217
  };
23545
24218
 
23546
24219
  // src/ui/root.tsx
23547
- import React21 from "react";
24220
+ import React22 from "react";
23548
24221
  import { render } from "ink";
23549
- import { jsx as jsx96 } from "react/jsx-runtime";
24222
+ import { jsx as jsx97 } from "react/jsx-runtime";
23550
24223
  var SLOW_RENDER_MS = 200;
23551
24224
  function validateDnsResolutionOrder(order) {
23552
24225
  const defaultValue = "ipv4first";
@@ -23578,7 +24251,7 @@ ${reason.stack}` : ""}`;
23578
24251
  }
23579
24252
  });
23580
24253
  }
23581
- async function startInteractiveUI(config, settings, startupWarnings, workspaceRoot = process.cwd(), initializationResult, conversationRuntime, approvalRuntime, userQuestionRuntime, commandRuntime, permissionSelectionRuntime, toolCatalogRuntime, promptCompletionRuntime, promptInputRuntime, modelSelectionRuntime, sessionManagementRuntime, initialPrompt, providerSetupRuntime) {
24254
+ async function startInteractiveUI(config, settings, startupWarnings, workspaceRoot = process.cwd(), initializationResult, conversationRuntime, approvalRuntime, userQuestionRuntime, commandRuntime, permissionSelectionRuntime, toolCatalogRuntime, promptCompletionRuntime, promptInputRuntime, modelSelectionRuntime, sessionManagementRuntime, initialPrompt, providerSetupRuntime, sideConversationRuntime, subagentCatalogRuntime) {
23582
24255
  const useAlternateBuffer2 = shouldEnterAlternateScreen(
23583
24256
  isAlternateBufferEnabled(settings),
23584
24257
  config.getScreenReader()
@@ -23590,21 +24263,21 @@ async function startInteractiveUI(config, settings, startupWarnings, workspaceRo
23590
24263
  disableMouseEvents();
23591
24264
  });
23592
24265
  }
23593
- setWindowTitle(basename3(workspaceRoot), settings);
24266
+ setWindowTitle(basename4(workspaceRoot), settings);
23594
24267
  const version = await getVersion();
23595
24268
  const AppWrapper = () => {
23596
24269
  useKittyKeyboardProtocol();
23597
- return /* @__PURE__ */ jsx96(SettingsContext.Provider, { value: settings, children: /* @__PURE__ */ jsx96(
24270
+ return /* @__PURE__ */ jsx97(SettingsContext.Provider, { value: settings, children: /* @__PURE__ */ jsx97(
23598
24271
  KeypressProvider,
23599
24272
  {
23600
24273
  config,
23601
24274
  debugKeystrokeLogging: settings.merged.general.debugKeystrokeLogging,
23602
- children: /* @__PURE__ */ jsx96(
24275
+ children: /* @__PURE__ */ jsx97(
23603
24276
  MouseProvider,
23604
24277
  {
23605
24278
  mouseEventsEnabled,
23606
24279
  debugKeystrokeLogging: settings.merged.general.debugKeystrokeLogging,
23607
- children: /* @__PURE__ */ jsx96(ScrollProvider, { children: /* @__PURE__ */ jsx96(SessionStatsProvider, { conversationRuntime, children: /* @__PURE__ */ jsx96(VimModeProvider, { settings, children: /* @__PURE__ */ jsx96(
24280
+ children: /* @__PURE__ */ jsx97(ScrollProvider, { children: /* @__PURE__ */ jsx97(SessionStatsProvider, { conversationRuntime, children: /* @__PURE__ */ jsx97(VimModeProvider, { settings, children: /* @__PURE__ */ jsx97(
23608
24281
  AppContainer,
23609
24282
  {
23610
24283
  config,
@@ -23622,6 +24295,8 @@ async function startInteractiveUI(config, settings, startupWarnings, workspaceRo
23622
24295
  commandRuntime,
23623
24296
  permissionSelectionRuntime,
23624
24297
  toolCatalogRuntime,
24298
+ sideConversationRuntime,
24299
+ subagentCatalogRuntime,
23625
24300
  initialPrompt
23626
24301
  }
23627
24302
  ) }) }) })
@@ -23632,7 +24307,7 @@ async function startInteractiveUI(config, settings, startupWarnings, workspaceRo
23632
24307
  };
23633
24308
  const { stdout: inkStdout, stderr: inkStderr } = createWorkingStdio();
23634
24309
  const instance = render(
23635
- process.env["DEBUG"] ? /* @__PURE__ */ jsx96(React21.StrictMode, { children: /* @__PURE__ */ jsx96(AppWrapper, {}) }) : /* @__PURE__ */ jsx96(AppWrapper, {}),
24310
+ process.env["DEBUG"] ? /* @__PURE__ */ jsx97(React22.StrictMode, { children: /* @__PURE__ */ jsx97(AppWrapper, {}) }) : /* @__PURE__ */ jsx97(AppWrapper, {}),
23636
24311
  {
23637
24312
  stdout: inkStdout,
23638
24313
  stderr: inkStderr,
@@ -23738,7 +24413,9 @@ async function main(options) {
23738
24413
  options.modelSelectionRuntime,
23739
24414
  options.sessionManagementRuntime,
23740
24415
  options.initialPrompt,
23741
- options.providerSetupRuntime
24416
+ options.providerSetupRuntime,
24417
+ options.sideConversationRuntime,
24418
+ options.subagentCatalogRuntime
23742
24419
  );
23743
24420
  }
23744
24421
  }
@@ -24266,6 +24943,167 @@ var DshPromptCompletionRuntime = class {
24266
24943
  }
24267
24944
  };
24268
24945
 
24946
+ // src/dsh/side-conversation.ts
24947
+ var SIDE_SESSION_PREFIX = "dsh-console-side-";
24948
+ function completedTurnSeed(events) {
24949
+ for (let index = events.length - 1; index >= 0; index -= 1) {
24950
+ if (events[index].type === "turn/end") return events.slice(0, index + 1);
24951
+ }
24952
+ return [];
24953
+ }
24954
+ function pendingUserText(events, seedLength) {
24955
+ for (let index = events.length - 1; index >= seedLength; index -= 1) {
24956
+ const event = events[index];
24957
+ if (event.type !== "user/message") continue;
24958
+ return event.data.content.flatMap((block) => block.type === "text" ? [block.text] : []).join("").trim();
24959
+ }
24960
+ return "";
24961
+ }
24962
+ function firstSidePrompt(question, pendingRequest) {
24963
+ return [
24964
+ "You are a Side conversation branching from the main conversation context above.",
24965
+ "Help with the side discussion without continuing or modifying the main task.",
24966
+ "No tools are available in this Side conversation.",
24967
+ ...pendingRequest ? ["The main Agent is currently working on this request:", pendingRequest] : [],
24968
+ "Side question:",
24969
+ question
24970
+ ].join("\n\n");
24971
+ }
24972
+
24973
+ // src/ui/conversation-workspace-runtime.ts
24974
+ var ConversationWorkspaceRuntime = class {
24975
+ constructor(main2, createSide) {
24976
+ this.main = main2;
24977
+ this.createSide = createSide;
24978
+ this.offMain = main2.subscribe(this.notify);
24979
+ this.workspaceSnapshot = this.createWorkspaceSnapshot();
24980
+ }
24981
+ listeners = /* @__PURE__ */ new Set();
24982
+ surfaceListeners = /* @__PURE__ */ new Set();
24983
+ offMain;
24984
+ side;
24985
+ offSide;
24986
+ activeSurface = "main";
24987
+ opening;
24988
+ closing;
24989
+ workspaceSnapshot;
24990
+ getSnapshot = () => this.current().getSnapshot();
24991
+ getSessionStats = () => this.current().getSessionStats();
24992
+ subscribe = (listener) => {
24993
+ this.listeners.add(listener);
24994
+ return () => this.listeners.delete(listener);
24995
+ };
24996
+ submit = (submission) => this.current().submit(submission);
24997
+ cancel = () => this.current().cancel();
24998
+ exit = () => this.main.exit();
24999
+ getWorkspaceSnapshot = () => this.workspaceSnapshot;
25000
+ subscribeWorkspace = this.subscribe;
25001
+ subscribeSurface = (listener) => {
25002
+ this.surfaceListeners.add(listener);
25003
+ return () => this.surfaceListeners.delete(listener);
25004
+ };
25005
+ open = async (question, signal) => {
25006
+ const normalized = question?.trim();
25007
+ let createdSide = false;
25008
+ if (this.closing) await this.closing;
25009
+ if (this.opening) throw new Error("A Side conversation is already opening.");
25010
+ if (this.side?.getSnapshot().busy && normalized) {
25011
+ this.switchToSide();
25012
+ throw new Error("The Side Agent is already working.");
25013
+ }
25014
+ if (!this.side) {
25015
+ const operation = this.createSide(signal).then(async (side) => {
25016
+ if (signal.aborted) {
25017
+ await side.dispose();
25018
+ signal.throwIfAborted();
25019
+ }
25020
+ this.side = side;
25021
+ createdSide = true;
25022
+ this.offSide = side.subscribe(this.notify);
25023
+ this.activeSurface = "side";
25024
+ this.notifySurface();
25025
+ });
25026
+ this.opening = operation;
25027
+ try {
25028
+ await operation;
25029
+ } finally {
25030
+ if (this.opening === operation) this.opening = void 0;
25031
+ }
25032
+ } else {
25033
+ this.switchToSide();
25034
+ }
25035
+ if (normalized) {
25036
+ try {
25037
+ await this.side?.submit({
25038
+ content: [{ type: "text", text: normalized }],
25039
+ displayContent: [{ type: "text", text: normalized }],
25040
+ signal
25041
+ });
25042
+ } catch (error) {
25043
+ if (createdSide) await this.closeSide();
25044
+ throw error;
25045
+ }
25046
+ }
25047
+ };
25048
+ switchToMain = () => {
25049
+ if (this.activeSurface === "main") return;
25050
+ this.activeSurface = "main";
25051
+ this.notifySurface();
25052
+ };
25053
+ switchToSide = () => {
25054
+ if (!this.side) throw new Error("No Side conversation is open. Use /btw <question> first.");
25055
+ if (this.activeSurface === "side") return;
25056
+ this.activeSurface = "side";
25057
+ this.notifySurface();
25058
+ };
25059
+ closeSide = async () => {
25060
+ if (this.closing) return this.closing;
25061
+ const side = this.side;
25062
+ if (!side) return;
25063
+ this.activeSurface = "main";
25064
+ this.side = void 0;
25065
+ this.offSide?.();
25066
+ this.offSide = void 0;
25067
+ this.notifySurface();
25068
+ const operation = side.dispose().finally(() => {
25069
+ if (this.closing === operation) this.closing = void 0;
25070
+ });
25071
+ this.closing = operation;
25072
+ await operation;
25073
+ };
25074
+ dispose = async () => {
25075
+ await this.closeSide();
25076
+ this.offMain();
25077
+ this.listeners.clear();
25078
+ this.surfaceListeners.clear();
25079
+ };
25080
+ current() {
25081
+ return this.activeSurface === "side" && this.side ? this.side : this.main;
25082
+ }
25083
+ createWorkspaceSnapshot() {
25084
+ return {
25085
+ activeSurface: this.activeSurface,
25086
+ mainBusy: this.main.getSnapshot().busy,
25087
+ sideBusy: this.side?.getSnapshot().busy ?? false,
25088
+ ...this.side === void 0 ? {} : {
25089
+ sideSessionId: this.side.getSessionStats().sessionId,
25090
+ sideModelLabel: this.side.modelLabel,
25091
+ ...this.side.reasoningEffortLabel === void 0 ? {} : {
25092
+ sideReasoningEffortLabel: this.side.reasoningEffortLabel
25093
+ }
25094
+ }
25095
+ };
25096
+ }
25097
+ notify = () => {
25098
+ this.workspaceSnapshot = this.createWorkspaceSnapshot();
25099
+ for (const listener of this.listeners) listener();
25100
+ };
25101
+ notifySurface = () => {
25102
+ this.notify();
25103
+ for (const listener of this.surfaceListeners) listener();
25104
+ };
25105
+ };
25106
+
24269
25107
  // src/dsh/prompt-input-runtime.ts
24270
25108
  import { promises as fs13 } from "node:fs";
24271
25109
  import path14 from "node:path";
@@ -24878,9 +25716,9 @@ var DshModelSelectionRuntime = class _DshModelSelectionRuntime {
24878
25716
  import { foldRequestHeader, SessionId as SessionId2 } from "@deepseek-ai/dsh-session";
24879
25717
  var SESSION_PREFIX = "dsh-console-";
24880
25718
  var COMPLETION_PREFIX = "dsh-console-completion-";
24881
- var SESSION_OBSERVATION_BATCH_SIZE = 8;
25719
+ var SIDE_PREFIX = "dsh-console-side-";
24882
25720
  function isConsoleSession(id) {
24883
- return id.startsWith(SESSION_PREFIX) && !id.startsWith(COMPLETION_PREFIX);
25721
+ return id.startsWith(SESSION_PREFIX) && !id.startsWith(COMPLETION_PREFIX) && !id.startsWith(SIDE_PREFIX);
24884
25722
  }
24885
25723
  function hasConversationEvents(events) {
24886
25724
  return events.some(
@@ -24911,62 +25749,23 @@ var DshSessionManagementRuntime = class {
24911
25749
  { kind: "parent", values: [null] }
24912
25750
  ], signal);
24913
25751
  signal?.throwIfAborted();
24914
- const candidates = records.filter((record) => {
25752
+ return records.filter((record) => {
24915
25753
  const id = String(record.header.id);
24916
25754
  return isConsoleSession(id) && (record.persisted || id === this.snapshot.currentSessionId);
24917
- });
24918
- const observations = [];
24919
- for (let offset = 0; offset < candidates.length; offset += SESSION_OBSERVATION_BATCH_SIZE) {
24920
- signal?.throwIfAborted();
24921
- const batch = candidates.slice(offset, offset + SESSION_OBSERVATION_BATCH_SIZE);
24922
- observations.push(...await Promise.all(batch.map(async (record) => {
24923
- if (!record.persisted) {
24924
- return { record, hasConversation: false, resumable: false };
24925
- }
24926
- try {
24927
- const events = await this.query.listEvents(record.header.id);
24928
- return {
24929
- record,
24930
- hasConversation: hasConversationEvents(events),
24931
- resumable: events.some((event) => event.type === "request/header")
24932
- };
24933
- } catch {
24934
- return {
24935
- record,
24936
- hasConversation: true,
24937
- resumable: false,
24938
- resumeUnavailableReason: "Session log could not be read."
24939
- };
24940
- }
24941
- })));
24942
- }
24943
- signal?.throwIfAborted();
24944
- const visible = observations.filter(
24945
- ({ record, hasConversation, resumable }) => String(record.header.id) === this.snapshot.currentSessionId || hasConversation || resumable
24946
- );
24947
- const titles = await this.query.readTitleSnapshots(
24948
- visible.map(({ record }) => record.header.id),
24949
- signal
24950
- );
24951
- signal?.throwIfAborted();
24952
- const titleById = /* @__PURE__ */ new Map();
24953
- for (const result of titles) {
24954
- if (result.status === "fulfilled" && result.value.title !== void 0) {
24955
- titleById.set(String(result.sessionId), result.value.title.title);
24956
- }
24957
- }
24958
- return visible.map(({ record, resumable, ...observation }) => ({
25755
+ }).map((record) => ({
24959
25756
  id: String(record.header.id),
24960
- ...titleById.has(String(record.header.id)) ? { title: titleById.get(String(record.header.id)) } : {},
24961
25757
  createdAt: record.header.createdAt,
24962
25758
  current: String(record.header.id) === this.snapshot.currentSessionId,
24963
25759
  persisted: record.persisted,
24964
- resumable,
24965
- ...!resumable && record.persisted ? {
24966
- resumeUnavailableReason: "resumeUnavailableReason" in observation ? observation.resumeUnavailableReason : "Missing model route."
24967
- } : {}
25760
+ resumable: record.persisted
24968
25761
  }));
24969
25762
  }
25763
+ async resolveSessionTitles(sessionIds, signal) {
25764
+ if (sessionIds.length === 0) return [];
25765
+ const results = await this.query.readTitleSnapshots(sessionIds.map(SessionId2), signal);
25766
+ signal?.throwIfAborted();
25767
+ return results.flatMap((result) => result.status === "fulfilled" && result.value.title ? [{ id: String(result.sessionId), title: result.value.title.title }] : []);
25768
+ }
24970
25769
  async createNew(signal) {
24971
25770
  this.beginSwitch();
24972
25771
  try {
@@ -25277,8 +26076,15 @@ var DshCommandRuntimeAdapter = class {
25277
26076
  return () => this.listeners.delete(listener);
25278
26077
  };
25279
26078
  async execute(line, signal) {
26079
+ const agent = this.activeAgent();
26080
+ if (agent === void 0) {
26081
+ return {
26082
+ kind: "error",
26083
+ text: "Start a conversation before using DSH commands."
26084
+ };
26085
+ }
25280
26086
  const execution = await this.commands.execute(
25281
- this.activeAgent(),
26087
+ agent,
25282
26088
  line,
25283
26089
  [],
25284
26090
  signal
@@ -25299,9 +26105,11 @@ var DshCommandRuntimeAdapter = class {
25299
26105
  this.listeners.clear();
25300
26106
  }
25301
26107
  readSnapshot() {
26108
+ const agent = this.activeAgent();
26109
+ if (agent === void 0) return Object.freeze({ commands: Object.freeze([]) });
25302
26110
  return Object.freeze({
25303
26111
  commands: Object.freeze(
25304
- this.commands.list(this.activeAgent()).map(
26112
+ this.commands.list(agent).map(
25305
26113
  (command) => Object.freeze({
25306
26114
  name: command.name,
25307
26115
  description: command.description,
@@ -25373,7 +26181,9 @@ var DshToolCatalogRuntime = class {
25373
26181
  this.listeners.clear();
25374
26182
  }
25375
26183
  readSnapshot() {
25376
- const schemas = this.tools.schemas(this.activeAgent());
26184
+ const agent = this.activeAgent();
26185
+ if (agent === void 0) return Object.freeze({ tools: Object.freeze([]) });
26186
+ const schemas = this.tools.schemas(agent);
25377
26187
  const catalog = schemas.map(projectTool).sort((left, right) => left.name.localeCompare(right.name));
25378
26188
  return Object.freeze({ tools: Object.freeze(catalog) });
25379
26189
  }
@@ -25393,7 +26203,8 @@ var DshPermissionSelectionRuntime = class {
25393
26203
  this.activeAgent = activeAgent;
25394
26204
  this.snapshot = this.readSnapshot(false);
25395
26205
  this.offProjection = projections.onChanged((session, key) => {
25396
- if (session !== this.activeAgent().session || key !== "permissions") return;
26206
+ const agent = this.activeAgent();
26207
+ if (agent === void 0 || session !== agent.session || key !== "permissions") return;
25397
26208
  this.refresh();
25398
26209
  });
25399
26210
  }
@@ -25444,9 +26255,11 @@ var DshPermissionSelectionRuntime = class {
25444
26255
  this.listeners.clear();
25445
26256
  }
25446
26257
  readSnapshot(busy) {
25447
- const selection = this.projections.snapshot(
25448
- this.activeAgent().session
25449
- ).values.permissions;
26258
+ const agent = this.activeAgent();
26259
+ if (agent === void 0) {
26260
+ return Object.freeze({ available: false, options: Object.freeze([]), busy });
26261
+ }
26262
+ const selection = this.projections.snapshot(agent.session).values.permissions;
25450
26263
  if (!selection) {
25451
26264
  return Object.freeze({ available: false, options: Object.freeze([]), busy });
25452
26265
  }
@@ -25644,6 +26457,211 @@ var DshProviderSetupRuntime = class _DshProviderSetupRuntime {
25644
26457
  }
25645
26458
  };
25646
26459
 
26460
+ // src/dsh/subagent-catalog-runtime.ts
26461
+ import { SessionId as SessionId3 } from "@deepseek-ai/dsh-session";
26462
+
26463
+ // src/dsh/subagent-transcript-runtime.ts
26464
+ function cancelled() {
26465
+ return new DOMException("Subagent transcript loading was cancelled.", "AbortError");
26466
+ }
26467
+ var DshSubagentTranscriptRuntime = class _DshSubagentTranscriptRuntime {
26468
+ constructor(projector, off) {
26469
+ this.projector = projector;
26470
+ this.off = off;
26471
+ }
26472
+ static async create(query, sessionId, presenter, subscribeToSession, signal) {
26473
+ signal?.throwIfAborted();
26474
+ const projector = new DshSessionProjector(
26475
+ String(sessionId),
26476
+ "subagent",
26477
+ presenter
26478
+ );
26479
+ const buffered = [];
26480
+ let replaying = true;
26481
+ const off = subscribeToSession(sessionId, (event) => {
26482
+ if (replaying) buffered.push(event);
26483
+ else projector.project(event);
26484
+ });
26485
+ try {
26486
+ const log = await query.readSession(sessionId);
26487
+ if (signal?.aborted) throw cancelled();
26488
+ projector.replay(log.events);
26489
+ const replayedSeq = log.events.at(-1)?.seq ?? -1;
26490
+ for (const event of buffered) {
26491
+ if (event.seq > replayedSeq) projector.project(event);
26492
+ }
26493
+ replaying = false;
26494
+ return new _DshSubagentTranscriptRuntime(projector, off);
26495
+ } catch (error) {
26496
+ off();
26497
+ throw error;
26498
+ }
26499
+ }
26500
+ disposed = false;
26501
+ getSnapshot = () => this.projector.getSnapshot();
26502
+ subscribe = (listener) => this.projector.subscribe(listener);
26503
+ dispose() {
26504
+ if (this.disposed) return;
26505
+ this.disposed = true;
26506
+ this.off();
26507
+ }
26508
+ };
26509
+
26510
+ // src/dsh/subagent-catalog-runtime.ts
26511
+ function fallbackLabel(id) {
26512
+ return `Agent ${String(id).slice(-8)}`;
26513
+ }
26514
+ function projectEntry(entry) {
26515
+ if (entry.kind === "diagnostic") {
26516
+ return Object.freeze({
26517
+ kind: "diagnostic",
26518
+ id: String(entry.id),
26519
+ parentId: String(entry.parentId),
26520
+ depth: entry.depth,
26521
+ reason: entry.reason
26522
+ });
26523
+ }
26524
+ return Object.freeze({
26525
+ kind: "agent",
26526
+ id: String(entry.id),
26527
+ parentId: String(entry.parentId),
26528
+ depth: entry.depth,
26529
+ label: entry.label?.trim() || fallbackLabel(entry.id),
26530
+ mode: entry.mode,
26531
+ activity: entry.activity,
26532
+ hasChildren: entry.hasChildren
26533
+ });
26534
+ }
26535
+ function isAbort(error, signal) {
26536
+ return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
26537
+ }
26538
+ var DshSubagentCatalogRuntime = class {
26539
+ constructor(subagents, rootSessionId, subscribeToChanges, query, presenter, subscribeToSession) {
26540
+ this.subagents = subagents;
26541
+ this.rootSessionId = rootSessionId;
26542
+ this.query = query;
26543
+ this.presenter = presenter;
26544
+ this.subscribeToSession = subscribeToSession;
26545
+ this.snapshot = Object.freeze({
26546
+ rootSessionId: String(rootSessionId() ?? ""),
26547
+ status: "idle",
26548
+ items: Object.freeze([]),
26549
+ runningCount: 0
26550
+ });
26551
+ this.off = subscribeToChanges(() => this.queueRefresh());
26552
+ this.queueRefresh();
26553
+ }
26554
+ listeners = /* @__PURE__ */ new Set();
26555
+ snapshot;
26556
+ off;
26557
+ generation = 0;
26558
+ refreshQueued = false;
26559
+ disposed = false;
26560
+ refreshController;
26561
+ getSnapshot = () => this.snapshot;
26562
+ subscribe = (listener) => {
26563
+ this.listeners.add(listener);
26564
+ return () => this.listeners.delete(listener);
26565
+ };
26566
+ async openTranscript(sessionId, signal) {
26567
+ const item = this.snapshot.items.find(
26568
+ (candidate) => candidate.id === sessionId && candidate.kind === "agent"
26569
+ );
26570
+ if (item === void 0) {
26571
+ throw new Error("The selected subagent is no longer available.");
26572
+ }
26573
+ return DshSubagentTranscriptRuntime.create(
26574
+ this.query,
26575
+ SessionId3(sessionId),
26576
+ this.presenter,
26577
+ this.subscribeToSession,
26578
+ signal
26579
+ );
26580
+ }
26581
+ async refresh(signal) {
26582
+ if (this.disposed || signal?.aborted) return;
26583
+ this.refreshController?.abort();
26584
+ const controller = new AbortController();
26585
+ this.refreshController = controller;
26586
+ const refreshSignal = signal === void 0 ? controller.signal : AbortSignal.any([signal, controller.signal]);
26587
+ const generation = ++this.generation;
26588
+ const rootSessionId = this.rootSessionId();
26589
+ if (rootSessionId === void 0) {
26590
+ this.publish({
26591
+ rootSessionId: "",
26592
+ status: "idle",
26593
+ items: Object.freeze([]),
26594
+ runningCount: 0
26595
+ });
26596
+ return;
26597
+ }
26598
+ this.publish({
26599
+ ...this.snapshot,
26600
+ rootSessionId: String(rootSessionId),
26601
+ status: "loading",
26602
+ error: void 0
26603
+ });
26604
+ try {
26605
+ const entries = await this.subagents.listDescendants(rootSessionId, refreshSignal);
26606
+ if (this.disposed || refreshSignal.aborted || generation !== this.generation) return;
26607
+ const items = Object.freeze(entries.map(projectEntry));
26608
+ this.publish({
26609
+ rootSessionId: String(rootSessionId),
26610
+ status: "ready",
26611
+ items,
26612
+ runningCount: items.filter(
26613
+ (item) => item.kind === "agent" && item.activity === "running"
26614
+ ).length
26615
+ });
26616
+ } catch (error) {
26617
+ if (this.disposed || generation !== this.generation || isAbort(error, refreshSignal)) return;
26618
+ debugLogger.debug(`Unable to list DSH subagents: ${String(error)}`);
26619
+ this.publish({
26620
+ ...this.snapshot,
26621
+ rootSessionId: String(rootSessionId),
26622
+ status: "error",
26623
+ error: "Unable to load the Agent catalog."
26624
+ });
26625
+ } finally {
26626
+ if (this.refreshController === controller) this.refreshController = void 0;
26627
+ }
26628
+ }
26629
+ activeAgentChanged() {
26630
+ this.refreshController?.abort();
26631
+ this.refreshController = void 0;
26632
+ this.generation += 1;
26633
+ this.publish({
26634
+ rootSessionId: String(this.rootSessionId() ?? ""),
26635
+ status: "idle",
26636
+ items: Object.freeze([]),
26637
+ runningCount: 0
26638
+ });
26639
+ this.queueRefresh();
26640
+ }
26641
+ dispose() {
26642
+ if (this.disposed) return;
26643
+ this.disposed = true;
26644
+ this.refreshController?.abort();
26645
+ this.refreshController = void 0;
26646
+ this.generation += 1;
26647
+ this.off();
26648
+ this.listeners.clear();
26649
+ }
26650
+ queueRefresh() {
26651
+ if (this.disposed || this.refreshQueued) return;
26652
+ this.refreshQueued = true;
26653
+ queueMicrotask(() => {
26654
+ this.refreshQueued = false;
26655
+ if (this.disposed) return;
26656
+ void this.refresh();
26657
+ });
26658
+ }
26659
+ publish(snapshot) {
26660
+ this.snapshot = Object.freeze(snapshot);
26661
+ for (const listener of this.listeners) listener();
26662
+ }
26663
+ };
26664
+
25647
26665
  // src/dsh/index.ts
25648
26666
  var name = "dsh-console-runner";
25649
26667
  var inject = [
@@ -25659,11 +26677,13 @@ var inject = [
25659
26677
  "commands",
25660
26678
  "sessionProjections",
25661
26679
  "credentials",
25662
- "settings"
26680
+ "settings",
26681
+ "subagents"
25663
26682
  ];
25664
26683
  var Config2 = z2.object({
25665
26684
  prompt: z2.string(),
25666
- debug: z2.boolean().default(false)
26685
+ debug: z2.boolean().default(false),
26686
+ pokemon: z2.number()
25667
26687
  });
25668
26688
  var CLEANUP_TIMEOUT_MS = 1500;
25669
26689
  var FORCE_EXIT_TIMEOUT_MS = 2500;
@@ -25686,6 +26706,7 @@ async function start(ctx, config) {
25686
26706
  const appExit = ctx.get("appExit");
25687
26707
  const credentials = ctx.get("credentials");
25688
26708
  const settings = ctx.get("settings");
26709
+ const subagents = ctx.get("subagents");
25689
26710
  if (!attachments)
25690
26711
  throw new Error("dsh-console requires the DSH attachment service");
25691
26712
  if (!sessionQuery)
@@ -25702,10 +26723,14 @@ async function start(ctx, config) {
25702
26723
  throw new Error("dsh-console requires the DSH credentials service");
25703
26724
  if (!settings)
25704
26725
  throw new Error("dsh-console requires the DSH settings service");
26726
+ if (!subagents)
26727
+ throw new Error("dsh-console requires the DSH subagent service");
25705
26728
  if (!agents || !defaultModel || !sessions || !tools || !llm || !appExit)
25706
26729
  return;
25707
26730
  const selection = defaultModel.currentSelection();
25708
26731
  let activeSelection = selection;
26732
+ let sideSelection;
26733
+ const workspaceRef = {};
25709
26734
  const runtimeListeners = /* @__PURE__ */ new Set();
25710
26735
  const notifyRuntime = () => {
25711
26736
  for (const listener of runtimeListeners) listener();
@@ -25715,7 +26740,7 @@ async function start(ctx, config) {
25715
26740
  createAgent: (options) => agents.create(options),
25716
26741
  onSessionEvent: (listener) => ctx.on("session/event", listener)
25717
26742
  },
25718
- () => activeSelection
26743
+ () => workspaceRef.current?.getWorkspaceSnapshot().activeSurface === "side" ? sideSelection ?? activeSelection : activeSelection
25719
26744
  );
25720
26745
  const promptInputRuntime = new WorkspacePromptInputRuntime();
25721
26746
  const attachmentInput = new DshAttachmentInputAdapter(attachments);
@@ -25737,10 +26762,16 @@ async function start(ctx, config) {
25737
26762
  assembled: void 0
25738
26763
  };
25739
26764
  installModelSelection2(agentCtx, ref);
26765
+ if (options.restrictTools) agentCtx.tools.restrict({ allow: [] });
25740
26766
  };
25741
26767
  const handle = options.resumeSessionId === void 0 ? await agents.create({
25742
- sessionId: SessionId3(`dsh-console-${randomUUID3()}`),
25743
- meta: { cwd: process.cwd() },
26768
+ sessionId: options.sessionId ?? SessionId4(`dsh-console-${randomUUID3()}`),
26769
+ meta: {
26770
+ cwd: process.cwd(),
26771
+ ...options.parentSession === void 0 ? {} : { parentSession: options.parentSession },
26772
+ ...options.seed === void 0 ? {} : { seedLength: options.seed.length }
26773
+ },
26774
+ ...options.seed === void 0 ? {} : { seed: options.seed },
25744
26775
  agentOptions,
25745
26776
  setup,
25746
26777
  ...options.signal === void 0 ? {} : { signal: options.signal }
@@ -25774,8 +26805,15 @@ async function start(ctx, config) {
25774
26805
  }
25775
26806
  }
25776
26807
  );
25777
- const offProjector = projector.subscribe(notifyRuntime);
25778
- return { handle, projector, offSession, offProjector };
26808
+ const offProjector = options.publishRuntimeEvents === false ? () => {
26809
+ } : projector.subscribe(notifyRuntime);
26810
+ return {
26811
+ kind: "materialized",
26812
+ handle,
26813
+ projector,
26814
+ offSession,
26815
+ offProjector
26816
+ };
25779
26817
  } catch (error) {
25780
26818
  offSession?.();
25781
26819
  try {
@@ -25788,7 +26826,29 @@ async function start(ctx, config) {
25788
26826
  throw error;
25789
26827
  }
25790
26828
  };
25791
- let active = await createActiveConversation(selection);
26829
+ const createPendingConversation = async (selected, signal) => {
26830
+ const modelInfo = await llm.resolveModelInfo(
26831
+ selected.provider,
26832
+ selected.model,
26833
+ signal
26834
+ );
26835
+ signal?.throwIfAborted();
26836
+ const projector = new DshSessionProjector(
26837
+ `dsh-console-pending-${randomUUID3()}`,
26838
+ String(selected.model),
26839
+ new DshToolPresentationAdapter(tools),
26840
+ modelInfo.context?.contextWindow
26841
+ );
26842
+ return {
26843
+ kind: "pending",
26844
+ projector,
26845
+ offProjector: projector.subscribe(notifyRuntime)
26846
+ };
26847
+ };
26848
+ let active = await createPendingConversation(selection);
26849
+ let visibleSideAgent;
26850
+ const mainAgent = () => active.kind === "materialized" ? active.handle.agent : void 0;
26851
+ const currentInteractiveAgent = () => workspaceRef.current?.getWorkspaceSnapshot().activeSurface === "side" && visibleSideAgent ? visibleSideAgent : mainAgent();
25792
26852
  const providerSetupRuntime = await DshProviderSetupRuntime.create(
25793
26853
  credentials,
25794
26854
  settings,
@@ -25797,27 +26857,48 @@ async function start(ctx, config) {
25797
26857
  );
25798
26858
  const approvalRuntime = new DshApprovalRuntime(
25799
26859
  (listener) => ctx.on("approval/request", listener),
25800
- (agent) => agent === active.handle.agent
26860
+ (agent) => agent === mainAgent()
25801
26861
  );
25802
26862
  const userQuestionRuntime = new DshUserQuestionRuntime(
25803
26863
  userQuestions,
25804
- (agent) => agent === active.handle.agent
26864
+ (agent) => agent === mainAgent()
25805
26865
  );
25806
26866
  const commandRuntime = new DshCommandRuntimeAdapter(
25807
26867
  commands,
25808
- () => active.handle.agent,
26868
+ currentInteractiveAgent,
25809
26869
  (listener) => ctx.on("commands/change", listener)
25810
26870
  );
25811
26871
  const permissionSelectionRuntime = new DshPermissionSelectionRuntime(
25812
26872
  sessionProjections,
25813
26873
  commandRuntime,
25814
- () => active.handle.agent
26874
+ currentInteractiveAgent
25815
26875
  );
25816
26876
  const toolCatalogRuntime = new DshToolCatalogRuntime(
25817
26877
  tools,
25818
- () => active.handle.agent,
26878
+ currentInteractiveAgent,
25819
26879
  (listener) => ctx.on("tools/change", listener)
25820
26880
  );
26881
+ const subagentCatalogRuntime = new DshSubagentCatalogRuntime(
26882
+ subagents,
26883
+ () => mainAgent()?.session.id,
26884
+ (listener) => {
26885
+ const offStart = ctx.on("subagent/start", () => listener());
26886
+ const offEnd = ctx.on("subagent/end", () => listener());
26887
+ const offDescriptor = ctx.on("session/event", (_session, event) => {
26888
+ if (event.type === "subagent/descriptor") listener();
26889
+ });
26890
+ return () => {
26891
+ offStart();
26892
+ offEnd();
26893
+ offDescriptor();
26894
+ };
26895
+ },
26896
+ sessionQuery,
26897
+ new DshToolPresentationAdapter(tools),
26898
+ (sessionId, listener) => ctx.on("session/event", (session, event) => {
26899
+ if (session.id === sessionId) listener(event);
26900
+ })
26901
+ );
25821
26902
  let switchingConversation = false;
25822
26903
  const isConversationBusy = () => switchingConversation || active.projector.getSnapshot().busy || approvalRuntime.getSnapshot().pending.length > 0 || userQuestionRuntime.getSnapshot().pending.length > 0 || permissionSelectionRuntime.getSnapshot().busy;
25823
26904
  const switchActiveConversation = async (selected, options = {}) => {
@@ -25831,39 +26912,46 @@ async function start(ctx, config) {
25831
26912
  }
25832
26913
  switchingConversation = true;
25833
26914
  try {
25834
- const next = await createActiveConversation(selected, options);
26915
+ const next = options.resumeSessionId === void 0 ? await createPendingConversation(selected, options.signal) : await createActiveConversation(selected, options);
25835
26916
  const previous = active;
25836
- try {
25837
- const flushed = await sessions.flush(previous.handle.agent.session);
25838
- if (!flushed)
25839
- throw new Error("DSH Session persistence is unavailable.");
25840
- } catch (error) {
25841
- next.offSession();
25842
- next.offProjector();
26917
+ if (previous.kind === "materialized") {
25843
26918
  try {
25844
- await next.handle.dispose();
25845
- } catch (disposeError) {
25846
- debugLogger.debug(
25847
- `Unable to dispose an uncommitted DSH Agent candidate: ${String(disposeError)}`
25848
- );
26919
+ const flushed = await sessions.flush(previous.handle.agent.session);
26920
+ if (!flushed)
26921
+ throw new Error("DSH Session persistence is unavailable.");
26922
+ } catch (error) {
26923
+ next.offProjector();
26924
+ if (next.kind === "materialized") {
26925
+ next.offSession();
26926
+ try {
26927
+ await next.handle.dispose();
26928
+ } catch (disposeError) {
26929
+ debugLogger.debug(
26930
+ `Unable to dispose an uncommitted DSH Agent candidate: ${String(disposeError)}`
26931
+ );
26932
+ }
26933
+ }
26934
+ throw error;
25849
26935
  }
25850
- throw error;
25851
26936
  }
25852
- previous.offSession();
25853
26937
  previous.offProjector();
26938
+ if (previous.kind === "materialized") previous.offSession();
25854
26939
  active = next;
25855
26940
  activeSelection = selected;
25856
26941
  await providerSetupRuntime.refreshCurrent();
25857
26942
  commandRuntime.activeAgentChanged();
25858
26943
  permissionSelectionRuntime.activeAgentChanged();
25859
26944
  toolCatalogRuntime.activeAgentChanged();
26945
+ subagentCatalogRuntime.activeAgentChanged();
25860
26946
  notifyRuntime();
25861
- try {
25862
- await previous.handle.dispose();
25863
- } catch (error) {
25864
- debugLogger.debug(
25865
- `Unable to dispose the previous DSH Agent: ${String(error)}`
25866
- );
26947
+ if (previous.kind === "materialized") {
26948
+ try {
26949
+ await previous.handle.dispose();
26950
+ } catch (error) {
26951
+ debugLogger.debug(
26952
+ `Unable to dispose the previous DSH Agent: ${String(error)}`
26953
+ );
26954
+ }
25867
26955
  }
25868
26956
  } finally {
25869
26957
  switchingConversation = false;
@@ -25879,19 +26967,19 @@ async function start(ctx, config) {
25879
26967
  sessionQuery,
25880
26968
  llm,
25881
26969
  process.cwd(),
25882
- String(active.handle.agent.session.id),
26970
+ active.projector.getSessionStats().sessionId,
25883
26971
  {
25884
26972
  currentSelection: () => modelSelectionRuntime.getSnapshot().current,
25885
26973
  createFresh: async (selected, signal) => {
25886
26974
  await switchActiveConversation(selected, { signal });
25887
- return String(active.handle.agent.session.id);
26975
+ return active.projector.getSessionStats().sessionId;
25888
26976
  },
25889
26977
  resume: async (sessionId, selected, signal) => {
25890
26978
  await switchActiveConversation(selected, {
25891
26979
  resumeSessionId: sessionId,
25892
26980
  signal
25893
26981
  });
25894
- return String(active.handle.agent.session.id);
26982
+ return active.projector.getSessionStats().sessionId;
25895
26983
  },
25896
26984
  adoptCurrentModel: (selected) => modelSelectionRuntime.adoptCurrent(selected),
25897
26985
  hasConversation: () => active.projector.getSnapshot().messages.length > 0,
@@ -25900,37 +26988,74 @@ async function start(ctx, config) {
25900
26988
  );
25901
26989
  let disposed = false;
25902
26990
  let exiting = false;
26991
+ let offWorkspaceSurface = () => {
26992
+ };
25903
26993
  const cleanup = async () => {
25904
26994
  if (disposed) return;
25905
26995
  disposed = true;
25906
- active.offSession();
26996
+ offWorkspaceSurface();
25907
26997
  active.offProjector();
26998
+ if (active.kind === "materialized") active.offSession();
25908
26999
  await Promise.all([
25909
- active.handle.dispose(),
27000
+ active.kind === "materialized" ? active.handle.dispose() : Promise.resolve(),
25910
27001
  promptCompletionRuntime.dispose(),
27002
+ workspaceRef.current?.dispose(),
25911
27003
  promptInputRuntime.dispose(),
25912
27004
  Promise.resolve(approvalRuntime.dispose()),
25913
27005
  Promise.resolve(userQuestionRuntime.dispose()),
25914
27006
  Promise.resolve(commandRuntime.dispose()),
25915
27007
  Promise.resolve(permissionSelectionRuntime.dispose()),
25916
- Promise.resolve(toolCatalogRuntime.dispose())
27008
+ Promise.resolve(toolCatalogRuntime.dispose()),
27009
+ Promise.resolve(subagentCatalogRuntime.dispose())
25917
27010
  ]);
25918
27011
  };
25919
- const submit = async ({
25920
- content,
25921
- displayContent,
25922
- signal
25923
- }) => {
25924
- const conversation = active;
25925
- if (conversation.projector.getSnapshot().busy) return;
27012
+ const materializeActiveConversation = async (signal) => {
27013
+ if (active.kind === "materialized") return active;
27014
+ if (switchingConversation) {
27015
+ throw new Error("Another Agent change is already in progress.");
27016
+ }
27017
+ switchingConversation = true;
27018
+ const previous = active;
27019
+ let next;
27020
+ try {
27021
+ next = await createActiveConversation(activeSelection, { signal });
27022
+ signal.throwIfAborted();
27023
+ previous.offProjector();
27024
+ active = next;
27025
+ commandRuntime.activeAgentChanged();
27026
+ permissionSelectionRuntime.activeAgentChanged();
27027
+ toolCatalogRuntime.activeAgentChanged();
27028
+ subagentCatalogRuntime.activeAgentChanged();
27029
+ notifyRuntime();
27030
+ return next;
27031
+ } catch (error) {
27032
+ if (next !== void 0 && active !== next) {
27033
+ next.offSession();
27034
+ next.offProjector();
27035
+ await next.handle.dispose().catch((disposeError) => {
27036
+ debugLogger.debug(
27037
+ `Unable to dispose an aborted DSH Agent candidate: ${String(disposeError)}`
27038
+ );
27039
+ });
27040
+ }
27041
+ throw error;
27042
+ } finally {
27043
+ switchingConversation = false;
27044
+ }
27045
+ };
27046
+ const prepareSubmission = async ({ content, displayContent, signal }, allowImages) => {
25926
27047
  if (content.some((part) => part.type === "image-source")) {
27048
+ if (!allowImages) {
27049
+ throw new Error(
27050
+ "Side conversations currently support text input only."
27051
+ );
27052
+ }
25927
27053
  await modelSelectionRuntime.assertCurrentSupportsImages(signal);
25928
27054
  }
25929
- const ingested = await attachmentInput.ingest(
25930
- content,
25931
- displayContent,
25932
- signal
25933
- );
27055
+ return attachmentInput.ingest(content, displayContent, signal);
27056
+ };
27057
+ const submitToConversation = async (conversation, ingested, signal) => {
27058
+ if (conversation.projector.getSnapshot().busy) return;
25934
27059
  signal.throwIfAborted();
25935
27060
  conversation.projector.addUser(
25936
27061
  projectDshContent(ingested.content),
@@ -25970,23 +27095,114 @@ async function start(ctx, config) {
25970
27095
  });
25971
27096
  void Promise.race([runExitCleanup(), cleanupTimeout]).then(cleanup).finally(() => appExit(0));
25972
27097
  };
25973
- const conversationRuntime = {
27098
+ const mainConversationRuntime = {
25974
27099
  getSnapshot: () => active.projector.getSnapshot(),
25975
27100
  getSessionStats: () => active.projector.getSessionStats(),
25976
27101
  subscribe: (listener) => {
25977
27102
  runtimeListeners.add(listener);
25978
27103
  return () => runtimeListeners.delete(listener);
25979
27104
  },
25980
- submit,
27105
+ submit: async (submission) => {
27106
+ const ingested = await prepareSubmission(submission, true);
27107
+ const conversation = await materializeActiveConversation(submission.signal);
27108
+ await submitToConversation(conversation, ingested, submission.signal);
27109
+ },
25981
27110
  cancel: () => {
25982
- active.handle.agent.cancel({ kind: "user" });
25983
- active.projector.cancel();
27111
+ if (active.kind === "materialized") {
27112
+ active.handle.agent.cancel({ kind: "user" });
27113
+ active.projector.cancel();
27114
+ }
25984
27115
  },
25985
27116
  exit
25986
27117
  };
27118
+ const conversationWorkspace = new ConversationWorkspaceRuntime(
27119
+ mainConversationRuntime,
27120
+ async (signal) => {
27121
+ if (active.kind !== "materialized") {
27122
+ throw new Error("Start the main conversation before opening a Side conversation.");
27123
+ }
27124
+ const parent = active.handle.agent;
27125
+ const parentEvents = parent.session.events;
27126
+ const seed = completedTurnSeed(parentEvents);
27127
+ const pendingRequest = pendingUserText(parentEvents, seed.length);
27128
+ const selected = activeSelection;
27129
+ const selectedView = modelSelectionRuntime.getSnapshot().current;
27130
+ const side = await createActiveConversation(selected, {
27131
+ signal,
27132
+ sessionId: SessionId4(`${SIDE_SESSION_PREFIX}${randomUUID3()}`),
27133
+ parentSession: parent.session.id,
27134
+ seed,
27135
+ restrictTools: true,
27136
+ publishRuntimeEvents: false
27137
+ });
27138
+ sideSelection = selected;
27139
+ visibleSideAgent = side.handle.agent;
27140
+ let firstSubmission = true;
27141
+ let sideDisposed = false;
27142
+ const handle = {
27143
+ parentSessionId: String(parent.session.id),
27144
+ modelLabel: modelSelectionLabel(selectedView),
27145
+ ...modelReasoningEffortLabel(selectedView) === void 0 ? {} : {
27146
+ reasoningEffortLabel: modelReasoningEffortLabel(selectedView)
27147
+ },
27148
+ getSnapshot: side.projector.getSnapshot,
27149
+ getSessionStats: side.projector.getSessionStats,
27150
+ subscribe: side.projector.subscribe,
27151
+ submit: async (submission) => {
27152
+ let prefixedFirstText = false;
27153
+ const prepared = firstSubmission ? {
27154
+ ...submission,
27155
+ content: submission.content.map((part) => {
27156
+ if (prefixedFirstText || part.type !== "text") return part;
27157
+ prefixedFirstText = true;
27158
+ return {
27159
+ ...part,
27160
+ text: firstSidePrompt(part.text, pendingRequest)
27161
+ };
27162
+ })
27163
+ } : submission;
27164
+ const ingested = await prepareSubmission(prepared, false);
27165
+ await submitToConversation(side, ingested, prepared.signal);
27166
+ firstSubmission = false;
27167
+ },
27168
+ cancel: () => {
27169
+ side.handle.agent.cancel({ kind: "user" });
27170
+ side.projector.cancel();
27171
+ },
27172
+ exit: () => {
27173
+ },
27174
+ dispose: async () => {
27175
+ if (sideDisposed) return;
27176
+ sideDisposed = true;
27177
+ if (side.projector.getSnapshot().busy) {
27178
+ side.handle.agent.cancel({ kind: "user" });
27179
+ await side.handle.agent.whenIdle();
27180
+ }
27181
+ await sessions.flush(side.handle.agent.session).catch((error) => {
27182
+ debugLogger.debug(
27183
+ `Unable to flush Side Session: ${String(error)}`
27184
+ );
27185
+ });
27186
+ side.offSession();
27187
+ side.offProjector();
27188
+ await side.handle.dispose();
27189
+ if (visibleSideAgent === side.handle.agent)
27190
+ visibleSideAgent = void 0;
27191
+ if (sideSelection === selected) sideSelection = void 0;
27192
+ }
27193
+ };
27194
+ return handle;
27195
+ }
27196
+ );
27197
+ workspaceRef.current = conversationWorkspace;
27198
+ offWorkspaceSurface = conversationWorkspace.subscribeSurface(() => {
27199
+ commandRuntime.activeAgentChanged();
27200
+ permissionSelectionRuntime.activeAgentChanged();
27201
+ toolCatalogRuntime.activeAgentChanged();
27202
+ });
25987
27203
  ctx.effect(() => cleanup, "dsh-console: terminal");
25988
27204
  await main({
25989
- conversationRuntime,
27205
+ conversationRuntime: conversationWorkspace,
25990
27206
  promptCompletionRuntime,
25991
27207
  promptInputRuntime,
25992
27208
  modelSelectionRuntime,
@@ -25997,8 +27213,13 @@ async function start(ctx, config) {
25997
27213
  commandRuntime,
25998
27214
  permissionSelectionRuntime,
25999
27215
  toolCatalogRuntime,
27216
+ subagentCatalogRuntime,
27217
+ sideConversationRuntime: conversationWorkspace,
26000
27218
  initialPrompt: config.prompt?.trim(),
26001
- argv: config.debug ? ["--debug"] : []
27219
+ argv: [
27220
+ ...config.debug ? ["--debug"] : [],
27221
+ ...config.pokemon === void 0 ? [] : ["--pokemon", String(config.pokemon)]
27222
+ ]
26002
27223
  });
26003
27224
  }
26004
27225
  function apply(ctx, config) {