wave-code 0.14.0 → 0.14.2

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 (71) hide show
  1. package/dist/components/BackgroundTaskManager.d.ts.map +1 -1
  2. package/dist/components/BackgroundTaskManager.js +36 -25
  3. package/dist/components/ChatInterface.js +2 -2
  4. package/dist/components/CompactDisplay.d.ts +9 -0
  5. package/dist/components/CompactDisplay.d.ts.map +1 -0
  6. package/dist/components/{CompressDisplay.js → CompactDisplay.js} +2 -2
  7. package/dist/components/InputBox.d.ts.map +1 -1
  8. package/dist/components/InputBox.js +2 -2
  9. package/dist/components/LoadingIndicator.d.ts +2 -2
  10. package/dist/components/LoadingIndicator.d.ts.map +1 -1
  11. package/dist/components/LoadingIndicator.js +2 -2
  12. package/dist/components/MarketplaceAddForm.d.ts.map +1 -1
  13. package/dist/components/MarketplaceAddForm.js +48 -17
  14. package/dist/components/MarketplaceDetail.d.ts.map +1 -1
  15. package/dist/components/MarketplaceDetail.js +2 -1
  16. package/dist/components/MarketplaceList.d.ts.map +1 -1
  17. package/dist/components/MarketplaceList.js +2 -1
  18. package/dist/components/McpManager.d.ts.map +1 -1
  19. package/dist/components/McpManager.js +22 -27
  20. package/dist/components/MessageBlockItem.js +2 -2
  21. package/dist/components/PluginDetail.d.ts.map +1 -1
  22. package/dist/components/PluginDetail.js +22 -22
  23. package/dist/components/PluginManagerShell.d.ts +1 -0
  24. package/dist/components/PluginManagerShell.d.ts.map +1 -1
  25. package/dist/components/PluginManagerShell.js +2 -2
  26. package/dist/components/PluginManagerTypes.d.ts +2 -2
  27. package/dist/components/PluginManagerTypes.d.ts.map +1 -1
  28. package/dist/contexts/useChat.d.ts +2 -1
  29. package/dist/contexts/useChat.d.ts.map +1 -1
  30. package/dist/contexts/useChat.js +127 -100
  31. package/dist/hooks/usePluginManager.d.ts +3 -1
  32. package/dist/hooks/usePluginManager.d.ts.map +1 -1
  33. package/dist/hooks/usePluginManager.js +16 -7
  34. package/dist/reducers/backgroundTaskManagerReducer.d.ts +43 -0
  35. package/dist/reducers/backgroundTaskManagerReducer.d.ts.map +1 -0
  36. package/dist/reducers/backgroundTaskManagerReducer.js +23 -0
  37. package/dist/reducers/marketplaceAddFormReducer.d.ts +24 -0
  38. package/dist/reducers/marketplaceAddFormReducer.d.ts.map +1 -0
  39. package/dist/reducers/marketplaceAddFormReducer.js +18 -0
  40. package/dist/reducers/mcpManagerReducer.d.ts +16 -0
  41. package/dist/reducers/mcpManagerReducer.d.ts.map +1 -0
  42. package/dist/reducers/mcpManagerReducer.js +15 -0
  43. package/dist/reducers/pluginDetailReducer.d.ts +25 -0
  44. package/dist/reducers/pluginDetailReducer.d.ts.map +1 -0
  45. package/dist/reducers/pluginDetailReducer.js +38 -0
  46. package/dist/utils/usageSummary.d.ts +1 -1
  47. package/dist/utils/usageSummary.d.ts.map +1 -1
  48. package/dist/utils/usageSummary.js +7 -7
  49. package/package.json +2 -2
  50. package/src/components/BackgroundTaskManager.tsx +32 -34
  51. package/src/components/ChatInterface.tsx +3 -3
  52. package/src/components/{CompressDisplay.tsx → CompactDisplay.tsx} +5 -5
  53. package/src/components/InputBox.tsx +7 -1
  54. package/src/components/LoadingIndicator.tsx +5 -5
  55. package/src/components/MarketplaceAddForm.tsx +76 -22
  56. package/src/components/MarketplaceDetail.tsx +4 -0
  57. package/src/components/MarketplaceList.tsx +4 -0
  58. package/src/components/McpManager.tsx +30 -34
  59. package/src/components/MessageBlockItem.tsx +3 -3
  60. package/src/components/PluginDetail.tsx +25 -33
  61. package/src/components/PluginManagerShell.tsx +3 -2
  62. package/src/components/PluginManagerTypes.ts +8 -2
  63. package/src/contexts/useChat.tsx +60 -26
  64. package/src/hooks/usePluginManager.ts +18 -7
  65. package/src/reducers/backgroundTaskManagerReducer.ts +60 -0
  66. package/src/reducers/marketplaceAddFormReducer.ts +35 -0
  67. package/src/reducers/mcpManagerReducer.ts +31 -0
  68. package/src/reducers/pluginDetailReducer.ts +58 -0
  69. package/src/utils/usageSummary.ts +8 -8
  70. package/dist/components/CompressDisplay.d.ts +0 -9
  71. package/dist/components/CompressDisplay.d.ts.map +0 -1
