@jmoyers/harness 0.1.10 → 0.1.20

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 (239) hide show
  1. package/README.md +31 -35
  2. package/package.json +31 -11
  3. package/packages/harness-ai/src/anthropic-protocol.ts +68 -68
  4. package/packages/harness-ai/src/stream-text.ts +13 -91
  5. package/packages/harness-ui/src/frame-primitives.ts +158 -0
  6. package/packages/harness-ui/src/index.ts +18 -0
  7. package/packages/harness-ui/src/interaction/conversation-input-forwarder.ts +221 -0
  8. package/packages/harness-ui/src/interaction/conversation-selection-input.ts +213 -0
  9. package/packages/harness-ui/src/interaction/global-shortcut-input.ts +172 -0
  10. package/{src/ui → packages/harness-ui/src/interaction}/input-preflight.ts +10 -12
  11. package/{src/ui → packages/harness-ui/src/interaction}/input-token-router.ts +120 -69
  12. package/packages/harness-ui/src/interaction/input.ts +420 -0
  13. package/packages/harness-ui/src/interaction/left-nav-input.ts +166 -0
  14. package/{src/ui → packages/harness-ui/src/interaction}/main-pane-pointer-input.ts +91 -23
  15. package/{src/ui → packages/harness-ui/src/interaction}/pointer-routing-input.ts +112 -48
  16. package/packages/harness-ui/src/interaction/rail-pointer-input.ts +62 -0
  17. package/packages/harness-ui/src/interaction/repository-fold-input.ts +118 -0
  18. package/packages/harness-ui/src/kit.ts +476 -0
  19. package/packages/harness-ui/src/layout.ts +238 -0
  20. package/{src/ui/modals/manager.ts → packages/harness-ui/src/modal-manager.ts} +94 -64
  21. package/{src/ui → packages/harness-ui/src}/screen.ts +53 -26
  22. package/packages/harness-ui/src/surface.ts +252 -0
  23. package/packages/harness-ui/src/text-layout.ts +210 -0
  24. package/packages/nim-core/src/contracts.ts +239 -0
  25. package/packages/nim-core/src/event-store.ts +299 -0
  26. package/packages/nim-core/src/events.ts +53 -0
  27. package/packages/nim-core/src/index.ts +9 -0
  28. package/packages/nim-core/src/provider-router.ts +129 -0
  29. package/packages/nim-core/src/providers/anthropic-driver.ts +291 -0
  30. package/packages/nim-core/src/runtime-factory.ts +49 -0
  31. package/packages/nim-core/src/runtime.ts +1797 -0
  32. package/packages/nim-core/src/session-store.ts +516 -0
  33. package/packages/nim-core/src/telemetry.ts +48 -0
  34. package/packages/nim-test-tui/src/index.ts +150 -0
  35. package/packages/nim-ui-core/src/index.ts +1 -0
  36. package/packages/nim-ui-core/src/projection.ts +87 -0
  37. package/scripts/codex-live-mux-runtime.ts +2 -3721
  38. package/scripts/control-plane-daemon.ts +24 -2
  39. package/scripts/harness-bin.js +5 -0
  40. package/scripts/harness-commands.ts +300 -0
  41. package/scripts/harness-runtime.ts +82 -0
  42. package/scripts/harness.ts +33 -3007
  43. package/scripts/nim-tui-smoke.ts +748 -0
  44. package/src/cli/auth/runtime.ts +948 -0
  45. package/src/cli/default-gateway-pointer.ts +193 -0
  46. package/src/cli/gateway/runtime.ts +1872 -0
  47. package/src/cli/parsing/flags.ts +23 -0
  48. package/src/cli/parsing/session.ts +42 -0
  49. package/src/cli/runtime/context.ts +193 -0
  50. package/src/cli/runtime-app/application.ts +392 -0
  51. package/src/cli/runtime-infra/gateway-control.ts +729 -0
  52. package/{scripts/harness-inspector.ts → src/cli/workflows/inspector.ts} +14 -11
  53. package/src/cli/workflows/runtime.ts +965 -0
  54. package/src/clients/tui/left-rail-interactions.ts +519 -0
  55. package/src/clients/tui/main-pane-interactions.ts +509 -0
  56. package/src/clients/tui/modal-input-routing.ts +71 -0
  57. package/src/clients/tui/render-snapshot-adapter.ts +88 -0
  58. package/src/clients/web/synced-selectors.ts +132 -0
  59. package/src/codex/live-session.ts +82 -29
  60. package/src/config/config-core.ts +361 -10
  61. package/src/config/harness-paths.ts +4 -7
  62. package/src/config/harness-runtime-migration.ts +142 -19
  63. package/src/config/harness.config.template.jsonc +33 -0
  64. package/src/config/secrets-core.ts +92 -4
  65. package/src/control-plane/agent-realtime-api.ts +82 -427
  66. package/src/control-plane/prompt/thread-title-namer.ts +49 -23
  67. package/src/control-plane/session-summary.ts +10 -81
  68. package/src/control-plane/status/reducer-base.ts +12 -12
  69. package/src/control-plane/status/reducers/claude-status-reducer.ts +3 -3
  70. package/src/control-plane/status/reducers/codex-status-reducer.ts +4 -4
  71. package/src/control-plane/status/reducers/cursor-status-reducer.ts +3 -3
  72. package/src/control-plane/stream-client.ts +12 -2
  73. package/src/control-plane/stream-command-parser.ts +83 -143
  74. package/src/control-plane/stream-protocol.ts +53 -37
  75. package/src/control-plane/stream-server-background.ts +18 -2
  76. package/src/control-plane/stream-server-command.ts +376 -69
  77. package/src/control-plane/stream-server-session-runtime.ts +3 -2
  78. package/src/control-plane/stream-server.ts +943 -80
  79. package/src/control-plane/stream-session-runtime-types.ts +41 -0
  80. package/src/{mux/live-mux/control-plane-records.ts → core/contracts/records.ts} +24 -97
  81. package/src/core/state/observed-stream-cursor.ts +43 -0
  82. package/src/core/state/synced-observed-state.ts +273 -0
  83. package/src/core/store/harness-synced-store.ts +81 -0
  84. package/src/diff/budget.ts +136 -0
  85. package/src/diff/build.ts +289 -0
  86. package/src/diff/chunker.ts +146 -0
  87. package/src/diff/git-invoke.ts +315 -0
  88. package/src/diff/git-parse.ts +472 -0
  89. package/src/diff/hash.ts +70 -0
  90. package/src/diff/index.ts +24 -0
  91. package/src/diff/normalize.ts +134 -0
  92. package/src/diff/types.ts +178 -0
  93. package/src/diff-ui/args.ts +346 -0
  94. package/src/diff-ui/commands.ts +123 -0
  95. package/src/diff-ui/finder.ts +94 -0
  96. package/src/diff-ui/highlight.ts +127 -0
  97. package/src/diff-ui/index.ts +2 -0
  98. package/src/diff-ui/model.ts +141 -0
  99. package/src/diff-ui/pager.ts +412 -0
  100. package/src/diff-ui/render.ts +337 -0
  101. package/src/diff-ui/runtime.ts +379 -0
  102. package/src/diff-ui/state.ts +224 -0
  103. package/src/diff-ui/types.ts +236 -0
  104. package/src/domain/conversations.ts +11 -7
  105. package/src/domain/workspace.ts +76 -4
  106. package/src/mux/control-plane-op-queue.ts +93 -7
  107. package/src/mux/conversation-rail.ts +28 -71
  108. package/src/mux/dual-pane-core.ts +13 -13
  109. package/src/mux/harness-core-ui.ts +313 -42
  110. package/src/mux/input-shortcuts.ts +22 -112
  111. package/src/mux/keybinding-catalog.ts +340 -0
  112. package/src/mux/keybinding-registry.ts +103 -0
  113. package/src/mux/live-mux/command-menu-open-in.ts +280 -0
  114. package/src/mux/live-mux/command-menu.ts +167 -4
  115. package/src/mux/live-mux/conversation-state.ts +13 -0
  116. package/src/mux/live-mux/directory-resolution.ts +1 -1
  117. package/src/mux/live-mux/git-parsing.ts +16 -0
  118. package/src/mux/live-mux/git-snapshot.ts +33 -2
  119. package/src/mux/live-mux/global-shortcut-handlers.ts +6 -0
  120. package/src/mux/live-mux/home-pane-drop.ts +1 -1
  121. package/src/mux/live-mux/home-pane-pointer.ts +10 -0
  122. package/src/mux/live-mux/input-forwarding.ts +59 -2
  123. package/src/mux/live-mux/left-nav-activation.ts +124 -7
  124. package/src/mux/live-mux/left-nav.ts +35 -0
  125. package/src/mux/live-mux/link-click.ts +292 -0
  126. package/src/mux/live-mux/modal-command-menu-handler.ts +46 -9
  127. package/src/mux/live-mux/modal-conversation-handlers.ts +5 -1
  128. package/src/mux/live-mux/modal-input-reducers.ts +106 -8
  129. package/src/mux/live-mux/modal-overlays.ts +210 -31
  130. package/src/mux/live-mux/modal-pointer.ts +3 -7
  131. package/src/mux/live-mux/modal-prompt-handlers.ts +107 -1
  132. package/src/mux/live-mux/modal-release-notes-handler.ts +111 -0
  133. package/src/mux/live-mux/modal-task-editor-handler.ts +16 -11
  134. package/src/mux/live-mux/pointer-routing.ts +5 -2
  135. package/src/mux/live-mux/project-pane-pointer.ts +8 -0
  136. package/src/mux/live-mux/rail-layout.ts +33 -30
  137. package/src/mux/live-mux/release-notes.ts +383 -0
  138. package/src/mux/live-mux/render-trace-analysis.ts +52 -7
  139. package/src/mux/live-mux/repository-folding.ts +3 -0
  140. package/src/mux/live-mux/selection.ts +0 -4
  141. package/src/mux/live-mux/session-diagnostics-paths.ts +21 -0
  142. package/src/mux/project-pane-github-review.ts +271 -0
  143. package/src/mux/render-frame.ts +4 -0
  144. package/src/mux/runtime-app/codex-live-mux-runtime.ts +5191 -0
  145. package/src/mux/task-composer.ts +21 -14
  146. package/src/mux/task-focused-pane.ts +118 -117
  147. package/src/mux/task-screen-keybindings.ts +19 -82
  148. package/src/mux/workspace-rail-model.ts +270 -104
  149. package/src/mux/workspace-rail.ts +45 -22
  150. package/src/pty/session-broker.ts +1 -1
  151. package/{scripts → src/recording}/terminal-recording-gif-lib.ts +2 -2
  152. package/src/services/control-plane.ts +50 -32
  153. package/src/services/conversation-lifecycle.ts +118 -87
  154. package/src/services/conversation-startup-hydration.ts +20 -12
  155. package/src/services/directory-hydration.ts +21 -16
  156. package/src/services/event-persistence.ts +7 -0
  157. package/src/services/left-rail-pointer-handler.ts +329 -0
  158. package/src/services/mux-ui-state-persistence.ts +5 -1
  159. package/src/services/recording.ts +34 -26
  160. package/src/services/runtime-command-menu-agent-tools.ts +1 -1
  161. package/src/services/runtime-control-actions.ts +79 -61
  162. package/src/services/runtime-control-plane-ops.ts +122 -83
  163. package/src/services/runtime-conversation-actions.ts +40 -26
  164. package/src/services/runtime-conversation-activation.ts +82 -30
  165. package/src/services/runtime-conversation-starter.ts +80 -48
  166. package/src/services/runtime-conversation-title-edit.ts +91 -80
  167. package/src/services/runtime-envelope-handler.ts +107 -105
  168. package/src/services/runtime-git-state.ts +42 -29
  169. package/src/services/runtime-layout-resize.ts +3 -1
  170. package/src/services/runtime-left-rail-render.ts +99 -63
  171. package/src/services/runtime-nim-cli-session.ts +438 -0
  172. package/src/services/runtime-nim-session.ts +705 -0
  173. package/src/services/runtime-nim-tool-bridge.ts +141 -0
  174. package/src/services/runtime-observed-event-projection-pipeline.ts +45 -0
  175. package/src/services/runtime-process-wiring.ts +29 -36
  176. package/src/services/runtime-project-pane-github-review-cache.ts +164 -0
  177. package/src/services/runtime-render-flush.ts +63 -70
  178. package/src/services/runtime-render-lifecycle.ts +65 -64
  179. package/src/services/runtime-render-orchestrator.ts +55 -45
  180. package/src/services/runtime-render-pipeline.ts +106 -103
  181. package/src/services/runtime-render-state.ts +62 -49
  182. package/src/services/runtime-repository-actions.ts +97 -70
  183. package/src/services/runtime-right-pane-render.ts +80 -53
  184. package/src/services/runtime-shutdown.ts +38 -35
  185. package/src/services/runtime-stream-subscriptions.ts +35 -27
  186. package/src/services/runtime-task-composer-persistence.ts +71 -59
  187. package/src/services/runtime-task-composer-snapshot.ts +14 -0
  188. package/src/services/runtime-task-editor-actions.ts +46 -29
  189. package/src/services/runtime-task-pane-actions.ts +220 -134
  190. package/src/services/runtime-task-pane-shortcuts.ts +323 -123
  191. package/src/services/runtime-workspace-observed-effect-queue.ts +25 -0
  192. package/src/services/runtime-workspace-observed-events.ts +33 -184
  193. package/src/services/runtime-workspace-observed-transition-policy.ts +228 -0
  194. package/src/services/session-diagnostics-store.ts +217 -0
  195. package/src/services/startup-background-resume.ts +26 -21
  196. package/src/services/startup-orchestrator.ts +16 -13
  197. package/src/services/startup-paint-tracker.ts +29 -21
  198. package/src/services/startup-persisted-conversation-queue.ts +19 -13
  199. package/src/services/startup-settled-gate.ts +25 -15
  200. package/src/services/startup-shutdown.ts +18 -22
  201. package/src/services/startup-state-hydration.ts +44 -34
  202. package/src/services/startup-visibility.ts +12 -4
  203. package/src/services/task-pane-selection-actions.ts +89 -72
  204. package/src/services/task-planning-hydration.ts +24 -18
  205. package/src/services/task-planning-observed-events.ts +50 -52
  206. package/src/services/workspace-observed-events.ts +66 -63
  207. package/src/storage/storage-lifecycle-core.ts +438 -0
  208. package/src/store/control-plane-store-normalize.ts +33 -242
  209. package/src/store/control-plane-store-types.ts +1 -35
  210. package/src/store/control-plane-store.ts +396 -56
  211. package/src/store/event-store.ts +397 -3
  212. package/src/terminal/snapshot-oracle.ts +207 -94
  213. package/src/ui/mux-theme.ts +112 -8
  214. package/src/ui/panes/home-gridfire.ts +40 -31
  215. package/src/ui/panes/home.ts +10 -2
  216. package/src/ui/panes/nim.ts +315 -0
  217. package/src/mux/live-mux/actions-task.ts +0 -115
  218. package/src/mux/live-mux/left-rail-actions.ts +0 -118
  219. package/src/mux/live-mux/left-rail-conversation-click.ts +0 -82
  220. package/src/mux/live-mux/left-rail-pointer.ts +0 -74
  221. package/src/mux/live-mux/task-pane-shortcuts.ts +0 -206
  222. package/src/services/runtime-directory-actions.ts +0 -164
  223. package/src/services/runtime-input-pipeline.ts +0 -50
  224. package/src/services/runtime-input-router.ts +0 -189
  225. package/src/services/runtime-main-pane-input.ts +0 -230
  226. package/src/services/runtime-modal-input.ts +0 -119
  227. package/src/services/runtime-navigation-input.ts +0 -197
  228. package/src/services/runtime-rail-input.ts +0 -278
  229. package/src/services/runtime-task-pane.ts +0 -62
  230. package/src/services/runtime-workspace-actions.ts +0 -158
  231. package/src/ui/conversation-input-forwarder.ts +0 -114
  232. package/src/ui/conversation-selection-input.ts +0 -103
  233. package/src/ui/global-shortcut-input.ts +0 -89
  234. package/src/ui/input.ts +0 -238
  235. package/src/ui/kit.ts +0 -509
  236. package/src/ui/left-nav-input.ts +0 -80
  237. package/src/ui/left-rail-pointer-input.ts +0 -148
  238. package/src/ui/repository-fold-input.ts +0 -91
  239. package/src/ui/surface.ts +0 -224
