@cueloop/client 0.1.0-alpha.75 → 0.1.0-alpha.77

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.
Files changed (82) hide show
  1. package/package.json +5 -5
  2. package/src/App.focus.test.ts +147 -0
  3. package/src/App.identity.test.tsx +78 -0
  4. package/src/App.regression.test.tsx +94 -0
  5. package/src/App.share-choice.test.tsx +105 -0
  6. package/src/App.test.tsx +11 -8
  7. package/src/App.toast.test.tsx +3 -1
  8. package/src/App.tsx +648 -221
  9. package/src/App.visual.test.tsx +57 -0
  10. package/src/App.workbench.test.tsx +41 -22
  11. package/src/app-screens.tsx +181 -123
  12. package/src/app-view-model.ts +1 -0
  13. package/src/components/AnnotatableFileView.tsx +9 -1
  14. package/src/components/AnnotationCards.tsx +22 -4
  15. package/src/components/AppShell.brand.test.tsx +1 -1
  16. package/src/components/AppShell.tsx +14 -1
  17. package/src/components/ChangesColumn.tsx +40 -12
  18. package/src/components/ChangesFileTree.test.tsx +61 -0
  19. package/src/components/ConfirmDialog.tsx +8 -1
  20. package/src/components/DiffContentView.tsx +12 -2
  21. package/src/components/DiscussionMarkerRail.tsx +2 -2
  22. package/src/components/EditorGrid.tsx +84 -26
  23. package/src/components/GridTabContent.tsx +12 -1
  24. package/src/components/ManageAccessDialog.stories.tsx +36 -0
  25. package/src/components/ManageAccessDialog.test.tsx +94 -0
  26. package/src/components/ManageAccessDialog.tsx +120 -0
  27. package/src/components/PanelColumn.tsx +3 -0
  28. package/src/components/ProjectTreeView.test.tsx +39 -12
  29. package/src/components/ProjectTreeView.tsx +38 -10
  30. package/src/components/PromptDialog.test.tsx +61 -0
  31. package/src/components/PromptDialog.tsx +16 -3
  32. package/src/components/RootOverlay.stories.tsx +1 -0
  33. package/src/components/RootOverlay.tsx +19 -6
  34. package/src/components/SettingsDialog.stories.tsx +3 -3
  35. package/src/components/SettingsDialog.tsx +3 -4
  36. package/src/components/ShareChoiceDialog.stories.tsx +34 -0
  37. package/src/components/ShareChoiceDialog.test.tsx +103 -0
  38. package/src/components/ShareChoiceDialog.tsx +82 -0
  39. package/src/components/ThreadFooter.test.tsx +12 -7
  40. package/src/components/ThreadFooter.tsx +18 -4
  41. package/src/components/ThreadTree.tsx +79 -36
  42. package/src/components/ThreadView.slash.test.tsx +36 -0
  43. package/src/components/ThreadView.tsx +12 -2
  44. package/src/components/WelcomePlayground.tsx +2 -0
  45. package/src/components/__snapshots__/stories.test.tsx.snap +147 -52
  46. package/src/components/menu-control.stories.tsx +35 -0
  47. package/src/components/menu-control.tsx +43 -0
  48. package/src/components/primitives/Dialog.test.tsx +37 -0
  49. package/src/components/primitives/Dialog.tsx +5 -0
  50. package/src/components/primitives/icons.ts +1 -1
  51. package/src/components/quick-actions-editor.stories.tsx +2 -0
  52. package/src/components/quick-actions-editor.test.tsx +35 -1
  53. package/src/components/quick-actions-editor.tsx +23 -22
  54. package/src/components/session-tree.test.ts +3 -3
  55. package/src/components/session-tree.ts +1 -1
  56. package/src/config-identity.test.ts +78 -0
  57. package/src/config.ts +45 -1
  58. package/src/diff-intraline.ts +26 -5
  59. package/src/github-identity.test.ts +58 -0
  60. package/src/github-identity.ts +41 -0
  61. package/src/intent-dispatch.test.ts +17 -2
  62. package/src/intent-dispatch.ts +7 -1
  63. package/src/keymap.ts +1 -0
  64. package/src/perf/otlp-trace.test.ts +116 -0
  65. package/src/perf/otlp-trace.ts +130 -0
  66. package/src/perf/perf-report.ts +17 -0
  67. package/src/perf/perf-timings.test.ts +18 -0
  68. package/src/perf/perf-timings.ts +38 -0
  69. package/src/run.ts +22 -2
  70. package/src/share.ts +10 -2
  71. package/src/thread-chords.test.ts +33 -1
  72. package/src/thread-chords.ts +114 -29
  73. package/src/thread-controller.curate.test.ts +1 -0
  74. package/src/thread-controller.live-diff.test.ts +1 -0
  75. package/src/thread-controller.share.test.ts +36 -2
  76. package/src/thread-controller.tree.test.ts +1 -0
  77. package/src/thread-controller.ts +18 -3
  78. package/src/use-annotation-surface.tsx +32 -2
  79. package/src/use-frame-measure.ts +4 -1
  80. package/src/use-settings-dialog.tsx +33 -7
  81. package/src/visual/contrast.test.ts +35 -0
  82. package/src/visual/contrast.ts +33 -0
