wave-code 0.14.3 → 0.15.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 (116) hide show
  1. package/dist/acp/agent.d.ts.map +1 -1
  2. package/dist/acp/agent.js +10 -0
  3. package/dist/components/BackgroundTaskManager.d.ts.map +1 -1
  4. package/dist/components/BackgroundTaskManager.js +17 -53
  5. package/dist/components/CommandSelector.d.ts.map +1 -1
  6. package/dist/components/CommandSelector.js +38 -28
  7. package/dist/components/ConfirmationSelector.d.ts.map +1 -1
  8. package/dist/components/ConfirmationSelector.js +18 -196
  9. package/dist/components/DiscoverView.d.ts.map +1 -1
  10. package/dist/components/DiscoverView.js +19 -11
  11. package/dist/components/FileSelector.d.ts.map +1 -1
  12. package/dist/components/FileSelector.js +29 -25
  13. package/dist/components/HelpView.d.ts.map +1 -1
  14. package/dist/components/HelpView.js +24 -28
  15. package/dist/components/HistorySearch.d.ts.map +1 -1
  16. package/dist/components/HistorySearch.js +26 -28
  17. package/dist/components/InputBox.d.ts.map +1 -1
  18. package/dist/components/InputBox.js +14 -6
  19. package/dist/components/InstalledView.d.ts.map +1 -1
  20. package/dist/components/InstalledView.js +19 -11
  21. package/dist/components/MarketplaceDetail.d.ts.map +1 -1
  22. package/dist/components/MarketplaceDetail.js +35 -16
  23. package/dist/components/MarketplaceView.d.ts.map +1 -1
  24. package/dist/components/MarketplaceView.js +21 -12
  25. package/dist/components/McpManager.d.ts.map +1 -1
  26. package/dist/components/McpManager.js +27 -46
  27. package/dist/components/ModelSelector.d.ts.map +1 -1
  28. package/dist/components/ModelSelector.js +27 -17
  29. package/dist/components/PluginDetail.d.ts.map +1 -1
  30. package/dist/components/PluginDetail.js +39 -26
  31. package/dist/components/RewindCommand.d.ts.map +1 -1
  32. package/dist/components/RewindCommand.js +27 -21
  33. package/dist/components/SessionSelector.d.ts.map +1 -1
  34. package/dist/components/SessionSelector.js +21 -16
  35. package/dist/components/StatusLine.d.ts.map +1 -1
  36. package/dist/components/StatusLine.js +5 -1
  37. package/dist/components/WorktreeExitPrompt.d.ts.map +1 -1
  38. package/dist/components/WorktreeExitPrompt.js +21 -12
  39. package/dist/contexts/useChat.d.ts +0 -1
  40. package/dist/contexts/useChat.d.ts.map +1 -1
  41. package/dist/contexts/useChat.js +13 -20
  42. package/dist/hooks/useInputManager.d.ts +5 -19
  43. package/dist/hooks/useInputManager.d.ts.map +1 -1
  44. package/dist/hooks/useInputManager.js +224 -79
  45. package/dist/managers/inputHandlers.d.ts +1 -1
  46. package/dist/managers/inputHandlers.d.ts.map +1 -1
  47. package/dist/managers/inputHandlers.js +3 -6
  48. package/dist/managers/inputReducer.d.ts +50 -4
  49. package/dist/managers/inputReducer.d.ts.map +1 -1
  50. package/dist/managers/inputReducer.js +519 -4
  51. package/dist/print-cli.d.ts.map +1 -1
  52. package/dist/print-cli.js +17 -9
  53. package/dist/reducers/backgroundTaskManagerReducer.d.ts +20 -0
  54. package/dist/reducers/backgroundTaskManagerReducer.d.ts.map +1 -1
  55. package/dist/reducers/backgroundTaskManagerReducer.js +83 -0
  56. package/dist/reducers/confirmationReducer.d.ts +11 -0
  57. package/dist/reducers/confirmationReducer.d.ts.map +1 -1
  58. package/dist/reducers/confirmationReducer.js +146 -0
  59. package/dist/reducers/helpSelectorReducer.d.ts +26 -0
  60. package/dist/reducers/helpSelectorReducer.d.ts.map +1 -0
  61. package/dist/reducers/helpSelectorReducer.js +52 -0
  62. package/dist/reducers/mcpManagerReducer.d.ts +22 -0
  63. package/dist/reducers/mcpManagerReducer.d.ts.map +1 -1
  64. package/dist/reducers/mcpManagerReducer.js +57 -0
  65. package/dist/reducers/pluginDetailReducer.d.ts +8 -0
  66. package/dist/reducers/pluginDetailReducer.d.ts.map +1 -1
  67. package/dist/reducers/pluginDetailReducer.js +32 -0
  68. package/dist/reducers/questionReducer.d.ts +21 -0
  69. package/dist/reducers/questionReducer.d.ts.map +1 -1
  70. package/dist/reducers/questionReducer.js +177 -0
  71. package/dist/reducers/rewindSelectorReducer.d.ts +22 -0
  72. package/dist/reducers/rewindSelectorReducer.d.ts.map +1 -0
  73. package/dist/reducers/rewindSelectorReducer.js +37 -0
  74. package/dist/reducers/selectorReducer.d.ts +22 -0
  75. package/dist/reducers/selectorReducer.d.ts.map +1 -0
  76. package/dist/reducers/selectorReducer.js +40 -0
  77. package/dist/utils/inputUtils.d.ts +18 -0
  78. package/dist/utils/inputUtils.d.ts.map +1 -0
  79. package/dist/utils/inputUtils.js +67 -0
  80. package/dist/utils/worktree.d.ts.map +1 -1
  81. package/dist/utils/worktree.js +1 -2
  82. package/package.json +2 -2
  83. package/src/acp/agent.ts +10 -0
  84. package/src/components/BackgroundTaskManager.tsx +19 -58
  85. package/src/components/CommandSelector.tsx +53 -44
  86. package/src/components/ConfirmationSelector.tsx +18 -202
  87. package/src/components/DiscoverView.tsx +21 -11
  88. package/src/components/FileSelector.tsx +40 -35
  89. package/src/components/HelpView.tsx +37 -43
  90. package/src/components/HistorySearch.tsx +29 -36
  91. package/src/components/InputBox.tsx +14 -7
  92. package/src/components/InstalledView.tsx +21 -11
  93. package/src/components/MarketplaceDetail.tsx +48 -24
  94. package/src/components/MarketplaceView.tsx +25 -10
  95. package/src/components/McpManager.tsx +29 -54
  96. package/src/components/ModelSelector.tsx +30 -23
  97. package/src/components/PluginDetail.tsx +50 -27
  98. package/src/components/RewindCommand.tsx +38 -32
  99. package/src/components/SessionSelector.tsx +23 -20
  100. package/src/components/StatusLine.tsx +10 -1
  101. package/src/components/WorktreeExitPrompt.tsx +23 -13
  102. package/src/contexts/useChat.tsx +13 -31
  103. package/src/hooks/useInputManager.ts +275 -141
  104. package/src/managers/inputHandlers.ts +1 -6
  105. package/src/managers/inputReducer.ts +680 -7
  106. package/src/print-cli.ts +15 -11
  107. package/src/reducers/backgroundTaskManagerReducer.ts +110 -1
  108. package/src/reducers/confirmationReducer.ts +173 -1
  109. package/src/reducers/helpSelectorReducer.ts +77 -0
  110. package/src/reducers/mcpManagerReducer.ts +82 -1
  111. package/src/reducers/pluginDetailReducer.ts +42 -1
  112. package/src/reducers/questionReducer.ts +204 -0
  113. package/src/reducers/rewindSelectorReducer.ts +54 -0
  114. package/src/reducers/selectorReducer.ts +57 -0
  115. package/src/utils/inputUtils.ts +94 -0
  116. package/src/utils/worktree.ts +1 -7