@@ -0,0 +1,16 @@
1
+ export interface McpManagerState {
2
+ selectedIndex: number;
3
+ viewMode: "list" | "detail";
4
+ }
5
+ export type McpManagerAction = {
6
+ type: "MOVE_UP";
7
+ serverCount: number;
8
+ } | {
9
+ type: "MOVE_DOWN";
10
+ serverCount: number;
11
+ } | {
12
+ type: "SET_VIEW_MODE";
13
+ viewMode: "list" | "detail";
14
+ };
15
+ export declare function mcpManagerReducer(state: McpManagerState, action: McpManagerAction): McpManagerState;
16
+ //# sourceMappingURL=mcpManagerReducer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpManagerReducer.d.ts","sourceRoot":"","sources":["../../src/reducers/mcpManagerReducer.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC7B;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAAC;AAE3D,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,eAAe,EACtB,MAAM,EAAE,gBAAgB,GACvB,eAAe,CAiBjB"}
@@ -0,0 +1,15 @@
1
+ export function mcpManagerReducer(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.serverCount - 1, state.selectedIndex + 1),
9
+ };
10
+ case "SET_VIEW_MODE":
11
+ return { ...state, viewMode: action.viewMode };
12
+ default:
13
+ return state;
14
+ }
15
+ }
@@ -0,0 +1,25 @@
1
+ export interface PluginDetailState {
2
+ selectedScopeIndex: number;
3
+ selectedActionIndex: number;
4
+ }
5
+ export type PluginDetailAction = {
6
+ type: "SELECT_SCOPE_INDEX";
7
+ index: number;
8
+ } | {
9
+ type: "SELECT_ACTION_INDEX";
10
+ index: number;
11
+ } | {
12
+ type: "MOVE_SCOPE_UP";
13
+ maxIndex: number;
14
+ } | {
15
+ type: "MOVE_SCOPE_DOWN";
16
+ maxIndex: number;
17
+ } | {
18
+ type: "MOVE_ACTION_UP";
19
+ maxIndex: number;
20
+ } | {
21
+ type: "MOVE_ACTION_DOWN";
22
+ maxIndex: number;
23
+ };
24
+ export declare function pluginDetailReducer(state: PluginDetailState, action: PluginDetailAction): PluginDetailState;
25
+ //# sourceMappingURL=pluginDetailReducer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pluginDetailReducer.d.ts","sourceRoot":"","sources":["../../src/reducers/pluginDetailReducer.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,kBAAkB,GACzB,iBAAiB,CAyCnB"}
@@ -0,0 +1,38 @@
1
+ export function pluginDetailReducer(state, action) {
2
+ switch (action.type) {
3
+ case "SELECT_SCOPE_INDEX":
4
+ return { ...state, selectedScopeIndex: action.index };
5
+ case "SELECT_ACTION_INDEX":
6
+ return { ...state, selectedActionIndex: action.index };
7
+ case "MOVE_SCOPE_UP":
8
+ return {
9
+ ...state,
10
+ selectedScopeIndex: state.selectedScopeIndex > 0
11
+ ? state.selectedScopeIndex - 1
12
+ : action.maxIndex,
13
+ };
14
+ case "MOVE_SCOPE_DOWN":
15
+ return {
16
+ ...state,
17
+ selectedScopeIndex: state.selectedScopeIndex < action.maxIndex
18
+ ? state.selectedScopeIndex + 1
19
+ : 0,
20
+ };
21
+ case "MOVE_ACTION_UP":
22
+ return {
23
+ ...state,
24
+ selectedActionIndex: state.selectedActionIndex > 0
25
+ ? state.selectedActionIndex - 1
26
+ : action.maxIndex,
27
+ };
28
+ case "MOVE_ACTION_DOWN":
29
+ return {
30
+ ...state,
31
+ selectedActionIndex: state.selectedActionIndex < action.maxIndex
32
+ ? state.selectedActionIndex + 1
33
+ : 0,
34
+ };
35
+ default:
36
+ return state;
37
+ }
38
+ }
@@ -9,7 +9,7 @@ export interface TokenSummary {
9
9
  total_tokens: number;
10
10
  operations: {
11
11
  agent_calls: number;
12
- compressions: number;
12
+ compactions: number;
13
13
  };
14
14
  cache_read_input_tokens?: number;
15
15
  cache_creation_input_tokens?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"usageSummary.d.ts","sourceRoot":"","sources":["../../src/utils/usageSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,cAAc,CAAC,EAAE;QACf,yBAAyB,EAAE,MAAM,CAAC;QAClC,yBAAyB,EAAE,MAAM,CAAC;KACnC,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,KAAK,EAAE,GACd,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAyE9B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,KAAK,EAAE,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,IAAI,CAwHN"}
1
+ {"version":3,"file":"usageSummary.d.ts","sourceRoot":"","sources":["../../src/utils/usageSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,cAAc,CAAC,EAAE;QACf,yBAAyB,EAAE,MAAM,CAAC;QAClC,yBAAyB,EAAE,MAAM,CAAC;KACnC,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,KAAK,EAAE,GACd,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAyE9B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,KAAK,EAAE,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,IAAI,CAwHN"}
@@ -15,7 +15,7 @@ export function calculateTokenSummary(usages) {
15
15
  total_tokens: 0,
16
16
  operations: {
17
17
  agent_calls: 0,
18
- compressions: 0,
18
+ compactions: 0,
19
19
  },
20
20
  });
21
21
  }