@@ -1,4 +1,4 @@
1
- // Bun Snapshot v1, https://goo.gl/fbAQLP
1
+ // Bun Snapshot v1, https://bun.sh/docs/test/snapshots
2
2
 
3
3
  exports[`stories catalog Surfaces/AnnotatableFileView/Loaded renders, snapshots, and carries its colors: Surfaces/AnnotatableFileView/Loaded 1`] = `
4
4
  " ▎1 export function add(a: number, b: number): number {
@@ -667,6 +667,50 @@ exports[`stories catalog Overlays/KeybindsDialog/Cheatsheet renders, snapshots,
667
667
 
668
668
 
669
669
 
670
+ "
671
+ `;
672
+
673
+ exports[`stories catalog Dialogs/ManageAccess/Empty renders, snapshots, and carries its colors: Dialogs/ManageAccess/Empty 1`] = `
674
+ "
675
+
676
+
677
+
678
+
679
+ ┌─ Manage access ────────────────────────────────────┐
680
+ │ Only these GitHub users can open the private link. │
681
+ │ │
682
+ │ no one yet - add a handle below │
683
+ │ │
684
+ │ │
685
+ │ @handle │
686
+ │ add create link close │
687
+ └────────────────────────────────────────────────────┘
688
+
689
+
690
+
691
+
692
+ "
693
+ `;
694
+
695
+ exports[`stories catalog Dialogs/ManageAccess/WithHandles renders, snapshots, and carries its colors: Dialogs/ManageAccess/WithHandles 1`] = `
696
+ "
697
+
698
+
699
+
700
+ ┌─ Manage access ────────────────────────────────────┐
701
+ │ Only these GitHub users can open the private link. │
702
+ │ │
703
+ │ @octocat remove │
704
+ │ @hubot remove │
705
+ │ │
706
+ │ │
707
+ │ │
708
+ │ @handle │
709
+ │ add create link close │
710
+ └────────────────────────────────────────────────────┘
711
+
712
+
713
+
670
714
  "
671
715
  `;
672
716
 
@@ -793,7 +837,7 @@ exports[`stories catalog Overlays/PromptDialog/NameYourself renders, snapshots,
793
837
  │ Your name (optional) - it attributes the notes │
794
838
  │ you leave: │
795
839
  │ your name │
796
- │ enter save · esc cancel │
840
+ │ enter save esc cancel │
797
841
  └────────────────────────────────────────────────────┘
798
842
 
799
843
 
