wave-code 1.0.10 → 1.1.0

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 (242) hide show
  1. package/bin/wave-code.js +8 -2
  2. package/dist/bundle/wave.mjs +3207 -0
  3. package/package.json +24 -25
  4. package/src/commands/update.ts +2 -7
  5. package/src/components/App.tsx +3 -7
  6. package/src/components/BtwDisplay.tsx +10 -1
  7. package/src/components/ChatInterface.tsx +21 -52
  8. package/src/components/ConfirmationDetails.tsx +144 -37
  9. package/src/components/DiffDisplay.tsx +335 -301
  10. package/src/components/InputBox.tsx +3 -1
  11. package/src/components/LoadingIndicator.tsx +16 -2
  12. package/src/components/MessageBlockItem.tsx +2 -4
  13. package/src/components/MessageList.tsx +75 -14
  14. package/src/components/ReasoningDisplay.tsx +2 -4
  15. package/src/components/SessionSelector.tsx +82 -11
  16. package/src/components/StatusCommand.tsx +2 -9
  17. package/src/components/ToolDisplay.tsx +2 -4
  18. package/src/contexts/useChat.tsx +156 -335
  19. package/src/daemon/commands.ts +57 -27
  20. package/src/daemon/jsonRpcClient.ts +1 -1
  21. package/src/daemon/socketClient.ts +2 -2
  22. package/src/hooks/useInputManager.ts +1 -1
  23. package/src/index.ts +57 -10
  24. package/src/managers/inputReducer.ts +186 -104
  25. package/src/print-cli.ts +21 -17
  26. package/src/reducers/selectorReducer.ts +10 -0
  27. package/src/session-selector-cli.tsx +269 -28
  28. package/src/stdio/agentBridge.ts +22 -21
  29. package/src/stdio/daemonServer.ts +3 -1
  30. package/src/utils/clipboard.ts +21 -0
  31. package/src/utils/highlightUtils.ts +46 -1
  32. package/src/utils/readPackageJson.ts +29 -0
  33. package/src/utils/streamingText.ts +11 -0
  34. package/src/utils/worktree.ts +191 -43
  35. package/dist/cli.d.ts +0 -6
  36. package/dist/cli.js +0 -53
  37. package/dist/commands/plugin/disable.d.ts +0 -5
  38. package/dist/commands/plugin/disable.js +0 -15
  39. package/dist/commands/plugin/enable.d.ts +0 -5
  40. package/dist/commands/plugin/enable.js +0 -15
  41. package/dist/commands/plugin/install.d.ts +0 -5
  42. package/dist/commands/plugin/install.js +0 -21
  43. package/dist/commands/plugin/list.d.ts +0 -1
  44. package/dist/commands/plugin/list.js +0 -31
  45. package/dist/commands/plugin/marketplace.d.ts +0 -10
  46. package/dist/commands/plugin/marketplace.js +0 -90
  47. package/dist/commands/plugin/uninstall.d.ts +0 -3
  48. package/dist/commands/plugin/uninstall.js +0 -16
  49. package/dist/commands/plugin/update.d.ts +0 -3
  50. package/dist/commands/plugin/update.js +0 -15
  51. package/dist/commands/update.d.ts +0 -1
  52. package/dist/commands/update.js +0 -97
  53. package/dist/components/AgentsManager.d.ts +0 -7
  54. package/dist/components/AgentsManager.js +0 -109
  55. package/dist/components/App.d.ts +0 -9
  56. package/dist/components/App.js +0 -76
  57. package/dist/components/BackgroundTaskManager.d.ts +0 -5
  58. package/dist/components/BackgroundTaskManager.js +0 -99
  59. package/dist/components/BangDisplay.d.ts +0 -8
  60. package/dist/components/BangDisplay.js +0 -17
  61. package/dist/components/BtwDisplay.d.ts +0 -7
  62. package/dist/components/BtwDisplay.js +0 -19
  63. package/dist/components/ChatInterface.d.ts +0 -2
  64. package/dist/components/ChatInterface.js +0 -61
  65. package/dist/components/CommandSelector.d.ts +0 -10
  66. package/dist/components/CommandSelector.js +0 -66
  67. package/dist/components/CompactDisplay.d.ts +0 -8
  68. package/dist/components/CompactDisplay.js +0 -13
  69. package/dist/components/ConfirmationDetails.d.ts +0 -9
  70. package/dist/components/ConfirmationDetails.js +0 -45
  71. package/dist/components/ConfirmationSelector.d.ts +0 -13
  72. package/dist/components/ConfirmationSelector.js +0 -127
  73. package/dist/components/DiffDisplay.d.ts +0 -8
  74. package/dist/components/DiffDisplay.js +0 -201
  75. package/dist/components/DiscoverView.d.ts +0 -2
  76. package/dist/components/DiscoverView.js +0 -37
  77. package/dist/components/FileSelector.d.ts +0 -11
  78. package/dist/components/FileSelector.js +0 -50
  79. package/dist/components/HelpView.d.ts +0 -7
  80. package/dist/components/HelpView.js +0 -74
  81. package/dist/components/HistorySearch.d.ts +0 -8
  82. package/dist/components/HistorySearch.js +0 -66
  83. package/dist/components/InputBox.d.ts +0 -24
  84. package/dist/components/InputBox.js +0 -149
  85. package/dist/components/InstalledView.d.ts +0 -2
  86. package/dist/components/InstalledView.js +0 -45
  87. package/dist/components/LoadingIndicator.d.ts +0 -10
  88. package/dist/components/LoadingIndicator.js +0 -6
  89. package/dist/components/LoginCommand.d.ts +0 -5
  90. package/dist/components/LoginCommand.js +0 -153
  91. package/dist/components/Markdown.d.ts +0 -5
  92. package/dist/components/Markdown.js +0 -127
  93. package/dist/components/MarketplaceAddForm.d.ts +0 -2
  94. package/dist/components/MarketplaceAddForm.js +0 -55
  95. package/dist/components/MarketplaceDetail.d.ts +0 -2
  96. package/dist/components/MarketplaceDetail.js +0 -74
  97. package/dist/components/MarketplaceList.d.ts +0 -8
  98. package/dist/components/MarketplaceList.js +0 -17
  99. package/dist/components/MarketplaceView.d.ts +0 -2
  100. package/dist/components/MarketplaceView.js +0 -41
  101. package/dist/components/McpManager.d.ts +0 -9
  102. package/dist/components/McpManager.js +0 -88
  103. package/dist/components/MessageBlockItem.d.ts +0 -8
  104. package/dist/components/MessageBlockItem.js +0 -15
  105. package/dist/components/MessageList.d.ts +0 -10
  106. package/dist/components/MessageList.js +0 -80
  107. package/dist/components/ModelSelector.d.ts +0 -8
  108. package/dist/components/ModelSelector.js +0 -45
  109. package/dist/components/Notifications.d.ts +0 -7
  110. package/dist/components/Notifications.js +0 -9
  111. package/dist/components/PlanDisplay.d.ts +0 -7
  112. package/dist/components/PlanDisplay.js +0 -6
  113. package/dist/components/PluginDetail.d.ts +0 -2
  114. package/dist/components/PluginDetail.js +0 -87
  115. package/dist/components/PluginList.d.ts +0 -13
  116. package/dist/components/PluginList.js +0 -15
  117. package/dist/components/PluginManagerShell.d.ts +0 -6
  118. package/dist/components/PluginManagerShell.js +0 -92
  119. package/dist/components/PluginManagerTypes.d.ts +0 -35
  120. package/dist/components/PluginManagerTypes.js +0 -1
  121. package/dist/components/QueuedMessageList.d.ts +0 -2
  122. package/dist/components/QueuedMessageList.js +0 -18
  123. package/dist/components/ReasoningDisplay.d.ts +0 -8
  124. package/dist/components/ReasoningDisplay.js +0 -13
  125. package/dist/components/RewindCommand.d.ts +0 -12
  126. package/dist/components/RewindCommand.js +0 -78
  127. package/dist/components/SessionSelector.d.ts +0 -12
  128. package/dist/components/SessionSelector.js +0 -47
  129. package/dist/components/StatusCommand.d.ts +0 -5
  130. package/dist/components/StatusCommand.js +0 -28
  131. package/dist/components/StatusLine.d.ts +0 -6
  132. package/dist/components/StatusLine.js +0 -9
  133. package/dist/components/TaskList.d.ts +0 -5
  134. package/dist/components/TaskList.js +0 -197
  135. package/dist/components/TaskNotificationMessage.d.ts +0 -5
  136. package/dist/components/TaskNotificationMessage.js +0 -12
  137. package/dist/components/ToolDisplay.d.ts +0 -9
  138. package/dist/components/ToolDisplay.js +0 -55
  139. package/dist/components/WorkflowManager.d.ts +0 -5
  140. package/dist/components/WorkflowManager.js +0 -102
  141. package/dist/components/WorktreeExitPrompt.d.ts +0 -12
  142. package/dist/components/WorktreeExitPrompt.js +0 -35
  143. package/dist/constants/commands.d.ts +0 -2
  144. package/dist/constants/commands.js +0 -92
  145. package/dist/contexts/PluginManagerContext.d.ts +0 -3
  146. package/dist/contexts/PluginManagerContext.js +0 -9
  147. package/dist/contexts/useAppConfig.d.ts +0 -10
  148. package/dist/contexts/useAppConfig.js +0 -13
  149. package/dist/contexts/useChat.d.ts +0 -101
  150. package/dist/contexts/useChat.js +0 -993
  151. package/dist/contracts/status.d.ts +0 -7
  152. package/dist/contracts/status.js +0 -1
  153. package/dist/daemon/commands.d.ts +0 -49
  154. package/dist/daemon/commands.js +0 -341
  155. package/dist/daemon/jsonRpcClient.d.ts +0 -38
  156. package/dist/daemon/jsonRpcClient.js +0 -129
  157. package/dist/daemon/socketClient.d.ts +0 -13
  158. package/dist/daemon/socketClient.js +0 -26
  159. package/dist/daemon-cli.d.ts +0 -10
  160. package/dist/daemon-cli.js +0 -15
  161. package/dist/hooks/useInputManager.d.ts +0 -75
  162. package/dist/hooks/useInputManager.js +0 -583
  163. package/dist/hooks/usePluginManager.d.ts +0 -4
  164. package/dist/hooks/usePluginManager.js +0 -265
  165. package/dist/hooks/useTasks.d.ts +0 -1
  166. package/dist/hooks/useTasks.js +0 -5
  167. package/dist/index.d.ts +0 -4
  168. package/dist/index.js +0 -447
  169. package/dist/managers/inputHandlers.d.ts +0 -30
  170. package/dist/managers/inputHandlers.js +0 -625
  171. package/dist/managers/inputReducer.d.ts +0 -271
  172. package/dist/managers/inputReducer.js +0 -1121
  173. package/dist/plugin-manager-cli.d.ts +0 -5
  174. package/dist/plugin-manager-cli.js +0 -12
  175. package/dist/print-cli.d.ts +0 -10
  176. package/dist/print-cli.js +0 -209
  177. package/dist/reducers/agentsManagerReducer.d.ts +0 -26
  178. package/dist/reducers/agentsManagerReducer.js +0 -54
  179. package/dist/reducers/backgroundTaskManagerReducer.d.ts +0 -62
  180. package/dist/reducers/backgroundTaskManagerReducer.js +0 -106
  181. package/dist/reducers/confirmationReducer.d.ts +0 -37
  182. package/dist/reducers/confirmationReducer.js +0 -193
  183. package/dist/reducers/helpSelectorReducer.d.ts +0 -25
  184. package/dist/reducers/helpSelectorReducer.js +0 -52
  185. package/dist/reducers/marketplaceAddFormReducer.d.ts +0 -24
  186. package/dist/reducers/marketplaceAddFormReducer.js +0 -58
  187. package/dist/reducers/mcpManagerReducer.d.ts +0 -37
  188. package/dist/reducers/mcpManagerReducer.js +0 -74
  189. package/dist/reducers/pluginDetailReducer.d.ts +0 -32
  190. package/dist/reducers/pluginDetailReducer.js +0 -70
  191. package/dist/reducers/questionReducer.d.ts +0 -82
  192. package/dist/reducers/questionReducer.js +0 -375
  193. package/dist/reducers/rewindSelectorReducer.d.ts +0 -21
  194. package/dist/reducers/rewindSelectorReducer.js +0 -37
  195. package/dist/reducers/selectorReducer.d.ts +0 -23
  196. package/dist/reducers/selectorReducer.js +0 -42
  197. package/dist/reducers/workflowManagerReducer.d.ts +0 -40
  198. package/dist/reducers/workflowManagerReducer.js +0 -100
  199. package/dist/session-selector-cli.d.ts +0 -3
  200. package/dist/session-selector-cli.js +0 -25
  201. package/dist/stdio/agentBridge.d.ts +0 -139
  202. package/dist/stdio/agentBridge.js +0 -999
  203. package/dist/stdio/daemonServer.d.ts +0 -67
  204. package/dist/stdio/daemonServer.js +0 -191
  205. package/dist/stdio/index.d.ts +0 -5
  206. package/dist/stdio/index.js +0 -5
  207. package/dist/stdio/jsonRpcConnection.d.ts +0 -39
  208. package/dist/stdio/jsonRpcConnection.js +0 -135
  209. package/dist/stdio/protocol.d.ts +0 -41
  210. package/dist/stdio/protocol.js +0 -26
  211. package/dist/stdio/stdioServer.d.ts +0 -36
  212. package/dist/stdio/stdioServer.js +0 -51
  213. package/dist/stdio-cli.d.ts +0 -8
  214. package/dist/stdio-cli.js +0 -15
  215. package/dist/types.d.ts +0 -20
  216. package/dist/types.js +0 -1
  217. package/dist/utils/bracketedPaste.d.ts +0 -39
  218. package/dist/utils/bracketedPaste.js +0 -122
  219. package/dist/utils/clipboard.d.ts +0 -21
  220. package/dist/utils/clipboard.js +0 -347
  221. package/dist/utils/constants.d.ts +0 -16
  222. package/dist/utils/constants.js +0 -18
  223. package/dist/utils/highlightUtils.d.ts +0 -1
  224. package/dist/utils/highlightUtils.js +0 -93
  225. package/dist/utils/inputUtils.d.ts +0 -17
  226. package/dist/utils/inputUtils.js +0 -67
  227. package/dist/utils/logger.d.ts +0 -71
  228. package/dist/utils/logger.js +0 -259
  229. package/dist/utils/markdownTable.d.ts +0 -34
  230. package/dist/utils/markdownTable.js +0 -302
  231. package/dist/utils/rewindCheckpoints.d.ts +0 -8
  232. package/dist/utils/rewindCheckpoints.js +0 -17
  233. package/dist/utils/throttle.d.ts +0 -14
  234. package/dist/utils/throttle.js +0 -55
  235. package/dist/utils/toolParameterTransforms.d.ts +0 -18
  236. package/dist/utils/toolParameterTransforms.js +0 -73
  237. package/dist/utils/usageSummary.d.ts +0 -28
  238. package/dist/utils/usageSummary.js +0 -121
  239. package/dist/utils/version.d.ts +0 -1
  240. package/dist/utils/version.js +0 -4
  241. package/dist/utils/worktree.d.ts +0 -35
  242. package/dist/utils/worktree.js +0 -219