@@ -52,8 +52,8 @@ export function calculateTokenSummary(usages) {
52
52
  if (usage.operation_type === "agent") {
53
53
  summary.operations.agent_calls += 1;
54
54
  }
55
- else if (usage.operation_type === "compress") {
56
- summary.operations.compressions += 1;
55
+ else if (usage.operation_type === "compact") {
56
+ summary.operations.compactions += 1;
57
57
  }
58
58
  }
59
59
  // Convert Map to Record and sort by total tokens
@@ -83,7 +83,7 @@ export function displayUsageSummary(usages, sessionFilePath) {
83
83
  let totalCompletion = 0;
84
84
  let totalTokens = 0;
85
85
  let totalAgentCalls = 0;
86
- let totalCompressions = 0;
86
+ let totalCompactions = 0;
87
87
  let totalCacheRead = 0;
88
88
  let totalCacheCreation = 0;
89
89
  let totalCache5m = 0;
@@ -121,13 +121,13 @@ export function displayUsageSummary(usages, sessionFilePath) {
121
121
  }
122
122
  }
123
123
  }
124
- console.log(` Operations: ${summary.operations.agent_calls} agent calls, ${summary.operations.compressions} compressions`);
124
+ console.log(` Operations: ${summary.operations.agent_calls} agent calls, ${summary.operations.compactions} compactions`);
125
125
  console.log();
126
126
  totalPrompt += summary.prompt_tokens;
127
127
  totalCompletion += summary.completion_tokens;
128
128
  totalTokens += summary.total_tokens;
129
129
  totalAgentCalls += summary.operations.agent_calls;
130
- totalCompressions += summary.operations.compressions;
130
+ totalCompactions += summary.operations.compactions;
131
131
  }