@@ -189,6 +189,183 @@ export function questionReducer(state, action) {
189
189
  };
190
190
  }
191
191
  }
192
+ case "CLEAR_DECISION":
193
+ return { ...state, decision: null };
194
+ case "HANDLE_KEY": {
195
+ const { input, key, currentQuestion, questions } = action;
196
+ if (!currentQuestion)
197
+ return state;
198
+ const options = [...currentQuestion.options, { label: "Other" }];
199
+ const isMultiSelect = currentQuestion.multiSelect;
200
+ if (key.return) {
201
+ const isOtherFocused = state.selectedOptionIndex === options.length - 1;
202
+ let answer = "";
203
+ if (isMultiSelect) {
204
+ const selectedLabels = Array.from(state.selectedOptionIndices)
205
+ .filter((i) => i < currentQuestion.options.length)
206
+ .map((i) => currentQuestion.options[i].label);
207
+ const isOtherChecked = state.selectedOptionIndices.has(options.length - 1);
208
+ if (isOtherChecked && state.otherText.trim()) {
209
+ selectedLabels.push(state.otherText.trim());
210
+ }
211
+ answer = selectedLabels.join(", ");
212
+ }
213
+ else {
214
+ if (isOtherFocused) {
215
+ answer = state.otherText.trim();
216
+ }
217
+ else {
218
+ answer = options[state.selectedOptionIndex].label;
219
+ }
220
+ }
221
+ if (!answer)
222
+ return state;
223
+ const newAnswers = {
224
+ ...state.userAnswers,
225
+ [currentQuestion.question]: answer,
226
+ };
227
+ if (state.currentQuestionIndex < questions.length - 1) {
228
+ const nextIndex = state.currentQuestionIndex + 1;
229
+ const savedStates = {
230
+ ...state.savedStates,
231
+ [state.currentQuestionIndex]: {
232
+ selectedOptionIndex: state.selectedOptionIndex,
233
+ selectedOptionIndices: state.selectedOptionIndices,
234
+ otherText: state.otherText,
235
+ otherCursorPosition: state.otherCursorPosition,
236
+ },
237
+ };
238
+ const nextState = savedStates[nextIndex] || {
239
+ selectedOptionIndex: 0,
240
+ selectedOptionIndices: new Set(),
241
+ otherText: "",
242
+ otherCursorPosition: 0,
243
+ };
244
+ return {
245
+ ...state,
246
+ currentQuestionIndex: nextIndex,
247
+ ...nextState,
248
+ userAnswers: newAnswers,
249
+ savedStates,
250
+ };
251
+ }
252
+ else {
253
+ const finalAnswers = { ...newAnswers };
254
+ for (const [idxStr, s] of Object.entries(state.savedStates)) {
255
+ const idx = parseInt(idxStr);
256
+ const q = questions[idx];
257
+ if (q && !finalAnswers[q.question]) {
258
+ const a = buildAnswerFromSavedState(q, s);
259
+ if (a)
260
+ finalAnswers[q.question] = a;
261
+ }
262
+ }
263
+ const allAnswered = questions.every((q) => finalAnswers[q.question]);
264
+ if (!allAnswered)
265
+ return state;
266
+ return {
267
+ ...state,
268
+ userAnswers: finalAnswers,
269
+ decision: {
270
+ behavior: "allow",
271
+ message: JSON.stringify(finalAnswers),
272
+ },
273
+ };
274
+ }
275
+ }
276
+ if (input === " ") {
277
+ const isOtherFocused = state.selectedOptionIndex === options.length - 1;
278
+ if (isMultiSelect &&
279
+ (!isOtherFocused ||
280
+ !state.selectedOptionIndices.has(state.selectedOptionIndex))) {
281
+ const nextIndices = new Set(state.selectedOptionIndices);
282
+ if (nextIndices.has(state.selectedOptionIndex))
283
+ nextIndices.delete(state.selectedOptionIndex);
284
+ else
285
+ nextIndices.add(state.selectedOptionIndex);
286
+ return { ...state, selectedOptionIndices: nextIndices };
287
+ }
288
+ }
289
+ if (key.upArrow) {
290
+ return {
291
+ ...state,
292
+ selectedOptionIndex: Math.max(0, state.selectedOptionIndex - 1),
293
+ };
294
+ }
295
+ if (key.downArrow) {
296
+ return {
297
+ ...state,
298
+ selectedOptionIndex: Math.min(options.length - 1, state.selectedOptionIndex + 1),
299
+ };
300
+ }
301
+ if (key.tab) {
302
+ const direction = key.shift ? -1 : 1;
303
+ let nextIndex = state.currentQuestionIndex + direction;
304
+ if (nextIndex < 0)
305
+ nextIndex = questions.length - 1;
306
+ if (nextIndex >= questions.length)
307
+ nextIndex = 0;
308
+ if (nextIndex === state.currentQuestionIndex)
309
+ return state;
310
+ const savedStates = {
311
+ ...state.savedStates,
312
+ [state.currentQuestionIndex]: {
313
+ selectedOptionIndex: state.selectedOptionIndex,
314
+ selectedOptionIndices: state.selectedOptionIndices,
315
+ otherText: state.otherText,
316
+ otherCursorPosition: state.otherCursorPosition,
317
+ },
318
+ };
319
+ const nextState = savedStates[nextIndex] || {
320
+ selectedOptionIndex: 0,
321
+ selectedOptionIndices: new Set(),
322
+ otherText: "",
323
+ otherCursorPosition: 0,
324
+ };
325
+ return {
326
+ ...state,
327
+ currentQuestionIndex: nextIndex,
328
+ ...nextState,
329
+ savedStates,
330
+ };
331
+ }
332
+ if (state.selectedOptionIndex === options.length - 1) {
333
+ if (key.leftArrow) {
334
+ return {
335
+ ...state,
336
+ otherCursorPosition: Math.max(0, state.otherCursorPosition - 1),
337
+ };
338
+ }
339
+ if (key.rightArrow) {
340
+ return {
341
+ ...state,
342
+ otherCursorPosition: Math.min(state.otherText.length, state.otherCursorPosition + 1),
343
+ };
344
+ }
345
+ if (key.backspace || key.delete) {
346
+ if (state.otherCursorPosition > 0) {
347
+ return {
348
+ ...state,
349
+ otherText: state.otherText.slice(0, state.otherCursorPosition - 1) +
350
+ state.otherText.slice(state.otherCursorPosition),
351
+ otherCursorPosition: state.otherCursorPosition - 1,
352
+ };
353
+ }
354
+ return state;
355
+ }
356
+ if (input && !key.ctrl && !key.meta) {
357
+ const newText = state.otherText.slice(0, state.otherCursorPosition) +
358
+ input +
359
+ state.otherText.slice(state.otherCursorPosition);
360
+ return {
361
+ ...state,
362
+ otherText: newText,
363
+ otherCursorPosition: state.otherCursorPosition + input.length,
364
+ };
365
+ }
366
+ }
367
+ return state;
368
+ }
192
369
  default:
193
370
  return state;
194
371
  }
@@ -0,0 +1,22 @@
1
+ import { Key } from "ink";
2
+ export interface SelectorState {
3
+ selectedIndex: number;
4
+ pendingDecision: "select" | "cancel" | null;
5
+ }
6
+ export type SelectorAction = {
7
+ type: "MOVE_UP";
8
+ } | {
9
+ type: "MOVE_DOWN";
10
+ maxIndex: number;
11
+ } | {
12
+ type: "RESET_INDEX";
13
+ index: number;
14
+ } | {
15
+ type: "HANDLE_KEY";
16
+ key: Key;
17
+ maxIndex: number;
18
+ } | {
19
+ type: "CLEAR_DECISION";
20
+ };
21
+ export declare function rewindSelectorReducer(state: SelectorState, action: SelectorAction): SelectorState;
22
+ //# sourceMappingURL=rewindSelectorReducer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rewindSelectorReducer.d.ts","sourceRoot":"","sources":["../../src/reducers/rewindSelectorReducer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;CAC7C;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE/B,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,cAAc,GACrB,aAAa,CAoCf"}
@@ -0,0 +1,37 @@
1
+ export function rewindSelectorReducer(state, action) {
2
+ switch (action.type) {
3
+ case "MOVE_UP":
4
+ return { ...state, selectedIndex: Math.max(0, state.selectedIndex - 1) };
5
+ case "MOVE_DOWN":
6
+ return {
7
+ ...state,
8
+ selectedIndex: Math.min(action.maxIndex, state.selectedIndex + 1),
9
+ };
10
+ case "RESET_INDEX":
11
+ return { ...state, selectedIndex: action.index };
12
+ case "HANDLE_KEY":
13
+ if (action.key.upArrow) {
14
+ return {
15
+ ...state,
16
+ selectedIndex: Math.max(0, state.selectedIndex - 1),
17
+ };
18
+ }
19
+ if (action.key.downArrow) {
20
+ return {
21
+ ...state,
22
+ selectedIndex: Math.min(action.maxIndex, state.selectedIndex + 1),
23
+ };
24
+ }
25
+ if (action.key.return) {
26
+ return { ...state, pendingDecision: "select" };
27
+ }
28
+ if (action.key.escape) {
29
+ return { ...state, pendingDecision: "cancel" };
30
+ }
31
+ return state;
32
+ case "CLEAR_DECISION":
33
+ return { ...state, pendingDecision: null };
34
+ default:
35
+ return state;
36
+ }
37
+ }
@@ -0,0 +1,22 @@
1
+ import { Key } from "ink";
2
+ export interface SelectorState {
3
+ selectedIndex: number;
4
+ pendingDecision: "select" | "insert" | "cancel" | null;
5
+ }
6
+ export type SelectorAction = {
7
+ type: "MOVE_UP";
8
+ } | {
9
+ type: "MOVE_DOWN";
10
+ maxIndex: number;
11
+ } | {
12
+ type: "RESET_INDEX";
13
+ } | {
14
+ type: "HANDLE_KEY";
15
+ key: Key;
16
+ maxIndex: number;
17
+ hasInsert: boolean;
18
+ } | {
19
+ type: "CLEAR_DECISION";
20
+ };
21
+ export declare function selectorReducer(state: SelectorState, action: SelectorAction): SelectorState;
22
+ //# sourceMappingURL=selectorReducer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectorReducer.d.ts","sourceRoot":"","sources":["../../src/reducers/selectorReducer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;CACxD;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE/B,wBAAgB,eAAe,CAC7B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,cAAc,GACrB,aAAa,CAuCf"}
@@ -0,0 +1,40 @@
1
+ export function selectorReducer(state, action) {
2
+ switch (action.type) {
3
+ case "MOVE_UP":
4
+ return { ...state, selectedIndex: Math.max(0, state.selectedIndex - 1) };
5
+ case "MOVE_DOWN":
6
+ return {
7
+ ...state,
8
+ selectedIndex: Math.min(action.maxIndex, state.selectedIndex + 1),
9
+ };
10
+ case "RESET_INDEX":
11
+ return { ...state, selectedIndex: 0 };
12
+ case "HANDLE_KEY":
13
+ if (action.key.upArrow) {
14
+ return {
15
+ ...state,
16
+ selectedIndex: Math.max(0, state.selectedIndex - 1),
17
+ };
18
+ }
19
+ if (action.key.downArrow) {
20
+ return {
21
+ ...state,
22
+ selectedIndex: Math.min(action.maxIndex, state.selectedIndex + 1),
23
+ };
24
+ }
25
+ if (action.key.return) {
26
+ return { ...state, pendingDecision: "select" };
27
+ }
28
+ if (action.key.tab && action.hasInsert) {
29
+ return { ...state, pendingDecision: "insert" };
30
+ }
31
+ if (action.key.escape) {
32
+ return { ...state, pendingDecision: "cancel" };
33
+ }
34
+ return state;
35
+ case "CLEAR_DECISION":
36
+ return { ...state, pendingDecision: null };
37
+ default:
38
+ return state;
39
+ }
40
+ }
@@ -0,0 +1,18 @@
1
+ export declare const expandLongTextPlaceholders: (text: string, longTextMap: Record<string, string>) => string;
2
+ export declare const getAtSelectorPosition: (text: string, cursorPosition: number) => number;
3
+ export declare const getSlashSelectorPosition: (text: string, cursorPosition: number) => number;
4
+ export declare const getWordEnd: (text: string, startPos: number) => number;
5
+ export declare const SELECTOR_TRIGGERS: readonly [{
6
+ readonly char: "@";
7
+ readonly type: "ACTIVATE_FILE_SELECTOR";
8
+ readonly shouldActivate: (char: string, pos: number, text: string) => boolean;
9
+ }, {
10
+ readonly char: "/";
11
+ readonly type: "ACTIVATE_COMMAND_SELECTOR";
12
+ readonly shouldActivate: (char: string, pos: number, text: string, showFileSelector: boolean) => boolean;
13
+ }];
14
+ export declare const getProjectedState: (inputText: string, cursorPosition: number, char: string) => {
15
+ newInputText: string;
16
+ newCursorPosition: number;
17
+ };
18
+ //# sourceMappingURL=inputUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputUtils.d.ts","sourceRoot":"","sources":["../../src/utils/inputUtils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,0BAA0B,GACrC,MAAM,MAAM,EACZ,aAAa,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAClC,MAcF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,MAAM,MAAM,EACZ,gBAAgB,MAAM,KACrB,MAYF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,MAAM,MAAM,EACZ,gBAAgB,MAAM,KACrB,MAYF,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,EAAE,UAAU,MAAM,KAAG,MAM3D,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;oCAIH,MAAM,OAAO,MAAM,QAAQ,MAAM;;;;oCAOhD,MAAM,OACP,MAAM,QACL,MAAM,oBACM,OAAO;EAMrB,CAAC;AAEX,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,gBAAgB,MAAM,EACtB,MAAM,MAAM;;;CAOb,CAAC"}
@@ -0,0 +1,67 @@
1
+ export const expandLongTextPlaceholders = (text, longTextMap) => {
2
+ let expandedText = text;
3
+ const longTextRegex = /\[LongText#(\d+)\]/g;
4
+ const matches = [...text.matchAll(longTextRegex)];
5
+ for (const match of matches) {
6
+ const placeholder = match[0];
7
+ const originalText = longTextMap[placeholder];
8
+ if (originalText) {
9
+ expandedText = expandedText.replace(placeholder, originalText);
10
+ }
11
+ }
12
+ return expandedText;
13
+ };
14
+ export const getAtSelectorPosition = (text, cursorPosition) => {
15
+ let i = cursorPosition - 1;
16
+ while (i >= 0 && !/\s/.test(text[i])) {
17
+ if (text[i] === "@") {
18
+ if (i === 0 || /\s/.test(text[i - 1])) {
19
+ return i;
20
+ }
21
+ break;
22
+ }
23
+ i--;
24
+ }
25
+ return -1;
26
+ };
27
+ export const getSlashSelectorPosition = (text, cursorPosition) => {
28
+ let i = cursorPosition - 1;
29
+ while (i >= 0 && !/\s/.test(text[i])) {
30
+ if (text[i] === "/") {
31
+ if (i === 0 || /\s/.test(text[i - 1])) {
32
+ return i;
33
+ }
34
+ break;
35
+ }
36
+ i--;
37
+ }
38
+ return -1;
39
+ };
40
+ export const getWordEnd = (text, startPos) => {
41
+ let i = startPos;
42
+ while (i < text.length && !/\s/.test(text[i])) {
43
+ i++;
44
+ }
45
+ return i;
46
+ };
47
+ export const SELECTOR_TRIGGERS = [
48
+ {
49
+ char: "@",
50
+ type: "ACTIVATE_FILE_SELECTOR",
51
+ shouldActivate: (char, pos, text) => char === "@" && (pos === 1 || /\s/.test(text[pos - 2])),
52
+ },
53
+ {
54
+ char: "/",
55
+ type: "ACTIVATE_COMMAND_SELECTOR",
56
+ shouldActivate: (char, pos, text, showFileSelector) => char === "/" &&
57
+ !showFileSelector &&
58
+ (pos === 1 || /\s/.test(text[pos - 2])),
59
+ },
60
+ ];
61
+ export const getProjectedState = (inputText, cursorPosition, char) => {
62
+ const beforeCursor = inputText.substring(0, cursorPosition);
63
+ const afterCursor = inputText.substring(cursorPosition);
64
+ const newInputText = beforeCursor + char + afterCursor;
65
+ const newCursorPosition = cursorPosition + char.length;
66
+ return { newInputText, newCursorPosition };
67
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/utils/worktree.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,CA+EzE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CA6D7D"}
1
+ {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/utils/worktree.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,CAyEzE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CA6D7D"}
@@ -10,8 +10,7 @@ import { getDefaultRemoteBranch, getGitMainRepoRoot } from "wave-agent-sdk";
10
10
  */
11
11
  export function createWorktree(name, cwd) {
12
12
  const repoRoot = getGitMainRepoRoot(cwd);
13
- const projectName = path.basename(repoRoot);
14
- const worktreePath = path.join(repoRoot, "..", `${projectName}.worktrees`, name);
13
+ const worktreePath = path.join(repoRoot, ".wave", "worktrees", name);
15
14
  const branchName = `worktree-${name}`;
16
15
  const baseBranch = getDefaultRemoteBranch(cwd);
17
16
  // Ensure parent directory exists
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.14.3",
3
+ "version": "0.15.0",
4
4
  "description": "CLI-based code assistant powered by AI, built with React and Ink",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,7 +42,7 @@
42
42
  "semver": "^7.7.4",
43
43
  "yargs": "^17.7.2",
44
44
  "zod": "^3.23.8",
45
- "wave-agent-sdk": "0.14.3"
45
+ "wave-agent-sdk": "0.15.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/react": "^19.1.8",
package/src/acp/agent.ts CHANGED
@@ -201,6 +201,7 @@ export class WaveAcpAgent implements AcpAgent {
201
201
  onPermissionModeChange: (mode) =>
202
202
  callbacks.onPermissionModeChange?.(mode),
203
203
  onModelChange: (model) => callbacks.onModelChange?.(model),
204
+ onUserMessageAdded: (params) => callbacks.onUserMessageAdded?.(params),
204
205
  },
205
206
  });
206
207
 
@@ -992,6 +993,15 @@ export class WaveAcpAgent implements AcpAgent {
992
993
  });
993
994
  }