@@ -255,6 +255,53 @@ function insertTextWithPlaceholder(
255
255
  return newState;
256
256
  }
257
257
 
258
+ /**
259
+ * Delete a placeholder token ([LongText#N] / [Image #N]) as a whole block
260
+ * when the cursor sits at the token's end, aligned with Claude Code's
261
+ * Cursor.deleteTokenBefore (Cursor.ts:937-969): the token must be preceded
262
+ * by start-of-input or whitespace and followed by whitespace or EOL, so a
263
+ * mid-token cursor or a token glued to following text falls back to
264
+ * one-character deletion. Also drops the deleted token's longTextMap entry.
265
+ * Returns null when no token is at the cursor position.
266
+ */
267
+ function deleteTokenBefore(
268
+ inputText: string,
269
+ cursorPosition: number,
270
+ longTextMap: Record<string, string>,
271
+ ): {
272
+ inputText: string;
273
+ cursorPosition: number;
274
+ longTextMap: Record<string, string>;
275
+ } | null {
276
+ if (cursorPosition <= 0) {
277
+ return null;
278
+ }
279
+
280
+ // Word-boundary guard (aligned with CC): only trigger when the char after
281
+ // the cursor is whitespace or the end of the string.
282
+ const charAfter = inputText[cursorPosition];
283
+ if (charAfter !== undefined && !/\s/.test(charAfter)) {
284
+ return null;
285
+ }
286
+
287
+ const textBefore = inputText.slice(0, cursorPosition);
288
+ const tokenMatch = textBefore.match(/(^|\s)\[(LongText#\d+|Image #\d+)\]$/);
289
+ if (!tokenMatch) {
290
+ return null;
291
+ }
292
+
293
+ const tokenStart = tokenMatch.index! + tokenMatch[1]!.length;
294
+ const token = tokenMatch[0].slice(tokenMatch[1]!.length);
295
+ const newLongTextMap = { ...longTextMap };
296
+ delete newLongTextMap[token];
297
+
298
+ return {
299
+ inputText: inputText.slice(0, tokenStart) + inputText.slice(cursorPosition),
300
+ cursorPosition: tokenStart,
301
+ longTextMap: newLongTextMap,
302
+ };
303
+ }
304
+
258
305
  /**
259
306
  * Submit the current input text: extract [Image #N] references, route /btw
260
307
  * and CLI-internal slash commands, otherwise send as a message. Returns null
@@ -823,7 +870,9 @@ export function inputReducer(
823
870
  // chunk (e.g. "\x7f\x7f") that ink cannot parse into a key event, so it
824
871
  // arrives as raw input and would otherwise be treated as a paste and
825
872
  // inserted literally. Treat each DEL as a synchronous backspace instead
826
- // (aligned with Claude Code Issue #1853).
873
+ // (aligned with Claude Code Issue #1853). Each DEL deletes a placeholder
874
+ // token as a whole block first, falling back to one character (aligned
875
+ // with Claude Code's useTextInput.ts:442-465).
827
876
  if (!key.backspace && !key.delete && input.includes("\x7f")) {
828
877
  const delCount = (input.match(/\x7f/g) || []).length;
829
878
 
@@ -834,74 +883,92 @@ export function inputReducer(
834
883
  };
835
884
  }
836
885
 
837
- if (state.cursorPosition > 0) {
838
- const newCursorPosition = Math.max(
839
- 0,
840
- state.cursorPosition - delCount,
841
- );
842
- const newInputText =
843
- state.inputText.substring(0, newCursorPosition) +
844
- state.inputText.substring(state.cursorPosition);
845
-
846
- const newState = {
847
- ...state,
848
- inputText: newInputText,
849
- cursorPosition: newCursorPosition,
850
- historyIndex: -1,
851
- };
852
-
853
- // Deactivate selectors if their trigger character was deleted
854
- if (
855
- newState.showFileSelector &&
856
- newCursorPosition <= newState.atPosition
857
- ) {
858
- newState.showFileSelector = false;
859
- newState.atPosition = -1;
860
- newState.fileSearchQuery = "";
861
- newState.isFileSearching = false;
862
- }
863
- if (
864
- newState.showCommandSelector &&
865
- newCursorPosition <= newState.slashPosition
866
- ) {
867
- newState.showCommandSelector = false;
868
- newState.slashPosition = -1;
869
- newState.commandSearchQuery = "";
870
- }
871
-
872
- // Reactivate selectors if cursor is within a trigger word
873
- const atPos = getAtSelectorPosition(newInputText, newCursorPosition);
874
- if (atPos !== -1 && !state.showFileSelector) {
875
- newState.showFileSelector = true;
876
- newState.atPosition = atPos;
877
- newState.isFileSearching = true;
878
- }
879
- const slashPos = getSlashSelectorPosition(
886
+ let newInputText = state.inputText;
887
+ let newCursorPosition = state.cursorPosition;
888
+ let newLongTextMap = state.longTextMap;
889
+ for (let i = 0; i < delCount; i++) {
890
+ const tokenDeletion = deleteTokenBefore(
880
891
  newInputText,
881
892
  newCursorPosition,
893
+ newLongTextMap,
882
894
  );
883
- if (slashPos !== -1 && !state.showCommandSelector) {
884
- newState.showCommandSelector = true;
885
- newState.slashPosition = slashPos;
895
+ if (tokenDeletion) {
896
+ newInputText = tokenDeletion.inputText;
897
+ newCursorPosition = tokenDeletion.cursorPosition;
898
+ newLongTextMap = tokenDeletion.longTextMap;
899
+ } else if (newCursorPosition > 0) {
900
+ newInputText =
901
+ newInputText.substring(0, newCursorPosition - 1) +
902
+ newInputText.substring(newCursorPosition);
903
+ newCursorPosition -= 1;
886
904
  }
905
+ }
887
906
 
888
- // Update queries
889
- if (newState.showFileSelector && newState.atPosition >= 0) {
890
- newState.fileSearchQuery = newInputText.substring(
891
- newState.atPosition + 1,
892
- newCursorPosition,
893
- );
894
- }
895
- if (newState.showCommandSelector && newState.slashPosition >= 0) {
896
- newState.commandSearchQuery = newInputText.substring(
897
- newState.slashPosition + 1,
898
- newCursorPosition,
899
- );
900
- }
907
+ if (
908
+ newInputText === state.inputText &&
909
+ newCursorPosition === state.cursorPosition
910
+ ) {
911
+ return state;
912
+ }
901
913
 
902
- return newState;
914
+ const newState = {
915
+ ...state,
916
+ inputText: newInputText,
917
+ cursorPosition: newCursorPosition,
918
+ longTextMap: newLongTextMap,
919
+ historyIndex: -1,
920
+ };
921
+
922
+ // Deactivate selectors if their trigger character was deleted
923
+ if (
924
+ newState.showFileSelector &&
925
+ newCursorPosition <= newState.atPosition
926
+ ) {
927
+ newState.showFileSelector = false;
928
+ newState.atPosition = -1;
929
+ newState.fileSearchQuery = "";
930
+ newState.isFileSearching = false;
903
931
  }
904
- return state;
932
+ if (
933
+ newState.showCommandSelector &&
934
+ newCursorPosition <= newState.slashPosition
935
+ ) {
936
+ newState.showCommandSelector = false;
937
+ newState.slashPosition = -1;
938
+ newState.commandSearchQuery = "";
939
+ }
940
+
941
+ // Reactivate selectors if cursor is within a trigger word
942
+ const atPos = getAtSelectorPosition(newInputText, newCursorPosition);
943
+ if (atPos !== -1 && !state.showFileSelector) {
944
+ newState.showFileSelector = true;
945
+ newState.atPosition = atPos;
946
+ newState.isFileSearching = true;
947
+ }
948
+ const slashPos = getSlashSelectorPosition(
949
+ newInputText,
950
+ newCursorPosition,
951
+ );
952
+ if (slashPos !== -1 && !state.showCommandSelector) {
953
+ newState.showCommandSelector = true;
954
+ newState.slashPosition = slashPos;
955
+ }
956
+
957
+ // Update queries
958
+ if (newState.showFileSelector && newState.atPosition >= 0) {
959
+ newState.fileSearchQuery = newInputText.substring(
960
+ newState.atPosition + 1,
961
+ newCursorPosition,
962
+ );
963
+ }
964
+ if (newState.showCommandSelector && newState.slashPosition >= 0) {
965
+ newState.commandSearchQuery = newInputText.substring(
966
+ newState.slashPosition + 1,
967
+ newCursorPosition,
968
+ );
969
+ }
970
+
971
+ return newState;
905
972
  }
906
973
 
907
974
  // 1. /btw overlay handling (active while a question is displayed, or
@@ -1425,54 +1492,69 @@ export function inputReducer(
1425
1492
 
1426
1493
  // 8. Backspace / Delete (Normal Mode)
1427
1494
  if (key.backspace || key.delete) {
1428
- if (state.cursorPosition > 0) {
1429
- const newCursorPosition = state.cursorPosition - 1;
1430
- const beforeCursor = state.inputText.substring(
1431
- 0,
1432
- state.cursorPosition - 1,
1433
- );
1434
- const afterCursor = state.inputText.substring(state.cursorPosition);
1435
- const newInputText = beforeCursor + afterCursor;
1495
+ // Placeholder token deletion first (aligned with Claude Code's
1496
+ // deleteTokenBefore, Cursor.ts:937-969): backspace at the end of a
1497
+ // [LongText#N] / [Image #N] token removes the whole token in one
1498
+ // press (and drops its longTextMap entry); otherwise delete one
1499
+ // character. Selector backspace (section 5) stays character-wise
1500
+ // @mention and /command words are intentionally not tokenized.
1501
+ const tokenDeletion = deleteTokenBefore(
1502
+ state.inputText,
1503
+ state.cursorPosition,
1504
+ state.longTextMap,
1505
+ );
1506
+ if (!tokenDeletion && state.cursorPosition <= 0) {
1507
+ return state;
1508
+ }
1509
+ const newInputText = tokenDeletion
1510
+ ? tokenDeletion.inputText
1511
+ : state.inputText.substring(0, state.cursorPosition - 1) +
1512
+ state.inputText.substring(state.cursorPosition);
1513
+ const newCursorPosition = tokenDeletion
1514
+ ? tokenDeletion.cursorPosition
1515
+ : state.cursorPosition - 1;
1436
1516
 
1437
- const newState = {
1438
- ...state,
1439
- inputText: newInputText,
1440
- cursorPosition: newCursorPosition,
1441
- historyIndex: -1,
1442
- };
1517
+ const newState = {
1518
+ ...state,
1519
+ inputText: newInputText,
1520
+ cursorPosition: newCursorPosition,
1521
+ longTextMap: tokenDeletion
1522
+ ? tokenDeletion.longTextMap
1523
+ : state.longTextMap,
1524
+ historyIndex: -1,
1525
+ };
1443
1526
 
1444
- // Reactivate selectors if cursor is within word
1445
- const atPos = getAtSelectorPosition(newInputText, newCursorPosition);
1446
- if (atPos !== -1 && !state.showFileSelector) {
1447
- newState.showFileSelector = true;
1448
- newState.atPosition = atPos;
1449
- newState.isFileSearching = true;
1450
- }
1527
+ // Reactivate selectors if cursor is within word
1528
+ const atPos = getAtSelectorPosition(newInputText, newCursorPosition);
1529
+ if (atPos !== -1 && !state.showFileSelector) {
1530
+ newState.showFileSelector = true;
1531
+ newState.atPosition = atPos;
1532
+ newState.isFileSearching = true;
1533
+ }
1451
1534
 
1452
- const slashPos = getSlashSelectorPosition(
1453
- newInputText,
1535
+ const slashPos = getSlashSelectorPosition(
1536
+ newInputText,
1537
+ newCursorPosition,
1538
+ );
1539
+ if (slashPos !== -1 && !state.showCommandSelector) {
1540
+ newState.showCommandSelector = true;
1541
+ newState.slashPosition = slashPos;
1542
+ }
1543
+
1544
+ // Update queries
1545
+ if (newState.showFileSelector && newState.atPosition >= 0) {
1546
+ newState.fileSearchQuery = newInputText.substring(
1547
+ newState.atPosition + 1,
1548
+ newCursorPosition,
1549
+ );
1550
+ }
1551
+ if (newState.showCommandSelector && newState.slashPosition >= 0) {
1552
+ newState.commandSearchQuery = newInputText.substring(
1553
+ newState.slashPosition + 1,
1454
1554
  newCursorPosition,
1455
1555
  );
1456
- if (slashPos !== -1 && !state.showCommandSelector) {
1457
- newState.showCommandSelector = true;
1458
- newState.slashPosition = slashPos;
1459
- }
1460
-
1461
- // Update queries
1462
- if (newState.showFileSelector && newState.atPosition >= 0) {
1463
- newState.fileSearchQuery = newInputText.substring(
1464
- newState.atPosition + 1,
1465
- newCursorPosition,
1466
- );
1467
- }
1468
- if (newState.showCommandSelector && newState.slashPosition >= 0) {
1469
- newState.commandSearchQuery = newInputText.substring(
1470
- newState.slashPosition + 1,
1471
- newCursorPosition,
1472
- );
1473
- }
1474
- return newState;
1475
1556
  }
1557
+ return newState;
1476
1558
  }
1477
1559
 
1478
1560
  // 9. Cursor Movement (Normal Mode)
package/src/print-cli.ts CHANGED
@@ -147,6 +147,7 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
147
147
  worktreeName: worktreeSession.name,
148
148
  isNew: worktreeSession.isNew,
149
149
  repoRoot: worktreeSession.repoRoot,
150
+ hookBased: worktreeSession.hookBased,
150
151
  };
151
152
  agent.setWorktreeSession(session);
152
153
  }
@@ -186,8 +187,7 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
186
187
  // Display timing information
187
188
  displayTimingInfo(startTime, showStats);
188
189
 
189
- // Trigger WorktreeRemove hook (before destroy it needs a live agent) and
190
- // decide whether the worktree is clean enough to remove
190
+ // Decide whether the worktree is clean enough to remove
191
191
  let cleanWorktree = false;
192
192
  if (worktreeSession) {
193
193
  const cwd = workdir || worktreeSession.path;
@@ -196,9 +196,7 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
196
196
  const hasCommits = hasNewCommits(cwd, baseBranch);
197
197
  cleanWorktree = !hasChanges && !hasCommits;
198
198
 
199
- if (cleanWorktree) {
200
- await agent.triggerWorktreeRemoveHook(worktreeSession.path);
201
- } else {
199
+ if (!cleanWorktree) {
202
200
  process.stdout.write(
203
201
  `\n⚠️ Worktree '${worktreeSession.name}' has changes or commits. Keeping it at: ${worktreeSession.path}\n`,
204
202
  );
@@ -211,10 +209,14 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
211
209
  // Handle worktree cleanup for print mode (git removal stays after destroy)
212
210
  if (worktreeSession && cleanWorktree) {
213
211
  try {
214
- validateWorktreeRemovalPath(
215
- worktreeSession.path,
216
- worktreeSession.repoRoot,
217
- );
212
+ // Hook-based worktrees are owned by the hook; the git-root
213
+ // containment check does not apply to them
214
+ if (!worktreeSession.hookBased) {
215
+ validateWorktreeRemovalPath(
216
+ worktreeSession.path,
217
+ worktreeSession.repoRoot,
218
+ );
219
+ }
218
220
  await removeWorktree(worktreeSession);
219
221
  } catch (error) {
220
222
  // Never block print-mode exit on worktree cleanup failures
@@ -242,7 +244,7 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
242
244
  // Display timing information even on error
243
245
  displayTimingInfo(startTime, showStats);
244
246
 
245
- // Trigger WorktreeRemove hook (before destroy) when the worktree is clean
247
+ // Decide whether the worktree is clean enough to remove
246
248
  let cleanWorktree = false;
247
249
  if (worktreeSession) {
248
250
  const cwd = workdir || worktreeSession.path;
@@ -251,9 +253,7 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
251
253
  const hasCommits = hasNewCommits(cwd, baseBranch);
252
254
  cleanWorktree = !hasChanges && !hasCommits;
253
255
 
254
- if (cleanWorktree) {
255
- await agent.triggerWorktreeRemoveHook(worktreeSession.path);
256
- } else {
256
+ if (!cleanWorktree) {
257
257
  process.stdout.write(
258
258
  `\n⚠️ Worktree '${worktreeSession.name}' has changes or commits. Keeping it at: ${worktreeSession.path}\n`,
259
259
  );
@@ -265,10 +265,14 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
265
265
  // Handle worktree cleanup for print mode even on error
266
266
  if (worktreeSession && cleanWorktree) {
267
267
  try {
268
- validateWorktreeRemovalPath(
269
- worktreeSession.path,
270
- worktreeSession.repoRoot,
271
- );
268
+ // Hook-based worktrees are owned by the hook; the git-root
269
+ // containment check does not apply to them
270
+ if (!worktreeSession.hookBased) {
271
+ validateWorktreeRemovalPath(
272
+ worktreeSession.path,
273
+ worktreeSession.repoRoot,
274
+ );
275
+ }
272
276
  await removeWorktree(worktreeSession);
273
277
  } catch (error) {
274
278
  process.stdout.write(
@@ -4,6 +4,10 @@ export interface SelectorState<T = unknown> {
4
4
  selectedIndex: number;
5
5
  pendingDecision: "select" | "insert" | "cancel" | null;
6
6
  items: T[];
7
+ /** View state: show sessions from all projects (Ctrl+A toggle). */
8
+ showAllProjects?: boolean;
9
+ /** View state: show sessions from all same-repo worktrees (Ctrl+W toggle). */
10
+ showAllWorktrees?: boolean;
7
11
  }
8
12
 
9
13
  export type SelectorAction<T = unknown> =
@@ -12,6 +16,8 @@ export type SelectorAction<T = unknown> =
12
16
  | { type: "RESET_INDEX" }
13
17
  | { type: "SET_ITEMS"; items: T[] }
14
18
  | { type: "HANDLE_KEY"; key: Key; hasInsert: boolean }
19
+ | { type: "TOGGLE_ALL_PROJECTS" }
20
+ | { type: "TOGGLE_ALL_WORKTREES" }
15
21
  | { type: "CLEAR_DECISION" };
16
22
 
17
23
  export function selectorReducer<T = unknown>(
@@ -33,6 +39,10 @@ export function selectorReducer<T = unknown>(
33
39
  return { ...state, selectedIndex: 0 };
34
40
  case "SET_ITEMS":
35
41
  return { ...state, items: action.items, selectedIndex: 0 };
42
+ case "TOGGLE_ALL_PROJECTS":
43
+ return { ...state, showAllProjects: !state.showAllProjects };
44
+ case "TOGGLE_ALL_WORKTREES":
45
+ return { ...state, showAllWorktrees: !state.showAllWorktrees };
36
46
  case "HANDLE_KEY":
37
47
  if (action.key.upArrow) {
38
48
  return {