132
132
  if (Object.keys(summaries).length > 1) {
133
133
  console.log("Overall Total:");
@@ -149,6 +149,6 @@ export function displayUsageSummary(usages, sessionFilePath) {
149
149
  console.log(` 1h cache: ${totalCache1h.toLocaleString()} tokens`);
150
150
  }
151
151
  }
152
- console.log(` Operations: ${totalAgentCalls} agent calls, ${totalCompressions} compressions`);
152
+ console.log(` Operations: ${totalAgentCalls} agent calls, ${totalCompactions} compactions`);
153
153
  }
154
154
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
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.0"
45
+ "wave-agent-sdk": "0.14.2"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/react": "^19.1.8",
@@ -1,18 +1,11 @@
1
- import React, { useState, useEffect } from "react";
1
+ import React, { useEffect, useReducer } from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { useChat } from "../contexts/useChat.js";
4
4
  import { getLastLines } from "wave-agent-sdk";
5
-
6
- interface Task {
7
- id: string;
8
- type: string;
9
- description?: string;
10
- status: "running" | "completed" | "failed" | "killed";
11
- startTime: number;
12
- exitCode?: number;
13
- runtime?: number;
14
- outputPath?: string;
15
- }
5
+ import {
6
+ backgroundTaskManagerReducer,
7
+ type BackgroundTaskManagerState,
8
+ } from "../reducers/backgroundTaskManagerReducer.js";
16
9
 