994
995
  },
996
+ onUserMessageAdded: (params) => {
997
+ this.connection.sessionUpdate({
998
+ sessionId: sessionId as AcpSessionId,
999
+ update: {
1000
+ sessionUpdate: "user_message_chunk",
1001
+ content: { type: "text", text: params.content },
1002
+ },
1003
+ });
1004
+ },
995
1005
  };
996
1006
  }
997
1007
  }
@@ -24,8 +24,26 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
24
24
  viewMode: "list",
25
25
  detailTaskId: null,
26
26
  detailOutput: null,
27
+ pendingEffect: null,
27
28
  } as BackgroundTaskManagerState);
28
29
 
30
+ // Handle pending effects
31
+ useEffect(() => {
32
+ if (!state.pendingEffect) return;
33
+
34
+ const effect = state.pendingEffect;
35
+ dispatch({ type: "CLEAR_PENDING_EFFECT" });
36
+
37
+ switch (effect.type) {
38
+ case "CANCEL":
39
+ onCancel();
40
+ break;
41
+ case "STOP_TASK":
42
+ stopBackgroundTask(effect.taskId);
43
+ break;
44
+ }
45
+ }, [state.pendingEffect, onCancel, stopBackgroundTask]);
46
+
29
47
  const { tasks, selectedIndex, viewMode, detailTaskId, detailOutput } = state;