@@ -0,0 +1,340 @@
1
+ import {
2
+ MUX_GLOBAL_SHORTCUT_ACTION_ORDER,
3
+ TASK_SCREEN_KEYBINDING_ACTION_ORDER,
4
+ type MuxGlobalShortcutAction,
5
+ type TaskScreenKeybindingAction,
6
+ } from './keybinding-registry.ts';
7
+ import type { ResolvedMuxShortcutBindings } from './input-shortcuts.ts';
8
+ import type { ResolvedTaskScreenKeybindings } from './task-screen-keybindings.ts';
9
+
10
+ export const SHORTCUT_CATALOG_ACTION_ID_PREFIX = 'shortcut.binding.';
11
+ const SHOW_KEYBINDINGS_ACTION_ID = 'shortcuts.show';
12
+
13
+ interface KeybindingActionMetadata {
14
+ readonly title: string;
15
+ readonly screenLabel: string;
16
+ readonly sectionLabel: string;
17
+ readonly aliases?: readonly string[];
18
+ readonly keywords?: readonly string[];
19
+ }
20
+
21
+ interface KeybindingCatalogEntry {
22
+ readonly id: string;
23
+ readonly actionId: string;
24
+ readonly title: string;
25
+ readonly aliases: readonly string[];
26
+ readonly keywords: readonly string[];
27
+ readonly detail: string;
28
+ readonly screenLabel: string;
29
+ readonly sectionLabel: string;
30
+ readonly bindingHint: string;
31
+ }
32
+
33
+ export const SHOW_KEYBINDINGS_COMMAND_ACTION = {
34
+ id: SHOW_KEYBINDINGS_ACTION_ID,
35
+ title: 'Show Keybindings',
36
+ aliases: ['shortcuts', 'keybinds', 'keybindings'],
37
+ keywords: ['shortcut', 'shortcuts', 'keybind', 'keybinds', 'keybindings', 'hotkeys'],
38
+ detail: 'browse active keyboard shortcuts',
39
+ } as const;
40
+
41
+ const GLOBAL_ACTION_METADATA: Readonly<Record<MuxGlobalShortcutAction, KeybindingActionMetadata>> =
42
+ {
43
+ 'mux.app.quit': {
44
+ title: 'Quit',
45
+ screenLabel: 'Global',
46
+ sectionLabel: 'App',
47
+ },
48
+ 'mux.app.interrupt-all': {
49
+ title: 'Interrupt All',
50
+ screenLabel: 'Global',
51
+ sectionLabel: 'App',
52
+ },
53
+ 'mux.command-menu.toggle': {
54
+ title: 'Toggle Command Menu',
55
+ screenLabel: 'Global',
56
+ sectionLabel: 'Navigation',
57
+ aliases: ['command palette'],
58
+ },
59
+ 'mux.debug-bar.toggle': {
60
+ title: 'Toggle Debug Bar',
61
+ screenLabel: 'Global',
62
+ sectionLabel: 'Debug',
63
+ },
64
+ 'mux.gateway.profile.toggle': {
65
+ title: 'Toggle Gateway Profile',
66
+ screenLabel: 'Global',
67
+ sectionLabel: 'Gateway',
68
+ },
69
+ 'mux.gateway.status-timeline.toggle': {
70
+ title: 'Toggle Status Timeline',
71
+ screenLabel: 'Global',
72
+ sectionLabel: 'Gateway',
73
+ },
74
+ 'mux.gateway.render-trace.toggle': {
75
+ title: 'Toggle Render Trace',
76
+ screenLabel: 'Global',
77
+ sectionLabel: 'Gateway',
78
+ },
79
+ 'mux.conversation.new': {
80
+ title: 'New Thread',
81
+ screenLabel: 'Global',
82
+ sectionLabel: 'Conversations',
83
+ },
84
+ 'mux.conversation.critique.open-or-create': {
85
+ title: 'Open/Create Critique Thread',
86
+ screenLabel: 'Global',
87
+ sectionLabel: 'Conversations',
88
+ },
89
+ 'mux.conversation.next': {
90
+ title: 'Next Thread',
91
+ screenLabel: 'Global',
92
+ sectionLabel: 'Conversations',
93
+ },
94
+ 'mux.conversation.previous': {
95
+ title: 'Previous Thread',
96
+ screenLabel: 'Global',
97
+ sectionLabel: 'Conversations',
98
+ },
99
+ 'mux.conversation.titles.refresh-all': {
100
+ title: 'Refresh Thread Titles',
101
+ screenLabel: 'Global',
102
+ sectionLabel: 'Conversations',
103
+ },
104
+ 'mux.conversation.interrupt': {
105
+ title: 'Interrupt Active Thread',
106
+ screenLabel: 'Global',
107
+ sectionLabel: 'Conversations',
108
+ },
109
+ 'mux.conversation.archive': {
110
+ title: 'Archive Active Thread',
111
+ screenLabel: 'Global',
112
+ sectionLabel: 'Conversations',
113
+ },
114
+ 'mux.conversation.takeover': {
115
+ title: 'Take Over Active Thread',
116
+ screenLabel: 'Global',
117
+ sectionLabel: 'Conversations',
118
+ },
119
+ 'mux.conversation.delete': {
120
+ title: 'Delete Active Thread',
121
+ screenLabel: 'Global',
122
+ sectionLabel: 'Conversations',
123
+ },
124
+ 'mux.directory.add': {
125
+ title: 'Add Project',
126
+ screenLabel: 'Global',
127
+ sectionLabel: 'Projects',
128
+ },
129
+ 'mux.directory.close': {
130
+ title: 'Close Active Project',
131
+ screenLabel: 'Global',
132
+ sectionLabel: 'Projects',
133
+ },
134
+ };
135
+
136
+ const TASK_ACTION_METADATA: Readonly<Record<TaskScreenKeybindingAction, KeybindingActionMetadata>> =
137
+ {
138
+ 'mux.home.repo.dropdown.toggle': {
139
+ title: 'Toggle Repository Picker',
140
+ screenLabel: 'Home',
141
+ sectionLabel: 'Repositories',
142
+ },
143
+ 'mux.home.repo.next': {
144
+ title: 'Next Repository',
145
+ screenLabel: 'Home',
146
+ sectionLabel: 'Repositories',
147
+ },
148
+ 'mux.home.repo.previous': {
149
+ title: 'Previous Repository',
150
+ screenLabel: 'Home',
151
+ sectionLabel: 'Repositories',
152
+ },
153
+ 'mux.home.task.submit': {
154
+ title: 'Submit Task as Ready',
155
+ screenLabel: 'Home',
156
+ sectionLabel: 'Tasks',
157
+ },
158
+ 'mux.home.task.queue': {
159
+ title: 'Queue Task as Draft',
160
+ screenLabel: 'Home',
161
+ sectionLabel: 'Tasks',
162
+ },
163
+ 'mux.home.task.newline': {
164
+ title: 'Insert Newline',
165
+ screenLabel: 'Home',
166
+ sectionLabel: 'Editor',
167
+ },
168
+ 'mux.home.task.status.ready': {
169
+ title: 'Set Task Ready',
170
+ screenLabel: 'Home',
171
+ sectionLabel: 'Tasks',
172
+ },
173
+ 'mux.home.task.status.draft': {
174
+ title: 'Set Task Draft',
175
+ screenLabel: 'Home',
176
+ sectionLabel: 'Tasks',
177
+ },
178
+ 'mux.home.task.status.complete': {
179
+ title: 'Set Task Complete',
180
+ screenLabel: 'Home',
181
+ sectionLabel: 'Tasks',
182
+ },
183
+ 'mux.home.task.reorder.up': {
184
+ title: 'Move Task Up',
185
+ screenLabel: 'Home',
186
+ sectionLabel: 'Tasks',
187
+ },
188
+ 'mux.home.task.reorder.down': {
189
+ title: 'Move Task Down',
190
+ screenLabel: 'Home',
191
+ sectionLabel: 'Tasks',
192
+ },
193
+ 'mux.home.editor.cursor.left': {
194
+ title: 'Move Cursor Left',
195
+ screenLabel: 'Home',
196
+ sectionLabel: 'Editor',
197
+ },
198
+ 'mux.home.editor.cursor.right': {
199
+ title: 'Move Cursor Right',
200
+ screenLabel: 'Home',
201
+ sectionLabel: 'Editor',
202
+ },
203
+ 'mux.home.editor.cursor.up': {
204
+ title: 'Move Cursor Up',
205
+ screenLabel: 'Home',
206
+ sectionLabel: 'Editor',
207
+ },
208
+ 'mux.home.editor.cursor.down': {
209
+ title: 'Move Cursor Down',
210
+ screenLabel: 'Home',
211
+ sectionLabel: 'Editor',
212
+ },
213
+ 'mux.home.editor.line.start': {
214
+ title: 'Move to Line Start',
215
+ screenLabel: 'Home',
216
+ sectionLabel: 'Editor',
217
+ },
218
+ 'mux.home.editor.line.end': {
219
+ title: 'Move to Line End',
220
+ screenLabel: 'Home',
221
+ sectionLabel: 'Editor',
222
+ },
223
+ 'mux.home.editor.word.left': {
224
+ title: 'Move to Previous Word',
225
+ screenLabel: 'Home',
226
+ sectionLabel: 'Editor',
227
+ },
228
+ 'mux.home.editor.word.right': {
229
+ title: 'Move to Next Word',
230
+ screenLabel: 'Home',
231
+ sectionLabel: 'Editor',
232
+ },
233
+ 'mux.home.editor.delete.backward': {
234
+ title: 'Delete Backward',
235
+ screenLabel: 'Home',
236
+ sectionLabel: 'Editor',
237
+ },
238
+ 'mux.home.editor.delete.forward': {
239
+ title: 'Delete Forward',
240
+ screenLabel: 'Home',
241
+ sectionLabel: 'Editor',
242
+ },
243
+ 'mux.home.editor.delete.word.backward': {
244
+ title: 'Delete Previous Word',
245
+ screenLabel: 'Home',
246
+ sectionLabel: 'Editor',
247
+ },
248
+ 'mux.home.editor.delete.line.start': {
249
+ title: 'Delete to Line Start',
250
+ screenLabel: 'Home',
251
+ sectionLabel: 'Editor',
252
+ },
253
+ 'mux.home.editor.delete.line.end': {
254
+ title: 'Delete to Line End',
255
+ screenLabel: 'Home',
256
+ sectionLabel: 'Editor',
257
+ },
258
+ };
259
+
260
+ function bindingHint(bindings: readonly string[]): string {
261
+ return bindings.length === 0 ? '(unbound)' : bindings.join(', ');
262
+ }
263
+
264
+ function uniqueLower(values: readonly string[]): readonly string[] {
265
+ const seen = new Set<string>();
266
+ const out: string[] = [];
267
+ for (const value of values) {
268
+ const normalized = value.trim().toLowerCase();
269
+ if (normalized.length === 0 || seen.has(normalized)) {
270
+ continue;
271
+ }
272
+ seen.add(normalized);
273
+ out.push(normalized);
274
+ }
275
+ return out;
276
+ }
277
+
278
+ function keywordsFromActionId(actionId: string): readonly string[] {
279
+ return actionId
280
+ .split('.')
281
+ .map((part) => part.trim().toLowerCase())
282
+ .filter((part) => part.length > 0 && part !== 'mux' && part !== 'home');
283
+ }
284
+
285
+ function toCatalogEntry(
286
+ actionId: string,
287
+ bindings: readonly string[],
288
+ metadata: KeybindingActionMetadata,
289
+ ): KeybindingCatalogEntry {
290
+ const hint = bindingHint(bindings);
291
+ const aliases = uniqueLower([
292
+ actionId,
293
+ metadata.title,
294
+ metadata.sectionLabel,
295
+ ...(metadata.aliases ?? []),
296
+ ...bindings,
297
+ ]);
298
+ const keywords = uniqueLower([
299
+ 'shortcut',
300
+ 'keybinding',
301
+ 'keybind',
302
+ metadata.screenLabel,
303
+ metadata.sectionLabel,
304
+ ...(metadata.keywords ?? []),
305
+ ...keywordsFromActionId(actionId),
306
+ ...bindings,
307
+ ]);
308
+ return {
309
+ id: `${SHORTCUT_CATALOG_ACTION_ID_PREFIX}${actionId}`,
310
+ actionId,
311
+ title: metadata.title,
312
+ aliases,
313
+ keywords,
314
+ detail: actionId,
315
+ screenLabel: metadata.screenLabel,
316
+ sectionLabel: metadata.sectionLabel,
317
+ bindingHint: hint,
318
+ };
319
+ }
320
+
321
+ export function buildKeybindingCatalogEntries(input: {
322
+ readonly globalBindings: ResolvedMuxShortcutBindings;
323
+ readonly taskScreenKeybindings: ResolvedTaskScreenKeybindings;
324
+ }): readonly KeybindingCatalogEntry[] {
325
+ const global = MUX_GLOBAL_SHORTCUT_ACTION_ORDER.map((actionId) =>
326
+ toCatalogEntry(
327
+ actionId,
328
+ input.globalBindings.rawByAction[actionId],
329
+ GLOBAL_ACTION_METADATA[actionId],
330
+ ),
331
+ );
332
+ const taskScreen = TASK_SCREEN_KEYBINDING_ACTION_ORDER.map((actionId) =>
333
+ toCatalogEntry(
334
+ actionId,
335
+ input.taskScreenKeybindings.rawByAction[actionId],
336
+ TASK_ACTION_METADATA[actionId],
337
+ ),
338
+ );
339
+ return [...global, ...taskScreen];
340
+ }
@@ -0,0 +1,103 @@
1
+ export const MUX_GLOBAL_SHORTCUT_ACTION_ORDER = [
2
+ 'mux.app.quit',
3
+ 'mux.app.interrupt-all',
4
+ 'mux.command-menu.toggle',
5
+ 'mux.debug-bar.toggle',
6
+ 'mux.gateway.profile.toggle',
7
+ 'mux.gateway.status-timeline.toggle',
8
+ 'mux.gateway.render-trace.toggle',
9
+ 'mux.conversation.new',
10
+ 'mux.conversation.critique.open-or-create',
11
+ 'mux.conversation.next',
12
+ 'mux.conversation.previous',
13
+ 'mux.conversation.titles.refresh-all',
14
+ 'mux.conversation.interrupt',
15
+ 'mux.conversation.archive',
16
+ 'mux.conversation.takeover',
17
+ 'mux.conversation.delete',
18
+ 'mux.directory.add',
19
+ 'mux.directory.close',
20
+ ] as const;
21
+
22
+ export type MuxGlobalShortcutAction = (typeof MUX_GLOBAL_SHORTCUT_ACTION_ORDER)[number];
23
+
24
+ export const DEFAULT_MUX_SHORTCUT_BINDINGS_RAW: Readonly<
25
+ Record<MuxGlobalShortcutAction, readonly string[]>
26
+ > = {
27
+ 'mux.app.quit': [],
28
+ 'mux.app.interrupt-all': ['ctrl+c'],
29
+ 'mux.command-menu.toggle': ['ctrl+p', 'cmd+p'],
30
+ 'mux.debug-bar.toggle': [],
31
+ 'mux.gateway.profile.toggle': ['ctrl+shift+p'],
32
+ 'mux.gateway.status-timeline.toggle': ['alt+r'],
33
+ 'mux.gateway.render-trace.toggle': ['ctrl+]'],
34
+ 'mux.conversation.new': ['ctrl+t'],
35
+ 'mux.conversation.critique.open-or-create': ['ctrl+g'],
36
+ 'mux.conversation.next': ['ctrl+j'],
37
+ 'mux.conversation.previous': ['ctrl+k'],
38
+ 'mux.conversation.titles.refresh-all': ['ctrl+r'],
39
+ 'mux.conversation.interrupt': [],
40
+ 'mux.conversation.archive': [],
41
+ 'mux.conversation.takeover': ['ctrl+l'],
42
+ 'mux.conversation.delete': ['ctrl+x'],
43
+ 'mux.directory.add': ['ctrl+o'],
44
+ 'mux.directory.close': ['ctrl+w'],
45
+ };
46
+
47
+ export const TASK_SCREEN_KEYBINDING_ACTION_ORDER = [
48
+ 'mux.home.repo.dropdown.toggle',
49
+ 'mux.home.repo.next',
50
+ 'mux.home.repo.previous',
51
+ 'mux.home.task.submit',
52
+ 'mux.home.task.queue',
53
+ 'mux.home.task.newline',
54
+ 'mux.home.task.status.ready',
55
+ 'mux.home.task.status.draft',
56
+ 'mux.home.task.status.complete',
57
+ 'mux.home.task.reorder.up',
58
+ 'mux.home.task.reorder.down',
59
+ 'mux.home.editor.cursor.left',
60
+ 'mux.home.editor.cursor.right',
61
+ 'mux.home.editor.cursor.up',
62
+ 'mux.home.editor.cursor.down',
63
+ 'mux.home.editor.line.start',
64
+ 'mux.home.editor.line.end',
65
+ 'mux.home.editor.word.left',
66
+ 'mux.home.editor.word.right',
67
+ 'mux.home.editor.delete.backward',
68
+ 'mux.home.editor.delete.forward',
69
+ 'mux.home.editor.delete.word.backward',
70
+ 'mux.home.editor.delete.line.start',
71
+ 'mux.home.editor.delete.line.end',
72
+ ] as const;
73
+
74
+ export type TaskScreenKeybindingAction = (typeof TASK_SCREEN_KEYBINDING_ACTION_ORDER)[number];
75
+
76
+ export const DEFAULT_TASK_SCREEN_KEYBINDINGS_RAW: Readonly<
77
+ Record<TaskScreenKeybindingAction, readonly string[]>
78
+ > = {
79
+ 'mux.home.repo.dropdown.toggle': ['alt+g'],
80
+ 'mux.home.repo.next': ['ctrl+n'],
81
+ 'mux.home.repo.previous': ['ctrl+p'],
82
+ 'mux.home.task.submit': ['enter'],
83
+ 'mux.home.task.queue': ['tab'],
84
+ 'mux.home.task.newline': ['shift+enter'],
85
+ 'mux.home.task.status.ready': ['alt+r'],
86
+ 'mux.home.task.status.draft': ['alt+d'],
87
+ 'mux.home.task.status.complete': ['alt+c'],
88
+ 'mux.home.task.reorder.up': ['ctrl+up'],
89
+ 'mux.home.task.reorder.down': ['ctrl+down'],
90
+ 'mux.home.editor.cursor.left': ['left', 'ctrl+b'],
91
+ 'mux.home.editor.cursor.right': ['right', 'ctrl+f'],
92
+ 'mux.home.editor.cursor.up': ['up'],
93
+ 'mux.home.editor.cursor.down': ['down'],
94
+ 'mux.home.editor.line.start': ['ctrl+a', 'home'],
95
+ 'mux.home.editor.line.end': ['ctrl+e', 'end'],
96
+ 'mux.home.editor.word.left': ['alt+b'],
97
+ 'mux.home.editor.word.right': ['alt+f'],
98
+ 'mux.home.editor.delete.backward': ['backspace'],
99
+ 'mux.home.editor.delete.forward': ['delete'],
100
+ 'mux.home.editor.delete.word.backward': ['ctrl+w', 'alt+backspace'],
101
+ 'mux.home.editor.delete.line.start': ['ctrl+u'],
102
+ 'mux.home.editor.delete.line.end': ['ctrl+k'],
103
+ };