17
10
  export interface BackgroundTaskManagerProps {
18
11
  onCancel: () => void;
@@ -23,22 +16,23 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
23
16
  }) => {
24
17
  const { backgroundTasks, getBackgroundTaskOutput, stopBackgroundTask } =
25
18
  useChat();
26
- const [tasks, setTasks] = useState<Task[]>([]);
27
- const [selectedIndex, setSelectedIndex] = useState(0);
28
19
  const MAX_VISIBLE_ITEMS = 3;
29
- const [viewMode, setViewMode] = useState<"list" | "detail">("list");
30
- const [detailTaskId, setDetailTaskId] = useState<string | null>(null);
31
- const [detailOutput, setDetailOutput] = useState<{
32
- stdout: string;
33
- stderr: string;
34
- status: string;
35
- outputPath?: string;
36
- } | null>(null);
20
+
21
+ const [state, dispatch] = useReducer(backgroundTaskManagerReducer, {
22
+ tasks: [],
23
+ selectedIndex: 0,
24
+ viewMode: "list",
25
+ detailTaskId: null,
26
+ detailOutput: null,
27
+ } as BackgroundTaskManagerState);
28
+
29
+ const { tasks, selectedIndex, viewMode, detailTaskId, detailOutput } = state;
37
30
 
38
31
  // Convert backgroundTasks to local Task format
39
32
  useEffect(() => {
40
- setTasks(
41
- backgroundTasks.map((task) => ({
33
+ dispatch({
34
+ type: "SET_TASKS",
35
+ tasks: backgroundTasks.map((task) => ({
42
36
  id: task.id,
43
37
  type: task.type,
44
38
  description: task.description,
@@ -48,14 +42,14 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
48
42
  runtime: task.runtime,
49
43
  outputPath: task.outputPath,
50
44
  })),
51
- );
45
+ });
52
46
  }, [backgroundTasks]);
53
47
 
54
48
  // Load detail output for selected task
55
49
  useEffect(() => {
56
50
  if (viewMode === "detail" && detailTaskId) {
57
51
  const output = getBackgroundTaskOutput(detailTaskId);
58
- setDetailOutput(output);
52
+ dispatch({ type: "SET_DETAIL_OUTPUT", output });
59
53
  }
60
54
  }, [viewMode, detailTaskId, getBackgroundTaskOutput]);
61
55
 
@@ -91,8 +85,8 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
91
85
  if (key.return) {
92
86
  if (tasks.length > 0 && selectedIndex < tasks.length) {
93
87
  const selectedTask = tasks[selectedIndex];
94
- setDetailTaskId(selectedTask.id);
95
- setViewMode("detail");
88
+ dispatch({ type: "SET_DETAIL_TASK_ID", id: selectedTask.id });
89
+ dispatch({ type: "SET_VIEW_MODE", mode: "detail" });
96
90
  }
97
91
  return;
98
92
  }
@@ -103,12 +97,18 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
103
97
  }
104
98
 
105
99
  if (key.upArrow) {
106
- setSelectedIndex(Math.max(0, selectedIndex - 1));
100
+ dispatch({
101
+ type: "SELECT_INDEX",
102
+ index: Math.max(0, selectedIndex - 1),
103
+ });
107
104
  return;
108
105
  }
109
106
 
110
107
  if (key.downArrow) {
111
- setSelectedIndex(Math.min(tasks.length - 1, selectedIndex + 1));
108
+ dispatch({
109
+ type: "SELECT_INDEX",
110
+ index: Math.min(tasks.length - 1, selectedIndex + 1),
111
+ });
112
112
  return;
113
113
  }
114
114
 
@@ -122,9 +122,7 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
122
122
  } else if (viewMode === "detail") {
123
123
  // Detail mode navigation
124
124
  if (key.escape) {
125
- setViewMode("list");
126
- setDetailTaskId(null);
127
- setDetailOutput(null);
125
+ dispatch({ type: "RESET_DETAIL" });
128
126
  return;
129
127
  }
130
128
 
@@ -141,7 +139,7 @@ export const BackgroundTaskManager: React.FC<BackgroundTaskManagerProps> = ({
141
139
  if (viewMode === "detail" && detailTaskId && detailOutput) {
142
140
  const task = tasks.find((t) => t.id === detailTaskId);
143
141
  if (!task) {
144
- setViewMode("list");
142
+ dispatch({ type: "RESET_DETAIL" });
145
143
  return null;
146
144
  }
147
145
 
@@ -16,7 +16,7 @@ export const ChatInterface: React.FC = () => {
16
16
  messages,
17
17
  isLoading,
18
18
  isCommandRunning,
19
- isCompressing,
19
+ isCompacting,
20
20
  sendMessage,
21
21
  abortMessage,
22
22
  mcpServers,
@@ -79,11 +79,11 @@ export const ChatInterface: React.FC = () => {
79
79
 
80
80
  {!isConfirmationVisible && !isExpanded && (
81
81
  <>
82
- {(isLoading || isCommandRunning || isCompressing) && (
82
+ {(isLoading || isCommandRunning || isCompacting) && (
83
83
  <LoadingIndicator
84
84
  isLoading={isLoading}
85
85
  isCommandRunning={isCommandRunning}
86
- isCompressing={isCompressing}
86
+ isCompacting={isCompacting}
87
87
  latestTotalTokens={latestTotalTokens}
88
88
  />
89
89
  )}
@@ -1,13 +1,13 @@
1
1
  import React, { useMemo } from "react";
2
2
  import { Box, Text } from "ink";
3
- import type { CompressBlock } from "wave-agent-sdk";
3
+ import type { CompactBlock } from "wave-agent-sdk";
4
4
 
5
- interface CompressDisplayProps {
6
- block: CompressBlock;
5
+ interface CompactDisplayProps {
6
+ block: CompactBlock;
7
7
  isExpanded?: boolean;
8
8
  }
9
9
 
10
- export const CompressDisplay: React.FC<CompressDisplayProps> = ({ block }) => {
10
+ export const CompactDisplay: React.FC<CompactDisplayProps> = ({ block }) => {
11
11
  const { content } = block;
12
12
 
13
13
  const { displayContent } = useMemo(() => {
@@ -21,7 +21,7 @@ export const CompressDisplay: React.FC<CompressDisplayProps> = ({ block }) => {
21
21
  return (
22
22
  <Box flexDirection="column">
23
23
  <Box>
24
- <Text>Compressed Messages</Text>
24
+ <Text>Compacted Messages</Text>
25
25
  </Box>
26
26
 
27
27
  {content && (
@@ -68,6 +68,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
68
68
  currentModel,
69
69
  configuredModels,
70
70
  setModel,
71
+ recreateAgent,
71
72
  } = useChat();
72
73
 
73
74
  // Input manager with all input state and functionality (including images)
@@ -205,7 +206,12 @@ export const InputBox: React.FC<InputBoxProps> = ({
205
206
  }
206
207
 
207
208
  if (showPluginManager) {
208
- return <PluginManagerShell onCancel={() => setShowPluginManager(false)} />;
209
+ return (
210
+ <PluginManagerShell
211
+ onCancel={() => setShowPluginManager(false)}
212
+ onPluginInstalled={recreateAgent}
213
+ />
214
+ );
209
215
  }
210
216
 
211
217
  if (showModelSelector) {
@@ -4,19 +4,19 @@ import { Box, Text } from "ink";
4
4
  export interface LoadingIndicatorProps {
5
5
  isLoading?: boolean;
6
6
  isCommandRunning?: boolean;
7
- isCompressing?: boolean;
7
+ isCompacting?: boolean;
8
8
  latestTotalTokens?: number;
9
9
  }
10
10
 
11
11
  export const LoadingIndicator = ({
12
12
  isLoading = false,
13
13
  isCommandRunning = false,
14
- isCompressing = false,
14
+ isCompacting = false,
15
15
  latestTotalTokens = 0,
16
16
  }: LoadingIndicatorProps) => {
17
17
  return (
18
18
  <Box flexDirection="column">
19
- {isLoading && !isCompressing && (
19
+ {isLoading && !isCompacting && (
20
20
  <Box>
21
21
  <Text color="yellow">✻ AI is thinking... </Text>
22
22
  {latestTotalTokens > 0 && (
@@ -46,8 +46,8 @@ export const LoadingIndicator = ({
46
46
  </Box>
47
47
  )}
48
48
  {isCommandRunning && <Text color="blue">✻ Command is running...</Text>}
49
- {isCompressing && (
50
- <Text color="magenta">✻ Compressing message history...</Text>
49
+ {isCompacting && (
50
+ <Text color="magenta">✻ Compacting message history...</Text>
51
51
  )}
52
52
  </Box>
53
53
  );
@@ -1,53 +1,107 @@
1
- import React, { useState, useRef, useEffect } from "react";
1
+ import React, { useReducer } from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
4
+ import { marketplaceAddFormReducer } from "../reducers/marketplaceAddFormReducer.js";
5
+
6
+ const SCOPES = [
7
+ { value: "user" as const, label: "user" },
8
+ { value: "project" as const, label: "project" },
9
+ { value: "local" as const, label: "local" },
10
+ ];
4
11
 
5
12
  export const MarketplaceAddForm: React.FC = () => {
6
13
  const { state, actions } = usePluginManagerContext();
7
- const [source, setSource] = useState("");
8
- const sourceRef = useRef(source);
9
-
10
- // Keep ref in sync with state
11
- useEffect(() => {
12
- sourceRef.current = source;
13
- }, [source]);
14
+ const [{ source, scopeIndex, step }, dispatch] = useReducer(
15
+ marketplaceAddFormReducer,
16
+ { source: "", scopeIndex: 0, step: "source" },
17
+ );
14
18
 
15
19
  useInput((input, key) => {
16
20
  if (key.escape) {
17
- actions.setView("MARKETPLACES");
21
+ if (step === "scope") {
22
+ dispatch({ type: "BACK_TO_SOURCE" });
23
+ } else {
24
+ actions.setView("MARKETPLACES");
25
+ }
18
26
  } else if (state.isLoading) {
19
27
  return;
20
- } else if (key.return) {
21
- if (sourceRef.current.trim()) {
22
- actions.addMarketplace(sourceRef.current.trim());
28
+ } else if (step === "source" && key.return) {
29
+ if (source.trim()) {
30
+ dispatch({ type: "SET_STEP", step: "scope" });
31
+ }
32
+ } else if (step === "source" && (key.backspace || key.delete)) {
33
+ dispatch({ type: "DELETE_CHAR" });
34
+ } else if (
35
+ step === "source" &&
36
+ input &&
37
+ !key.ctrl &&
38
+ !key.meta &&
39
+ !("alt" in key && key.alt)
40
+ ) {
41
+ dispatch({ type: "INSERT_CHAR", text: input });
42
+ } else if (step === "scope") {
43
+ if (key.upArrow) {
44
+ dispatch({
45
+ type: "SET_SCOPE_INDEX",
46
+ index: Math.max(0, scopeIndex - 1),
47
+ });
48
+ } else if (key.downArrow) {
49
+ dispatch({
50
+ type: "SET_SCOPE_INDEX",
51
+ index: Math.min(SCOPES.length - 1, scopeIndex + 1),
52
+ });
53
+ } else if (key.return) {
54
+ const scope = SCOPES[scopeIndex].value;
55
+ actions.addMarketplace(source.trim(), scope);
23
56
  }
24
- } else if (key.backspace || key.delete) {
25
- setSource((prev) => prev.slice(0, -1));
26
- } else if (input.length === 1) {
27
- setSource((prev) => prev + input);
28
57
  }
29
58
  });
30
59
 
60
+ if (step === "source") {
61
+ return (
62
+ <Box flexDirection="column" padding={1}>
63
+ <Text bold color="cyan">
64
+ Step 1/2: Enter marketplace source
65
+ </Text>
66
+ <Box marginTop={1}>
67
+ <Text>Source: </Text>
68
+ <Text color="yellow">{source}</Text>
69
+ {!state.isLoading && <Text color="yellow">_</Text>}
70
+ </Box>
71
+ <Box marginTop={1}>
72
+ <Text dimColor>Enter to continue, Esc to cancel</Text>
73
+ </Box>
74
+ </Box>
75
+ );
76
+ }
77
+
31
78
  return (
32
79
  <Box flexDirection="column" padding={1}>
33
80
  <Text bold color="cyan">
34
- Add Marketplace
81
+ Step 2/2: Select scope
35
82
  </Text>
36
83
  <Box marginTop={1}>
37
- <Text>Source (URL or Path): </Text>
38
- <Text color={state.isLoading ? "gray" : "yellow"}>{source}</Text>
39
- {!state.isLoading && <Text color="yellow">_</Text>}
84
+ <Text dimColor>Source: </Text>
85
+ <Text dimColor>{source}</Text>
86
+ </Box>
87
+ <Box marginTop={1} flexDirection="column">
88
+ {SCOPES.map((s, i) => (
89
+ <Text key={s.value} color={i === scopeIndex ? "yellow" : "dim"}>
90
+ {i === scopeIndex ? "> " : " "}
91
+ {s.label}
92
+ </Text>
93
+ ))}
40
94
  </Box>
41
95
  {state.isLoading && (
42
96
  <Box marginTop={1}>
43
- <Text color="yellow">⌛ Adding marketplace...</Text>
97
+ <Text color="yellow">Adding marketplace...</Text>
44
98
  </Box>
45
99
  )}
46
100
  <Box marginTop={1}>
47
101
  <Text dimColor>
48
102
  {state.isLoading
49
103
  ? "Please wait..."
50
- : "Press Enter to add, Esc to cancel"}
104
+ : "Enter to confirm, \u2191/\u2193 to navigate, Esc to go back"}
51
105
  </Text>
52
106
  </Box>
53
107
  </Box>
@@ -55,6 +55,10 @@ export const MarketplaceDetail: React.FC = () => {
55
55
  {marketplace.name}
56
56
  </Text>
57
57
  {marketplace.isBuiltin && <Text dimColor> (Built-in)</Text>}
58
+ {marketplace.declaredScope &&
59
+ marketplace.declaredScope !== "builtin" && (
60
+ <Text dimColor> ({marketplace.declaredScope} scope)</Text>
61
+ )}
58
62
  </Box>
59
63
 
60
64
  <Box marginBottom={1}>
@@ -39,6 +39,10 @@ export const MarketplaceList: React.FC<MarketplaceListProps> = ({
39
39
  {marketplace.isBuiltin && (
40
40
  <Text color="yellow"> [Built-in]</Text>
41
41
  )}
42
+ {marketplace.declaredScope &&
43
+ marketplace.declaredScope !== "builtin" && (
44
+ <Text color="magenta"> [{marketplace.declaredScope}]</Text>
45
+ )}
42
46
  </Text>
43
47
  </Box>
44
48
  <Box marginLeft={4} flexDirection="column">