@@ -813,7 +857,7 @@ exports[`stories catalog Overlays/PromptDialog/RenameAuthor renders, snapshots,
813
857
  │ Display name for this collaborator: │
814
858
  │ Robin │
815
859
  │ │
816
- │ enter save · esc cancel │
860
+ │ enter save esc cancel │
817
861
  └────────────────────────────────────────────────────┘
818
862
 
819
863
 
@@ -878,10 +922,10 @@ exports[`stories catalog Overlays/SettingsDialog/AppearanceThemed renders, snaps
878
922
 
879
923
 
880
924
  ┌─ Settings ───────────────────────────────────────────────────────────────┐
881
- │ General │ Appearance │
882
- │ Display │ the color theme │
925
+ │ General │ Theme Rosé Pine Moon │
926
+ │ Display │ │
883
927
  │ Appearance │ │
884
- │ │ Theme Rosé Pine Moon │
928
+ │ │ │
885
929
  │ │ │
886
930
  │ │ │
887
931
  │ │ │
@@ -912,11 +956,11 @@ exports[`stories catalog Overlays/SettingsDialog/BodyZone renders, snapshots, an
912
956
 
913
957
 
914
958
  ┌─ Settings ───────────────────────────────────────────────────────────────┐
915
- │ General │ Display │
916
- │ Display │ plan width and chrome │
959
+ │ General │ Plan width default │
960
+ │ Display │ Line numbers on │
917
961
  │ Appearance │ │
918
- │ │ Plan width default │
919
- │ │ Line numbers on │
962
+ │ │ │
963
+ │ │ │
920
964
  │ │ │
921
965
  │ │ │
922
966
  │ │ │
@@ -946,11 +990,11 @@ exports[`stories catalog Overlays/SettingsDialog/NavZone renders, snapshots, and
946
990
 
947
991
 
948
992
  ┌─ Settings ───────────────────────────────────────────────────────────────┐
949
- │ General │ General │
950
- │ Display │ identity and submission │
993
+ │ General │ Display name amber-heron │
994
+ │ Display │ Auto-close on submit 3s │
951
995
  │ Appearance │ │
952
- │ │ Display name amber-heron │
953
- │ │ Auto-close on submit 3s │
996
+ │ │ │
997
+ │ │ │
954
998
  │ │ │
955
999
  │ │ │
956
1000
  │ │ │
@@ -999,6 +1043,16 @@ exports[`stories catalog Chrome/SettingsRows/AllKinds renders, snapshots, and ca
999
1043
 
1000
1044
 
1001
1045
 
1046
+ "
1047
+ `;
1048
+
1049
+ exports[`stories catalog Chrome/ShareMenu/Closed renders, snapshots, and carries its colors: Chrome/ShareMenu/Closed 1`] = `
1050
+ " share
1051
+
1052
+
1053
+
1054
+
1055
+
1002
1056
  "
1003
1057
  `;
1004
1058
 
@@ -1044,6 +1098,7 @@ exports[`stories catalog Surfaces/ThreadTree/TwoPending renders, snapshots, and
1044
1098
  " Projects
1045
1099
   widget
1046
1100
  Migration Plan
1101
+
1047
1102
  Threads
1048
1103
  working tree
1049
1104
 
@@ -1052,7 +1107,6 @@ exports[`stories catalog Surfaces/ThreadTree/TwoPending renders, snapshots, and
1052
1107
 
1053
1108
 
1054
1109
 
1055
-
1056
1110
  "
1057
1111
  `;
1058
1112
 
@@ -1098,6 +1152,7 @@ exports[`stories catalog Surfaces/ThreadsSidebar/Open renders, snapshots, and ca
1098
1152
  " Projects │
1099
1153
   widget │
1100
1154
  Migration Plan │
1155
+ │
1101
1156
  Threads │
1102
1157
  working tree │
1103
1158
  │
@@ -1106,7 +1161,6 @@ exports[`stories catalog Surfaces/ThreadsSidebar/Open renders, snapshots, and ca
1106
1161
  │
1107
1162
  │
1108
1163
  │
1109
- │
1110
1164
  "
1111
1165
  `;
1112
1166
 
@@ -1367,6 +1421,15 @@ exports[`stories catalog Chrome/AgentLauncher/Launcher renders, snapshots, and c
1367
1421
 
1368
1422
 
1369
1423
 
1424
+ "
1425
+ `;
1426
+
1427
+ exports[`stories catalog Layout/MenuControl/OneOpenAtATime renders, snapshots, and carries its colors: Layout/MenuControl/OneOpenAtATime 1`] = `
1428
+ "
1429
+ alpha: open
1430
+ beta: closed
1431
+
1432
+
1370
1433
  "
1371
1434
  `;
1372
1435
 
@@ -1753,54 +1816,54 @@ exports[`stories catalog Primitives/Tree/ProjectsThreads renders, snapshots, and
1753
1816
  `;
1754
1817
 
1755
1818
  exports[`stories catalog Chrome/QuickActionsEditor/Collapsed renders, snapshots, and carries its colors: Chrome/QuickActionsEditor/Collapsed 1`] = `
1756
- " click a prompt to edit its system reset to
1757
- prompt defaults ▸
1819
+ " reset
1758
1820
 
1759
- ▸ Zoom out, research in depth
1760
- Research the broader problem, prior art, an…
1761
- ▸ Restate simplified
1762
- Restate this as the simplest thing that wor…
1763
- ▸ Out of scope
1764
- This is out of scope for the task, so captu…
1765
- ▸ Let's chat about this
1766
- Do not implement yet, and surface the open …
1767
- ▸ Prototype this
1768
- Build a throwaway prototype to answer the q…
1769
- ▸ Ensure 0 regressions
1770
- Characterize the current behavior with test…
1771
- ▸ Consider existing repo patterns
1772
- Follow the nearest existing pattern in this…
1773
- ▸ LGTM
1774
- This looks good to me.
1821
+ Zoom out, research in depth
1822
+ Research the broader problem, prior art, an…
1823
+ Restate simplified
1824
+ Restate this as the simplest thing that wor…
1825
+ Out of scope
1826
+ This is out of scope for the task, so captu…
1827
+ Let's chat about this
1828
+ Do not implement yet, and surface the open …
1829
+ Prototype this
1830
+ Build a throwaway prototype to answer the q…
1831
+ Ensure 0 regressions
1832
+ Characterize the current behavior with test…
1833
+ Consider existing repo patterns
1834
+ Follow the nearest existing pattern in this…
1835
+ LGTM
1836
+ This looks good to me.
1775
1837
  + Add action
1776
1838
 
1777
1839
 
1840
+
1778
1841
  "
1779
1842
  `;
1780
1843
 
1781
1844
  exports[`stories catalog Chrome/QuickActionsEditor/RowExpanded renders, snapshots, and carries its colors: Chrome/QuickActionsEditor/RowExpanded 1`] = `
1782
- " click a prompt to edit its system reset to
1783
- prompt defaults ▸
1845
+ " reset
1784
1846
 
1785
- ▸ Zoom out, research in depth
1786
- Research the broader problem, prior art, an…
1787
- ▾ Restate simplified
1788
- > Restate this as the simplest thing that works
1789
- ▸ Out of scope
1790
- This is out of scope for the task, so captu…
1791
- ▸ Let's chat about this
1792
- Do not implement yet, and surface the open …
1793
- ▸ Prototype this
1794
- Build a throwaway prototype to answer the q…
1795
- ▸ Ensure 0 regressions
1796
- Characterize the current behavior with test…
1797
- ▸ Consider existing repo patterns
1798
- Follow the nearest existing pattern in this…
1799
- ▸ LGTM
1800
- This looks good to me.
1847
+ Zoom out, research in depth
1848
+ Research the broader problem, prior art, an…
1849
+ Restate simplified
1850
+ Restate this as the simplest thing that works and
1851
+ Out of scope
1852
+ This is out of scope for the task, so captu…
1853
+ Let's chat about this
1854
+ Do not implement yet, and surface the open …
1855
+ Prototype this
1856
+ Build a throwaway prototype to answer the q…
1857
+ Ensure 0 regressions
1858
+ Characterize the current behavior with test…
1859
+ Consider existing repo patterns
1860
+ Follow the nearest existing pattern in this…
1861
+ LGTM
1862
+ This looks good to me.
1801
1863
  + Add action
1802
1864
 
1803
1865
 
1866
+
1804
1867
  "
1805
1868
  `;
1806
1869
 
@@ -1885,5 +1948,37 @@ exports[`stories catalog Foundations/Theme/ProviderSwap renders, snapshots, and
1885
1948
 
1886
1949
 
1887
1950
 
1951
+ "
1952
+ `;
1953
+
1954
+ exports[`stories catalog Dialogs/ShareChoice/PrivateSelected renders, snapshots, and carries its colors: Dialogs/ShareChoice/PrivateSelected 1`] = `
1955
+ "
1956
+
1957
+
1958
+ ┌─ Share ────────────────────────────────────┐
1959
+ │ public link │
1960
+ │ › private link │
1961
+ │ │
1962
+ │ │
1963
+ │ ↑↓ choose · enter select · esc cancel │
1964
+ └────────────────────────────────────────────┘
1965
+
1966
+
1967
+ "
1968
+ `;
1969
+
1970
+ exports[`stories catalog Dialogs/ShareChoice/PublicSelected renders, snapshots, and carries its colors: Dialogs/ShareChoice/PublicSelected 1`] = `
1971
+ "
1972
+
1973
+
1974
+ ┌─ Share ────────────────────────────────────┐
1975
+ │ › public link │
1976
+ │ private link │
1977
+ │ │
1978
+ │ │
1979
+ │ ↑↓ choose · enter select · esc cancel │
1980
+ └────────────────────────────────────────────┘
1981
+
1982
+
1888
1983
  "
1889
1984
  `;
@@ -0,0 +1,35 @@
1
+ import React from "react";
2
+ import { DARK } from "../theme";
3
+ import type { Story, StoryMeta } from "./story";
4
+ import { MenuControlProvider, useMenuControl } from "./menu-control";
5
+
6
+ export const meta: StoryMeta = { title: "Layout/MenuControl" };
7
+
8
+ // One open menu at a time: with "alpha" open, only its row reads as open.
9
+ function MenuControlDemo(): React.ReactNode {
10
+ const { openMenuId } = useMenuControl();
11
+ const row = (id: string): React.ReactNode => (
12
+ <text fg={openMenuId === id ? DARK.accent : DARK.textDim}>
13
+ {`${id}: ${openMenuId === id ? "open" : "closed"}`}
14
+ </text>
15
+ );
16
+
17
+ return (
18
+ <box style={{ flexDirection: "column" }}>
19
+ {row("alpha")}
20
+ {row("beta")}
21
+ </box>
22
+ );
23
+ }
24
+
25
+ export const OneOpenAtATime: Story = {
26
+ render: () => (
27
+ <MenuControlProvider value={{ openMenuId: "alpha", toggleMenu: () => {}, closeMenu: () => {} }}>
28
+ <box style={{ padding: 1, backgroundColor: DARK.panel }}>
29
+ <MenuControlDemo />
30
+ </box>
31
+ </MenuControlProvider>
32
+ ),
33
+ expectedColors: [DARK.accent],
34
+ size: { width: 30, height: 5 },
35
+ };
@@ -0,0 +1,43 @@
1
+ // One open menu at a time across a shell: the thread row menu and the editor split menu share this
2
+ // single open id, so opening either closes the other. Owned by App and by the no-thread shell, one each.
3
+
4
+ import React, { createContext, useContext, useMemo, useState } from "react";
5
+
6
+ export interface MenuControlApi {
7
+ openMenuId: string | null;
8
+ toggleMenu: (id: string) => void;
9
+ closeMenu: () => void;
10
+ }
11
+
12
+ const MenuControlContext = createContext<MenuControlApi>({
13
+ openMenuId: null,
14
+ toggleMenu: () => {},
15
+ closeMenu: () => {},
16
+ });
17
+
18
+ export function useMenuControl(): MenuControlApi {
19
+ return useContext(MenuControlContext);
20
+ }
21
+
22
+ export function useMenuControlState(): MenuControlApi {
23
+ const [openMenuId, setOpenMenuId] = useState<string | null>(null);
24
+
25
+ return useMemo(
26
+ () => ({
27
+ openMenuId,
28
+ toggleMenu: (id: string) => setOpenMenuId((current) => (current === id ? null : id)),
29
+ closeMenu: () => setOpenMenuId(null),
30
+ }),
31
+ [openMenuId],
32
+ );
33
+ }
34
+
35
+ export function MenuControlProvider({
36
+ value,
37
+ children,
38
+ }: {
39
+ value: MenuControlApi;
40
+ children: React.ReactNode;
41
+ }): React.ReactNode {
42
+ return <MenuControlContext.Provider value={value}>{children}</MenuControlContext.Provider>;
43
+ }
@@ -0,0 +1,37 @@
1
+ /** The dialog dismisses on a backdrop click (outside the panel) but never on a click inside it. */
2
+
3
+ import { test, expect } from "bun:test";
4
+ import React from "react";
5
+ import { testRender } from "@opentui/react/test-utils";
6
+ import { Dialog } from "./Dialog";
7
+ import { settle } from "../../test-support";
8
+ import { DARK } from "../../theme";
9
+
10
+ test("clicking the backdrop dismisses; clicking inside the panel does not", async () => {
11
+ let dismissed = 0;
12
+ const setup = await testRender(
13
+ <Dialog
14
+ isOpen
15
+ title=" test "
16
+ width={20}
17
+ height={5}
18
+ background={DARK.elevated}
19
+ onDismiss={() => (dismissed += 1)}
20
+ theme={DARK}
21
+ >
22
+ <text>body</text>
23
+ </Dialog>,
24
+ { width: 60, height: 20 },
25
+ );
26
+ await settle(setup);
27
+
28
+ // the top-left corner is backdrop, outside the centered panel
29
+ await setup.mockMouse.click(0, 0);
30
+ expect(dismissed).toBe(1);
31
+
32
+ // the screen centre lands inside the panel, so it must not dismiss
33
+ await setup.mockMouse.click(30, 10);
34
+ expect(dismissed).toBe(1);
35
+
36
+ setup.renderer.destroy();
37
+ });
@@ -17,6 +17,8 @@ export interface DialogProps {
17
17
  height: number;
18
18
  /** Solid panel fill for content-heavy dialogs; default transparent. */
19
19
  background?: string;
20
+ /** Dismiss on a click outside the panel. */
21
+ onDismiss?: () => void;
20
22
  theme?: Theme;
21
23
  children: React.ReactNode;
22
24
  }
@@ -27,6 +29,7 @@ export function Dialog({
27
29
  width,
28
30
  height,
29
31
  background,
32
+ onDismiss,
30
33
  theme,
31
34
  children,
32
35
  }: DialogProps): React.ReactNode {
@@ -36,6 +39,7 @@ export function Dialog({
36
39
 
37
40
  return (
38
41
  <box
42
+ onMouseUp={onDismiss}
39
43
  style={{
40
44
  position: "absolute",
41
45
  left: 0,
@@ -48,6 +52,7 @@ export function Dialog({
48
52
  }}
49
53
  >
50
54
  <box
55
+ onMouseUp={(event) => event.stopPropagation()}
51
56
  style={{
52
57
  width,
53
58
  height,
@@ -13,7 +13,7 @@ export const NERD = {
13
13
  copy: "",
14
14
  unfold: "",
15
15
  kebab: "⋮",
16
- pin: "⚑",
16
+ star: "★",
17
17
  close: "✕",
18
18
  listTree: "",
19
19
  sidebarLeft: "",
@@ -24,6 +24,7 @@ export const Collapsed: Story = {
24
24
  actions={DEFAULT_QUICK_ACTIONS}
25
25
  selectedIndex={0}
26
26
  expandedIndex={null}
27
+ expandedField="prompt"
27
28
  onToggleExpand={noop}
28
29
  onEditPrompt={() => {}}
29
30
  onEditMetadata={noop}
@@ -43,6 +44,7 @@ export const RowExpanded: Story = {
43
44
  actions={DEFAULT_QUICK_ACTIONS}
44
45
  selectedIndex={1}
45
46
  expandedIndex={1}
47
+ expandedField="prompt"
46
48
  onToggleExpand={noop}
47
49
  onEditPrompt={() => {}}
48
50
  onEditMetadata={noop}
@@ -4,7 +4,7 @@ import { describe, expect, test } from "bun:test";
4
4
  import React from "react";
5
5
  import { testRender } from "@opentui/react/test-utils";
6
6
  import type { QuickAction } from "../config";
7
- import { settle, typeText } from "../test-support";
7
+ import { locateText, settle, typeText } from "../test-support";
8
8
  import { QuickActionsEditor } from "./quick-actions-editor";
9
9
 
10
10
  const MANY: QuickAction[] = Array.from({ length: 14 }, (_, index) => ({
@@ -17,6 +17,7 @@ async function mount(selectedIndex: number) {
17
17
  actions={MANY}
18
18
  selectedIndex={selectedIndex}
19
19
  expandedIndex={null}
20
+ expandedField="prompt"
20
21
  onToggleExpand={() => {}}
21
22
  onEditPrompt={() => {}}
22
23
  onEditMetadata={() => {}}
@@ -58,6 +59,7 @@ describe("editing an expanded action", () => {
58
59
  actions={[{ prompt: "Ship it", metadata: "be terse" }]}
59
60
  selectedIndex={0}
60
61
  expandedIndex={0}
62
+ expandedField="prompt"
61
63
  onToggleExpand={() => {}}
62
64
  onEditPrompt={(_index, prompt) => prompts.push(prompt)}
63
65
  onEditMetadata={(_index, metadata) => metadatas.push(metadata)}
@@ -80,4 +82,36 @@ describe("editing an expanded action", () => {
80
82
 
81
83
  setup.renderer.destroy();
82
84
  });
85
+
86
+ test("clicking the description row opens the editor on the metadata field directly", async () => {
87
+ const toggles: Array<{ index: number; field: "prompt" | "metadata" }> = [];
88
+ const setup = await testRender(
89
+ <QuickActionsEditor
90
+ actions={[{ prompt: "Ship it", metadata: "be terse" }]}
91
+ selectedIndex={0}
92
+ expandedIndex={null}
93
+ expandedField="prompt"
94
+ onToggleExpand={(index, field) => toggles.push({ index, field })}
95
+ onEditPrompt={() => {}}
96
+ onEditMetadata={() => {}}
97
+ onReset={() => {}}
98
+ onAdd={() => {}}
99
+ />,
100
+ { width: 60, height: 8 },
101
+ );
102
+ await settle(setup);
103
+
104
+ // clicking the title opens the title field; clicking the description opens the metadata field
105
+ const title = locateText(setup, "Ship it");
106
+ await setup.mockMouse.click(title.column, title.row);
107
+ const description = locateText(setup, "be terse");
108
+ await setup.mockMouse.click(description.column, description.row);
109
+
110
+ expect(toggles).toEqual([
111
+ { index: 0, field: "prompt" },
112
+ { index: 0, field: "metadata" },
113
+ ]);
114
+
115
+ setup.renderer.destroy();
116
+ });
83
117
  });