30
48
 
31
49
  // Convert backgroundTasks to local Task format
@@ -65,10 +83,6 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
65
83
  return new Date(timestamp).toLocaleTimeString();
66
84
  };
67
85
 
68
- const stopTask = (taskId: string) => {
69
- stopBackgroundTask(taskId);
70
- };
71
-
72
86
  // Calculate visible window
73
87
  const startIndex = Math.max(
74
88
  0,
@@ -80,60 +94,7 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
80
94
  const visibleTasks = tasks.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
81
95
 
82
96
  useInput((input, key) => {
83
- if (viewMode === "list") {
84
- // List mode navigation
85
- if (key.return) {
86
- if (tasks.length > 0 && selectedIndex < tasks.length) {
87
- const selectedTask = tasks[selectedIndex];
88
- dispatch({ type: "SET_DETAIL_TASK_ID", id: selectedTask.id });
89
- dispatch({ type: "SET_VIEW_MODE", mode: "detail" });
90
- }
91
- return;
92
- }
93
-
94
- if (key.escape) {
95
- onCancel();
96
- return;
97
- }
98
-
99
- if (key.upArrow) {
100
- dispatch({
101
- type: "SELECT_INDEX",
102
- index: Math.max(0, selectedIndex - 1),
103
- });
104
- return;
105
- }
106
-
107
- if (key.downArrow) {
108
- dispatch({
109
- type: "SELECT_INDEX",
110
- index: Math.min(tasks.length - 1, selectedIndex + 1),
111
- });
112
- return;
113
- }
114
-
115
- if (input === "k" && tasks.length > 0 && selectedIndex < tasks.length) {
116
- const selectedTask = tasks[selectedIndex];
117
- if (selectedTask.status === "running") {
118
- stopTask(selectedTask.id);
119
- }
120
- return;
121
- }
122
- } else if (viewMode === "detail") {
123
- // Detail mode navigation
124
- if (key.escape) {
125
- dispatch({ type: "RESET_DETAIL" });
126
- return;
127
- }
128
-
129
- if (input === "k" && detailTaskId) {
130
- const task = tasks.find((t) => t.id === detailTaskId);
131
- if (task && task.status === "running") {
132
- stopTask(detailTaskId);
133
- }
134
- return;
135
- }
136
- }
97
+ dispatch({ type: "HANDLE_KEY", input, key });
137
98
  });
138
99
 
139
100
  if (viewMode === "detail" && detailTaskId && detailOutput) {