@cofy-x/dsh-console 0.1.0-alpha.13 → 0.1.0-alpha.14

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.
@@ -67,7 +67,7 @@ import {
67
67
  unescapePath,
68
68
  writeToStderr,
69
69
  writeToStdout
70
- } from "./chunk-3WB6AZUB.js";
70
+ } from "./chunk-GNENCGXA.js";
71
71
 
72
72
  // src/dsh/index.ts
73
73
  import { randomUUID as randomUUID3 } from "node:crypto";
@@ -2377,7 +2377,7 @@ function setWindowTitle(title, settings) {
2377
2377
  const windowTitle = computeTerminalTitle({
2378
2378
  streamingState: "idle" /* Idle */,
2379
2379
  isConfirming: false,
2380
- isSilentWorking: false,
2380
+ isSilentWorking: true,
2381
2381
  folderName: title,
2382
2382
  useDynamicTitle: settings.merged.ui.dynamicWindowTitle
2383
2383
  });
@@ -2437,13 +2437,13 @@ function computeTerminalTitle({
2437
2437
 
2438
2438
  // src/ui/app-container.tsx
2439
2439
  import {
2440
- useMemo as useMemo40,
2441
- useState as useState56,
2442
- useCallback as useCallback50,
2443
- useEffect as useEffect55,
2440
+ useMemo as useMemo42,
2441
+ useState as useState59,
2442
+ useCallback as useCallback51,
2443
+ useEffect as useEffect56,
2444
2444
  useRef as useRef34,
2445
2445
  useLayoutEffect as useLayoutEffect5,
2446
- useSyncExternalStore as useSyncExternalStore6
2446
+ useSyncExternalStore as useSyncExternalStore8
2447
2447
  } from "react";
2448
2448
  import { measureElement as measureElement3, useApp } from "ink";
2449
2449
 
@@ -4195,7 +4195,7 @@ var ErrorMessage = ({ text }) => {
4195
4195
  };
4196
4196
 
4197
4197
  // src/ui/components/messages/tool-group-message.tsx
4198
- import { useCallback as useCallback7, useMemo as useMemo5, useState as useState7 } from "react";
4198
+ import { useCallback as useCallback7, useMemo as useMemo5, useState as useState8 } from "react";
4199
4199
  import { Box as Box19, Text as Text19 } from "ink";
4200
4200
 
4201
4201
  // src/ui/components/messages/tool-message.tsx
@@ -5182,7 +5182,8 @@ import {
5182
5182
  useCallback as useCallback5,
5183
5183
  useContext as useContext6,
5184
5184
  useEffect as useEffect8,
5185
- useRef as useRef4
5185
+ useRef as useRef4,
5186
+ useState as useState7
5186
5187
  } from "react";
5187
5188
 
5188
5189
  // src/ui/hooks/terminal/use-focus.ts
@@ -5193,7 +5194,7 @@ var DISABLE_FOCUS_REPORTING = "\x1B[?1004l";
5193
5194
  var FOCUS_IN = "\x1B[I";
5194
5195
  var FOCUS_OUT = "\x1B[O";
5195
5196
  var useFocus = () => {
5196
- const { stdin } = useStdin();
5197
+ const { internal_eventEmitter } = useStdin();
5197
5198
  const { stdout } = useStdout();
5198
5199
  const [isFocused, setIsFocused] = useState6(true);
5199
5200
  useEffect7(() => {
@@ -5208,12 +5209,12 @@ var useFocus = () => {
5208
5209
  }
5209
5210
  };
5210
5211
  stdout?.write(ENABLE_FOCUS_REPORTING);
5211
- stdin?.on("data", handleData);
5212
+ internal_eventEmitter.on("input", handleData);
5212
5213
  return () => {
5213
5214
  stdout?.write(DISABLE_FOCUS_REPORTING);
5214
- stdin?.removeListener("data", handleData);
5215
+ internal_eventEmitter.removeListener("input", handleData);
5215
5216
  };
5216
- }, [stdin, stdout]);
5217
+ }, [internal_eventEmitter, stdout]);
5217
5218
  useKeypress(
5218
5219
  (_) => {
5219
5220
  if (!isFocused) {
@@ -5712,7 +5713,9 @@ function KeypressProvider({
5712
5713
  config,
5713
5714
  debugKeystrokeLogging
5714
5715
  }) {
5715
- const { stdin, setRawMode } = useStdin2();
5716
+ const { stdin, setRawMode, internal_eventEmitter } = useStdin2();
5717
+ const [isStdinReady, setIsStdinReady] = useState7(false);
5718
+ const [inputSubscriberCount, setInputSubscriberCount] = useState7(0);
5716
5719
  const subscribers = useRef4(/* @__PURE__ */ new Set()).current;
5717
5720
  const subscribe = useCallback5(
5718
5721
  (handler) => subscribers.add(handler),
@@ -5722,6 +5725,12 @@ function KeypressProvider({
5722
5725
  (handler) => subscribers.delete(handler),
5723
5726
  [subscribers]
5724
5727
  );
5728
+ const registerInputSubscriber = useCallback5(() => {
5729
+ setInputSubscriberCount((count) => count + 1);
5730
+ return () => {
5731
+ setInputSubscriberCount((count) => Math.max(0, count - 1));
5732
+ };
5733
+ }, []);
5725
5734
  const broadcast = useCallback5(
5726
5735
  (key) => {
5727
5736
  if (debugKeystrokeLogging) {
@@ -5737,11 +5746,7 @@ function KeypressProvider({
5737
5746
  [debugKeystrokeLogging, subscribers]
5738
5747
  );
5739
5748
  useEffect8(() => {
5740
- const wasRaw = stdin.isRaw;
5741
- if (wasRaw === false) {
5742
- setRawMode(true);
5743
- }
5744
- process.stdin.setEncoding("utf8");
5749
+ setRawMode(true);
5745
5750
  let processor = nonKeyboardEventFilter(broadcast);
5746
5751
  if (!terminalCapabilityManager.isKittyProtocolEnabled()) {
5747
5752
  processor = bufferFastReturn(processor);
@@ -5760,35 +5765,56 @@ function KeypressProvider({
5760
5765
  forward(data);
5761
5766
  };
5762
5767
  }
5763
- stdin.on("data", dataListener);
5768
+ internal_eventEmitter.on("input", dataListener);
5769
+ setIsStdinReady(true);
5764
5770
  return () => {
5765
- stdin.removeListener("data", dataListener);
5766
- if (wasRaw === false) {
5767
- setRawMode(false);
5768
- }
5771
+ setIsStdinReady(false);
5772
+ internal_eventEmitter.removeListener("input", dataListener);
5773
+ setRawMode(false);
5769
5774
  };
5770
5775
  }, [
5771
5776
  stdin,
5772
5777
  setRawMode,
5778
+ internal_eventEmitter,
5773
5779
  config,
5774
5780
  debugKeystrokeLogging,
5775
5781
  broadcast
5776
5782
  ]);
5777
- return /* @__PURE__ */ jsx23(KeypressContext.Provider, { value: { subscribe, unsubscribe }, children });
5783
+ return /* @__PURE__ */ jsx23(
5784
+ KeypressContext.Provider,
5785
+ {
5786
+ value: {
5787
+ isReady: isStdinReady && inputSubscriberCount > 0,
5788
+ registerInputSubscriber,
5789
+ subscribe,
5790
+ unsubscribe
5791
+ },
5792
+ children
5793
+ }
5794
+ );
5778
5795
  }
5779
5796
 
5780
5797
  // src/ui/hooks/input/use-keypress.ts
5781
- function useKeypress(onKeypress, { isActive }) {
5782
- const { subscribe, unsubscribe } = useKeypressContext();
5798
+ function useKeypress(onKeypress, { isActive, isInput = false }) {
5799
+ const { registerInputSubscriber, subscribe, unsubscribe } = useKeypressContext();
5783
5800
  useEffect9(() => {
5784
5801
  if (!isActive) {
5785
5802
  return;
5786
5803
  }
5787
5804
  subscribe(onKeypress);
5805
+ const unregisterInputSubscriber = isInput ? registerInputSubscriber() : void 0;
5788
5806
  return () => {
5789
5807
  unsubscribe(onKeypress);
5808
+ unregisterInputSubscriber?.();
5790
5809
  };
5791
- }, [isActive, onKeypress, subscribe, unsubscribe]);
5810
+ }, [
5811
+ isActive,
5812
+ isInput,
5813
+ onKeypress,
5814
+ registerInputSubscriber,
5815
+ subscribe,
5816
+ unsubscribe
5817
+ ]);
5792
5818
  }
5793
5819
 
5794
5820
  // src/terminal/keys.ts
@@ -6217,7 +6243,7 @@ var ToolGroupMessage = ({
6217
6243
  );
6218
6244
  const config = useConfig();
6219
6245
  const visibleToolCalls = useMemo5(() => toolCalls.filter((t) => t.status !== "Pending" /* Pending */), [toolCalls]);
6220
- const [expandedCallIds, setExpandedCallIds] = useState7(
6246
+ const [expandedCallIds, setExpandedCallIds] = useState8(
6221
6247
  () => /* @__PURE__ */ new Set()
6222
6248
  );
6223
6249
  const resultWidth = Math.max(1, terminalWidth - 4);
@@ -6402,7 +6428,7 @@ import { Box as Box25 } from "ink";
6402
6428
  import { Box as Box21, Text as Text21 } from "ink";
6403
6429
 
6404
6430
  // src/generated/git-commit.ts
6405
- var GIT_COMMIT_INFO = "d287de5";
6431
+ var GIT_COMMIT_INFO = "2d435aa";
6406
6432
 
6407
6433
  // src/ui/components/dialogs/about-box.tsx
6408
6434
  import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
@@ -6474,7 +6500,7 @@ import {
6474
6500
  useContext as useContext8,
6475
6501
  useEffect as useEffect10,
6476
6502
  useMemo as useMemo6,
6477
- useState as useState8
6503
+ useState as useState9
6478
6504
  } from "react";
6479
6505
  import { jsx as jsx30 } from "react/jsx-runtime";
6480
6506
  var SessionStatsContext = createContext7(
@@ -6482,7 +6508,7 @@ var SessionStatsContext = createContext7(
6482
6508
  );
6483
6509
  var SessionStatsProvider = ({ children, conversationRuntime }) => {
6484
6510
  const initial = conversationRuntime.getSessionStats();
6485
- const [stats, setStats] = useState8({
6511
+ const [stats, setStats] = useState9({
6486
6512
  ...initial,
6487
6513
  sessionStartTime: /* @__PURE__ */ new Date(),
6488
6514
  promptCount: 0
@@ -6587,9 +6613,9 @@ var computeSessionStats = (metrics) => {
6587
6613
  };
6588
6614
 
6589
6615
  // src/ui/hooks/terminal/use-terminal-size.ts
6590
- import { useEffect as useEffect11, useState as useState9 } from "react";
6616
+ import { useEffect as useEffect11, useState as useState10 } from "react";
6591
6617
  function useTerminalSize() {
6592
- const [size, setSize] = useState9({
6618
+ const [size, setSize] = useState10({
6593
6619
  columns: process.stdout.columns || 60,
6594
6620
  rows: process.stdout.rows || 20
6595
6621
  });
@@ -7044,7 +7070,7 @@ import { Box as Box66 } from "ink";
7044
7070
 
7045
7071
  // src/ui/components/indicators/notifications.tsx
7046
7072
  import { Box as Box27, Text as Text26, useIsScreenReaderEnabled as useIsScreenReaderEnabled3 } from "ink";
7047
- import { useEffect as useEffect12, useState as useState10 } from "react";
7073
+ import { useEffect as useEffect12, useState as useState11 } from "react";
7048
7074
 
7049
7075
  // src/ui/contexts/app-context.tsx
7050
7076
  import { createContext as createContext8, useContext as useContext9 } from "react";
@@ -7127,7 +7153,7 @@ var Notifications = () => {
7127
7153
  const isScreenReaderEnabled = useIsScreenReaderEnabled3();
7128
7154
  const showStartupWarnings = startupWarnings.length > 0;
7129
7155
  const showInitError = initError && streamingState !== "responding" /* Responding */;
7130
- const [hasSeenScreenReaderNudge] = useState10(
7156
+ const [hasSeenScreenReaderNudge] = useState11(
7131
7157
  () => persistentState.get("hasSeenScreenReaderNudge") ?? false
7132
7158
  );
7133
7159
  const showScreenReaderNudge = isScreenReaderEnabled && hasSeenScreenReaderNudge === false;
@@ -7215,7 +7241,7 @@ var compactDshLogo = `\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2
7215
7241
  var tinyDshLogo = "DSH CONSOLE";
7216
7242
 
7217
7243
  // src/ui/hooks/visual/use-snow-fall.ts
7218
- import { useState as useState11, useEffect as useEffect13, useMemo as useMemo8 } from "react";
7244
+ import { useState as useState12, useEffect as useEffect13, useMemo as useMemo8 } from "react";
7219
7245
  var SNOW_CHARS = ["*", ".", "\xB7", "+"];
7220
7246
  var FRAME_RATE = 150;
7221
7247
  var addHolidayTrees = (art) => {
@@ -7257,7 +7283,7 @@ var useSnowfall = (displayTitle, terminalWidth) => {
7257
7283
  );
7258
7284
  const displayTitleWidth = getAsciiArtWidth(displayTitle);
7259
7285
  const containsAnsi = displayTitle.includes("\x1B");
7260
- const [showSnow, setShowSnow] = useState11(true);
7286
+ const [showSnow, setShowSnow] = useState12(true);
7261
7287
  useEffect13(() => {
7262
7288
  setShowSnow(true);
7263
7289
  const timer = setTimeout(() => {
@@ -7272,7 +7298,7 @@ var useSnowfall = (displayTitle, terminalWidth) => {
7272
7298
  }
7273
7299
  return displayTitle;
7274
7300
  }, [displayTitle, showAnimation]);
7275
- const [snowflakes, setSnowflakes] = useState11([]);
7301
+ const [snowflakes, setSnowflakes] = useState12([]);
7276
7302
  const lines = displayArt.split("\n");
7277
7303
  const height = lines.length;
7278
7304
  const width = getAsciiArtWidth(displayArt);
@@ -7324,13 +7350,13 @@ import { useRef as useRef6 } from "react";
7324
7350
 
7325
7351
  // src/ui/hooks/use-mouse-hover.ts
7326
7352
  import { getBoundingBox as getBoundingBox2 } from "ink";
7327
- import { useCallback as useCallback9, useLayoutEffect as useLayoutEffect3, useRef as useRef5, useState as useState12 } from "react";
7353
+ import { useCallback as useCallback9, useLayoutEffect as useLayoutEffect3, useRef as useRef5, useState as useState13 } from "react";
7328
7354
  function useMouseHover(ref, {
7329
7355
  isActive = true,
7330
7356
  priority = MOUSE_EVENT_PRIORITY.interactive,
7331
7357
  onHoverChange
7332
7358
  } = {}) {
7333
- const [hovered, setHovered] = useState12(false);
7359
+ const [hovered, setHovered] = useState13(false);
7334
7360
  const hoveredRef = useRef5(false);
7335
7361
  const onHoverChangeRef = useRef5(onHoverChange);
7336
7362
  onHoverChangeRef.current = onHoverChange;
@@ -7442,7 +7468,7 @@ var VerticalHeader = ({
7442
7468
  };
7443
7469
 
7444
7470
  // src/ui/components/layout/horizontal-header.tsx
7445
- import { useCallback as useCallback10, useMemo as useMemo9, useState as useState13 } from "react";
7471
+ import { useCallback as useCallback10, useMemo as useMemo9, useState as useState14 } from "react";
7446
7472
  import { Box as Box32, Text as Text30 } from "ink";
7447
7473
 
7448
7474
  // src/ui/components/layout/resources/quotes.ts
@@ -7592,7 +7618,7 @@ var HorizontalHeader = ({
7592
7618
  () => Math.floor(Math.random() * QUOTES.length),
7593
7619
  []
7594
7620
  );
7595
- const [quoteRevision, setQuoteRevision] = useState13(0);
7621
+ const [quoteRevision, setQuoteRevision] = useState14(0);
7596
7622
  const randomQuote = QUOTES[(initialQuoteIndex + quoteRevision) % QUOTES.length];
7597
7623
  const handleShufflePokemon = useCallback10(() => {
7598
7624
  setQuoteRevision((revision) => revision + 1);
@@ -7761,7 +7787,7 @@ var Header = ({
7761
7787
  };
7762
7788
 
7763
7789
  // src/ui/components/layout/app-header.tsx
7764
- import { useCallback as useCallback11, useEffect as useEffect14, useMemo as useMemo11, useRef as useRef7, useState as useState14 } from "react";
7790
+ import { useCallback as useCallback11, useEffect as useEffect14, useMemo as useMemo11, useRef as useRef7, useState as useState15 } from "react";
7765
7791
  import { jsx as jsx45 } from "react/jsx-runtime";
7766
7792
  var AppHeader = ({
7767
7793
  version,
@@ -7775,7 +7801,7 @@ var AppHeader = ({
7775
7801
  const artResourcesPath = settings.merged.ui.header.artResourcesPath;
7776
7802
  const customAsciiArtPath = settings.merged.ui.header.customAsciiArtPath;
7777
7803
  const pokemonNumber = config.getPokemonNumber();
7778
- const [artRevision, setArtRevision] = useState14(0);
7804
+ const [artRevision, setArtRevision] = useState15(0);
7779
7805
  const previousHeaderArtIdRef = useRef7(void 0);
7780
7806
  const customAsciiArt = useMemo11(() => {
7781
7807
  if (pokemonNumber === void 0 && customAsciiArtPath) {
@@ -7829,7 +7855,7 @@ var AppHeader = ({
7829
7855
 
7830
7856
  // src/ui/components/shared/virtualized-list.tsx
7831
7857
  import {
7832
- useState as useState15,
7858
+ useState as useState16,
7833
7859
  useRef as useRef9,
7834
7860
  useLayoutEffect as useLayoutEffect4,
7835
7861
  forwardRef,
@@ -7883,7 +7909,7 @@ function VirtualizedList(props, ref) {
7883
7909
  useEffect16(() => {
7884
7910
  dataRef.current = data;
7885
7911
  }, [data]);
7886
- const [scrollAnchor, setScrollAnchor] = useState15(() => {
7912
+ const [scrollAnchor, setScrollAnchor] = useState16(() => {
7887
7913
  const scrollToEnd = initialScrollIndex === SCROLL_TO_ITEM_END || typeof initialScrollIndex === "number" && initialScrollIndex >= data.length - 1 && initialScrollOffsetInIndex === SCROLL_TO_ITEM_END;
7888
7914
  if (scrollToEnd) {
7889
7915
  return {
@@ -7899,14 +7925,14 @@ function VirtualizedList(props, ref) {
7899
7925
  }
7900
7926
  return { index: 0, offset: 0 };
7901
7927
  });
7902
- const [isStickingToBottom, setIsStickingToBottom] = useState15(() => {
7928
+ const [isStickingToBottom, setIsStickingToBottom] = useState16(() => {
7903
7929
  const scrollToEnd = initialScrollIndex === SCROLL_TO_ITEM_END || typeof initialScrollIndex === "number" && initialScrollIndex >= data.length - 1 && initialScrollOffsetInIndex === SCROLL_TO_ITEM_END;
7904
7930
  return scrollToEnd;
7905
7931
  });
7906
7932
  const containerRef = useRef9(null);
7907
- const [containerHeight, setContainerHeight] = useState15(0);
7933
+ const [containerHeight, setContainerHeight] = useState16(0);
7908
7934
  const itemRefs = useRef9([]);
7909
- const [heights, setHeights] = useState15([]);
7935
+ const [heights, setHeights] = useState16([]);
7910
7936
  const isInitialScrollSet = useRef9(false);
7911
7937
  const { totalHeight, offsets } = useMemo12(() => {
7912
7938
  const offsets2 = [0];
@@ -8224,7 +8250,7 @@ import {
8224
8250
  useEffect as useEffect18,
8225
8251
  useMemo as useMemo13,
8226
8252
  useRef as useRef10,
8227
- useState as useState16
8253
+ useState as useState17
8228
8254
  } from "react";
8229
8255
  import { getBoundingBox as getBoundingBox3 } from "ink";
8230
8256
 
@@ -8271,7 +8297,7 @@ var findScrollableCandidates = (mouseEvent, scrollables) => {
8271
8297
  var ScrollProvider = ({
8272
8298
  children
8273
8299
  }) => {
8274
- const [scrollables, setScrollables] = useState16(
8300
+ const [scrollables, setScrollables] = useState17(
8275
8301
  /* @__PURE__ */ new Map()
8276
8302
  );
8277
8303
  const register = useCallback14((entry) => {
@@ -8474,7 +8500,7 @@ var useScrollable = (entry, isActive) => {
8474
8500
  if (!context) {
8475
8501
  throw new Error("useScrollable must be used within a ScrollProvider");
8476
8502
  }
8477
- const [id] = useState16(() => `scrollable-${nextId++}`);
8503
+ const [id] = useState17(() => `scrollable-${nextId++}`);
8478
8504
  useEffect18(() => {
8479
8505
  if (isActive) {
8480
8506
  context.register({ ...entry, id });
@@ -8490,9 +8516,9 @@ var useScrollable = (entry, isActive) => {
8490
8516
  import { Box as Box37 } from "ink";
8491
8517
 
8492
8518
  // src/ui/hooks/visual/use-animated-scrollbar.ts
8493
- import { useState as useState17, useEffect as useEffect19, useRef as useRef11, useCallback as useCallback15 } from "react";
8519
+ import { useState as useState18, useEffect as useEffect19, useRef as useRef11, useCallback as useCallback15 } from "react";
8494
8520
  function useAnimatedScrollbar(isFocused, scrollBy) {
8495
- const [scrollbarColor, setScrollbarColor] = useState17(theme.ui.dark);
8521
+ const [scrollbarColor, setScrollbarColor] = useState18(theme.ui.dark);
8496
8522
  const colorRef = useRef11(scrollbarColor);
8497
8523
  colorRef.current = scrollbarColor;
8498
8524
  const animationFrame = useRef11(null);
@@ -9151,7 +9177,7 @@ import "react";
9151
9177
  import { Text as Text33 } from "ink";
9152
9178
 
9153
9179
  // src/ui/components/shared/base-selection-list.tsx
9154
- import { useEffect as useEffect22, useState as useState18 } from "react";
9180
+ import { useEffect as useEffect22, useState as useState19 } from "react";
9155
9181
  import { Text as Text32, Box as Box39 } from "ink";
9156
9182
 
9157
9183
  // src/ui/hooks/input/use-selection-list.ts
@@ -9472,7 +9498,7 @@ function BaseSelectionList({
9472
9498
  wrapAround,
9473
9499
  focusKey
9474
9500
  });
9475
- const [scrollOffset, setScrollOffset] = useState18(0);
9501
+ const [scrollOffset, setScrollOffset] = useState19(0);
9476
9502
  useEffect22(() => {
9477
9503
  const newScrollOffset = Math.max(
9478
9504
  0,
@@ -9639,7 +9665,7 @@ var ConsentPrompt = (props) => {
9639
9665
  };
9640
9666
 
9641
9667
  // src/ui/components/dialogs/theme-dialog.tsx
9642
- import { useCallback as useCallback19, useState as useState19 } from "react";
9668
+ import { useCallback as useCallback19, useState as useState20 } from "react";
9643
9669
  import { Box as Box41, Text as Text34 } from "ink";
9644
9670
  import { jsx as jsx53, jsxs as jsxs37 } from "react/jsx-runtime";
9645
9671
  function generateThemeItem(name2, typeDisplay, themeType, themeBackground, terminalBackgroundColor, terminalThemeType) {
@@ -9667,7 +9693,7 @@ function ThemeDialog({
9667
9693
  const isAlternateBuffer = useAlternateBuffer();
9668
9694
  const { refreshStatic } = useUIActions();
9669
9695
  const { terminalBackgroundColor } = useUIState();
9670
- const [highlightedThemeName, setHighlightedThemeName] = useState19(
9696
+ const [highlightedThemeName, setHighlightedThemeName] = useState20(
9671
9697
  () => {
9672
9698
  if (settings.merged.ui.theme) {
9673
9699
  return settings.merged.ui.theme;
@@ -9876,7 +9902,7 @@ def fibonacci(n):
9876
9902
  }
9877
9903
 
9878
9904
  // src/ui/components/dialogs/settings-dialog.tsx
9879
- import { useState as useState23, useEffect as useEffect26, useMemo as useMemo17, useCallback as useCallback24 } from "react";
9905
+ import { useState as useState24, useEffect as useEffect26, useMemo as useMemo17, useCallback as useCallback24 } from "react";
9880
9906
  import { Text as Text37 } from "ink";
9881
9907
  import { AsyncFzf } from "fzf";
9882
9908
 
@@ -10033,7 +10059,7 @@ import {
10033
10059
  useCallback as useCallback20,
10034
10060
  useContext as useContext11,
10035
10061
  useEffect as useEffect23,
10036
- useState as useState20
10062
+ useState as useState21
10037
10063
  } from "react";
10038
10064
  import { jsx as jsx54 } from "react/jsx-runtime";
10039
10065
  var VimModeContext = createContext10(void 0);
@@ -10042,8 +10068,8 @@ var VimModeProvider = ({
10042
10068
  settings
10043
10069
  }) => {
10044
10070
  const initialVimEnabled = settings.merged.general.vimMode;
10045
- const [vimEnabled, setVimEnabled] = useState20(initialVimEnabled);
10046
- const [vimMode, setVimMode] = useState20(
10071
+ const [vimEnabled, setVimEnabled] = useState21(initialVimEnabled);
10072
+ const [vimMode, setVimMode] = useState21(
10047
10073
  initialVimEnabled ? "NORMAL" : "INSERT"
10048
10074
  );
10049
10075
  useEffect23(() => {
@@ -10083,7 +10109,7 @@ import { spawnSync } from "node:child_process";
10083
10109
  import fs7 from "node:fs";
10084
10110
  import os2 from "node:os";
10085
10111
  import pathMod from "node:path";
10086
- import { useState as useState21, useCallback as useCallback21, useEffect as useEffect24, useMemo as useMemo16, useReducer as useReducer2 } from "react";
10112
+ import { useState as useState22, useCallback as useCallback21, useEffect as useEffect24, useMemo as useMemo16, useReducer as useReducer2 } from "react";
10087
10113
 
10088
10114
  // src/terminal/clipboard/parser.ts
10089
10115
  var PATH_PREFIX_PATTERN = /^([/~.]|[a-zA-Z]:|\\\\)/;
@@ -12670,7 +12696,7 @@ function useTextBuffer({
12670
12696
  transformedToLogicalMaps,
12671
12697
  visualToTransformedMap
12672
12698
  } = visualLayout;
12673
- const [scrollRowState, setScrollRowState] = useState21(0);
12699
+ const [scrollRowState, setScrollRowState] = useState22(0);
12674
12700
  useEffect24(() => {
12675
12701
  if (onChange) {
12676
12702
  onChange(text);
@@ -13329,7 +13355,7 @@ function useTextBuffer({
13329
13355
  }
13330
13356
 
13331
13357
  // src/ui/components/shared/base-settings-dialog.tsx
13332
- import React14, { useCallback as useCallback23, useEffect as useEffect25, useState as useState22 } from "react";
13358
+ import React14, { useCallback as useCallback23, useEffect as useEffect25, useState as useState23 } from "react";
13333
13359
  import { Box as Box43, Text as Text36 } from "ink";
13334
13360
  import chalk2 from "chalk";
13335
13361
 
@@ -13427,15 +13453,15 @@ function BaseSettingsDialog({
13427
13453
  onKeyPress,
13428
13454
  footerContent
13429
13455
  }) {
13430
- const [activeIndex, setActiveIndex] = useState22(0);
13431
- const [scrollOffset, setScrollOffset] = useState22(0);
13432
- const [focusSection, setFocusSection] = useState22(
13456
+ const [activeIndex, setActiveIndex] = useState23(0);
13457
+ const [scrollOffset, setScrollOffset] = useState23(0);
13458
+ const [focusSection, setFocusSection] = useState23(
13433
13459
  "settings"
13434
13460
  );
13435
- const [editingKey, setEditingKey] = useState22(null);
13436
- const [editBuffer, setEditBuffer] = useState22("");
13437
- const [editCursorPos, setEditCursorPos] = useState22(0);
13438
- const [cursorVisible, setCursorVisible] = useState22(true);
13461
+ const [editingKey, setEditingKey] = useState23(null);
13462
+ const [editBuffer, setEditBuffer] = useState23("");
13463
+ const [editCursorPos, setEditCursorPos] = useState23(0);
13464
+ const [cursorVisible, setCursorVisible] = useState23(true);
13439
13465
  useEffect25(() => {
13440
13466
  if (activeIndex >= items.length) {
13441
13467
  setActiveIndex(Math.max(0, items.length - 1));
@@ -13798,9 +13824,9 @@ function SettingsDialog({
13798
13824
  }) {
13799
13825
  const { vimEnabled, toggleVimEnabled } = useVimMode();
13800
13826
  const selectedScope = "User" /* User */;
13801
- const [showRestartPrompt, setShowRestartPrompt] = useState23(false);
13802
- const [searchQuery, setSearchQuery] = useState23("");
13803
- const [filteredKeys, setFilteredKeys] = useState23(
13827
+ const [showRestartPrompt, setShowRestartPrompt] = useState24(false);
13828
+ const [searchQuery, setSearchQuery] = useState24("");
13829
+ const [filteredKeys, setFilteredKeys] = useState24(
13804
13830
  () => getDialogSettingKeys()
13805
13831
  );
13806
13832
  const { fzfInstance, searchMap } = useMemo17(() => {
@@ -13841,13 +13867,13 @@ function SettingsDialog({
13841
13867
  active = false;
13842
13868
  };
13843
13869
  }, [searchQuery, fzfInstance, searchMap]);
13844
- const [pendingSettings, setPendingSettings] = useState23(
13870
+ const [pendingSettings, setPendingSettings] = useState24(
13845
13871
  () => (
13846
13872
  // Deep clone to avoid mutation
13847
13873
  structuredClone(settings.forScope(selectedScope).settings)
13848
13874
  )
13849
13875
  );
13850
- const [modifiedSettings, setModifiedSettings] = useState23(
13876
+ const [modifiedSettings, setModifiedSettings] = useState24(
13851
13877
  /* @__PURE__ */ new Set()
13852
13878
  );
13853
13879
  const maxLabelOrDescriptionWidth = useMemo17(() => {
@@ -14351,7 +14377,7 @@ var DialogManager = ({ terminalWidth }) => {
14351
14377
  };
14352
14378
 
14353
14379
  // src/ui/components/input/composer.tsx
14354
- import { useState as useState34 } from "react";
14380
+ import { useState as useState35 } from "react";
14355
14381
  import { Box as Box60, useIsScreenReaderEnabled as useIsScreenReaderEnabled4 } from "ink";
14356
14382
 
14357
14383
  // src/ui/components/indicators/loading-indicator.tsx
@@ -14570,7 +14596,7 @@ var RawMarkdownIndicator = () => {
14570
14596
 
14571
14597
  // src/ui/components/input/input-prompt.tsx
14572
14598
  import clipboardy2 from "clipboardy";
14573
- import { useCallback as useCallback32, useEffect as useEffect33, useState as useState31, useRef as useRef18, useMemo as useMemo22 } from "react";
14599
+ import { useCallback as useCallback32, useEffect as useEffect33, useState as useState32, useRef as useRef18, useMemo as useMemo22 } from "react";
14574
14600
  import { Box as Box51, Text as Text46, useStdout as useStdout2 } from "ink";
14575
14601
 
14576
14602
  // src/ui/components/input/suggestions-display.tsx
@@ -14718,6 +14744,14 @@ var Colors = {
14718
14744
  // src/ui/components/input/suggestions-display.tsx
14719
14745
  import { jsx as jsx65, jsxs as jsxs47 } from "react/jsx-runtime";
14720
14746
  var MAX_SUGGESTIONS_TO_SHOW = 8;
14747
+ function commandSource(commandKind) {
14748
+ switch (commandKind) {
14749
+ case "skill" /* SKILL */:
14750
+ return { label: "[skill]", color: theme.command.skill };
14751
+ default:
14752
+ return void 0;
14753
+ }
14754
+ }
14721
14755
  function SuggestionsDisplay({
14722
14756
  suggestions,
14723
14757
  activeIndex,
@@ -14752,6 +14786,7 @@ function SuggestionsDisplay({
14752
14786
  const isActive = originalIndex === activeIndex;
14753
14787
  const isExpanded = originalIndex === expandedIndex;
14754
14788
  const textColor = isActive ? theme.text.accent : theme.text.secondary;
14789
+ const source = mode === "slash" ? commandSource(suggestion.commandKind) : void 0;
14755
14790
  const isLong = suggestion.value.length >= MAX_WIDTH;
14756
14791
  const labelElement = /* @__PURE__ */ jsx65(
14757
14792
  ExpandableText,
@@ -14771,7 +14806,13 @@ function SuggestionsDisplay({
14771
14806
  children: /* @__PURE__ */ jsx65(Box50, { children: labelElement })
14772
14807
  }
14773
14808
  ),
14774
- suggestion.description && /* @__PURE__ */ jsx65(Box50, { flexGrow: 1, paddingLeft: 3, children: /* @__PURE__ */ jsx65(Text45, { color: textColor, wrap: "truncate", children: sanitizeForDisplay(suggestion.description, 100) }) }),
14809
+ suggestion.description && /* @__PURE__ */ jsx65(Box50, { flexGrow: 1, paddingLeft: 3, children: /* @__PURE__ */ jsxs47(Text45, { color: textColor, wrap: "truncate", children: [
14810
+ source && /* @__PURE__ */ jsxs47(Text45, { color: source.color, children: [
14811
+ source.label,
14812
+ " "
14813
+ ] }),
14814
+ sanitizeForDisplay(suggestion.description, 100)
14815
+ ] }) }),
14775
14816
  isActive && isLong && /* @__PURE__ */ jsx65(Box50, { width: 3, flexShrink: 0, children: /* @__PURE__ */ jsx65(Text45, { color: Colors.Gray, children: isExpanded ? " \u2190 " : " \u2192 " }) })
14776
14817
  ] }, `${suggestion.value}-${originalIndex}`);
14777
14818
  }),
@@ -14787,7 +14828,7 @@ function SuggestionsDisplay({
14787
14828
  }
14788
14829
 
14789
14830
  // src/ui/hooks/input/use-input-history.ts
14790
- import { useState as useState24, useCallback as useCallback26 } from "react";
14831
+ import { useState as useState25, useCallback as useCallback26 } from "react";
14791
14832
  function useInputHistory({
14792
14833
  userMessages,
14793
14834
  onSubmit,
@@ -14795,8 +14836,8 @@ function useInputHistory({
14795
14836
  currentQuery,
14796
14837
  onChange
14797
14838
  }) {
14798
- const [historyIndex, setHistoryIndex] = useState24(-1);
14799
- const [originalQueryBeforeNav, setOriginalQueryBeforeNav] = useState24("");
14839
+ const [historyIndex, setHistoryIndex] = useState25(-1);
14840
+ const [originalQueryBeforeNav, setOriginalQueryBeforeNav] = useState25("");
14800
14841
  const resetHistoryNav = useCallback26(() => {
14801
14842
  setHistoryIndex(-1);
14802
14843
  setOriginalQueryBeforeNav("");
@@ -14872,7 +14913,7 @@ import chalk3 from "chalk";
14872
14913
  import stringWidth3 from "string-width";
14873
14914
 
14874
14915
  // src/ui/hooks/input/use-shell-history.ts
14875
- import { useState as useState25, useEffect as useEffect27, useCallback as useCallback27 } from "react";
14916
+ import { useState as useState26, useEffect as useEffect27, useCallback as useCallback27 } from "react";
14876
14917
  import * as fs8 from "node:fs/promises";
14877
14918
  import * as path9 from "node:path";
14878
14919
  var MAX_HISTORY_LENGTH = 100;
@@ -14913,9 +14954,9 @@ async function writeHistoryFile(filePath, history) {
14913
14954
  }
14914
14955
  }
14915
14956
  function useShellHistory(projectRoot, storage) {
14916
- const [history, setHistory] = useState25([]);
14917
- const [historyIndex, setHistoryIndex] = useState25(-1);
14918
- const [historyFilePath, setHistoryFilePath] = useState25(null);
14957
+ const [history, setHistory] = useState26([]);
14958
+ const [historyIndex, setHistoryIndex] = useState26(-1);
14959
+ const [historyFilePath, setHistoryFilePath] = useState26(null);
14919
14960
  useEffect27(() => {
14920
14961
  async function loadHistory() {
14921
14962
  const filePath = await getHistoryFilePath(projectRoot, storage);
@@ -14969,17 +15010,17 @@ function useShellHistory(projectRoot, storage) {
14969
15010
  }
14970
15011
 
14971
15012
  // src/ui/hooks/completion/use-reverse-search-completion.tsx
14972
- import { useState as useState27, useEffect as useEffect28, useMemo as useMemo18, useCallback as useCallback29, useRef as useRef15 } from "react";
15013
+ import { useState as useState28, useEffect as useEffect28, useMemo as useMemo18, useCallback as useCallback29, useRef as useRef15 } from "react";
14973
15014
 
14974
15015
  // src/ui/hooks/completion/use-completion.ts
14975
- import { useState as useState26, useCallback as useCallback28 } from "react";
15016
+ import { useState as useState27, useCallback as useCallback28 } from "react";
14976
15017
  function useCompletion() {
14977
- const [suggestions, setSuggestions] = useState26([]);
14978
- const [activeSuggestionIndex, setActiveSuggestionIndex] = useState26(-1);
14979
- const [visibleStartIndex, setVisibleStartIndex] = useState26(0);
14980
- const [showSuggestions, setShowSuggestions] = useState26(false);
14981
- const [isLoadingSuggestions, setIsLoadingSuggestions] = useState26(false);
14982
- const [isPerfectMatch, setIsPerfectMatch] = useState26(false);
15018
+ const [suggestions, setSuggestions] = useState27([]);
15019
+ const [activeSuggestionIndex, setActiveSuggestionIndex] = useState27(-1);
15020
+ const [visibleStartIndex, setVisibleStartIndex] = useState27(0);
15021
+ const [showSuggestions, setShowSuggestions] = useState27(false);
15022
+ const [isLoadingSuggestions, setIsLoadingSuggestions] = useState27(false);
15023
+ const [isPerfectMatch, setIsPerfectMatch] = useState27(false);
14983
15024
  const resetCompletionState = useCallback28(() => {
14984
15025
  setSuggestions([]);
14985
15026
  setActiveSuggestionIndex(-1);
@@ -15042,7 +15083,7 @@ function useCompletion() {
15042
15083
 
15043
15084
  // src/ui/hooks/completion/use-reverse-search-completion.tsx
15044
15085
  function useDebouncedValue(value, delay = 200) {
15045
- const [debounced, setDebounced] = useState27(value);
15086
+ const [debounced, setDebounced] = useState28(value);
15046
15087
  useEffect28(() => {
15047
15088
  const handle = setTimeout(() => setDebounced(value), delay);
15048
15089
  return () => clearTimeout(handle);
@@ -15326,7 +15367,7 @@ function useAtCompletion(props) {
15326
15367
  }
15327
15368
 
15328
15369
  // src/ui/hooks/completion/use-slash-completion.ts
15329
- import { useState as useState28, useEffect as useEffect30, useMemo as useMemo19 } from "react";
15370
+ import { useState as useState29, useEffect as useEffect30, useMemo as useMemo19 } from "react";
15330
15371
  import { AsyncFzf as AsyncFzf2 } from "fzf";
15331
15372
  function logErrorSafely(error, context) {
15332
15373
  if (error instanceof Error) {
@@ -15412,8 +15453,8 @@ function useCommandParser(query, slashCommands) {
15412
15453
  }, [query, slashCommands]);
15413
15454
  }
15414
15455
  function useCommandSuggestions(query, parserResult, commandContext, getFzfForCommands, getPrefixSuggestions) {
15415
- const [suggestions, setSuggestions] = useState28([]);
15416
- const [isLoading, setIsLoading] = useState28(false);
15456
+ const [suggestions, setSuggestions] = useState29([]);
15457
+ const [isLoading, setIsLoading] = useState29(false);
15417
15458
  useEffect30(() => {
15418
15459
  const abortController = new AbortController();
15419
15460
  const { signal } = abortController;
@@ -15424,6 +15465,9 @@ function useCommandSuggestions(query, parserResult, commandContext, getFzfForCom
15424
15465
  partial,
15425
15466
  currentLevel
15426
15467
  } = parserResult;
15468
+ setIsLoading(
15469
+ isArgumentCompletion && leafCommand?.completion !== void 0 && leafCommand.showCompletionLoading !== false
15470
+ );
15427
15471
  if (isArgumentCompletion) {
15428
15472
  const fetchAndSetSuggestions = async () => {
15429
15473
  if (signal.aborted) return;
@@ -15433,10 +15477,6 @@ function useCommandSuggestions(query, parserResult, commandContext, getFzfForCom
15433
15477
  );
15434
15478
  return;
15435
15479
  }
15436
- const showLoading = leafCommand.showCompletionLoading !== false;
15437
- if (showLoading) {
15438
- setIsLoading(true);
15439
- }
15440
15480
  try {
15441
15481
  const rawParts = [...commandPathParts];
15442
15482
  if (partial) rawParts.push(partial);
@@ -15454,10 +15494,14 @@ function useCommandSuggestions(query, parserResult, commandContext, getFzfForCom
15454
15494
  argString
15455
15495
  ) || [];
15456
15496
  if (!signal.aborted) {
15457
- const finalSuggestions = results.map((s) => ({
15458
- label: s,
15459
- value: s
15460
- }));
15497
+ const finalSuggestions = results.map((result) => {
15498
+ const item = typeof result === "string" ? { value: result } : result;
15499
+ return {
15500
+ label: item.value,
15501
+ value: item.value,
15502
+ ...item.description === void 0 ? {} : { description: item.description }
15503
+ };
15504
+ });
15461
15505
  setSuggestions(finalSuggestions);
15462
15506
  setIsLoading(false);
15463
15507
  }
@@ -15474,6 +15518,31 @@ function useCommandSuggestions(query, parserResult, commandContext, getFzfForCom
15474
15518
  }
15475
15519
  const commandsToSearch = currentLevel || [];
15476
15520
  if (commandsToSearch.length > 0) {
15521
+ let lastPublishedCommands;
15522
+ const publishSuggestions = (potentialSuggestions) => {
15523
+ if (signal.aborted) return;
15524
+ const sortedSuggestions = [...potentialSuggestions].sort((a, b) => {
15525
+ const aIsExact = matchesCommand(a, partial);
15526
+ const bIsExact = matchesCommand(b, partial);
15527
+ if (aIsExact && !bIsExact) return -1;
15528
+ if (!aIsExact && bIsExact) return 1;
15529
+ return 0;
15530
+ });
15531
+ if (lastPublishedCommands?.length === sortedSuggestions.length && lastPublishedCommands.every(
15532
+ (command, index) => command === sortedSuggestions[index]
15533
+ )) {
15534
+ return;
15535
+ }
15536
+ lastPublishedCommands = sortedSuggestions;
15537
+ setSuggestions(
15538
+ sortedSuggestions.map((cmd) => ({
15539
+ label: cmd.name,
15540
+ value: cmd.name,
15541
+ description: cmd.description,
15542
+ commandKind: cmd.kind
15543
+ }))
15544
+ );
15545
+ };
15477
15546
  const performFuzzySearch = async () => {
15478
15547
  if (signal.aborted) return;
15479
15548
  let potentialSuggestions;
@@ -15482,6 +15551,11 @@ function useCommandSuggestions(query, parserResult, commandContext, getFzfForCom
15482
15551
  (cmd) => cmd.description && !cmd.hidden
15483
15552
  );
15484
15553
  } else {
15554
+ const prefixSuggestions = getPrefixSuggestions(
15555
+ commandsToSearch,
15556
+ partial
15557
+ );
15558
+ publishSuggestions(prefixSuggestions);
15485
15559
  const fzfInstance = getFzfForCommands(commandsToSearch);
15486
15560
  if (fzfInstance) {
15487
15561
  try {
@@ -15496,38 +15570,14 @@ function useCommandSuggestions(query, parserResult, commandContext, getFzfForCom
15496
15570
  });
15497
15571
  potentialSuggestions = Array.from(uniqueCommands);
15498
15572
  } catch (error) {
15499
- logErrorSafely(
15500
- error,
15501
- "Fuzzy search - falling back to prefix matching"
15502
- );
15503
- potentialSuggestions = getPrefixSuggestions(
15504
- commandsToSearch,
15505
- partial
15506
- );
15573
+ logErrorSafely(error, "Fuzzy command search");
15574
+ return;
15507
15575
  }
15508
15576
  } else {
15509
- potentialSuggestions = getPrefixSuggestions(
15510
- commandsToSearch,
15511
- partial
15512
- );
15577
+ potentialSuggestions = prefixSuggestions;
15513
15578
  }
15514
15579
  }
15515
- if (!signal.aborted) {
15516
- const sortedSuggestions = [...potentialSuggestions].sort((a, b) => {
15517
- const aIsExact = matchesCommand(a, partial);
15518
- const bIsExact = matchesCommand(b, partial);
15519
- if (aIsExact && !bIsExact) return -1;
15520
- if (!aIsExact && bIsExact) return 1;
15521
- return 0;
15522
- });
15523
- const finalSuggestions = sortedSuggestions.map((cmd) => ({
15524
- label: cmd.name,
15525
- value: cmd.name,
15526
- description: cmd.description,
15527
- commandKind: cmd.kind
15528
- }));
15529
- setSuggestions(finalSuggestions);
15530
- }
15580
+ publishSuggestions(potentialSuggestions);
15531
15581
  };
15532
15582
  performFuzzySearch().catch((error) => {
15533
15583
  logErrorSafely(error, "Unexpected fuzzy search error");
@@ -15609,8 +15659,8 @@ function useSlashCompletion(props) {
15609
15659
  setIsLoadingSuggestions,
15610
15660
  setIsPerfectMatch
15611
15661
  } = props;
15612
- const [completionStart, setCompletionStart] = useState28(-1);
15613
- const [completionEnd, setCompletionEnd] = useState28(-1);
15662
+ const [completionStart, setCompletionStart] = useState29(-1);
15663
+ const [completionEnd, setCompletionEnd] = useState29(-1);
15614
15664
  const fzfInstanceCache = useMemo19(
15615
15665
  () => /* @__PURE__ */ new WeakMap(),
15616
15666
  []
@@ -15720,7 +15770,7 @@ function useSlashCompletion(props) {
15720
15770
  }
15721
15771
 
15722
15772
  // src/ui/hooks/completion/use-prompt-completion.ts
15723
- import { useState as useState29, useCallback as useCallback30, useRef as useRef17, useEffect as useEffect31, useMemo as useMemo20 } from "react";
15773
+ import { useState as useState30, useCallback as useCallback30, useRef as useRef17, useEffect as useEffect31, useMemo as useMemo20 } from "react";
15724
15774
  var PROMPT_COMPLETION_MIN_LENGTH = 5;
15725
15775
  var PROMPT_COMPLETION_DEBOUNCE_MS = 250;
15726
15776
  function usePromptCompletion({
@@ -15728,10 +15778,10 @@ function usePromptCompletion({
15728
15778
  completePrompt,
15729
15779
  enabled
15730
15780
  }) {
15731
- const [ghostText, setGhostText] = useState29("");
15732
- const [isLoadingGhostText, setIsLoadingGhostText] = useState29(false);
15781
+ const [ghostText, setGhostText] = useState30("");
15782
+ const [isLoadingGhostText, setIsLoadingGhostText] = useState30(false);
15733
15783
  const abortControllerRef = useRef17(null);
15734
- const [justSelectedSuggestion, setJustSelectedSuggestion] = useState29(false);
15784
+ const [justSelectedSuggestion, setJustSelectedSuggestion] = useState30(false);
15735
15785
  const lastSelectedTextRef = useRef17("");
15736
15786
  const lastRequestedTextRef = useRef17("");
15737
15787
  const isPromptCompletionEnabled = enabled && completePrompt !== void 0;
@@ -16185,9 +16235,9 @@ function parseSegmentsFromTokens(tokens, sliceStart, sliceEnd) {
16185
16235
  }
16186
16236
 
16187
16237
  // src/ui/hooks/terminal/use-kitty-keyboard-protocol.ts
16188
- import { useState as useState30 } from "react";
16238
+ import { useState as useState31 } from "react";
16189
16239
  function useKittyKeyboardProtocol() {
16190
- const [status] = useState30({
16240
+ const [status] = useState31({
16191
16241
  enabled: terminalCapabilityManager.isKittyProtocolEnabled(),
16192
16242
  checking: false
16193
16243
  });
@@ -16299,21 +16349,21 @@ var InputPrompt = ({
16299
16349
  const isShellFocused = useShellFocusState();
16300
16350
  const { setEmbeddedShellFocused } = useUIActions();
16301
16351
  const { terminalWidth, activePtyId, terminalBackgroundColor } = useUIState();
16302
- const [justNavigatedHistory, setJustNavigatedHistory] = useState31(false);
16352
+ const [justNavigatedHistory, setJustNavigatedHistory] = useState32(false);
16303
16353
  const escPressCount = useRef18(0);
16304
- const [showEscapePrompt, setShowEscapePrompt] = useState31(false);
16354
+ const [showEscapePrompt, setShowEscapePrompt] = useState32(false);
16305
16355
  const escapeTimerRef = useRef18(null);
16306
- const [recentUnsafePasteTime, setRecentUnsafePasteTime] = useState31(null);
16356
+ const [recentUnsafePasteTime, setRecentUnsafePasteTime] = useState32(null);
16307
16357
  const pasteTimeoutRef = useRef18(null);
16308
16358
  const innerBoxRef = useRef18(null);
16309
- const [reverseSearchActive, setReverseSearchActive] = useState31(false);
16310
- const [commandSearchActive, setCommandSearchActive] = useState31(false);
16311
- const [textBeforeReverseSearch, setTextBeforeReverseSearch] = useState31("");
16312
- const [cursorPosition, setCursorPosition] = useState31([
16359
+ const [reverseSearchActive, setReverseSearchActive] = useState32(false);
16360
+ const [commandSearchActive, setCommandSearchActive] = useState32(false);
16361
+ const [textBeforeReverseSearch, setTextBeforeReverseSearch] = useState32("");
16362
+ const [cursorPosition, setCursorPosition] = useState32([
16313
16363
  0,
16314
16364
  0
16315
16365
  ]);
16316
- const [expandedSuggestionIndex, setExpandedSuggestionIndex] = useState31(-1);
16366
+ const [expandedSuggestionIndex, setExpandedSuggestionIndex] = useState32(-1);
16317
16367
  const shellHistory = useShellHistory(config.getProjectRoot());
16318
16368
  const shellHistoryData = shellHistory.history;
16319
16369
  const completion = useCommandCompletion(
@@ -16904,7 +16954,10 @@ var InputPrompt = ({
16904
16954
  onTogglePlanMode
16905
16955
  ]
16906
16956
  );
16907
- useKeypress(handleInput, { isActive: !isEmbeddedShellFocused });
16957
+ useKeypress(handleInput, {
16958
+ isActive: !isEmbeddedShellFocused,
16959
+ isInput: true
16960
+ });
16908
16961
  const linesToRender = buffer.viewportVisualLines;
16909
16962
  const [cursorVisualRowAbsolute, cursorVisualColAbsolute] = buffer.visualCursor;
16910
16963
  const scrollVisualRow = buffer.visualScrollRow;
@@ -17253,13 +17306,13 @@ var ConsoleSummaryDisplay = ({
17253
17306
  };
17254
17307
 
17255
17308
  // src/ui/components/stats/memory-usage-display.tsx
17256
- import { useEffect as useEffect34, useState as useState32 } from "react";
17309
+ import { useEffect as useEffect34, useState as useState33 } from "react";
17257
17310
  import { Box as Box53, Text as Text48 } from "ink";
17258
17311
  import process5 from "node:process";
17259
17312
  import { jsx as jsx68, jsxs as jsxs50 } from "react/jsx-runtime";
17260
17313
  var MemoryUsageDisplay = () => {
17261
- const [memoryUsage, setMemoryUsage] = useState32("");
17262
- const [memoryUsageColor, setMemoryUsageColor] = useState32(
17314
+ const [memoryUsage, setMemoryUsage] = useState33("");
17315
+ const [memoryUsageColor, setMemoryUsageColor] = useState33(
17263
17316
  theme.text.secondary
17264
17317
  );
17265
17318
  useEffect34(() => {
@@ -17282,7 +17335,7 @@ var MemoryUsageDisplay = () => {
17282
17335
 
17283
17336
  // src/ui/components/stats/debug-profiler.tsx
17284
17337
  import { Text as Text49 } from "ink";
17285
- import { useEffect as useEffect35, useState as useState33 } from "react";
17338
+ import { useEffect as useEffect35, useState as useState34 } from "react";
17286
17339
  import { FixedDeque } from "mnemonist";
17287
17340
  import { Fragment as Fragment14, jsx as jsx69, jsxs as jsxs51 } from "react/jsx-runtime";
17288
17341
  var MIN_TIME_FROM_ACTION_TO_BE_IDLE = 500;
@@ -17383,7 +17436,7 @@ var profiler = {
17383
17436
  };
17384
17437
  var DebugProfiler = ({ compact = false }) => {
17385
17438
  const { showDebugProfiler, constrainHeight } = useUIState();
17386
- const [forceRefresh, setForceRefresh] = useState33(0);
17439
+ const [forceRefresh, setForceRefresh] = useState34(0);
17387
17440
  useEffect35(() => {
17388
17441
  profiler.profilersActive++;
17389
17442
  const stdin = process.stdin;
@@ -17879,7 +17932,7 @@ var Composer = ({ isFocused = true }) => {
17879
17932
  const terminalWidth = process.stdout.columns;
17880
17933
  const isNarrow = isNarrowWidth(terminalWidth);
17881
17934
  const debugConsoleMaxHeight = Math.floor(Math.max(terminalWidth * 0.2, 5));
17882
- const [, setSuggestionsVisible] = useState34(false);
17935
+ const [, setSuggestionsVisible] = useState35(false);
17883
17936
  const isAlternateBuffer = useAlternateBuffer();
17884
17937
  const suggestionsPosition = isAlternateBuffer ? "above" : "below";
17885
17938
  return /* @__PURE__ */ jsxs58(
@@ -19398,9 +19451,9 @@ var App = () => {
19398
19451
  import process8 from "node:process";
19399
19452
 
19400
19453
  // src/ui/hooks/session/use-history-manager.ts
19401
- import { useState as useState35, useRef as useRef20, useCallback as useCallback35, useMemo as useMemo30 } from "react";
19454
+ import { useState as useState36, useRef as useRef20, useCallback as useCallback35, useMemo as useMemo30 } from "react";
19402
19455
  function useHistory() {
19403
- const [history, setHistory] = useState35([]);
19456
+ const [history, setHistory] = useState36([]);
19404
19457
  const messageIdCounterRef = useRef20(0);
19405
19458
  const getNextMessageId = useCallback35((baseTimestamp) => {
19406
19459
  messageIdCounterRef.current += 1;
@@ -19457,7 +19510,7 @@ function useHistory() {
19457
19510
  }
19458
19511
 
19459
19512
  // src/ui/hooks/commands/use-slash-command-processor.ts
19460
- import { useCallback as useCallback40, useMemo as useMemo38, useEffect as useEffect44, useRef as useRef25, useState as useState44 } from "react";
19513
+ import { useCallback as useCallback41, useMemo as useMemo40, useEffect as useEffect45, useRef as useRef25, useState as useState47 } from "react";
19461
19514
 
19462
19515
  // src/services/command-service.ts
19463
19516
  var CommandService = class _CommandService {
@@ -19579,7 +19632,7 @@ function loadChangelog() {
19579
19632
  }
19580
19633
 
19581
19634
  // src/ui/components/dialogs/changelog-dialog.tsx
19582
- import { useMemo as useMemo31, useState as useState36 } from "react";
19635
+ import { useMemo as useMemo31, useState as useState37 } from "react";
19583
19636
  import { Box as Box70, Text as Text65 } from "ink";
19584
19637
  import stringWidth4 from "string-width";
19585
19638
 
@@ -19686,7 +19739,7 @@ function ChangelogDialog({
19686
19739
  [content, contentWidth]
19687
19740
  );
19688
19741
  const maxOffset = Math.max(0, lines.length - viewportHeight);
19689
- const [offset, setOffset] = useState36(0);
19742
+ const [offset, setOffset] = useState37(0);
19690
19743
  const visibleOffset = Math.min(offset, maxOffset);
19691
19744
  useKeypress(
19692
19745
  (key) => {
@@ -19879,11 +19932,11 @@ var vimCommand = {
19879
19932
  import React19 from "react";
19880
19933
 
19881
19934
  // src/ui/components/dialogs/model-dialog.tsx
19882
- import { useCallback as useCallback36, useEffect as useEffect39, useMemo as useMemo32, useRef as useRef22, useState as useState38 } from "react";
19935
+ import { useCallback as useCallback36, useEffect as useEffect39, useMemo as useMemo32, useRef as useRef22, useState as useState39 } from "react";
19883
19936
  import { Box as Box72, Text as Text67 } from "ink";
19884
19937
 
19885
19938
  // src/ui/components/dialogs/provider-setup-dialog.tsx
19886
- import { useEffect as useEffect38, useRef as useRef21, useState as useState37 } from "react";
19939
+ import { useEffect as useEffect38, useRef as useRef21, useState as useState38 } from "react";
19887
19940
  import { Box as Box71, Text as Text66 } from "ink";
19888
19941
  import { jsx as jsx94, jsxs as jsxs68 } from "react/jsx-runtime";
19889
19942
  function ProviderSetupDialog({
@@ -19894,10 +19947,10 @@ function ProviderSetupDialog({
19894
19947
  onConfigured
19895
19948
  }) {
19896
19949
  useSensitiveInputProtection();
19897
- const [view, setView] = useState37();
19898
- const [secret, setSecret] = useState37("");
19899
- const [saving, setSaving] = useState37(false);
19900
- const [error, setError] = useState37();
19950
+ const [view, setView] = useState38();
19951
+ const [secret, setSecret] = useState38("");
19952
+ const [saving, setSaving] = useState38(false);
19953
+ const [error, setError] = useState38();
19901
19954
  const mountedRef = useRef21(true);
19902
19955
  const saveControllerRef = useRef21(void 0);
19903
19956
  useEffect38(() => {
@@ -20083,17 +20136,17 @@ function ModelDialog({
20083
20136
  onSwitched,
20084
20137
  providerSetupRuntime
20085
20138
  }) {
20086
- const [models, setModels] = useState38([]);
20087
- const [highlighted, setHighlighted] = useState38(
20139
+ const [models, setModels] = useState39([]);
20140
+ const [highlighted, setHighlighted] = useState39(
20088
20141
  runtime.getSnapshot().current
20089
20142
  );
20090
- const [pending, setPending] = useState38();
20091
- const [loading, setLoading] = useState38(true);
20092
- const [switching, setSwitching] = useState38(false);
20093
- const [checkingProvider, setCheckingProvider] = useState38(false);
20094
- const [error, setError] = useState38();
20095
- const [setupSelection, setSetupSelection] = useState38();
20096
- const [reasoningSelection, setReasoningSelection] = useState38();
20143
+ const [pending, setPending] = useState39();
20144
+ const [loading, setLoading] = useState39(true);
20145
+ const [switching, setSwitching] = useState39(false);
20146
+ const [checkingProvider, setCheckingProvider] = useState39(false);
20147
+ const [error, setError] = useState39();
20148
+ const [setupSelection, setSetupSelection] = useState39();
20149
+ const [reasoningSelection, setReasoningSelection] = useState39();
20097
20150
  const providerCheckRef = useRef22(void 0);
20098
20151
  useEffect39(() => {
20099
20152
  const controller = new AbortController();
@@ -20480,7 +20533,7 @@ var modelCommand = {
20480
20533
  import React20 from "react";
20481
20534
 
20482
20535
  // src/ui/components/dialogs/provider-dialog.tsx
20483
- import { useEffect as useEffect40, useMemo as useMemo33, useState as useState39 } from "react";
20536
+ import { useEffect as useEffect40, useMemo as useMemo33, useState as useState40 } from "react";
20484
20537
  import { Box as Box73, Text as Text68 } from "ink";
20485
20538
  import { Fragment as Fragment22, jsx as jsx96, jsxs as jsxs70 } from "react/jsx-runtime";
20486
20539
  function statusLabel(status) {
@@ -20523,11 +20576,11 @@ function ProviderDialog({
20523
20576
  initialProvider,
20524
20577
  onClose
20525
20578
  }) {
20526
- const [providers, setProviders] = useState39([]);
20527
- const [highlighted, setHighlighted] = useState39();
20528
- const [editing, setEditing] = useState39();
20529
- const [loading, setLoading] = useState39(true);
20530
- const [error, setError] = useState39();
20579
+ const [providers, setProviders] = useState40([]);
20580
+ const [highlighted, setHighlighted] = useState40();
20581
+ const [editing, setEditing] = useState40();
20582
+ const [loading, setLoading] = useState40(true);
20583
+ const [error, setError] = useState40();
20531
20584
  useEffect40(() => {
20532
20585
  const controller = new AbortController();
20533
20586
  void runtime.listProviders(controller.signal).then((available) => {
@@ -20715,7 +20768,7 @@ var providerCommand = {
20715
20768
  import React21 from "react";
20716
20769
 
20717
20770
  // src/ui/components/dialogs/session-dialog.tsx
20718
- import { useCallback as useCallback37, useEffect as useEffect41, useMemo as useMemo34, useRef as useRef23, useState as useState40 } from "react";
20771
+ import { useCallback as useCallback37, useEffect as useEffect41, useMemo as useMemo34, useRef as useRef23, useState as useState41 } from "react";
20719
20772
  import { Box as Box74, Text as Text69 } from "ink";
20720
20773
  import { Fragment as Fragment23, jsx as jsx97, jsxs as jsxs71 } from "react/jsx-runtime";
20721
20774
  function shortId(id) {
@@ -20729,12 +20782,12 @@ function SessionDialog({
20729
20782
  runtime,
20730
20783
  onClose
20731
20784
  }) {
20732
- const [sessions, setSessions] = useState40([]);
20733
- const [highlighted, setHighlighted] = useState40();
20734
- const [pending, setPending] = useState40();
20735
- const [loading, setLoading] = useState40(true);
20736
- const [switching, setSwitching] = useState40(false);
20737
- const [error, setError] = useState40();
20785
+ const [sessions, setSessions] = useState41([]);
20786
+ const [highlighted, setHighlighted] = useState41();
20787
+ const [pending, setPending] = useState41();
20788
+ const [loading, setLoading] = useState41(true);
20789
+ const [switching, setSwitching] = useState41(false);
20790
+ const [error, setError] = useState41();
20738
20791
  const switchingRef = useRef23(false);
20739
20792
  const titleRequestsRef = useRef23(/* @__PURE__ */ new Map());
20740
20793
  const resolveTitles = useCallback37(
@@ -21028,7 +21081,7 @@ var statsCommand = {
21028
21081
  import React22 from "react";
21029
21082
 
21030
21083
  // src/ui/components/dialogs/tools-dialog.tsx
21031
- import { useEffect as useEffect42, useMemo as useMemo35, useState as useState41, useSyncExternalStore as useSyncExternalStore3 } from "react";
21084
+ import { useEffect as useEffect42, useMemo as useMemo35, useState as useState42, useSyncExternalStore as useSyncExternalStore3 } from "react";
21032
21085
  import { Box as Box76, Text as Text71 } from "ink";
21033
21086
 
21034
21087
  // src/ui/components/shared/descriptive-radio-button-select.tsx
@@ -21078,7 +21131,7 @@ function ToolsDialog({
21078
21131
  runtime.getSnapshot,
21079
21132
  runtime.getSnapshot
21080
21133
  );
21081
- const [selectedName, setSelectedName] = useState41(snapshot.tools[0]?.name);
21134
+ const [selectedName, setSelectedName] = useState42(snapshot.tools[0]?.name);
21082
21135
  const selected = snapshot.tools.find((tool) => tool.name === selectedName) ?? snapshot.tools[0];
21083
21136
  useEffect42(() => {
21084
21137
  if (selected?.name !== selectedName) setSelectedName(selected?.name);
@@ -21189,7 +21242,7 @@ var toolsCommand = {
21189
21242
  import React23 from "react";
21190
21243
 
21191
21244
  // src/ui/components/dialogs/permission-dialog.tsx
21192
- import { useCallback as useCallback38, useMemo as useMemo36, useState as useState42, useSyncExternalStore as useSyncExternalStore4 } from "react";
21245
+ import { useCallback as useCallback38, useMemo as useMemo36, useState as useState43, useSyncExternalStore as useSyncExternalStore4 } from "react";
21193
21246
  import { Box as Box77, Text as Text72 } from "ink";
21194
21247
  import { Fragment as Fragment25, jsx as jsx100, jsxs as jsxs74 } from "react/jsx-runtime";
21195
21248
  function PermissionDialog({
@@ -21202,9 +21255,9 @@ function PermissionDialog({
21202
21255
  runtime.getSnapshot,
21203
21256
  runtime.getSnapshot
21204
21257
  );
21205
- const [highlighted, setHighlighted] = useState42();
21206
- const [pending, setPending] = useState42();
21207
- const [error, setError] = useState42();
21258
+ const [highlighted, setHighlighted] = useState43();
21259
+ const [pending, setPending] = useState43();
21260
+ const [error, setError] = useState43();
21208
21261
  const selected = highlighted ?? snapshot.options.find((option) => option.value === snapshot.currentValue) ?? snapshot.options[0];
21209
21262
  const items = useMemo36(
21210
21263
  () => snapshot.options.map((option) => ({
@@ -21485,7 +21538,7 @@ import {
21485
21538
  useEffect as useEffect43,
21486
21539
  useMemo as useMemo37,
21487
21540
  useRef as useRef24,
21488
- useState as useState43,
21541
+ useState as useState44,
21489
21542
  useSyncExternalStore as useSyncExternalStore5
21490
21543
  } from "react";
21491
21544
  import { Box as Box78, Text as Text73 } from "ink";
@@ -21586,11 +21639,11 @@ function AgentsDialog({ runtime, onClose }) {
21586
21639
  runtime.getSnapshot,
21587
21640
  runtime.getSnapshot
21588
21641
  );
21589
- const [selectedId, setSelectedId] = useState43(snapshot.items[0]?.id);
21590
- const [transcript, setTranscript] = useState43();
21591
- const [transcriptSessionId, setTranscriptSessionId] = useState43();
21592
- const [opening, setOpening] = useState43(false);
21593
- const [openError, setOpenError] = useState43();
21642
+ const [selectedId, setSelectedId] = useState44(snapshot.items[0]?.id);
21643
+ const [transcript, setTranscript] = useState44();
21644
+ const [transcriptSessionId, setTranscriptSessionId] = useState44();
21645
+ const [opening, setOpening] = useState44(false);
21646
+ const [openError, setOpenError] = useState44();
21594
21647
  const openController = useRef24(void 0);
21595
21648
  const openingRef = useRef24(false);
21596
21649
  const transcriptRef = useRef24(void 0);
@@ -21890,6 +21943,330 @@ var agentsCommand = {
21890
21943
  }
21891
21944
  };
21892
21945
 
21946
+ // src/ui/commands/preset-command.ts
21947
+ import React25 from "react";
21948
+
21949
+ // src/ui/components/dialogs/agent-preset-dialog.tsx
21950
+ import { useCallback as useCallback40, useMemo as useMemo38, useState as useState45, useSyncExternalStore as useSyncExternalStore6 } from "react";
21951
+ import { Box as Box79, Text as Text74 } from "ink";
21952
+ import { Fragment as Fragment27, jsx as jsx102, jsxs as jsxs76 } from "react/jsx-runtime";
21953
+ function AgentPresetDialog({
21954
+ runtime,
21955
+ onClose,
21956
+ onSwitched
21957
+ }) {
21958
+ const snapshot = useSyncExternalStore6(
21959
+ runtime.subscribe,
21960
+ runtime.getSnapshot,
21961
+ runtime.getSnapshot
21962
+ );
21963
+ const [highlighted, setHighlighted] = useState45();
21964
+ const [error, setError] = useState45();
21965
+ const selected = highlighted ?? snapshot.options.find((item) => item.id === snapshot.currentId) ?? snapshot.options[0];
21966
+ const items = useMemo38(
21967
+ () => snapshot.options.map((option) => ({
21968
+ key: option.id,
21969
+ value: option,
21970
+ label: option.name
21971
+ })),
21972
+ [snapshot.options]
21973
+ );
21974
+ const initialIndex = Math.max(
21975
+ 0,
21976
+ snapshot.options.findIndex((option) => option.id === snapshot.currentId)
21977
+ );
21978
+ const selectPreset = useCallback40(
21979
+ async (option) => {
21980
+ setError(void 0);
21981
+ if (option.broken !== void 0) {
21982
+ setError(`This preset is unavailable: ${option.broken}`);
21983
+ return;
21984
+ }
21985
+ if (option.id === snapshot.currentId) {
21986
+ onClose();
21987
+ return;
21988
+ }
21989
+ try {
21990
+ onSwitched(await runtime.select(option.id));
21991
+ } catch (cause) {
21992
+ setError(cause instanceof Error ? cause.message : String(cause));
21993
+ }
21994
+ },
21995
+ [onClose, onSwitched, runtime, snapshot.currentId]
21996
+ );
21997
+ useKeypress(
21998
+ (key) => {
21999
+ if (key.name === "escape" && !snapshot.busy) onClose();
22000
+ },
22001
+ { isActive: true }
22002
+ );
22003
+ return /* @__PURE__ */ jsxs76(
22004
+ Box79,
22005
+ {
22006
+ borderStyle: "round",
22007
+ borderColor: theme.border.default,
22008
+ flexDirection: "column",
22009
+ paddingX: 1,
22010
+ paddingY: 1,
22011
+ width: "100%",
22012
+ children: [
22013
+ /* @__PURE__ */ jsxs76(Box79, { justifyContent: "space-between", children: [
22014
+ /* @__PURE__ */ jsx102(Text74, { bold: true, color: theme.text.primary, children: "Select DSH Agent Preset" }),
22015
+ /* @__PURE__ */ jsx102(DialogCloseAction, { onClose, isActive: !snapshot.busy })
22016
+ ] }),
22017
+ (error ?? snapshot.error) && /* @__PURE__ */ jsx102(Box79, { marginTop: 1, children: /* @__PURE__ */ jsx102(Text74, { color: theme.status.error, children: error ?? snapshot.error }) }),
22018
+ snapshot.options.length === 0 ? /* @__PURE__ */ jsx102(Box79, { marginTop: 1, children: /* @__PURE__ */ jsx102(Text74, { color: theme.text.secondary, children: "No Agent presets are available." }) }) : /* @__PURE__ */ jsxs76(Box79, { flexDirection: "row", marginTop: 1, children: [
22019
+ /* @__PURE__ */ jsx102(Box79, { width: "50%", paddingRight: 2, flexDirection: "column", children: /* @__PURE__ */ jsx102(
22020
+ RadioButtonSelect,
22021
+ {
22022
+ items,
22023
+ initialIndex,
22024
+ onHighlight: setHighlighted,
22025
+ onSelect: (option) => void selectPreset(option),
22026
+ isFocused: !snapshot.busy,
22027
+ showNumbers: false,
22028
+ renderItem: (item, { titleColor }) => /* @__PURE__ */ jsxs76(
22029
+ Text74,
22030
+ {
22031
+ color: item.value.broken === void 0 ? titleColor : theme.text.secondary,
22032
+ wrap: "truncate",
22033
+ children: [
22034
+ item.value.name,
22035
+ item.value.id === snapshot.currentId && /* @__PURE__ */ jsx102(Text74, { color: theme.text.accent, children: " Current" }),
22036
+ item.value.isDefault && /* @__PURE__ */ jsx102(Text74, { color: theme.text.secondary, children: " Default" })
22037
+ ]
22038
+ }
22039
+ )
22040
+ },
22041
+ items.map((item) => item.key).join("|")
22042
+ ) }),
22043
+ /* @__PURE__ */ jsx102(Box79, { width: "50%", paddingLeft: 2, flexDirection: "column", children: selected && /* @__PURE__ */ jsxs76(Fragment27, { children: [
22044
+ /* @__PURE__ */ jsx102(Text74, { bold: true, color: theme.text.accent, children: selected.name }),
22045
+ /* @__PURE__ */ jsxs76(Text74, { color: theme.text.secondary, children: [
22046
+ selected.id,
22047
+ " \xB7 ",
22048
+ selected.trust
22049
+ ] }),
22050
+ /* @__PURE__ */ jsx102(Box79, { marginTop: 1, children: /* @__PURE__ */ jsx102(Text74, { wrap: "wrap", children: selected.description ?? "No description is available for this preset." }) }),
22051
+ selected.broken && /* @__PURE__ */ jsx102(Box79, { marginTop: 1, children: /* @__PURE__ */ jsx102(Text74, { color: theme.status.warning, children: selected.broken }) }),
22052
+ snapshot.busy && /* @__PURE__ */ jsx102(Box79, { marginTop: 1, children: /* @__PURE__ */ jsx102(Text74, { color: theme.text.accent, children: "Applying preset..." }) })
22053
+ ] }) })
22054
+ ] }),
22055
+ /* @__PURE__ */ jsx102(Box79, { marginTop: 1, children: /* @__PURE__ */ jsx102(Text74, { color: theme.text.secondary, children: "A preset can change only before the current Session starts." }) })
22056
+ ]
22057
+ }
22058
+ );
22059
+ }
22060
+
22061
+ // src/ui/commands/preset-command.ts
22062
+ var switchedMessage2 = (name2, id) => `Agent preset changed to ${name2} (${id}).`;
22063
+ var completionDescription = (option, currentId) => {
22064
+ const status = [
22065
+ ...option.id === currentId ? ["Current"] : [],
22066
+ ...option.isDefault ? ["Default"] : []
22067
+ ].join(", ");
22068
+ const details = [
22069
+ ...option.name === option.id ? [] : [option.name],
22070
+ ...status === "" ? [] : [status],
22071
+ ...option.description === void 0 ? [] : [option.description]
22072
+ ];
22073
+ return details.length === 0 ? void 0 : details.join(" | ");
22074
+ };
22075
+ var presetCommand = {
22076
+ name: "preset",
22077
+ description: "Show or change the current DSH Agent preset",
22078
+ inputHint: "[preset]",
22079
+ kind: "built-in" /* BUILT_IN */,
22080
+ autoExecute: true,
22081
+ action: async (context, args) => {
22082
+ if (context.services.sideConversation?.getWorkspaceSnapshot().sideSessionId !== void 0) {
22083
+ return {
22084
+ type: "message",
22085
+ messageType: "error",
22086
+ content: "Close the Side conversation before changing the Main Agent preset. Use /side, then Ctrl+C."
22087
+ };
22088
+ }
22089
+ const runtime = context.services.agentPreset;
22090
+ if (runtime === void 0) {
22091
+ return {
22092
+ type: "message",
22093
+ messageType: "error",
22094
+ content: "DSH Agent presets are unavailable."
22095
+ };
22096
+ }
22097
+ await runtime.prepare(context.invocation.signal);
22098
+ const value = args.trim();
22099
+ if (value === "") {
22100
+ return {
22101
+ type: "custom_dialog",
22102
+ component: React25.createElement(AgentPresetDialog, {
22103
+ runtime,
22104
+ onClose: context.ui.removeComponent,
22105
+ onSwitched: (selection) => {
22106
+ context.ui.addItem({
22107
+ type: "info" /* INFO */,
22108
+ text: switchedMessage2(selection.name, selection.id)
22109
+ });
22110
+ context.ui.removeComponent();
22111
+ }
22112
+ })
22113
+ };
22114
+ }
22115
+ if (/\s/.test(value)) {
22116
+ return {
22117
+ type: "message",
22118
+ messageType: "error",
22119
+ content: "Usage: /preset [preset]"
22120
+ };
22121
+ }
22122
+ const option = await runtime.select(value, context.invocation.signal);
22123
+ return {
22124
+ type: "message",
22125
+ messageType: "info",
22126
+ content: switchedMessage2(option.name, option.id)
22127
+ };
22128
+ },
22129
+ completion: async (context, partialArg) => {
22130
+ const runtime = context.services.agentPreset;
22131
+ if (runtime === void 0) return [];
22132
+ await runtime.prepare();
22133
+ const prefix = partialArg.trimStart();
22134
+ const snapshot = runtime.getSnapshot();
22135
+ return snapshot.options.filter(
22136
+ (option) => option.broken === void 0 && option.id.startsWith(prefix)
22137
+ ).map((option) => {
22138
+ const description = completionDescription(option, snapshot.currentId);
22139
+ return {
22140
+ value: option.id,
22141
+ ...description === void 0 ? {} : { description }
22142
+ };
22143
+ });
22144
+ }
22145
+ };
22146
+
22147
+ // src/ui/commands/skills-command.ts
22148
+ import React26 from "react";
22149
+
22150
+ // src/ui/components/dialogs/skills-dialog.tsx
22151
+ import { useEffect as useEffect44, useMemo as useMemo39, useState as useState46, useSyncExternalStore as useSyncExternalStore7 } from "react";
22152
+ import { Box as Box80, Text as Text75 } from "ink";
22153
+ import { Fragment as Fragment28, jsx as jsx103, jsxs as jsxs77 } from "react/jsx-runtime";
22154
+ function summary2(value) {
22155
+ const line = value.replace(/\s+/g, " ").trim();
22156
+ return line.length > 90 ? `${line.slice(0, 89)}...` : line;
22157
+ }
22158
+ function SkillsDialog({
22159
+ runtime,
22160
+ onClose
22161
+ }) {
22162
+ const snapshot = useSyncExternalStore7(
22163
+ runtime.subscribe,
22164
+ runtime.getSnapshot,
22165
+ runtime.getSnapshot
22166
+ );
22167
+ const [selectedName, setSelectedName] = useState46(snapshot.skills[0]?.name);
22168
+ const selected = snapshot.skills.find((skill) => skill.name === selectedName) ?? snapshot.skills[0];
22169
+ useEffect44(() => {
22170
+ if (selected?.name !== selectedName) setSelectedName(selected?.name);
22171
+ }, [selected?.name, selectedName]);
22172
+ useKeypress(
22173
+ (key) => {
22174
+ if (key.name === "escape") onClose();
22175
+ },
22176
+ { isActive: true }
22177
+ );
22178
+ const items = useMemo39(
22179
+ () => snapshot.skills.map((skill) => ({
22180
+ key: skill.name,
22181
+ value: skill.name,
22182
+ title: `/${skill.name}`,
22183
+ description: summary2(skill.description)
22184
+ })),
22185
+ [snapshot.skills]
22186
+ );
22187
+ return /* @__PURE__ */ jsxs77(
22188
+ Box80,
22189
+ {
22190
+ borderStyle: "round",
22191
+ borderColor: theme.border.default,
22192
+ flexDirection: "column",
22193
+ paddingX: 1,
22194
+ paddingY: 1,
22195
+ width: "100%",
22196
+ children: [
22197
+ /* @__PURE__ */ jsxs77(Box80, { justifyContent: "space-between", children: [
22198
+ /* @__PURE__ */ jsxs77(Text75, { bold: true, color: theme.text.primary, children: [
22199
+ "DSH Skills (",
22200
+ snapshot.skills.length,
22201
+ ")"
22202
+ ] }),
22203
+ /* @__PURE__ */ jsx103(DialogCloseAction, { onClose })
22204
+ ] }),
22205
+ snapshot.error && /* @__PURE__ */ jsx103(Box80, { marginTop: 1, children: /* @__PURE__ */ jsx103(Text75, { color: theme.status.error, children: snapshot.error }) }),
22206
+ snapshot.skills.length === 0 ? /* @__PURE__ */ jsx103(Box80, { marginTop: 1, children: /* @__PURE__ */ jsx103(Text75, { color: theme.text.secondary, children: "No user-invocable Skills are visible to the current Agent." }) }) : /* @__PURE__ */ jsxs77(Box80, { flexDirection: "row", marginTop: 1, children: [
22207
+ /* @__PURE__ */ jsx103(Box80, { width: "55%", paddingRight: 2, flexDirection: "column", children: /* @__PURE__ */ jsx103(
22208
+ DescriptiveRadioButtonSelect,
22209
+ {
22210
+ items,
22211
+ onHighlight: setSelectedName,
22212
+ onSelect: setSelectedName,
22213
+ showNumbers: false,
22214
+ showScrollArrows: true,
22215
+ maxItemsToShow: 10
22216
+ }
22217
+ ) }),
22218
+ /* @__PURE__ */ jsx103(Box80, { width: "45%", paddingLeft: 2, flexDirection: "column", children: selected && /* @__PURE__ */ jsxs77(Fragment28, { children: [
22219
+ /* @__PURE__ */ jsxs77(Text75, { bold: true, color: theme.text.accent, children: [
22220
+ "/",
22221
+ selected.name
22222
+ ] }),
22223
+ !selected.modelInvocable && /* @__PURE__ */ jsx103(Text75, { color: theme.status.warning, children: "User invocation only" }),
22224
+ /* @__PURE__ */ jsx103(Box80, { marginTop: 1, children: /* @__PURE__ */ jsx103(Text75, { wrap: "wrap", children: selected.description }) }),
22225
+ selected.whenToUse && /* @__PURE__ */ jsxs77(Box80, { marginTop: 1, flexDirection: "column", children: [
22226
+ /* @__PURE__ */ jsx103(Text75, { bold: true, color: theme.text.primary, children: "When to use" }),
22227
+ /* @__PURE__ */ jsx103(Text75, { wrap: "wrap", children: selected.whenToUse })
22228
+ ] })
22229
+ ] }) })
22230
+ ] }),
22231
+ snapshot.skills.length > 0 && /* @__PURE__ */ jsx103(Box80, { marginTop: 1, children: /* @__PURE__ */ jsx103(Text75, { color: theme.text.secondary, children: "Type /name to invoke a Skill through DSH." }) })
22232
+ ]
22233
+ }
22234
+ );
22235
+ }
22236
+
22237
+ // src/ui/commands/skills-command.ts
22238
+ var skillsCommand = {
22239
+ name: "skills",
22240
+ description: "Inspect Skills visible to the current DSH Agent",
22241
+ kind: "built-in" /* BUILT_IN */,
22242
+ autoExecute: true,
22243
+ action: async (context, args) => {
22244
+ if (args.trim().length > 0) {
22245
+ return {
22246
+ type: "message",
22247
+ messageType: "error",
22248
+ content: "Usage: /skills"
22249
+ };
22250
+ }
22251
+ const runtime = context.services.skillCatalog;
22252
+ if (runtime === void 0) {
22253
+ return {
22254
+ type: "message",
22255
+ messageType: "error",
22256
+ content: "DSH Skill catalog is unavailable."
22257
+ };
22258
+ }
22259
+ await runtime.prepare(context.invocation.signal);
22260
+ return {
22261
+ type: "custom_dialog",
22262
+ component: React26.createElement(SkillsDialog, {
22263
+ runtime,
22264
+ onClose: context.ui.removeComponent
22265
+ })
22266
+ };
22267
+ }
22268
+ };
22269
+
21893
22270
  // src/services/builtin-command-loader.ts
21894
22271
  var BuiltinCommandLoader = class {
21895
22272
  constructor(enableProfiler = false) {
@@ -21913,6 +22290,8 @@ var BuiltinCommandLoader = class {
21913
22290
  changelogCommand,
21914
22291
  statsCommand,
21915
22292
  toolsCommand,
22293
+ skillsCommand,
22294
+ presetCommand,
21916
22295
  agentsCommand,
21917
22296
  btwCommand,
21918
22297
  mainCommand,
@@ -21957,6 +22336,7 @@ var DshCommandLoader = class {
21957
22336
  const invocation = context.invocation;
21958
22337
  const result = await this.runtime.execute(
21959
22338
  invocation.raw,
22339
+ invocation.attachments ?? [],
21960
22340
  invocation.signal
21961
22341
  );
21962
22342
  if (result.text === void 0) return;
@@ -21971,19 +22351,39 @@ var DshCommandLoader = class {
21971
22351
  }
21972
22352
  };
21973
22353
 
21974
- // src/ui/hooks/commands/use-slash-command-processor.ts
21975
- var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic, toggleVimEnabled, setIsProcessing, actions, setCustomDialog, modelSelection, permissionSelection, sessionManagement, toolCatalog, dshCommands, enableProfiler = false, providerSetup, sideConversation, subagentCatalog) => {
21976
- const session = useSessionStats();
21977
- const [commands, setCommands] = useState44(
21978
- void 0
22354
+ // src/services/skill-command-loader.ts
22355
+ var SkillCommandLoader = class {
22356
+ constructor(runtime) {
22357
+ this.runtime = runtime;
22358
+ }
22359
+ loadCommands(signal) {
22360
+ signal.throwIfAborted();
22361
+ return Promise.resolve(
22362
+ this.runtime.getSnapshot().skills.map((skill) => ({
22363
+ name: skill.name,
22364
+ description: skill.description,
22365
+ inputHint: "[request]",
22366
+ kind: "skill" /* SKILL */,
22367
+ autoExecute: false,
22368
+ recordInvocation: false
22369
+ }))
22370
+ );
22371
+ }
22372
+ };
22373
+
22374
+ // src/ui/hooks/commands/use-slash-command-processor.ts
22375
+ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic, toggleVimEnabled, setIsProcessing, actions, setCustomDialog, modelSelection, permissionSelection, sessionManagement, toolCatalog, dshCommands, enableProfiler = false, providerSetup, sideConversation, subagentCatalog, agentPreset, skillCatalog) => {
22376
+ const session = useSessionStats();
22377
+ const [commands, setCommands] = useState47(
22378
+ void 0
21979
22379
  );
21980
- const [reloadTrigger, setReloadTrigger] = useState44(0);
22380
+ const [reloadTrigger, setReloadTrigger] = useState47(0);
21981
22381
  const commandAbortRef = useRef25(void 0);
21982
- const reloadCommands = useCallback40(() => {
22382
+ const reloadCommands = useCallback41(() => {
21983
22383
  setReloadTrigger((v) => v + 1);
21984
22384
  }, []);
21985
- const [confirmationRequest, setConfirmationRequest] = useState44(null);
21986
- const commandContext = useMemo38(
22385
+ const [confirmationRequest, setConfirmationRequest] = useState47(null);
22386
+ const commandContext = useMemo40(
21987
22387
  () => ({
21988
22388
  services: {
21989
22389
  modelSelection,
@@ -21992,7 +22392,9 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
21992
22392
  sessionManagement,
21993
22393
  toolCatalog,
21994
22394
  sideConversation,
21995
- subagentCatalog
22395
+ subagentCatalog,
22396
+ agentPreset,
22397
+ skillCatalog
21996
22398
  },
21997
22399
  ui: {
21998
22400
  addItem,
@@ -22023,6 +22425,8 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
22023
22425
  toolCatalog,
22024
22426
  sideConversation,
22025
22427
  subagentCatalog,
22428
+ agentPreset,
22429
+ skillCatalog,
22026
22430
  loadHistory,
22027
22431
  addItem,
22028
22432
  clearItems,
@@ -22033,10 +22437,11 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
22033
22437
  setCustomDialog
22034
22438
  ]
22035
22439
  );
22036
- useEffect44(() => {
22440
+ useEffect45(() => {
22037
22441
  const controller = new AbortController();
22038
22442
  (async () => {
22039
22443
  const loaders = [
22444
+ ...skillCatalog === void 0 ? [] : [new SkillCommandLoader(skillCatalog)],
22040
22445
  ...dshCommands === void 0 ? [] : [new DshCommandLoader(dshCommands)],
22041
22446
  new BuiltinCommandLoader(enableProfiler)
22042
22447
  ];
@@ -22049,14 +22454,18 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
22049
22454
  return () => {
22050
22455
  controller.abort();
22051
22456
  };
22052
- }, [dshCommands, enableProfiler, reloadTrigger]);
22053
- useEffect44(
22457
+ }, [dshCommands, enableProfiler, reloadTrigger, skillCatalog]);
22458
+ useEffect45(
22054
22459
  () => dshCommands?.subscribe(reloadCommands),
22055
22460
  [dshCommands, reloadCommands]
22056
22461
  );
22057
- useEffect44(() => () => commandAbortRef.current?.abort(), []);
22058
- const handleSlashCommand = useCallback40(
22059
- async (rawQuery, overwriteConfirmed, addToHistory = true) => {
22462
+ useEffect45(
22463
+ () => skillCatalog?.subscribe(reloadCommands),
22464
+ [skillCatalog, reloadCommands]
22465
+ );
22466
+ useEffect45(() => () => commandAbortRef.current?.abort(), []);
22467
+ const handleSlashCommand = useCallback41(
22468
+ async (rawQuery, overwriteConfirmed, addToHistory = true, attachments = []) => {
22060
22469
  if (!commands) {
22061
22470
  return false;
22062
22471
  }
@@ -22064,19 +22473,32 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
22064
22473
  if (!trimmed.startsWith("/") && !trimmed.startsWith("?")) {
22065
22474
  return false;
22066
22475
  }
22476
+ const { commandToExecute, args } = parseSlashCommand(trimmed, commands);
22477
+ if (commandToExecute?.kind === "skill" /* SKILL */) return false;
22067
22478
  setIsProcessing(true);
22068
22479
  const commandController = new AbortController();
22069
22480
  commandAbortRef.current?.abort();
22070
22481
  commandAbortRef.current = commandController;
22071
- const { commandToExecute, args } = parseSlashCommand(trimmed, commands);
22072
- if (addToHistory && commandToExecute?.recordInvocation !== false) {
22073
- const userMessageTimestamp = Date.now();
22074
- addItem(
22075
- { type: "user" /* USER */, text: trimmed },
22076
- userMessageTimestamp
22077
- );
22078
- }
22079
22482
  try {
22483
+ if (attachments.length > 0 && commandToExecute?.kind === "built-in" /* BUILT_IN */) {
22484
+ throw new Error(
22485
+ `/${commandToExecute.name} does not accept image attachments.`
22486
+ );
22487
+ }
22488
+ if (commandToExecute === void 0 && skillCatalog !== void 0) {
22489
+ await skillCatalog.prepare(commandController.signal);
22490
+ const name2 = /^\/([^\s]+)/.exec(trimmed)?.[1];
22491
+ const dshOwnsName = dshCommands?.getSnapshot().commands.some((command) => command.name === name2);
22492
+ const skillOwnsName = skillCatalog.getSnapshot().skills.some((skill) => skill.name === name2);
22493
+ if (!dshOwnsName && skillOwnsName) return false;
22494
+ }
22495
+ if (addToHistory && commandToExecute?.recordInvocation !== false) {
22496
+ const userMessageTimestamp = Date.now();
22497
+ addItem(
22498
+ { type: "user" /* USER */, text: trimmed },
22499
+ userMessageTimestamp
22500
+ );
22501
+ }
22080
22502
  if (commandToExecute) {
22081
22503
  if (commandToExecute.action) {
22082
22504
  const fullCommandContext = {
@@ -22085,7 +22507,8 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
22085
22507
  raw: trimmed,
22086
22508
  name: commandToExecute.name,
22087
22509
  args,
22088
- signal: commandController.signal
22510
+ signal: commandController.signal,
22511
+ attachments
22089
22512
  },
22090
22513
  overwriteConfirmed
22091
22514
  };
@@ -22150,7 +22573,8 @@ var useSlashCommandProcessor = (addItem, clearItems, loadHistory, refreshStatic,
22150
22573
  return await handleSlashCommand(
22151
22574
  result.originalInvocation.raw,
22152
22575
  true,
22153
- false
22576
+ false,
22577
+ attachments
22154
22578
  );
22155
22579
  }
22156
22580
  case "custom_dialog": {
@@ -22176,6 +22600,7 @@ ${commandToExecute.subCommands.map((sc) => ` - ${sc.name}: ${sc.description ||
22176
22600
  if (dshCommands !== void 0) {
22177
22601
  const result = await dshCommands.execute(
22178
22602
  trimmed,
22603
+ attachments,
22179
22604
  commandController.signal
22180
22605
  );
22181
22606
  if (result.text !== void 0) {
@@ -22195,6 +22620,7 @@ ${commandToExecute.subCommands.map((sc) => ` - ${sc.name}: ${sc.description ||
22195
22620
  );
22196
22621
  return { type: "handled" };
22197
22622
  } catch (e) {
22623
+ if (commandController.signal.aborted) return { type: "handled" };
22198
22624
  addItem(
22199
22625
  {
22200
22626
  type: "error" /* ERROR */,
@@ -22216,6 +22642,7 @@ ${commandToExecute.subCommands.map((sc) => ` - ${sc.name}: ${sc.description ||
22216
22642
  commands,
22217
22643
  commandContext,
22218
22644
  dshCommands,
22645
+ skillCatalog,
22219
22646
  setIsProcessing,
22220
22647
  setConfirmationRequest,
22221
22648
  setCustomDialog
@@ -22237,13 +22664,13 @@ import * as fs12 from "node:fs";
22237
22664
  import { basename as basename3, join as join6 } from "node:path";
22238
22665
 
22239
22666
  // src/ui/hooks/commands/use-settings-command.ts
22240
- import { useState as useState45, useCallback as useCallback41 } from "react";
22667
+ import { useState as useState48, useCallback as useCallback42 } from "react";
22241
22668
  function useSettingsCommand() {
22242
- const [isSettingsDialogOpen, setIsSettingsDialogOpen] = useState45(false);
22243
- const openSettingsDialog = useCallback41(() => {
22669
+ const [isSettingsDialogOpen, setIsSettingsDialogOpen] = useState48(false);
22670
+ const openSettingsDialog = useCallback42(() => {
22244
22671
  setIsSettingsDialogOpen(true);
22245
22672
  }, []);
22246
- const closeSettingsDialog = useCallback41(() => {
22673
+ const closeSettingsDialog = useCallback42(() => {
22247
22674
  setIsSettingsDialogOpen(false);
22248
22675
  }, []);
22249
22676
  return {
@@ -22254,11 +22681,11 @@ function useSettingsCommand() {
22254
22681
  }
22255
22682
 
22256
22683
  // src/ui/hooks/commands/use-theme-command.ts
22257
- import { useState as useState46, useCallback as useCallback42 } from "react";
22684
+ import { useState as useState49, useCallback as useCallback43 } from "react";
22258
22685
  import process6 from "node:process";
22259
22686
  var useThemeCommand = (loadedSettings, setThemeError, addItem, initialThemeError) => {
22260
- const [isThemeDialogOpen, setIsThemeDialogOpen] = useState46(!!initialThemeError);
22261
- const openThemeDialog = useCallback42(() => {
22687
+ const [isThemeDialogOpen, setIsThemeDialogOpen] = useState49(!!initialThemeError);
22688
+ const openThemeDialog = useCallback43(() => {
22262
22689
  if (process6.env["NO_COLOR"]) {
22263
22690
  addItem(
22264
22691
  {
@@ -22271,7 +22698,7 @@ var useThemeCommand = (loadedSettings, setThemeError, addItem, initialThemeError
22271
22698
  }
22272
22699
  setIsThemeDialogOpen(true);
22273
22700
  }, [addItem]);
22274
- const applyTheme = useCallback42(
22701
+ const applyTheme = useCallback43(
22275
22702
  (themeName) => {
22276
22703
  if (!themeManager.setActiveTheme(themeName)) {
22277
22704
  setIsThemeDialogOpen(true);
@@ -22282,17 +22709,17 @@ var useThemeCommand = (loadedSettings, setThemeError, addItem, initialThemeError
22282
22709
  },
22283
22710
  [setThemeError]
22284
22711
  );
22285
- const handleThemeHighlight = useCallback42(
22712
+ const handleThemeHighlight = useCallback43(
22286
22713
  (themeName) => {
22287
22714
  applyTheme(themeName);
22288
22715
  },
22289
22716
  [applyTheme]
22290
22717
  );
22291
- const closeThemeDialog = useCallback42(() => {
22718
+ const closeThemeDialog = useCallback43(() => {
22292
22719
  applyTheme(loadedSettings.merged.ui.theme);
22293
22720
  setIsThemeDialogOpen(false);
22294
22721
  }, [applyTheme, loadedSettings]);
22295
- const handleThemeSelect = useCallback42(
22722
+ const handleThemeSelect = useCallback43(
22296
22723
  (themeName, scope) => {
22297
22724
  try {
22298
22725
  const mergedCustomThemes = {
@@ -22328,7 +22755,7 @@ var useThemeCommand = (loadedSettings, setThemeError, addItem, initialThemeError
22328
22755
  };
22329
22756
 
22330
22757
  // src/ui/hooks/input/use-vim.ts
22331
- import { useCallback as useCallback43, useReducer as useReducer5, useEffect as useEffect45, useRef as useRef26 } from "react";
22758
+ import { useCallback as useCallback44, useReducer as useReducer5, useEffect as useEffect46, useRef as useRef26 } from "react";
22332
22759
  var DIGIT_MULTIPLIER = 10;
22333
22760
  var DEFAULT_COUNT = 1;
22334
22761
  var DIGIT_1_TO_9 = /^[1-9]$/;
@@ -22394,21 +22821,21 @@ function useVim(buffer, onSubmit) {
22394
22821
  const { vimEnabled, vimMode, setVimMode } = useVimMode();
22395
22822
  const [state, dispatch] = useReducer5(vimReducer, initialVimState);
22396
22823
  const lastEscapeTimestampRef = useRef26(0);
22397
- useEffect45(() => {
22824
+ useEffect46(() => {
22398
22825
  dispatch({ type: "SET_MODE", mode: vimMode });
22399
22826
  }, [vimMode]);
22400
- const updateMode = useCallback43(
22827
+ const updateMode = useCallback44(
22401
22828
  (mode) => {
22402
22829
  setVimMode(mode);
22403
22830
  dispatch({ type: "SET_MODE", mode });
22404
22831
  },
22405
22832
  [setVimMode]
22406
22833
  );
22407
- const getCurrentCount = useCallback43(
22834
+ const getCurrentCount = useCallback44(
22408
22835
  () => state.count || DEFAULT_COUNT,
22409
22836
  [state.count]
22410
22837
  );
22411
- const checkDoubleEscape = useCallback43(() => {
22838
+ const checkDoubleEscape = useCallback44(() => {
22412
22839
  const now = Date.now();
22413
22840
  const lastEscape = lastEscapeTimestampRef.current;
22414
22841
  lastEscapeTimestampRef.current = now;
@@ -22418,7 +22845,7 @@ function useVim(buffer, onSubmit) {
22418
22845
  }
22419
22846
  return false;
22420
22847
  }, []);
22421
- const executeCommand = useCallback43(
22848
+ const executeCommand = useCallback44(
22422
22849
  (cmdType, count) => {
22423
22850
  switch (cmdType) {
22424
22851
  case CMD_TYPES.DELETE_WORD_FORWARD: {
@@ -22494,7 +22921,7 @@ function useVim(buffer, onSubmit) {
22494
22921
  },
22495
22922
  [buffer, updateMode]
22496
22923
  );
22497
- const handleInsertModeInput = useCallback43(
22924
+ const handleInsertModeInput = useCallback44(
22498
22925
  (normalizedKey) => {
22499
22926
  if (keyMatchers["basic.cancel" /* ESCAPE */](normalizedKey)) {
22500
22927
  checkDoubleEscape();
@@ -22526,7 +22953,7 @@ function useVim(buffer, onSubmit) {
22526
22953
  },
22527
22954
  [buffer, dispatch, updateMode, onSubmit, checkDoubleEscape]
22528
22955
  );
22529
- const normalizeKey = useCallback43(
22956
+ const normalizeKey = useCallback44(
22530
22957
  (key) => ({
22531
22958
  name: key.name || "",
22532
22959
  sequence: key.sequence || "",
@@ -22538,7 +22965,7 @@ function useVim(buffer, onSubmit) {
22538
22965
  }),
22539
22966
  []
22540
22967
  );
22541
- const handleChangeMovement = useCallback43(
22968
+ const handleChangeMovement = useCallback44(
22542
22969
  (movement) => {
22543
22970
  const count = getCurrentCount();
22544
22971
  dispatch({ type: "CLEAR_COUNT" });
@@ -22559,7 +22986,7 @@ function useVim(buffer, onSubmit) {
22559
22986
  },
22560
22987
  [getCurrentCount, dispatch, buffer, updateMode]
22561
22988
  );
22562
- const handleOperatorMotion = useCallback43(
22989
+ const handleOperatorMotion = useCallback44(
22563
22990
  (operator, motion) => {
22564
22991
  const count = getCurrentCount();
22565
22992
  const commandMap = {
@@ -22586,7 +23013,7 @@ function useVim(buffer, onSubmit) {
22586
23013
  },
22587
23014
  [getCurrentCount, executeCommand, dispatch]
22588
23015
  );
22589
- const handleInput = useCallback43(
23016
+ const handleInput = useCallback44(
22590
23017
  (key) => {
22591
23018
  if (!vimEnabled) {
22592
23019
  return false;
@@ -22893,13 +23320,13 @@ function useVim(buffer, onSubmit) {
22893
23320
  }
22894
23321
 
22895
23322
  // src/ui/hooks/session/use-git-branch-name.ts
22896
- import { useState as useState47, useEffect as useEffect46, useCallback as useCallback44 } from "react";
23323
+ import { useState as useState50, useEffect as useEffect47, useCallback as useCallback45 } from "react";
22897
23324
  import fs9 from "node:fs";
22898
23325
  import fsPromises2 from "node:fs/promises";
22899
23326
  import path11 from "node:path";
22900
23327
  function useGitBranchName(cwd) {
22901
- const [branchName, setBranchName] = useState47(void 0);
22902
- const fetchBranchName = useCallback44(async () => {
23328
+ const [branchName, setBranchName] = useState50(void 0);
23329
+ const fetchBranchName = useCallback45(async () => {
22903
23330
  try {
22904
23331
  const { stdout } = await spawnAsync(
22905
23332
  "git",
@@ -22921,7 +23348,7 @@ function useGitBranchName(cwd) {
22921
23348
  setBranchName(void 0);
22922
23349
  }
22923
23350
  }, [cwd, setBranchName]);
22924
- useEffect46(() => {
23351
+ useEffect47(() => {
22925
23352
  fetchBranchName();
22926
23353
  const gitLogsHeadPath = path11.join(cwd, ".git", "logs", "HEAD");
22927
23354
  let watcher;
@@ -22948,7 +23375,7 @@ function useGitBranchName(cwd) {
22948
23375
  }
22949
23376
 
22950
23377
  // src/ui/hooks/settings/use-editor-settings.ts
22951
- import { useState as useState48, useCallback as useCallback45 } from "react";
23378
+ import { useState as useState51, useCallback as useCallback46 } from "react";
22952
23379
 
22953
23380
  // src/config/setting-paths.ts
22954
23381
  var SettingPaths = {
@@ -22959,11 +23386,11 @@ var SettingPaths = {
22959
23386
 
22960
23387
  // src/ui/hooks/settings/use-editor-settings.ts
22961
23388
  var useEditorSettings = (loadedSettings, setEditorError, addItem) => {
22962
- const [isEditorDialogOpen, setIsEditorDialogOpen] = useState48(false);
22963
- const openEditorDialog = useCallback45(() => {
23389
+ const [isEditorDialogOpen, setIsEditorDialogOpen] = useState51(false);
23390
+ const openEditorDialog = useCallback46(() => {
22964
23391
  setIsEditorDialogOpen(true);
22965
23392
  }, []);
22966
- const handleEditorSelect = useCallback45(
23393
+ const handleEditorSelect = useCallback46(
22967
23394
  (editorType, scope) => {
22968
23395
  if (editorType && !checkHasEditorType(editorType)) {
22969
23396
  return;
@@ -22989,7 +23416,7 @@ var useEditorSettings = (loadedSettings, setEditorError, addItem) => {
22989
23416
  },
22990
23417
  [loadedSettings, setEditorError, addItem]
22991
23418
  );
22992
- const exitEditorDialog = useCallback45(() => {
23419
+ const exitEditorDialog = useCallback46(() => {
22993
23420
  setIsEditorDialogOpen(false);
22994
23421
  }, []);
22995
23422
  return {
@@ -23001,12 +23428,12 @@ var useEditorSettings = (loadedSettings, setEditorError, addItem) => {
23001
23428
  };
23002
23429
 
23003
23430
  // src/ui/hooks/terminal/use-memory-monitor.ts
23004
- import { useEffect as useEffect47 } from "react";
23431
+ import { useEffect as useEffect48 } from "react";
23005
23432
  import process7 from "node:process";
23006
23433
  var MEMORY_WARNING_THRESHOLD = 7 * 1024 * 1024 * 1024;
23007
23434
  var MEMORY_CHECK_INTERVAL = 60 * 1e3;
23008
23435
  var useMemoryMonitor = ({ addItem }) => {
23009
- useEffect47(() => {
23436
+ useEffect48(() => {
23010
23437
  const intervalId = setInterval(() => {
23011
23438
  const usage = process7.memoryUsage().rss;
23012
23439
  if (usage > MEMORY_WARNING_THRESHOLD) {
@@ -23026,8 +23453,8 @@ var useMemoryMonitor = ({ addItem }) => {
23026
23453
 
23027
23454
  // src/ui/hooks/visual/use-console-messages.ts
23028
23455
  import {
23029
- useCallback as useCallback46,
23030
- useEffect as useEffect48,
23456
+ useCallback as useCallback47,
23457
+ useEffect as useEffect49,
23031
23458
  useReducer as useReducer6,
23032
23459
  useRef as useRef27,
23033
23460
  useTransition
@@ -23060,7 +23487,7 @@ function useConsoleMessages() {
23060
23487
  const messageQueueRef = useRef27([]);
23061
23488
  const timeoutRef = useRef27(null);
23062
23489
  const [, startTransition] = useTransition();
23063
- const processQueue = useCallback46(() => {
23490
+ const processQueue = useCallback47(() => {
23064
23491
  if (messageQueueRef.current.length > 0) {
23065
23492
  const messagesToProcess = messageQueueRef.current;
23066
23493
  messageQueueRef.current = [];
@@ -23070,7 +23497,7 @@ function useConsoleMessages() {
23070
23497
  }
23071
23498
  timeoutRef.current = null;
23072
23499
  }, []);
23073
- const handleNewMessage = useCallback46(
23500
+ const handleNewMessage = useCallback47(
23074
23501
  (message) => {
23075
23502
  messageQueueRef.current.push(message);
23076
23503
  if (!timeoutRef.current) {
@@ -23079,7 +23506,7 @@ function useConsoleMessages() {
23079
23506
  },
23080
23507
  [processQueue]
23081
23508
  );
23082
- useEffect48(() => {
23509
+ useEffect49(() => {
23083
23510
  const handleConsoleLog = (payload) => {
23084
23511
  handleNewMessage({
23085
23512
  type: payload.type,
@@ -23098,7 +23525,7 @@ function useConsoleMessages() {
23098
23525
  coreEvents.off(CoreEvent.Output, handleOutput);
23099
23526
  };
23100
23527
  }, [handleNewMessage]);
23101
- const clearConsoleMessages = useCallback46(() => {
23528
+ const clearConsoleMessages = useCallback47(() => {
23102
23529
  if (timeoutRef.current) {
23103
23530
  clearTimeout(timeoutRef.current);
23104
23531
  timeoutRef.current = null;
@@ -23108,7 +23535,7 @@ function useConsoleMessages() {
23108
23535
  dispatch({ type: "CLEAR" });
23109
23536
  });
23110
23537
  }, []);
23111
- useEffect48(
23538
+ useEffect49(
23112
23539
  () => () => {
23113
23540
  if (timeoutRef.current) {
23114
23541
  clearTimeout(timeoutRef.current);
@@ -23120,13 +23547,13 @@ function useConsoleMessages() {
23120
23547
  }
23121
23548
 
23122
23549
  // src/ui/hooks/visual/use-timer.ts
23123
- import { useState as useState49, useEffect as useEffect49, useRef as useRef28 } from "react";
23550
+ import { useState as useState52, useEffect as useEffect50, useRef as useRef28 } from "react";
23124
23551
  var useTimer = (isActive, resetKey) => {
23125
- const [elapsedTime, setElapsedTime] = useState49(0);
23552
+ const [elapsedTime, setElapsedTime] = useState52(0);
23126
23553
  const timerRef = useRef28(null);
23127
23554
  const prevResetKeyRef = useRef28(resetKey);
23128
23555
  const prevIsActiveRef = useRef28(isActive);
23129
- useEffect49(() => {
23556
+ useEffect50(() => {
23130
23557
  let shouldResetTime = false;
23131
23558
  if (prevResetKeyRef.current !== resetKey) {
23132
23559
  shouldResetTime = true;
@@ -23163,7 +23590,7 @@ var useTimer = (isActive, resetKey) => {
23163
23590
  };
23164
23591
 
23165
23592
  // src/ui/hooks/visual/use-phrase-cycler.ts
23166
- import { useState as useState50, useEffect as useEffect50, useRef as useRef29 } from "react";
23593
+ import { useState as useState53, useEffect as useEffect51, useRef as useRef29 } from "react";
23167
23594
 
23168
23595
  // src/ui/components/indicators/loading-phrases.ts
23169
23596
  var WITTY_LOADING_PHRASES = [
@@ -23305,12 +23732,12 @@ var PHRASE_CHANGE_INTERVAL_MS = 15e3;
23305
23732
  var INTERACTIVE_SHELL_WAITING_PHRASE = "Interactive shell awaiting input... press tab to focus shell";
23306
23733
  var usePhraseCycler = (isActive, shouldShowFocusHint, customPhrases) => {
23307
23734
  const loadingPhrases = customPhrases && customPhrases.length > 0 ? customPhrases : WITTY_LOADING_PHRASES;
23308
- const [currentLoadingPhrase, setCurrentLoadingPhrase] = useState50(
23735
+ const [currentLoadingPhrase, setCurrentLoadingPhrase] = useState53(
23309
23736
  loadingPhrases[0]
23310
23737
  );
23311
23738
  const phraseIntervalRef = useRef29(null);
23312
23739
  const hasShownFirstRequestTipRef = useRef29(false);
23313
- useEffect50(() => {
23740
+ useEffect51(() => {
23314
23741
  if (phraseIntervalRef.current) {
23315
23742
  clearInterval(phraseIntervalRef.current);
23316
23743
  phraseIntervalRef.current = null;
@@ -23355,13 +23782,13 @@ var usePhraseCycler = (isActive, shouldShowFocusHint, customPhrases) => {
23355
23782
  };
23356
23783
 
23357
23784
  // src/ui/hooks/visual/use-loading-indicator.ts
23358
- import { useState as useState51, useEffect as useEffect51, useRef as useRef30 } from "react";
23785
+ import { useState as useState54, useEffect as useEffect52, useRef as useRef30 } from "react";
23359
23786
  var useLoadingIndicator = ({
23360
23787
  streamingState,
23361
23788
  shouldShowFocusHint,
23362
23789
  customWittyPhrases
23363
23790
  }) => {
23364
- const [timerResetKey, setTimerResetKey] = useState51(0);
23791
+ const [timerResetKey, setTimerResetKey] = useState54(0);
23365
23792
  const isTimerActive = streamingState === "responding" /* Responding */;
23366
23793
  const elapsedTimeFromTimer = useTimer(isTimerActive, timerResetKey);
23367
23794
  const isPhraseCyclingActive = streamingState === "responding" /* Responding */;
@@ -23371,7 +23798,7 @@ var useLoadingIndicator = ({
23371
23798
  customWittyPhrases
23372
23799
  );
23373
23800
  const prevStreamingStateRef = useRef30(null);
23374
- useEffect51(() => {
23801
+ useEffect52(() => {
23375
23802
  if (streamingState === "idle" /* Idle */ && prevStreamingStateRef.current === "responding" /* Responding */) {
23376
23803
  setTimerResetKey((prevKey) => prevKey + 1);
23377
23804
  }
@@ -23384,18 +23811,18 @@ var useLoadingIndicator = ({
23384
23811
  };
23385
23812
 
23386
23813
  // src/ui/hooks/session/use-message-queue.ts
23387
- import { useCallback as useCallback47, useEffect as useEffect52, useMemo as useMemo39, useState as useState52 } from "react";
23814
+ import { useCallback as useCallback48, useEffect as useEffect53, useMemo as useMemo41, useState as useState55 } from "react";
23388
23815
  function useMessageQueue({
23389
23816
  queueKey,
23390
23817
  streamingState,
23391
23818
  submitQuery
23392
23819
  }) {
23393
- const [queuedMessages, setQueuedMessages] = useState52([]);
23394
- const messageQueue = useMemo39(
23820
+ const [queuedMessages, setQueuedMessages] = useState55([]);
23821
+ const messageQueue = useMemo41(
23395
23822
  () => queuedMessages.filter((entry) => entry.key === queueKey).map((entry) => entry.message),
23396
23823
  [queueKey, queuedMessages]
23397
23824
  );
23398
- const addMessage = useCallback47((message) => {
23825
+ const addMessage = useCallback48((message) => {
23399
23826
  const trimmedMessage = message.trim();
23400
23827
  if (trimmedMessage.length > 0) {
23401
23828
  setQueuedMessages((previous) => [
@@ -23404,16 +23831,16 @@ function useMessageQueue({
23404
23831
  ]);
23405
23832
  }
23406
23833
  }, [queueKey]);
23407
- const clearQueue = useCallback47(() => {
23834
+ const clearQueue = useCallback48(() => {
23408
23835
  setQueuedMessages(
23409
23836
  (previous) => previous.filter((entry) => entry.key !== queueKey)
23410
23837
  );
23411
23838
  }, [queueKey]);
23412
- const getQueuedMessagesText = useCallback47(() => {
23839
+ const getQueuedMessagesText = useCallback48(() => {
23413
23840
  if (messageQueue.length === 0) return "";
23414
23841
  return messageQueue.join("\n\n");
23415
23842
  }, [messageQueue]);
23416
- const popAllMessages = useCallback47(() => {
23843
+ const popAllMessages = useCallback48(() => {
23417
23844
  if (messageQueue.length === 0) {
23418
23845
  return void 0;
23419
23846
  }
@@ -23423,7 +23850,7 @@ function useMessageQueue({
23423
23850
  );
23424
23851
  return allMessages;
23425
23852
  }, [messageQueue, queueKey]);
23426
- useEffect52(() => {
23853
+ useEffect53(() => {
23427
23854
  if (streamingState === "idle" /* Idle */ && messageQueue.length > 0) {
23428
23855
  const combinedMessage = messageQueue.join("\n\n");
23429
23856
  setQueuedMessages(
@@ -23442,16 +23869,16 @@ function useMessageQueue({
23442
23869
  }
23443
23870
 
23444
23871
  // src/ui/hooks/input/use-input-history-store.ts
23445
- import { useCallback as useCallback48, useRef as useRef31, useState as useState53 } from "react";
23872
+ import { useCallback as useCallback49, useRef as useRef31, useState as useState56 } from "react";
23446
23873
  function deduplicateConsecutive(messages) {
23447
23874
  return messages.filter(
23448
23875
  (message, index) => index === 0 || message !== messages[index - 1]
23449
23876
  );
23450
23877
  }
23451
23878
  function useInputHistoryStore() {
23452
- const [inputHistory, setInputHistory] = useState53([]);
23879
+ const [inputHistory, setInputHistory] = useState56([]);
23453
23880
  const initializationStarted = useRef31(false);
23454
- const initializeFromHistory = useCallback48(
23881
+ const initializeFromHistory = useCallback49(
23455
23882
  async (history) => {
23456
23883
  if (initializationStarted.current) return;
23457
23884
  initializationStarted.current = true;
@@ -23472,7 +23899,7 @@ function useInputHistoryStore() {
23472
23899
  },
23473
23900
  []
23474
23901
  );
23475
- const addInput = useCallback48(
23902
+ const addInput = useCallback49(
23476
23903
  (input) => {
23477
23904
  const trimmedInput = input.trim();
23478
23905
  if (!trimmedInput) return;
@@ -23572,12 +23999,12 @@ var PromptHistoryStore = class {
23572
23999
  };
23573
24000
 
23574
24001
  // src/ui/hooks/ai/use-turn-activity-monitor.ts
23575
- import { useState as useState54, useEffect as useEffect53, useRef as useRef32 } from "react";
24002
+ import { useState as useState57, useEffect as useEffect54, useRef as useRef32 } from "react";
23576
24003
  var useTurnActivityMonitor = (streamingState, activePtyId) => {
23577
- const [operationStartTime, setOperationStartTime] = useState54(0);
24004
+ const [operationStartTime, setOperationStartTime] = useState57(0);
23578
24005
  const prevPtyIdRef = useRef32(void 0);
23579
24006
  const prevStreamingStateRef = useRef32(void 0);
23580
- useEffect53(() => {
24007
+ useEffect54(() => {
23581
24008
  const isNowResponding = streamingState === "responding" /* Responding */;
23582
24009
  const wasResponding = prevStreamingStateRef.current === "responding" /* Responding */;
23583
24010
  const ptyChanged = activePtyId !== prevPtyIdRef.current;
@@ -23636,7 +24063,7 @@ var useShellInactivityStatus = ({
23636
24063
  };
23637
24064
 
23638
24065
  // src/ui/hooks/input/use-local-shell-command.ts
23639
- import { useCallback as useCallback49, useEffect as useEffect54, useRef as useRef33, useState as useState55 } from "react";
24066
+ import { useCallback as useCallback50, useEffect as useEffect55, useRef as useRef33, useState as useState58 } from "react";
23640
24067
  import crypto2 from "node:crypto";
23641
24068
  import fs11 from "node:fs";
23642
24069
  import os3 from "node:os";
@@ -23655,18 +24082,18 @@ function useLocalShellCommand({
23655
24082
  }) {
23656
24083
  const controllerRef = useRef33(void 0);
23657
24084
  const mountedRef = useRef33(true);
23658
- const [isExecuting, setIsExecuting] = useState55(false);
23659
- const [activePtyId, setActivePtyId] = useState55(void 0);
23660
- const [lastOutputTime, setLastOutputTime] = useState55(0);
23661
- const cancel = useCallback49(() => controllerRef.current?.abort(), []);
23662
- useEffect54(() => {
24085
+ const [isExecuting, setIsExecuting] = useState58(false);
24086
+ const [activePtyId, setActivePtyId] = useState58(void 0);
24087
+ const [lastOutputTime, setLastOutputTime] = useState58(0);
24088
+ const cancel = useCallback50(() => controllerRef.current?.abort(), []);
24089
+ useEffect55(() => {
23663
24090
  mountedRef.current = true;
23664
24091
  return () => {
23665
24092
  mountedRef.current = false;
23666
24093
  controllerRef.current?.abort();
23667
24094
  };
23668
24095
  }, []);
23669
- const execute = useCallback49(
24096
+ const execute = useCallback50(
23670
24097
  (rawCommand) => {
23671
24098
  const command = rawCommand.trim();
23672
24099
  if (command.length === 0 || controllerRef.current !== void 0) {
@@ -23865,7 +24292,7 @@ ${output}`;
23865
24292
  }
23866
24293
 
23867
24294
  // src/ui/app-container.tsx
23868
- import { jsx as jsx102 } from "react/jsx-runtime";
24295
+ import { jsx as jsx104 } from "react/jsx-runtime";
23869
24296
  var SHELL_WIDTH_FRACTION = 0.89;
23870
24297
  var SHELL_HEIGHT_PADDING = 10;
23871
24298
  var noopExternalStoreSubscribe = () => () => {
@@ -23885,6 +24312,7 @@ var EMPTY_SUBAGENT_CATALOG_SNAPSHOT = {
23885
24312
  };
23886
24313
  var emptySubagentCatalogSnapshot = () => EMPTY_SUBAGENT_CATALOG_SNAPSHOT;
23887
24314
  var AppContainer = (props) => {
24315
+ const { isReady: isKeypressReady } = useKeypressContext();
23888
24316
  const {
23889
24317
  config,
23890
24318
  initializationResult,
@@ -23900,38 +24328,40 @@ var AppContainer = (props) => {
23900
24328
  permissionSelectionRuntime,
23901
24329
  interactionModeRuntime,
23902
24330
  toolCatalogRuntime,
24331
+ agentPresetRuntime,
24332
+ skillCatalogRuntime,
23903
24333
  sideConversationRuntime,
23904
24334
  subagentCatalogRuntime
23905
24335
  } = props;
23906
24336
  const historyManager = useHistory();
23907
- const conversationSnapshot = useSyncExternalStore6(
24337
+ const conversationSnapshot = useSyncExternalStore8(
23908
24338
  conversationRuntime.subscribe,
23909
24339
  conversationRuntime.getSnapshot,
23910
24340
  conversationRuntime.getSnapshot
23911
24341
  );
23912
- const sideConversationSnapshot = useSyncExternalStore6(
24342
+ const sideConversationSnapshot = useSyncExternalStore8(
23913
24343
  sideConversationRuntime?.subscribeWorkspace ?? noopExternalStoreSubscribe,
23914
24344
  sideConversationRuntime?.getWorkspaceSnapshot ?? emptySideConversationSnapshot,
23915
24345
  sideConversationRuntime?.getWorkspaceSnapshot ?? emptySideConversationSnapshot
23916
24346
  );
23917
- const subagentCatalogSnapshot = useSyncExternalStore6(
24347
+ const subagentCatalogSnapshot = useSyncExternalStore8(
23918
24348
  subagentCatalogRuntime?.subscribe ?? noopExternalStoreSubscribe,
23919
24349
  subagentCatalogRuntime?.getSnapshot ?? emptySubagentCatalogSnapshot,
23920
24350
  subagentCatalogRuntime?.getSnapshot ?? emptySubagentCatalogSnapshot
23921
24351
  );
23922
- const approvalSnapshot = useSyncExternalStore6(
24352
+ const approvalSnapshot = useSyncExternalStore8(
23923
24353
  approvalRuntime.subscribe,
23924
24354
  approvalRuntime.getSnapshot,
23925
24355
  approvalRuntime.getSnapshot
23926
24356
  );
23927
24357
  const pendingApproval = approvalSnapshot.pending[0];
23928
- const userQuestionSnapshot = useSyncExternalStore6(
24358
+ const userQuestionSnapshot = useSyncExternalStore8(
23929
24359
  userQuestionRuntime.subscribe,
23930
24360
  userQuestionRuntime.getSnapshot,
23931
24361
  userQuestionRuntime.getSnapshot
23932
24362
  );
23933
24363
  const pendingUserQuestion = userQuestionSnapshot.pending[0];
23934
- const interactionModeSnapshot = useSyncExternalStore6(
24364
+ const interactionModeSnapshot = useSyncExternalStore8(
23935
24365
  interactionModeRuntime.subscribe,
23936
24366
  interactionModeRuntime.getSnapshot,
23937
24367
  interactionModeRuntime.getSnapshot
@@ -23939,15 +24369,15 @@ var AppContainer = (props) => {
23939
24369
  const conversationHistoryIds = useRef34(/* @__PURE__ */ new Map());
23940
24370
  const conversationHistoryTexts = useRef34(/* @__PURE__ */ new Map());
23941
24371
  const conversationSessionId = conversationRuntime.getSessionStats().sessionId;
23942
- const [projectedSessionId, setProjectedSessionId] = useState56(
24372
+ const [projectedSessionId, setProjectedSessionId] = useState59(
23943
24373
  conversationSessionId
23944
24374
  );
23945
24375
  const promptInputAbortRef = useRef34(void 0);
23946
- const [promptInputPreparing, setPromptInputPreparing] = useState56(false);
24376
+ const [promptInputPreparing, setPromptInputPreparing] = useState59(false);
23947
24377
  const addConversationHistoryItem = historyManager.addItem;
23948
24378
  const updateConversationHistoryItem = historyManager.updateItem;
23949
24379
  const clearConversationHistory = historyManager.clearItems;
23950
- useEffect55(() => {
24380
+ useEffect56(() => {
23951
24381
  if (projectedSessionId !== conversationSessionId) {
23952
24382
  conversationHistoryIds.current.clear();
23953
24383
  conversationHistoryTexts.current.clear();
@@ -23992,32 +24422,32 @@ var AppContainer = (props) => {
23992
24422
  useMemoryMonitor(historyManager);
23993
24423
  const settings = useSettings();
23994
24424
  const isAlternateBuffer = useAlternateBuffer();
23995
- const [debugMessage, setDebugMessage] = useState56("");
23996
- const [quittingMessages, setQuittingMessages] = useState56(null);
23997
- const [themeError, setThemeError] = useState56(
24425
+ const [debugMessage, setDebugMessage] = useState59("");
24426
+ const [quittingMessages, setQuittingMessages] = useState59(null);
24427
+ const [themeError, setThemeError] = useState59(
23998
24428
  initializationResult.themeError
23999
24429
  );
24000
- const [isProcessing, setIsProcessing] = useState56(false);
24001
- const [embeddedShellFocused, setEmbeddedShellFocused] = useState56(false);
24430
+ const [isProcessing, setIsProcessing] = useState59(false);
24431
+ const [embeddedShellFocused, setEmbeddedShellFocused] = useState59(false);
24002
24432
  const enableProfiler = config.getDebugMode() || process8.env["NODE_ENV"] === "development";
24003
- const [showDebugProfiler, setShowDebugProfiler] = useState56(enableProfiler);
24004
- const [customDialog, setCustomDialog] = useState56(
24433
+ const [showDebugProfiler, setShowDebugProfiler] = useState59(enableProfiler);
24434
+ const [customDialog, setCustomDialog] = useState59(
24005
24435
  null
24006
24436
  );
24007
- const [copyModeEnabled, setCopyModeEnabled] = useState56(false);
24008
- const [pendingRestorePrompt, setPendingRestorePrompt] = useState56(false);
24009
- const [shellModeActive, setShellModeActive] = useState56(false);
24010
- const [pendingShellHistoryItem, setPendingShellHistoryItem] = useState56(null);
24011
- const [historyRemountKey, setHistoryRemountKey] = useState56(0);
24012
- const [settingsNonce, setSettingsNonce] = useState56(0);
24013
- const [queueErrorMessage, setQueueErrorMessage] = useState56(
24437
+ const [copyModeEnabled, setCopyModeEnabled] = useState59(false);
24438
+ const [pendingRestorePrompt, setPendingRestorePrompt] = useState59(false);
24439
+ const [shellModeActive, setShellModeActive] = useState59(false);
24440
+ const [pendingShellHistoryItem, setPendingShellHistoryItem] = useState59(null);
24441
+ const [historyRemountKey, setHistoryRemountKey] = useState59(0);
24442
+ const [settingsNonce, setSettingsNonce] = useState59(0);
24443
+ const [queueErrorMessage, setQueueErrorMessage] = useState59(
24014
24444
  null
24015
24445
  );
24016
- const toggleDebugProfiler = useCallback50(
24446
+ const toggleDebugProfiler = useCallback51(
24017
24447
  () => setShowDebugProfiler((visible) => !visible),
24018
24448
  []
24019
24449
  );
24020
- const togglePlanMode = useCallback50(
24450
+ const togglePlanMode = useCallback51(
24021
24451
  (active) => {
24022
24452
  void interactionModeRuntime.togglePlan(void 0, active).catch((error) => {
24023
24453
  setQueueErrorMessage(getErrorMessage(error));
@@ -24025,10 +24455,10 @@ var AppContainer = (props) => {
24025
24455
  },
24026
24456
  [interactionModeRuntime]
24027
24457
  );
24028
- const [modelSelectionSnapshot, setModelSelectionSnapshot] = useState56(
24458
+ const [modelSelectionSnapshot, setModelSelectionSnapshot] = useState59(
24029
24459
  () => modelSelectionRuntime?.getSnapshot()
24030
24460
  );
24031
- useEffect55(
24461
+ useEffect56(
24032
24462
  () => modelSelectionRuntime?.subscribe(
24033
24463
  () => setModelSelectionSnapshot(modelSelectionRuntime.getSnapshot())
24034
24464
  ),
@@ -24036,13 +24466,13 @@ var AppContainer = (props) => {
24036
24466
  );
24037
24467
  const currentModel = sideConversationSnapshot.activeSurface === "side" && sideConversationSnapshot.sideModelLabel ? sideConversationSnapshot.sideModelLabel : modelSelectionSnapshot ? modelSelectionLabel(modelSelectionSnapshot.current) : "DSH default";
24038
24468
  const currentReasoningEffort = sideConversationSnapshot.activeSurface === "side" ? sideConversationSnapshot.sideReasoningEffortLabel : modelSelectionSnapshot ? modelReasoningEffortLabel(modelSelectionSnapshot.current) : void 0;
24039
- const providerSetupSnapshot = useSyncExternalStore6(
24469
+ const providerSetupSnapshot = useSyncExternalStore8(
24040
24470
  providerSetupRuntime?.subscribe ?? noopExternalStoreSubscribe,
24041
24471
  providerSetupRuntime?.getSnapshot ?? emptyProviderSetupSnapshot,
24042
24472
  providerSetupRuntime?.getSnapshot ?? emptyProviderSetupSnapshot
24043
24473
  );
24044
- const [providerSetupDismissed, setProviderSetupDismissed] = useState56(false);
24045
- const promptHistory = useMemo40(
24474
+ const [providerSetupDismissed, setProviderSetupDismissed] = useState59(false);
24475
+ const promptHistory = useMemo42(
24046
24476
  () => new PromptHistoryStore(
24047
24477
  join6(config.storage.getProjectTempDir(), "prompt_history.json")
24048
24478
  ),
@@ -24059,12 +24489,12 @@ var AppContainer = (props) => {
24059
24489
  const rootUiRef = useRef34(null);
24060
24490
  const lastTitleRef = useRef34(null);
24061
24491
  const staticExtraHeight = 3;
24062
- useEffect55(() => {
24492
+ useEffect56(() => {
24063
24493
  void (async () => {
24064
24494
  startupProfiler.flush();
24065
24495
  })();
24066
24496
  }, []);
24067
- useEffect55(() => {
24497
+ useEffect56(() => {
24068
24498
  const handleSettingsChanged = () => {
24069
24499
  setSettingsNonce((prev) => prev + 1);
24070
24500
  };
@@ -24075,19 +24505,19 @@ var AppContainer = (props) => {
24075
24505
  }, []);
24076
24506
  const { consoleMessages, clearConsoleMessages: clearConsoleMessagesState } = useConsoleMessages();
24077
24507
  const mainAreaWidth = calculateMainAreaWidth(terminalWidth, settings);
24078
- const { inputWidth, suggestionsWidth } = useMemo40(() => {
24508
+ const { inputWidth, suggestionsWidth } = useMemo42(() => {
24079
24509
  const { inputWidth: inputWidth2, suggestionsWidth: suggestionsWidth2 } = calculatePromptWidths(mainAreaWidth);
24080
24510
  return { inputWidth: inputWidth2, suggestionsWidth: suggestionsWidth2 };
24081
24511
  }, [mainAreaWidth]);
24082
24512
  const staticAreaMaxItemHeight = Math.max(terminalHeight * 4, 100);
24083
- const isValidPath = useCallback50((filePath) => {
24513
+ const isValidPath = useCallback51((filePath) => {
24084
24514
  try {
24085
24515
  return fs12.existsSync(filePath) && fs12.statSync(filePath).isFile();
24086
24516
  } catch (_e) {
24087
24517
  return false;
24088
24518
  }
24089
24519
  }, []);
24090
- const getPreferredEditor = useCallback50(
24520
+ const getPreferredEditor = useCallback51(
24091
24521
  () => settings.merged.general.preferredEditor,
24092
24522
  [settings.merged.general.preferredEditor]
24093
24523
  );
@@ -24100,16 +24530,16 @@ var AppContainer = (props) => {
24100
24530
  shellModeActive,
24101
24531
  getPreferredEditor
24102
24532
  });
24103
- useEffect55(() => {
24533
+ useEffect56(() => {
24104
24534
  initializeFromHistory(promptHistory);
24105
24535
  }, [initializeFromHistory, promptHistory]);
24106
- const refreshStatic = useCallback50(() => {
24536
+ const refreshStatic = useCallback51(() => {
24107
24537
  if (!isAlternateBuffer) {
24108
24538
  stdout.write(ansiEscapes.clearTerminal);
24109
24539
  }
24110
24540
  setHistoryRemountKey((prev) => prev + 1);
24111
24541
  }, [setHistoryRemountKey, isAlternateBuffer, stdout]);
24112
- const handleEditorClose = useCallback50(() => {
24542
+ const handleEditorClose = useCallback51(() => {
24113
24543
  if (shouldEnterAlternateScreen(isAlternateBuffer, config.getScreenReader())) {
24114
24544
  enterAlternateScreen();
24115
24545
  resumeMouseEvents();
@@ -24119,7 +24549,7 @@ var AppContainer = (props) => {
24119
24549
  terminalCapabilityManager.enableSupportedModes();
24120
24550
  refreshStatic();
24121
24551
  }, [refreshStatic, isAlternateBuffer, app, config]);
24122
- useEffect55(() => {
24552
+ useEffect56(() => {
24123
24553
  coreEvents.on(CoreEvent.ExternalEditorClosed, handleEditorClose);
24124
24554
  return () => {
24125
24555
  coreEvents.off(CoreEvent.ExternalEditorClosed, handleEditorClose);
@@ -24137,7 +24567,7 @@ var AppContainer = (props) => {
24137
24567
  historyManager.addItem,
24138
24568
  initializationResult.themeError
24139
24569
  );
24140
- const [editorError, setEditorError] = useState56(null);
24570
+ const [editorError, setEditorError] = useState59(null);
24141
24571
  const {
24142
24572
  isEditorDialogOpen,
24143
24573
  openEditorDialog,
@@ -24146,7 +24576,7 @@ var AppContainer = (props) => {
24146
24576
  } = useEditorSettings(settings, setEditorError, historyManager.addItem);
24147
24577
  const { isSettingsDialogOpen, openSettingsDialog, closeSettingsDialog } = useSettingsCommand();
24148
24578
  const { toggleVimEnabled } = useVimMode();
24149
- const slashCommandActions = useMemo40(
24579
+ const slashCommandActions = useMemo42(
24150
24580
  () => ({
24151
24581
  openThemeDialog,
24152
24582
  openEditorDialog,
@@ -24193,10 +24623,12 @@ var AppContainer = (props) => {
24193
24623
  enableProfiler,
24194
24624
  providerSetupRuntime,
24195
24625
  sideConversationRuntime,
24196
- subagentCatalogRuntime
24626
+ subagentCatalogRuntime,
24627
+ agentPresetRuntime,
24628
+ skillCatalogRuntime
24197
24629
  );
24198
24630
  const commandPreparationRef = useRef34(void 0);
24199
- useEffect55(() => {
24631
+ useEffect56(() => {
24200
24632
  if (!isSlashCommand(buffer.text.trim()) || commandPreparationRef.current !== void 0) {
24201
24633
  return;
24202
24634
  }
@@ -24212,12 +24644,12 @@ var AppContainer = (props) => {
24212
24644
  }
24213
24645
  });
24214
24646
  }, [buffer.text, commandRuntime]);
24215
- useEffect55(() => () => commandPreparationRef.current?.abort(), []);
24647
+ useEffect56(() => () => commandPreparationRef.current?.abort(), []);
24216
24648
  const cancelHandlerRef = useRef34(
24217
24649
  () => {
24218
24650
  }
24219
24651
  );
24220
- useEffect55(() => {
24652
+ useEffect56(() => {
24221
24653
  if (pendingRestorePrompt) {
24222
24654
  const lastHistoryUserMsg = historyManager.history.findLast(
24223
24655
  (h) => h.type === "user"
@@ -24230,7 +24662,7 @@ var AppContainer = (props) => {
24230
24662
  }
24231
24663
  }, [pendingRestorePrompt, inputHistory, historyManager.history]);
24232
24664
  const initError = initializationResult.initError;
24233
- const todos = useMemo40(
24665
+ const todos = useMemo42(
24234
24666
  () => ({
24235
24667
  todos: conversationSnapshot.todos.map((todo) => ({
24236
24668
  description: todo.content,
@@ -24255,12 +24687,8 @@ var AppContainer = (props) => {
24255
24687
  terminalHeight
24256
24688
  });
24257
24689
  const streamingState = conversationSnapshot.busy || promptInputPreparing || localShellExecuting || isProcessing ? "responding" /* Responding */ : "idle" /* Idle */;
24258
- const submitQuery = useCallback50(
24690
+ const submitQuery = useCallback51(
24259
24691
  (query) => {
24260
- if (isSlashCommand(query.trim())) {
24261
- void handleSlashCommand(query);
24262
- return;
24263
- }
24264
24692
  promptInputAbortRef.current?.abort();
24265
24693
  const controller = new AbortController();
24266
24694
  promptInputAbortRef.current = controller;
@@ -24276,12 +24704,33 @@ var AppContainer = (props) => {
24276
24704
  content: [{ type: "text", text: query }],
24277
24705
  displayContent: [{ type: "text", text: query }]
24278
24706
  });
24279
- void prepared.then(
24280
- (input) => conversationRuntime.submit({
24707
+ void prepared.then(async (input) => {
24708
+ if (isSlashCommand(query.trim())) {
24709
+ const line = input.displayContent.filter((part) => part.type === "text").map((part) => part.text).join("");
24710
+ const attachments = input.content.filter((part) => part.type === "image-source").map((part) => ({
24711
+ sourceKind: part.source.kind,
24712
+ path: part.source.path,
24713
+ mediaType: part.declaredMediaType,
24714
+ name: part.displayName
24715
+ }));
24716
+ if (attachments.length > 0 && commandRuntime.attachmentPolicy?.(line) === false) {
24717
+ throw new Error(
24718
+ `The DSH command in ${line.trim()} does not accept image attachments.`
24719
+ );
24720
+ }
24721
+ const handled = await handleSlashCommand(
24722
+ line,
24723
+ void 0,
24724
+ true,
24725
+ attachments
24726
+ );
24727
+ if (handled !== false) return;
24728
+ }
24729
+ await conversationRuntime.submit({
24281
24730
  ...input,
24282
24731
  signal: controller.signal
24283
- })
24284
- ).catch((error) => {
24732
+ });
24733
+ }).catch((error) => {
24285
24734
  buffer.setText(query);
24286
24735
  if (!(error instanceof Error && error.name === "AbortError")) {
24287
24736
  debugLogger.debug(
@@ -24305,23 +24754,24 @@ var AppContainer = (props) => {
24305
24754
  config,
24306
24755
  promptInputRuntime,
24307
24756
  handleSlashCommand,
24757
+ commandRuntime,
24308
24758
  buffer
24309
24759
  ]
24310
24760
  );
24311
- const cancelOngoingRequest = useCallback50(() => {
24761
+ const cancelOngoingRequest = useCallback51(() => {
24312
24762
  cancelCommand();
24313
24763
  cancelLocalShell();
24314
24764
  promptInputAbortRef.current?.abort();
24315
24765
  conversationRuntime.cancel();
24316
24766
  }, [cancelCommand, cancelLocalShell, conversationRuntime]);
24317
- useEffect55(
24767
+ useEffect56(
24318
24768
  () => () => {
24319
24769
  promptInputAbortRef.current?.abort();
24320
24770
  },
24321
24771
  []
24322
24772
  );
24323
24773
  const lastOutputTimeRef = useRef34(0);
24324
- useEffect55(() => {
24774
+ useEffect56(() => {
24325
24775
  lastOutputTimeRef.current = lastOutputTime;
24326
24776
  }, [lastOutputTime]);
24327
24777
  const { shouldShowFocusHint, inactivityStatus } = useShellInactivityStatus({
@@ -24344,7 +24794,7 @@ var AppContainer = (props) => {
24344
24794
  streamingState,
24345
24795
  submitQuery
24346
24796
  });
24347
- cancelHandlerRef.current = useCallback50(
24797
+ cancelHandlerRef.current = useCallback51(
24348
24798
  (shouldRestorePrompt = true) => {
24349
24799
  const lastUserMessage = inputHistory.at(-1);
24350
24800
  let textToSet = shouldRestorePrompt ? lastUserMessage || "" : "";
@@ -24361,7 +24811,7 @@ ${queuedText}` : queuedText;
24361
24811
  },
24362
24812
  [buffer, inputHistory, getQueuedMessagesText, clearQueue]
24363
24813
  );
24364
- const handleFinalSubmit = useCallback50(
24814
+ const handleFinalSubmit = useCallback51(
24365
24815
  (submittedValue) => {
24366
24816
  if (shellModeActive) {
24367
24817
  executeLocalShell(submittedValue);
@@ -24396,14 +24846,14 @@ ${queuedText}` : queuedText;
24396
24846
  streamingState
24397
24847
  ]
24398
24848
  );
24399
- const handleClearScreen = useCallback50(() => {
24849
+ const handleClearScreen = useCallback51(() => {
24400
24850
  historyManager.clearItems();
24401
24851
  clearConsoleMessagesState();
24402
24852
  refreshStatic();
24403
24853
  }, [historyManager, clearConsoleMessagesState, refreshStatic]);
24404
24854
  const { handleInput: vimHandleInput } = useVim(buffer, handleFinalSubmit);
24405
24855
  const isInputActive = !initError && !isProcessing && pendingApproval === void 0 && pendingUserQuestion === void 0 && !!slashCommands && (streamingState === "idle" /* Idle */ || streamingState === "responding" /* Responding */);
24406
- const [controlsHeight, setControlsHeight] = useState56(0);
24856
+ const [controlsHeight, setControlsHeight] = useState59(0);
24407
24857
  useLayoutEffect5(() => {
24408
24858
  if (mainControlsRef.current) {
24409
24859
  const fullFooterMeasurement = measureElement3(mainControlsRef.current);
@@ -24427,18 +24877,18 @@ ${queuedText}` : queuedText;
24427
24877
  sanitizationConfig: config.sanitizationConfig
24428
24878
  });
24429
24879
  const isFocused = useFocus();
24430
- const initialPrompt = useMemo40(
24880
+ const initialPrompt = useMemo42(
24431
24881
  () => props.initialPrompt ?? config.getQuestion(),
24432
24882
  [config, props.initialPrompt]
24433
24883
  );
24434
24884
  const initialPromptSubmitted = useRef34(false);
24435
24885
  const providerSetupRequired = providerSetupSnapshot?.current.status === "missing";
24436
- useEffect55(() => {
24886
+ useEffect56(() => {
24437
24887
  if (!providerSetupRuntime || !providerSetupRequired || providerSetupDismissed || customDialog) {
24438
24888
  return;
24439
24889
  }
24440
24890
  setCustomDialog(
24441
- /* @__PURE__ */ jsx102(
24891
+ /* @__PURE__ */ jsx104(
24442
24892
  ProviderSetupDialog,
24443
24893
  {
24444
24894
  runtime: providerSetupRuntime,
@@ -24465,7 +24915,7 @@ ${queuedText}` : queuedText;
24465
24915
  providerSetupRuntime,
24466
24916
  providerSetupSnapshot
24467
24917
  ]);
24468
- useEffect55(() => {
24918
+ useEffect56(() => {
24469
24919
  if (activePtyId) {
24470
24920
  try {
24471
24921
  ShellExecutionService.resizePty(
@@ -24483,7 +24933,7 @@ ${queuedText}` : queuedText;
24483
24933
  }
24484
24934
  }
24485
24935
  }, [terminalWidth, availableTerminalHeight, activePtyId]);
24486
- useEffect55(() => {
24936
+ useEffect56(() => {
24487
24937
  if (initialPrompt && !initialPromptSubmitted.current && !isThemeDialogOpen && !isEditorDialogOpen && !providerSetupRequired && !customDialog && conversationRuntime) {
24488
24938
  handleFinalSubmit(initialPrompt);
24489
24939
  initialPromptSubmitted.current = true;
@@ -24497,20 +24947,20 @@ ${queuedText}` : queuedText;
24497
24947
  customDialog,
24498
24948
  conversationRuntime
24499
24949
  ]);
24500
- const [showErrorDetails, setShowErrorDetails] = useState56(false);
24501
- const [showFullTodos, setShowFullTodos] = useState56(false);
24502
- const [renderMarkdown, setRenderMarkdown] = useState56(true);
24503
- const [ctrlCPressCount, setCtrlCPressCount] = useState56(0);
24950
+ const [showErrorDetails, setShowErrorDetails] = useState59(false);
24951
+ const [showFullTodos, setShowFullTodos] = useState59(false);
24952
+ const [renderMarkdown, setRenderMarkdown] = useState59(true);
24953
+ const [ctrlCPressCount, setCtrlCPressCount] = useState59(0);
24504
24954
  const ctrlCTimerRef = useRef34(null);
24505
- const [ctrlDPressCount, setCtrlDPressCount] = useState56(0);
24955
+ const [ctrlDPressCount, setCtrlDPressCount] = useState59(0);
24506
24956
  const ctrlDTimerRef = useRef34(null);
24507
- const [constrainHeight, setConstrainHeight] = useState56(true);
24508
- const [showEscapePrompt, setShowEscapePrompt] = useState56(false);
24509
- const [warningMessage, setWarningMessage] = useState56(null);
24957
+ const [constrainHeight, setConstrainHeight] = useState59(true);
24958
+ const [showEscapePrompt, setShowEscapePrompt] = useState59(false);
24959
+ const [warningMessage, setWarningMessage] = useState59(null);
24510
24960
  const isInitialMount = useRef34(true);
24511
24961
  const warningTimeoutRef = useRef34(null);
24512
24962
  const tabFocusTimeoutRef = useRef34(null);
24513
- const handleWarning = useCallback50((message) => {
24963
+ const handleWarning = useCallback51((message) => {
24514
24964
  setWarningMessage(message);
24515
24965
  if (warningTimeoutRef.current) {
24516
24966
  clearTimeout(warningTimeoutRef.current);
@@ -24519,7 +24969,7 @@ ${queuedText}` : queuedText;
24519
24969
  setWarningMessage(null);
24520
24970
  }, WARNING_PROMPT_DURATION_MS);
24521
24971
  }, []);
24522
- useEffect55(() => {
24972
+ useEffect56(() => {
24523
24973
  const handleSelectionWarning = () => {
24524
24974
  handleWarning("Press Ctrl-S to enter selection mode to copy text.");
24525
24975
  };
@@ -24539,7 +24989,7 @@ ${queuedText}` : queuedText;
24539
24989
  }
24540
24990
  };
24541
24991
  }, [handleWarning]);
24542
- useEffect55(() => {
24992
+ useEffect56(() => {
24543
24993
  if (queueErrorMessage) {
24544
24994
  const timer = setTimeout(() => {
24545
24995
  setQueueErrorMessage(null);
@@ -24548,7 +24998,7 @@ ${queuedText}` : queuedText;
24548
24998
  }
24549
24999
  return void 0;
24550
25000
  }, [queueErrorMessage, setQueueErrorMessage]);
24551
- useEffect55(() => {
25001
+ useEffect56(() => {
24552
25002
  if (isInitialMount.current) {
24553
25003
  isInitialMount.current = false;
24554
25004
  return;
@@ -24560,7 +25010,7 @@ ${queuedText}` : queuedText;
24560
25010
  clearTimeout(handler);
24561
25011
  };
24562
25012
  }, [terminalWidth, refreshStatic]);
24563
- useEffect55(() => {
25013
+ useEffect56(() => {
24564
25014
  const openDebugConsole = () => {
24565
25015
  setShowErrorDetails(true);
24566
25016
  setConstrainHeight(false);
@@ -24570,7 +25020,7 @@ ${queuedText}` : queuedText;
24570
25020
  appEvents.off("open-debug-console" /* OpenDebugConsole */, openDebugConsole);
24571
25021
  };
24572
25022
  }, [config]);
24573
- useEffect55(() => {
25023
+ useEffect56(() => {
24574
25024
  if (ctrlCTimerRef.current) {
24575
25025
  clearTimeout(ctrlCTimerRef.current);
24576
25026
  ctrlCTimerRef.current = null;
@@ -24584,7 +25034,7 @@ ${queuedText}` : queuedText;
24584
25034
  }, WARNING_PROMPT_DURATION_MS);
24585
25035
  }
24586
25036
  }, [ctrlCPressCount, config, setCtrlCPressCount, handleSlashCommand]);
24587
- useEffect55(() => {
25037
+ useEffect56(() => {
24588
25038
  if (ctrlDTimerRef.current) {
24589
25039
  clearTimeout(ctrlDTimerRef.current);
24590
25040
  ctrlCTimerRef.current = null;
@@ -24598,7 +25048,7 @@ ${queuedText}` : queuedText;
24598
25048
  }, WARNING_PROMPT_DURATION_MS);
24599
25049
  }
24600
25050
  }, [ctrlDPressCount, config, setCtrlDPressCount, handleSlashCommand]);
24601
- const handleEscapePromptChange = useCallback50((showPrompt) => {
25051
+ const handleEscapePromptChange = useCallback51((showPrompt) => {
24602
25052
  setShowEscapePrompt(showPrompt);
24603
25053
  }, []);
24604
25054
  const { elapsedTime, currentLoadingPhrase } = useLoadingIndicator({
@@ -24606,7 +25056,7 @@ ${queuedText}` : queuedText;
24606
25056
  shouldShowFocusHint,
24607
25057
  customWittyPhrases: settings.merged.ui.customWittyPhrases
24608
25058
  });
24609
- const handleGlobalKeypress = useCallback50(
25059
+ const handleGlobalKeypress = useCallback51(
24610
25060
  (key) => {
24611
25061
  if (copyModeEnabled) {
24612
25062
  setCopyModeEnabled(false);
@@ -24735,12 +25185,12 @@ ${queuedText}` : queuedText;
24735
25185
  ]
24736
25186
  );
24737
25187
  useKeypress(handleGlobalKeypress, { isActive: true });
24738
- useEffect55(() => {
25188
+ useEffect56(() => {
24739
25189
  if (settings.merged.ui.hideWindowTitle) return;
24740
25190
  const paddedTitle = computeTerminalTitle({
24741
25191
  streamingState,
24742
25192
  isConfirming: pendingApproval !== void 0 || !!confirmationRequest || shouldShowActionRequiredTitle,
24743
- isSilentWorking: shouldShowSilentWorkingTitle,
25193
+ isSilentWorking: !isKeypressReady || slashCommands === void 0 || shouldShowSilentWorkingTitle,
24744
25194
  folderName: basename3(config.getTargetDir()),
24745
25195
  useDynamicTitle: settings.merged.ui.dynamicWindowTitle
24746
25196
  });
@@ -24754,12 +25204,14 @@ ${queuedText}` : queuedText;
24754
25204
  pendingApproval,
24755
25205
  shouldShowActionRequiredTitle,
24756
25206
  shouldShowSilentWorkingTitle,
25207
+ slashCommands,
25208
+ isKeypressReady,
24757
25209
  settings.merged.ui.dynamicWindowTitle,
24758
25210
  settings.merged.ui.hideWindowTitle,
24759
25211
  config,
24760
25212
  stdout
24761
25213
  ]);
24762
- useEffect55(() => {
25214
+ useEffect56(() => {
24763
25215
  const handleUserFeedback = (payload) => {
24764
25216
  let type;
24765
25217
  switch (payload.severity) {
@@ -24797,23 +25249,23 @@ ${queuedText}` : queuedText;
24797
25249
  coreEvents.off(CoreEvent.UserFeedback, handleUserFeedback);
24798
25250
  };
24799
25251
  }, [historyManager]);
24800
- const filteredConsoleMessages = useMemo40(() => {
25252
+ const filteredConsoleMessages = useMemo42(() => {
24801
25253
  if (config.getDebugMode()) {
24802
25254
  return consoleMessages;
24803
25255
  }
24804
25256
  return consoleMessages.filter((msg) => msg.type !== "debug");
24805
25257
  }, [consoleMessages, config]);
24806
- const errorCount = useMemo40(
25258
+ const errorCount = useMemo42(
24807
25259
  () => filteredConsoleMessages.filter((msg) => msg.type === "error").reduce((total, msg) => total + msg.count, 0),
24808
25260
  [filteredConsoleMessages]
24809
25261
  );
24810
25262
  const nightly = props.version.includes("nightly");
24811
25263
  const dialogsVisible = pendingUserQuestion !== void 0 || !!confirmationRequest || !!customDialog || isThemeDialogOpen || isSettingsDialogOpen || isEditorDialogOpen;
24812
- const pendingHistoryItems = useMemo40(
25264
+ const pendingHistoryItems = useMemo42(
24813
25265
  () => pendingShellHistoryItem ? [pendingShellHistoryItem] : [],
24814
25266
  [pendingShellHistoryItem]
24815
25267
  );
24816
- const uiState = useMemo40(
25268
+ const uiState = useMemo42(
24817
25269
  () => ({
24818
25270
  history: historyManager.history,
24819
25271
  isThemeDialogOpen,
@@ -24943,7 +25395,7 @@ ${queuedText}` : queuedText;
24943
25395
  subagentCatalogSnapshot
24944
25396
  ]
24945
25397
  );
24946
- const uiActions = useMemo40(
25398
+ const uiActions = useMemo42(
24947
25399
  () => ({
24948
25400
  handleThemeSelect,
24949
25401
  closeThemeDialog,
@@ -24987,22 +25439,22 @@ ${queuedText}` : queuedText;
24987
25439
  setEmbeddedShellFocused
24988
25440
  ]
24989
25441
  );
24990
- return /* @__PURE__ */ jsx102(UIStateContext.Provider, { value: uiState, children: /* @__PURE__ */ jsx102(UIActionsContext.Provider, { value: uiActions, children: /* @__PURE__ */ jsx102(ConfigContext.Provider, { value: config, children: /* @__PURE__ */ jsx102(
25442
+ return /* @__PURE__ */ jsx104(UIStateContext.Provider, { value: uiState, children: /* @__PURE__ */ jsx104(UIActionsContext.Provider, { value: uiActions, children: /* @__PURE__ */ jsx104(ConfigContext.Provider, { value: config, children: /* @__PURE__ */ jsx104(
24991
25443
  AppContext.Provider,
24992
25444
  {
24993
25445
  value: {
24994
25446
  version: props.version,
24995
25447
  startupWarnings: props.startupWarnings || []
24996
25448
  },
24997
- children: /* @__PURE__ */ jsx102(ApprovalRuntimeProvider, { runtime: approvalRuntime, children: /* @__PURE__ */ jsx102(UserQuestionRuntimeProvider, { runtime: userQuestionRuntime, children: /* @__PURE__ */ jsx102(ShellFocusContext.Provider, { value: isFocused, children: /* @__PURE__ */ jsx102(App, {}) }) }) })
25449
+ children: /* @__PURE__ */ jsx104(ApprovalRuntimeProvider, { runtime: approvalRuntime, children: /* @__PURE__ */ jsx104(UserQuestionRuntimeProvider, { runtime: userQuestionRuntime, children: /* @__PURE__ */ jsx104(ShellFocusContext.Provider, { value: isFocused, children: /* @__PURE__ */ jsx104(App, {}) }) }) })
24998
25450
  }
24999
25451
  ) }) }) });
25000
25452
  };
25001
25453
 
25002
25454
  // src/ui/root.tsx
25003
- import React25 from "react";
25455
+ import React27 from "react";
25004
25456
  import { render } from "ink";
25005
- import { jsx as jsx103 } from "react/jsx-runtime";
25457
+ import { jsx as jsx105 } from "react/jsx-runtime";
25006
25458
  var SLOW_RENDER_MS = 200;
25007
25459
  function validateDnsResolutionOrder(order) {
25008
25460
  const defaultValue = "ipv4first";
@@ -25034,7 +25486,7 @@ ${reason.stack}` : ""}`;
25034
25486
  }
25035
25487
  });
25036
25488
  }
25037
- async function startInteractiveUI(config, settings, startupWarnings, workspaceRoot = process.cwd(), initializationResult, conversationRuntime, approvalRuntime, userQuestionRuntime, commandRuntime, permissionSelectionRuntime, interactionModeRuntime, toolCatalogRuntime, promptCompletionRuntime, promptInputRuntime, modelSelectionRuntime, sessionManagementRuntime, initialPrompt, providerSetupRuntime, sideConversationRuntime, subagentCatalogRuntime) {
25489
+ async function startInteractiveUI(config, settings, startupWarnings, workspaceRoot = process.cwd(), initializationResult, conversationRuntime, approvalRuntime, userQuestionRuntime, commandRuntime, permissionSelectionRuntime, interactionModeRuntime, toolCatalogRuntime, agentPresetRuntime, skillCatalogRuntime, promptCompletionRuntime, promptInputRuntime, modelSelectionRuntime, sessionManagementRuntime, initialPrompt, providerSetupRuntime, sideConversationRuntime, subagentCatalogRuntime) {
25038
25490
  const useAlternateBuffer2 = shouldEnterAlternateScreen(
25039
25491
  isAlternateBufferEnabled(settings),
25040
25492
  config.getScreenReader()
@@ -25044,17 +25496,17 @@ async function startInteractiveUI(config, settings, startupWarnings, workspaceRo
25044
25496
  const version = await getVersion();
25045
25497
  const AppWrapper = () => {
25046
25498
  useKittyKeyboardProtocol();
25047
- return /* @__PURE__ */ jsx103(SettingsContext.Provider, { value: settings, children: /* @__PURE__ */ jsx103(
25499
+ return /* @__PURE__ */ jsx105(SettingsContext.Provider, { value: settings, children: /* @__PURE__ */ jsx105(
25048
25500
  KeypressProvider,
25049
25501
  {
25050
25502
  config,
25051
25503
  debugKeystrokeLogging: settings.merged.general.debugKeystrokeLogging,
25052
- children: /* @__PURE__ */ jsx103(
25504
+ children: /* @__PURE__ */ jsx105(
25053
25505
  MouseProvider,
25054
25506
  {
25055
25507
  mouseEventsEnabled,
25056
25508
  debugKeystrokeLogging: settings.merged.general.debugKeystrokeLogging,
25057
- children: /* @__PURE__ */ jsx103(ScrollProvider, { children: /* @__PURE__ */ jsx103(SessionStatsProvider, { conversationRuntime, children: /* @__PURE__ */ jsx103(VimModeProvider, { settings, children: /* @__PURE__ */ jsx103(
25509
+ children: /* @__PURE__ */ jsx105(ScrollProvider, { children: /* @__PURE__ */ jsx105(SessionStatsProvider, { conversationRuntime, children: /* @__PURE__ */ jsx105(VimModeProvider, { settings, children: /* @__PURE__ */ jsx105(
25058
25510
  AppContainer,
25059
25511
  {
25060
25512
  config,
@@ -25073,6 +25525,8 @@ async function startInteractiveUI(config, settings, startupWarnings, workspaceRo
25073
25525
  permissionSelectionRuntime,
25074
25526
  interactionModeRuntime,
25075
25527
  toolCatalogRuntime,
25528
+ agentPresetRuntime,
25529
+ skillCatalogRuntime,
25076
25530
  sideConversationRuntime,
25077
25531
  subagentCatalogRuntime,
25078
25532
  initialPrompt
@@ -25085,7 +25539,7 @@ async function startInteractiveUI(config, settings, startupWarnings, workspaceRo
25085
25539
  };
25086
25540
  const { stdout: inkStdout, stderr: inkStderr } = createWorkingStdio();
25087
25541
  const instance = render(
25088
- process.env["DEBUG"] ? /* @__PURE__ */ jsx103(React25.StrictMode, { children: /* @__PURE__ */ jsx103(AppWrapper, {}) }) : /* @__PURE__ */ jsx103(AppWrapper, {}),
25542
+ process.env["DEBUG"] ? /* @__PURE__ */ jsx105(React27.StrictMode, { children: /* @__PURE__ */ jsx105(AppWrapper, {}) }) : /* @__PURE__ */ jsx105(AppWrapper, {}),
25089
25543
  {
25090
25544
  stdout: inkStdout,
25091
25545
  stderr: inkStderr,
@@ -25188,6 +25642,8 @@ async function main(options) {
25188
25642
  options.permissionSelectionRuntime,
25189
25643
  options.interactionModeRuntime,
25190
25644
  options.toolCatalogRuntime,
25645
+ options.agentPresetRuntime,
25646
+ options.skillCatalogRuntime,
25191
25647
  options.promptCompletionRuntime,
25192
25648
  options.promptInputRuntime,
25193
25649
  options.modelSelectionRuntime,
@@ -26584,11 +27040,11 @@ var DshToolPresentationAdapter = class {
26584
27040
  description: "Todo update failed"
26585
27041
  };
26586
27042
  }
26587
- const summary2 = todoSummary(args);
26588
- if (summary2 !== void 0) {
27043
+ const summary3 = todoSummary(args);
27044
+ if (summary3 !== void 0) {
26589
27045
  return {
26590
27046
  kind: "compact",
26591
- label: summary2.total === 0 ? "Todo list cleared" : summary2.completed === summary2.total ? `Todo completed | ${String(summary2.completed)}/${String(summary2.total)}` : `Todo | ${String(summary2.completed)} completed | ${String(summary2.inProgress)} active | ${String(summary2.pending)} pending`
27047
+ label: summary3.total === 0 ? "Todo list cleared" : summary3.completed === summary3.total ? `Todo completed | ${String(summary3.completed)}/${String(summary3.total)}` : `Todo | ${String(summary3.completed)} completed | ${String(summary3.inProgress)} active | ${String(summary3.pending)} pending`
26592
27048
  };
26593
27049
  }
26594
27050
  }
@@ -27224,6 +27680,7 @@ var DshUserQuestionRuntime = class {
27224
27680
  };
27225
27681
 
27226
27682
  // src/dsh/command-runtime.ts
27683
+ import { promises as fs15 } from "node:fs";
27227
27684
  var DshCommandRuntimeAdapter = class {
27228
27685
  constructor(commands, activeAgent, subscribe, ensureActiveAgent) {
27229
27686
  this.commands = commands;
@@ -27253,7 +27710,7 @@ var DshCommandRuntimeAdapter = class {
27253
27710
  this.preparing = preparing;
27254
27711
  return preparing;
27255
27712
  }
27256
- async execute(line, signal) {
27713
+ async execute(line, attachments, signal) {
27257
27714
  await this.prepare(signal);
27258
27715
  signal.throwIfAborted();
27259
27716
  const agent = this.activeAgent();
@@ -27263,15 +27720,37 @@ var DshCommandRuntimeAdapter = class {
27263
27720
  text: "Unable to prepare the active conversation for DSH commands."
27264
27721
  };
27265
27722
  }
27266
- const execution = await this.commands.execute(agent, line, [], signal);
27723
+ const submittedAttachments = await Promise.all(
27724
+ attachments.map(async (attachment) => ({
27725
+ type: "image",
27726
+ mediaType: attachment.mediaType,
27727
+ data: Buffer.from(
27728
+ await fs15.readFile(attachment.path, { signal })
27729
+ ).toString("base64"),
27730
+ name: attachment.name
27731
+ }))
27732
+ );
27733
+ signal.throwIfAborted();
27734
+ const execution = await this.commands.execute(
27735
+ agent,
27736
+ line,
27737
+ submittedAttachments,
27738
+ signal
27739
+ );
27267
27740
  if (execution === void 0) {
27268
27741
  return { kind: "error", text: `Unknown DSH command: ${line.trim()}` };
27269
27742
  }
27270
27743
  return {
27271
27744
  kind: execution.result.kind,
27272
- ...execution.result.text === void 0 ? {} : { text: execution.result.text }
27745
+ ...execution.result.text === void 0 ? {} : { text: execution.result.text },
27746
+ ...execution.result.kind === "success" && execution.result.sourceEventSeq !== void 0 ? { sourceEventSeq: execution.result.sourceEventSeq } : {}
27273
27747
  };
27274
27748
  }
27749
+ attachmentPolicy(line) {
27750
+ const match = /^\/([^\s]+)/.exec(line.trim());
27751
+ if (match === null) return void 0;
27752
+ return this.snapshot.commands.find((command) => command.name === match[1])?.acceptsAttachments;
27753
+ }
27275
27754
  activeAgentChanged() {
27276
27755
  this.refresh();
27277
27756
  }
@@ -27289,6 +27768,7 @@ var DshCommandRuntimeAdapter = class {
27289
27768
  (command) => Object.freeze({
27290
27769
  name: command.name,
27291
27770
  description: command.description,
27771
+ acceptsAttachments: command.input?.attachments === true,
27292
27772
  ...command.input === void 0 ? {} : { inputHint: command.input.hint }
27293
27773
  })
27294
27774
  )
@@ -27380,7 +27860,8 @@ var DshPermissionSelectionRuntime = class {
27380
27860
  this.snapshot = this.readSnapshot(false);
27381
27861
  this.offProjection = projections.onChanged((session, key) => {
27382
27862
  const agent = this.activeAgent();
27383
- if (agent === void 0 || session !== agent.session || key !== "permissions") return;
27863
+ if (agent === void 0 || session !== agent.session || key !== "permissions")
27864
+ return;
27384
27865
  this.refresh();
27385
27866
  });
27386
27867
  }
@@ -27400,16 +27881,24 @@ var DshPermissionSelectionRuntime = class {
27400
27881
  if (!this.snapshot.available) {
27401
27882
  throw new Error("DSH permission presets are unavailable.");
27402
27883
  }
27403
- const option = this.snapshot.options.find((candidate) => candidate.value === value);
27884
+ const option = this.snapshot.options.find(
27885
+ (candidate) => candidate.value === value
27886
+ );
27404
27887
  if (!option) throw new Error(`Unknown permission preset: ${value}`);
27405
27888
  if (this.snapshot.currentValue === value) return option;
27406
27889
  this.snapshot = Object.freeze({ ...this.snapshot, busy: true });
27407
27890
  this.emit();
27408
27891
  try {
27409
- const result = await this.commands.execute(`/permission ${value}`, signal ?? new AbortController().signal);
27892
+ const result = await this.commands.execute(
27893
+ `/permission ${value}`,
27894
+ [],
27895
+ signal ?? new AbortController().signal
27896
+ );
27410
27897
  signal?.throwIfAborted();
27411
27898
  if (result.kind === "error") {
27412
- throw new Error(result.text ?? `Unable to switch permission preset to ${value}.`);
27899
+ throw new Error(
27900
+ result.text ?? `Unable to switch permission preset to ${value}.`
27901
+ );
27413
27902
  }
27414
27903
  this.snapshot = this.readSnapshot(false);
27415
27904
  if (this.snapshot.currentValue !== value) {
@@ -27433,11 +27922,19 @@ var DshPermissionSelectionRuntime = class {
27433
27922
  readSnapshot(busy) {
27434
27923
  const agent = this.activeAgent();
27435
27924
  if (agent === void 0) {
27436
- return Object.freeze({ available: false, options: Object.freeze([]), busy });
27925
+ return Object.freeze({
27926
+ available: false,
27927
+ options: Object.freeze([]),
27928
+ busy
27929
+ });
27437
27930
  }
27438
27931
  const selection = this.projections.snapshot(agent.session).values.permissions;
27439
27932
  if (!selection) {
27440
- return Object.freeze({ available: false, options: Object.freeze([]), busy });
27933
+ return Object.freeze({
27934
+ available: false,
27935
+ options: Object.freeze([]),
27936
+ busy
27937
+ });
27441
27938
  }
27442
27939
  return Object.freeze({
27443
27940
  available: true,
@@ -27499,6 +27996,7 @@ var DshPlanSelectionRuntime = class {
27499
27996
  try {
27500
27997
  const result = await this.commands.execute(
27501
27998
  active ? "/plan" : "/plan off",
27999
+ [],
27502
28000
  signal ?? new AbortController().signal
27503
28001
  );
27504
28002
  signal?.throwIfAborted();
@@ -28054,10 +28552,311 @@ var DshSubagentCatalogRuntime = class {
28054
28552
  }
28055
28553
  };
28056
28554
 
28555
+ // src/dsh/wait-for-shared-promise.ts
28556
+ function waitForSharedPromise(promise, signal) {
28557
+ signal?.throwIfAborted();
28558
+ if (signal === void 0) return promise;
28559
+ return new Promise((resolve, reject) => {
28560
+ const cleanup = () => signal.removeEventListener("abort", onAbort);
28561
+ const onAbort = () => {
28562
+ cleanup();
28563
+ reject(
28564
+ signal.reason ?? new DOMException("This operation was aborted", "AbortError")
28565
+ );
28566
+ };
28567
+ signal.addEventListener("abort", onAbort, { once: true });
28568
+ if (signal.aborted) {
28569
+ onAbort();
28570
+ return;
28571
+ }
28572
+ promise.then(
28573
+ (value) => {
28574
+ cleanup();
28575
+ resolve(value);
28576
+ },
28577
+ (error) => {
28578
+ cleanup();
28579
+ reject(error);
28580
+ }
28581
+ );
28582
+ });
28583
+ }
28584
+
28585
+ // src/dsh/agent-preset-runtime.ts
28586
+ var EMPTY_OPTIONS = Object.freeze([]);
28587
+ var DshAgentPresetRuntime = class {
28588
+ constructor(presets, projections, activeAgent, pendingPresetId, selectPendingPreset, onSelected) {
28589
+ this.presets = presets;
28590
+ this.projections = projections;
28591
+ this.activeAgent = activeAgent;
28592
+ this.pendingPresetId = pendingPresetId;
28593
+ this.selectPendingPreset = selectPendingPreset;
28594
+ this.onSelected = onSelected;
28595
+ this.snapshot = Object.freeze({
28596
+ status: "idle",
28597
+ currentId: this.currentId(),
28598
+ options: EMPTY_OPTIONS,
28599
+ busy: false
28600
+ });
28601
+ this.offProjection = projections.onChanged((session, key) => {
28602
+ const agent = this.activeAgent();
28603
+ if (agent === void 0 || session !== agent.session || key !== "agentPreset")
28604
+ return;
28605
+ this.refreshCurrent();
28606
+ });
28607
+ }
28608
+ listeners = /* @__PURE__ */ new Set();
28609
+ snapshot;
28610
+ loading;
28611
+ offProjection;
28612
+ getSnapshot = () => this.snapshot;
28613
+ subscribe = (listener) => {
28614
+ this.listeners.add(listener);
28615
+ return () => this.listeners.delete(listener);
28616
+ };
28617
+ async prepare(signal) {
28618
+ signal?.throwIfAborted();
28619
+ if (this.snapshot.status === "ready") return;
28620
+ let loading = this.loading;
28621
+ if (loading === void 0) {
28622
+ loading = this.load().finally(() => {
28623
+ if (this.loading === loading) this.loading = void 0;
28624
+ });
28625
+ this.loading = loading;
28626
+ }
28627
+ return waitForSharedPromise(loading, signal);
28628
+ }
28629
+ async select(id, signal) {
28630
+ await this.prepare(signal);
28631
+ signal?.throwIfAborted();
28632
+ const option = this.snapshot.options.find(
28633
+ (candidate) => candidate.id === id
28634
+ );
28635
+ if (option === void 0) throw new Error(`Unknown Agent preset: ${id}`);
28636
+ if (option.broken !== void 0) {
28637
+ throw new Error(`Agent preset ${id} is unavailable: ${option.broken}`);
28638
+ }
28639
+ if (this.snapshot.currentId === id) return option;
28640
+ if (this.snapshot.busy) {
28641
+ throw new Error("Another Agent preset change is already in progress.");
28642
+ }
28643
+ const agent = this.activeAgent();
28644
+ if (agent === void 0) {
28645
+ this.selectPendingPreset(id);
28646
+ this.refreshCurrent();
28647
+ if (this.snapshot.currentId !== id) {
28648
+ throw new Error(`DSH did not select Agent preset ${id}.`);
28649
+ }
28650
+ this.onSelected();
28651
+ return option;
28652
+ }
28653
+ this.snapshot = Object.freeze({ ...this.snapshot, busy: true });
28654
+ this.emit();
28655
+ try {
28656
+ await this.presets.select(agent, id);
28657
+ this.refreshCurrent();
28658
+ if (this.snapshot.currentId !== id) {
28659
+ throw new Error(`DSH did not activate Agent preset ${id}.`);
28660
+ }
28661
+ this.onSelected();
28662
+ return option;
28663
+ } finally {
28664
+ this.snapshot = Object.freeze({ ...this.snapshot, busy: false });
28665
+ this.emit();
28666
+ }
28667
+ }
28668
+ activeAgentChanged() {
28669
+ this.refreshCurrent();
28670
+ }
28671
+ dispose() {
28672
+ this.offProjection();
28673
+ this.listeners.clear();
28674
+ }
28675
+ async load() {
28676
+ this.snapshot = Object.freeze({
28677
+ ...this.snapshot,
28678
+ status: "loading",
28679
+ error: void 0
28680
+ });
28681
+ this.emit();
28682
+ try {
28683
+ const options = (await this.presets.list()).map(
28684
+ (preset) => Object.freeze({
28685
+ id: preset.id,
28686
+ name: preset.name ?? preset.id,
28687
+ ...preset.description === void 0 ? {} : { description: preset.description },
28688
+ trust: preset.trust,
28689
+ isDefault: preset.id === this.presets.defaultId,
28690
+ ...preset.broken === void 0 ? {} : { broken: preset.broken }
28691
+ })
28692
+ );
28693
+ this.snapshot = Object.freeze({
28694
+ status: "ready",
28695
+ currentId: this.currentId(),
28696
+ options: Object.freeze(options),
28697
+ busy: this.snapshot.busy
28698
+ });
28699
+ this.emit();
28700
+ } catch (error) {
28701
+ this.snapshot = Object.freeze({
28702
+ ...this.snapshot,
28703
+ status: "error",
28704
+ error: error instanceof Error ? error.message : String(error)
28705
+ });
28706
+ this.emit();
28707
+ throw error;
28708
+ }
28709
+ }
28710
+ currentId() {
28711
+ const agent = this.activeAgent();
28712
+ if (agent === void 0)
28713
+ return this.pendingPresetId() ?? this.presets.defaultId;
28714
+ return this.projections.snapshot(agent.session).values.agentPreset ?? this.presets.defaultId;
28715
+ }
28716
+ refreshCurrent() {
28717
+ this.snapshot = Object.freeze({
28718
+ ...this.snapshot,
28719
+ currentId: this.currentId()
28720
+ });
28721
+ this.emit();
28722
+ }
28723
+ emit() {
28724
+ for (const listener of this.listeners) listener();
28725
+ }
28726
+ };
28727
+
28728
+ // src/dsh/skill-catalog-runtime.ts
28729
+ import { isUserInvocable } from "@deepseek-ai/dsh-skill";
28730
+ var EMPTY_SKILLS = Object.freeze([]);
28731
+ var DshSkillCatalogRuntime = class {
28732
+ constructor(skills, presets, activeAgent, ensureActiveAgent, subscribe) {
28733
+ this.skills = skills;
28734
+ this.presets = presets;
28735
+ this.activeAgent = activeAgent;
28736
+ this.ensureActiveAgent = ensureActiveAgent;
28737
+ this.off = subscribe(() => this.invalidate(true));
28738
+ }
28739
+ listeners = /* @__PURE__ */ new Set();
28740
+ snapshot = Object.freeze({
28741
+ status: "idle",
28742
+ skills: EMPTY_SKILLS
28743
+ });
28744
+ loading;
28745
+ controller;
28746
+ off;
28747
+ generation = 0;
28748
+ disposed = false;
28749
+ getSnapshot = () => this.snapshot;
28750
+ subscribe = (listener) => {
28751
+ this.listeners.add(listener);
28752
+ return () => this.listeners.delete(listener);
28753
+ };
28754
+ async prepare(signal) {
28755
+ if (this.disposed) return;
28756
+ while (this.snapshot.status !== "ready") {
28757
+ if (this.disposed) return;
28758
+ signal?.throwIfAborted();
28759
+ const agent = this.activeAgent() ?? await this.ensureActiveAgent(signal ?? new AbortController().signal);
28760
+ signal?.throwIfAborted();
28761
+ let loading = this.loading;
28762
+ if (loading === void 0) {
28763
+ const controller = new AbortController();
28764
+ const generation = this.generation;
28765
+ this.controller = controller;
28766
+ loading = Promise.resolve().then(() => this.load(agent, controller.signal, generation)).finally(() => {
28767
+ if (this.loading === loading) this.loading = void 0;
28768
+ if (this.controller === controller) this.controller = void 0;
28769
+ });
28770
+ this.loading = loading;
28771
+ }
28772
+ await waitForSharedPromise(loading, signal);
28773
+ }
28774
+ }
28775
+ activeAgentChanged() {
28776
+ this.invalidate(false);
28777
+ if (this.activeAgent() !== void 0) void this.prepare().catch(() => {
28778
+ });
28779
+ }
28780
+ dispose() {
28781
+ if (this.disposed) return;
28782
+ this.disposed = true;
28783
+ this.generation += 1;
28784
+ const controller = this.controller;
28785
+ this.controller = void 0;
28786
+ this.loading = void 0;
28787
+ controller?.abort();
28788
+ this.off();
28789
+ this.listeners.clear();
28790
+ }
28791
+ invalidate(reload) {
28792
+ if (this.disposed) return;
28793
+ this.generation += 1;
28794
+ const controller = this.controller;
28795
+ this.controller = void 0;
28796
+ this.loading = void 0;
28797
+ controller?.abort();
28798
+ this.snapshot = Object.freeze({ status: "idle", skills: EMPTY_SKILLS });
28799
+ this.emit();
28800
+ if (reload && this.activeAgent() !== void 0) {
28801
+ void this.prepare().catch(() => {
28802
+ });
28803
+ }
28804
+ }
28805
+ async load(agent, signal, generation) {
28806
+ if (this.disposed || signal.aborted || generation !== this.generation)
28807
+ return;
28808
+ this.snapshot = Object.freeze({
28809
+ status: "loading",
28810
+ skills: this.snapshot.skills
28811
+ });
28812
+ this.emit();
28813
+ try {
28814
+ const registry = this.presets.serviceFor(agent, "skills") ?? this.skills;
28815
+ if (registry === void 0) {
28816
+ throw new Error("No DSH Skill registry is available.");
28817
+ }
28818
+ const summaries = await registry.list({
28819
+ cwd: agent.session.header.cwd,
28820
+ scope: agent,
28821
+ signal
28822
+ });
28823
+ signal.throwIfAborted();
28824
+ if (this.disposed || generation !== this.generation) return;
28825
+ const skills = summaries.filter(isUserInvocable).map(
28826
+ (skill) => Object.freeze({
28827
+ name: skill.name,
28828
+ description: skill.description,
28829
+ ...skill.whenToUse === void 0 ? {} : { whenToUse: skill.whenToUse },
28830
+ modelInvocable: skill.invocation.modelInvocable
28831
+ })
28832
+ );
28833
+ this.snapshot = Object.freeze({
28834
+ status: "ready",
28835
+ skills: Object.freeze(skills)
28836
+ });
28837
+ this.emit();
28838
+ } catch (error) {
28839
+ if (this.disposed || signal.aborted || generation !== this.generation)
28840
+ return;
28841
+ this.snapshot = Object.freeze({
28842
+ status: "error",
28843
+ skills: this.snapshot.skills,
28844
+ error: error instanceof Error ? error.message : String(error)
28845
+ });
28846
+ this.emit();
28847
+ throw error;
28848
+ }
28849
+ }
28850
+ emit() {
28851
+ for (const listener of this.listeners) listener();
28852
+ }
28853
+ };
28854
+
28057
28855
  // src/dsh/index.ts
28058
28856
  var name = "dsh-console-runner";
28059
28857
  var inject = [
28060
28858
  "agentDefaultModel",
28859
+ "agentPresets",
28061
28860
  "agents",
28062
28861
  "sessions",
28063
28862
  "sessionQuery",
@@ -28070,6 +28869,7 @@ var inject = [
28070
28869
  "sessionProjections",
28071
28870
  "credentials",
28072
28871
  "settings",
28872
+ "skills",
28073
28873
  "subagents"
28074
28874
  ];
28075
28875
  var Config2 = z2.object({
@@ -28109,7 +28909,9 @@ async function start(ctx, config) {
28109
28909
  const appExit = ctx.get("appExit");
28110
28910
  const credentials = ctx.get("credentials");
28111
28911
  const settings = ctx.get("settings");
28912
+ const skills = ctx.get("skills");
28112
28913
  const subagents = ctx.get("subagents");
28914
+ const agentPresets = ctx.get("agentPresets");
28113
28915
  if (!attachments)
28114
28916
  throw new Error("dsh-console requires the DSH attachment service");
28115
28917
  if (!sessionQuery)
@@ -28128,11 +28930,14 @@ async function start(ctx, config) {
28128
28930
  throw new Error("dsh-console requires the DSH settings service");
28129
28931
  if (!subagents)
28130
28932
  throw new Error("dsh-console requires the DSH subagent service");
28933
+ if (!agentPresets)
28934
+ throw new Error("dsh-console requires the DSH Agent preset service");
28131
28935
  if (!agents || !defaultModel || !sessions || !tools || !llm || !appExit)
28132
28936
  return;
28133
28937
  const selection = defaultModel.currentSelection();
28134
28938
  let activeSelection = selection;
28135
28939
  let sideSelection;
28940
+ let pendingPresetId;
28136
28941
  const workspaceRef = {};
28137
28942
  const runtimeListeners = /* @__PURE__ */ new Set();
28138
28943
  const notifyRuntime = () => {
@@ -28159,12 +28964,20 @@ async function start(ctx, config) {
28159
28964
  model: selected.model,
28160
28965
  ...selected.reasoningEffort === void 0 ? {} : { reasoningEffort: selected.reasoningEffort }
28161
28966
  };
28162
- const setup = (agentCtx) => {
28967
+ const preset = options.resumeSessionId === void 0 && options.inheritPresetFrom === void 0 ? await agentPresets.resolve(options.presetId) : void 0;
28968
+ const inheritedPresetId = options.inheritPresetFrom === void 0 ? void 0 : sessionProjections.snapshot(options.inheritPresetFrom.session).values.agentPreset ?? void 0;
28969
+ const setup = async (agentCtx, agent) => {
28163
28970
  const ref = {
28164
28971
  current: selected,
28165
28972
  assembled: void 0
28166
28973
  };
28167
28974
  installModelSelection2(agentCtx, ref);
28975
+ if (options.inheritPresetFrom !== void 0) {
28976
+ agentPresets.composeFrom(agentCtx, options.inheritPresetFrom.ctx);
28977
+ } else {
28978
+ const presetId = options.resumeSessionId === void 0 ? preset?.id : sessionProjections.snapshot(agent.session).values.agentPreset ?? void 0;
28979
+ await agentPresets.mount(agentCtx, presetId);
28980
+ }
28168
28981
  if (options.restrictTools) agentCtx.tools.restrict({ allow: [] });
28169
28982
  };
28170
28983
  const handle = options.resumeSessionId === void 0 ? await agents.create({
@@ -28172,7 +28985,8 @@ async function start(ctx, config) {
28172
28985
  meta: {
28173
28986
  cwd: process.cwd(),
28174
28987
  ...options.parentSession === void 0 ? {} : { parentSession: options.parentSession },
28175
- ...options.seed === void 0 ? {} : { seedLength: options.seed.length }
28988
+ ...options.seed === void 0 ? {} : { seedLength: options.seed.length },
28989
+ ...(preset?.id ?? inheritedPresetId) === void 0 ? {} : { agentPreset: preset?.id ?? inheritedPresetId }
28176
28990
  },
28177
28991
  ...options.seed === void 0 ? {} : { seed: options.seed },
28178
28992
  agentOptions,
@@ -28311,6 +29125,30 @@ async function start(ctx, config) {
28311
29125
  currentInteractiveAgent,
28312
29126
  (listener) => ctx.on("tools/change", listener)
28313
29127
  );
29128
+ const skillCatalogRuntime = new DshSkillCatalogRuntime(
29129
+ skills,
29130
+ agentPresets,
29131
+ currentInteractiveAgent,
29132
+ async (signal) => (await materializeActiveConversation(signal)).handle.agent,
29133
+ (listener) => ctx.on("skills/change", listener)
29134
+ );
29135
+ const agentPresetRuntime = new DshAgentPresetRuntime(
29136
+ agentPresets,
29137
+ sessionProjections,
29138
+ mainAgent,
29139
+ () => pendingPresetId,
29140
+ (id) => {
29141
+ pendingPresetId = id;
29142
+ },
29143
+ () => {
29144
+ commandRuntime.activeAgentChanged();
29145
+ permissionSelectionRuntime.activeAgentChanged();
29146
+ planSelectionRuntime.activeAgentChanged();
29147
+ toolCatalogRuntime.activeAgentChanged();
29148
+ skillCatalogRuntime.activeAgentChanged();
29149
+ notifyRuntime();
29150
+ }
29151
+ );
28314
29152
  const subagentCatalogRuntime = new DshSubagentCatalogRuntime(
28315
29153
  subagents,
28316
29154
  () => mainAgent()?.session.id,
@@ -28347,6 +29185,7 @@ async function start(ctx, config) {
28347
29185
  try {
28348
29186
  const next = options.resumeSessionId === void 0 ? await createPendingConversation(selected, options.signal) : await createActiveConversation(selected, options);
28349
29187
  const previous = active;
29188
+ const nextPendingPresetId = next.kind === "pending" && previous.kind === "pending" ? pendingPresetId : void 0;
28350
29189
  if (previous.kind === "materialized") {
28351
29190
  try {
28352
29191
  const flushed = await sessions.flush(previous.handle.agent.session);
@@ -28370,12 +29209,15 @@ async function start(ctx, config) {
28370
29209
  previous.offProjector();
28371
29210
  if (previous.kind === "materialized") previous.offSession();
28372
29211
  active = next;
29212
+ pendingPresetId = nextPendingPresetId;
28373
29213
  activeSelection = selected;
28374
29214
  await providerSetupRuntime.refreshCurrent();
28375
29215
  commandRuntime.activeAgentChanged();
28376
29216
  permissionSelectionRuntime.activeAgentChanged();
28377
29217
  planSelectionRuntime.activeAgentChanged();
28378
29218
  toolCatalogRuntime.activeAgentChanged();
29219
+ agentPresetRuntime.activeAgentChanged();
29220
+ skillCatalogRuntime.activeAgentChanged();
28379
29221
  subagentCatalogRuntime.activeAgentChanged();
28380
29222
  notifyRuntime();
28381
29223
  if (previous.kind === "materialized") {
@@ -28442,6 +29284,8 @@ async function start(ctx, config) {
28442
29284
  Promise.resolve(permissionSelectionRuntime.dispose()),
28443
29285
  Promise.resolve(planSelectionRuntime.dispose()),
28444
29286
  Promise.resolve(toolCatalogRuntime.dispose()),
29287
+ Promise.resolve(agentPresetRuntime.dispose()),
29288
+ Promise.resolve(skillCatalogRuntime.dispose()),
28445
29289
  Promise.resolve(subagentCatalogRuntime.dispose())
28446
29290
  ]);
28447
29291
  };
@@ -28454,14 +29298,20 @@ async function start(ctx, config) {
28454
29298
  const previous = active;
28455
29299
  let next;
28456
29300
  try {
28457
- next = await createActiveConversation(activeSelection, { signal });
29301
+ next = await createActiveConversation(activeSelection, {
29302
+ signal,
29303
+ presetId: pendingPresetId
29304
+ });
28458
29305
  signal.throwIfAborted();
28459
29306
  previous.offProjector();
28460
29307
  active = next;
29308
+ pendingPresetId = void 0;
28461
29309
  commandRuntime.activeAgentChanged();
28462
29310
  permissionSelectionRuntime.activeAgentChanged();
28463
29311
  planSelectionRuntime.activeAgentChanged();
28464
29312
  toolCatalogRuntime.activeAgentChanged();
29313
+ agentPresetRuntime.activeAgentChanged();
29314
+ skillCatalogRuntime.activeAgentChanged();
28465
29315
  subagentCatalogRuntime.activeAgentChanged();
28466
29316
  notifyRuntime();
28467
29317
  return next;
@@ -28574,7 +29424,8 @@ async function start(ctx, config) {
28574
29424
  parentSession: parent.session.id,
28575
29425
  seed,
28576
29426
  restrictTools: true,
28577
- publishRuntimeEvents: false
29427
+ publishRuntimeEvents: false,
29428
+ inheritPresetFrom: parent
28578
29429
  });
28579
29430
  sideSelection = selected;
28580
29431
  visibleSideAgent = side.handle.agent;
@@ -28641,6 +29492,8 @@ async function start(ctx, config) {
28641
29492
  permissionSelectionRuntime.activeAgentChanged();
28642
29493
  planSelectionRuntime.activeAgentChanged();
28643
29494
  toolCatalogRuntime.activeAgentChanged();
29495
+ agentPresetRuntime.activeAgentChanged();
29496
+ skillCatalogRuntime.activeAgentChanged();
28644
29497
  });
28645
29498
  ctx.effect(() => cleanup, "dsh-console: terminal");
28646
29499
  const startupResumeSessionId = config.resumeSessionId?.trim();
@@ -28667,6 +29520,8 @@ async function start(ctx, config) {
28667
29520
  permissionSelectionRuntime,
28668
29521
  interactionModeRuntime,
28669
29522
  toolCatalogRuntime,
29523
+ agentPresetRuntime,
29524
+ skillCatalogRuntime,
28670
29525
  subagentCatalogRuntime,
28671
29526
  sideConversationRuntime: conversationWorkspace,
28672
29527
  initialPrompt: config.prompt?.trim(),