wave-code 0.6.5 → 0.7.1

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 (101) hide show
  1. package/dist/cli.d.ts +1 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +2 -2
  4. package/dist/commands/plugin/disable.d.ts.map +1 -1
  5. package/dist/commands/plugin/disable.js +3 -10
  6. package/dist/commands/plugin/enable.d.ts.map +1 -1
  7. package/dist/commands/plugin/enable.js +3 -10
  8. package/dist/commands/plugin/install.d.ts.map +1 -1
  9. package/dist/commands/plugin/install.js +4 -11
  10. package/dist/commands/plugin/list.d.ts.map +1 -1
  11. package/dist/commands/plugin/list.js +5 -39
  12. package/dist/commands/plugin/marketplace.js +9 -9
  13. package/dist/commands/plugin/uninstall.d.ts.map +1 -1
  14. package/dist/commands/plugin/uninstall.js +4 -17
  15. package/dist/commands/plugin/update.js +3 -3
  16. package/dist/components/App.d.ts +1 -0
  17. package/dist/components/App.d.ts.map +1 -1
  18. package/dist/components/App.js +4 -4
  19. package/dist/components/BackgroundTaskManager.d.ts.map +1 -1
  20. package/dist/components/BackgroundTaskManager.js +34 -18
  21. package/dist/components/ChatInterface.d.ts.map +1 -1
  22. package/dist/components/ChatInterface.js +28 -15
  23. package/dist/components/ConfirmationDetails.d.ts +1 -0
  24. package/dist/components/ConfirmationDetails.d.ts.map +1 -1
  25. package/dist/components/ConfirmationDetails.js +7 -14
  26. package/dist/components/ConfirmationSelector.d.ts +1 -0
  27. package/dist/components/ConfirmationSelector.d.ts.map +1 -1
  28. package/dist/components/ConfirmationSelector.js +164 -117
  29. package/dist/components/DiffDisplay.d.ts +1 -0
  30. package/dist/components/DiffDisplay.d.ts.map +1 -1
  31. package/dist/components/DiffDisplay.js +94 -36
  32. package/dist/components/HistorySearch.d.ts.map +1 -1
  33. package/dist/components/HistorySearch.js +26 -20
  34. package/dist/components/Markdown.d.ts.map +1 -1
  35. package/dist/components/Markdown.js +3 -1
  36. package/dist/components/McpManager.d.ts.map +1 -1
  37. package/dist/components/McpManager.js +49 -52
  38. package/dist/components/MessageBlockItem.d.ts +9 -0
  39. package/dist/components/MessageBlockItem.d.ts.map +1 -0
  40. package/dist/components/MessageBlockItem.js +11 -0
  41. package/dist/components/MessageList.d.ts +2 -4
  42. package/dist/components/MessageList.d.ts.map +1 -1
  43. package/dist/components/MessageList.js +28 -23
  44. package/dist/components/PluginDetail.d.ts.map +1 -1
  45. package/dist/components/PluginDetail.js +19 -22
  46. package/dist/components/SessionSelector.d.ts.map +1 -1
  47. package/dist/components/SessionSelector.js +8 -5
  48. package/dist/components/TaskList.d.ts.map +1 -1
  49. package/dist/components/TaskList.js +2 -5
  50. package/dist/components/ToolDisplay.d.ts.map +1 -1
  51. package/dist/components/ToolDisplay.js +1 -1
  52. package/dist/contexts/useChat.d.ts +1 -0
  53. package/dist/contexts/useChat.d.ts.map +1 -1
  54. package/dist/contexts/useChat.js +20 -3
  55. package/dist/hooks/usePluginManager.d.ts.map +1 -1
  56. package/dist/hooks/usePluginManager.js +20 -39
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +16 -0
  59. package/dist/print-cli.d.ts +1 -0
  60. package/dist/print-cli.d.ts.map +1 -1
  61. package/dist/print-cli.js +2 -1
  62. package/dist/utils/highlightUtils.d.ts +2 -0
  63. package/dist/utils/highlightUtils.d.ts.map +1 -0
  64. package/dist/utils/highlightUtils.js +69 -0
  65. package/dist/utils/toolParameterTransforms.d.ts +2 -6
  66. package/dist/utils/toolParameterTransforms.d.ts.map +1 -1
  67. package/dist/utils/toolParameterTransforms.js +10 -14
  68. package/package.json +4 -2
  69. package/src/cli.tsx +3 -0
  70. package/src/commands/plugin/disable.ts +3 -17
  71. package/src/commands/plugin/enable.ts +3 -17
  72. package/src/commands/plugin/install.ts +4 -18
  73. package/src/commands/plugin/list.ts +5 -55
  74. package/src/commands/plugin/marketplace.ts +9 -9
  75. package/src/commands/plugin/uninstall.ts +4 -26
  76. package/src/commands/plugin/update.ts +3 -3
  77. package/src/components/App.tsx +10 -2
  78. package/src/components/BackgroundTaskManager.tsx +69 -44
  79. package/src/components/ChatInterface.tsx +35 -23
  80. package/src/components/ConfirmationDetails.tsx +13 -15
  81. package/src/components/ConfirmationSelector.tsx +207 -128
  82. package/src/components/DiffDisplay.tsx +164 -75
  83. package/src/components/HistorySearch.tsx +31 -25
  84. package/src/components/Markdown.tsx +3 -1
  85. package/src/components/McpManager.tsx +51 -59
  86. package/src/components/MessageBlockItem.tsx +83 -0
  87. package/src/components/MessageList.tsx +55 -52
  88. package/src/components/PluginDetail.tsx +30 -31
  89. package/src/components/SessionSelector.tsx +8 -5
  90. package/src/components/TaskList.tsx +2 -5
  91. package/src/components/ToolDisplay.tsx +5 -1
  92. package/src/contexts/useChat.tsx +22 -2
  93. package/src/hooks/usePluginManager.ts +21 -57
  94. package/src/index.ts +17 -0
  95. package/src/print-cli.ts +3 -0
  96. package/src/utils/highlightUtils.ts +76 -0
  97. package/src/utils/toolParameterTransforms.ts +11 -20
  98. package/dist/components/MessageItem.d.ts +0 -8
  99. package/dist/components/MessageItem.d.ts.map +0 -1
  100. package/dist/components/MessageItem.js +0 -13
  101. package/src/components/MessageItem.tsx +0 -81
@@ -0,0 +1,83 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+ import type { Message, MessageBlock } from "wave-agent-sdk";
4
+ import { MessageSource } from "wave-agent-sdk";
5
+ import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
6
+ import { ToolDisplay } from "./ToolDisplay.js";
7
+ import { CompressDisplay } from "./CompressDisplay.js";
8
+ import { ReasoningDisplay } from "./ReasoningDisplay.js";
9
+ import { Markdown } from "./Markdown.js";
10
+
11
+ export interface MessageBlockItemProps {
12
+ block: MessageBlock;
13
+ message: Message;
14
+ isExpanded: boolean;
15
+ paddingTop?: number;
16
+ }
17
+
18
+ export const MessageBlockItem = ({
19
+ block,
20
+ message,
21
+ isExpanded,
22
+ paddingTop = 0,
23
+ }: MessageBlockItemProps) => {
24
+ return (
25
+ <Box flexDirection="column" paddingTop={paddingTop}>
26
+ {block.type === "text" && block.content.trim() && (
27
+ <Box>
28
+ {block.customCommandContent && (
29
+ <Text color="cyan" bold>
30
+ ${" "}
31
+ </Text>
32
+ )}
33
+ {block.source === MessageSource.HOOK && (
34
+ <Text color="magenta" bold>
35
+ ~{" "}
36
+ </Text>
37
+ )}
38
+ {message.role === "user" ? (
39
+ <Text backgroundColor="gray" color="white">
40
+ {block.content}
41
+ </Text>
42
+ ) : (
43
+ <Markdown>{block.content}</Markdown>
44
+ )}
45
+ </Box>
46
+ )}
47
+
48
+ {block.type === "error" && (
49
+ <Box>
50
+ <Text color="red">Error: {block.content}</Text>
51
+ </Box>
52
+ )}
53
+
54
+ {block.type === "command_output" && (
55
+ <CommandOutputDisplay block={block} isExpanded={isExpanded} />
56
+ )}
57
+
58
+ {block.type === "tool" && (
59
+ <ToolDisplay block={block} isExpanded={isExpanded} />
60
+ )}
61
+
62
+ {block.type === "image" && (
63
+ <Box>
64
+ <Text color="magenta" bold>
65
+ # Image
66
+ </Text>
67
+ {block.imageUrls && block.imageUrls.length > 0 && (
68
+ <Text color="gray" dimColor>
69
+ {" "}
70
+ ({block.imageUrls.length})
71
+ </Text>
72
+ )}
73
+ </Box>
74
+ )}
75
+
76
+ {block.type === "compress" && (
77
+ <CompressDisplay block={block} isExpanded={isExpanded} />
78
+ )}
79
+
80
+ {block.type === "reasoning" && <ReasoningDisplay block={block} />}
81
+ </Box>
82
+ );
83
+ };
@@ -1,23 +1,19 @@
1
1
  import React from "react";
2
2
  import { Box, Text, Static } from "ink";
3
3
  import type { Message } from "wave-agent-sdk";
4
- import { MessageItem } from "./MessageItem.js";
4
+ import { MessageBlockItem } from "./MessageBlockItem.js";
5
5
 
6
6
  export interface MessageListProps {
7
7
  messages: Message[];
8
- isLoading?: boolean;
9
- isCommandRunning?: boolean;
10
8
  isExpanded?: boolean;
11
- forceStaticLastMessage?: boolean;
9
+ hideDynamicBlocks?: boolean;
12
10
  }
13
11
 
14
12
  export const MessageList = React.memo(
15
13
  ({
16
14
  messages,
17
- isLoading = false,
18
- isCommandRunning = false,
19
15
  isExpanded = false,
20
- forceStaticLastMessage = false,
16
+ hideDynamicBlocks = false,
21
17
  }: MessageListProps) => {
22
18
  // Empty message state
23
19
  if (messages.length === 0) {
@@ -38,59 +34,66 @@ export const MessageList = React.memo(
38
34
  ? messages.slice(-maxExpandedMessages)
39
35
  : messages;
40
36
 
41
- // Compute which messages to render statically vs dynamically
42
- const lastMessage = displayMessages[displayMessages.length - 1];
43
- const hasNonEndTool = lastMessage?.blocks.some(
44
- (block) => block.type === "tool" && block.stage !== "end",
45
- );
46
- const hasRunningCommand = lastMessage?.blocks.some(
47
- (block) => block.type === "command_output" && block.isRunning,
48
- );
49
- const shouldRenderLastDynamic =
50
- !forceStaticLastMessage &&
51
- (isLoading || isCommandRunning || hasNonEndTool || hasRunningCommand);
52
- const staticMessages = shouldRenderLastDynamic
53
- ? displayMessages.slice(0, -1)
54
- : displayMessages;
55
- const dynamicMessages =
56
- shouldRenderLastDynamic && displayMessages.length > 0
57
- ? [displayMessages[displayMessages.length - 1]]
58
- : [];
37
+ // Flatten messages into blocks with metadata
38
+ const allBlocks = displayMessages.flatMap((message, index) => {
39
+ const messageIndex = shouldLimitMessages
40
+ ? messages.length - maxExpandedMessages + index
41
+ : index;
42
+ return message.blocks.map((block, blockIndex) => ({
43
+ block,
44
+ message,
45
+ isLastMessage: messageIndex === messages.length - 1,
46
+ // Unique key for each block to help Static component
47
+ key: `${message.id || messageIndex}-${blockIndex}`,
48
+ }));
49
+ });
50
+
51
+ // Determine which blocks are static vs dynamic
52
+ const blocksWithStatus = allBlocks.map((item) => {
53
+ const { block, isLastMessage } = item;
54
+ const isDynamic =
55
+ isLastMessage &&
56
+ ((block.type === "tool" && block.stage !== "end") ||
57
+ (block.type === "command_output" && block.isRunning));
58
+ return { ...item, isDynamic };
59
+ });
60
+
61
+ const staticBlocks = blocksWithStatus.filter((b) => !b.isDynamic);
62
+ const dynamicBlocks = hideDynamicBlocks
63
+ ? []
64
+ : blocksWithStatus.filter((b) => b.isDynamic);
59
65
 
60
66
  return (
61
67
  <Box flexDirection="column" paddingBottom={1}>
62
- {/* Static messages */}
63
- <Static items={staticMessages}>
64
- {(message, key) => {
65
- // Get previous message
66
- const previousMessage =
67
- key > 0 ? staticMessages[key - 1] : undefined;
68
- return (
69
- <MessageItem
70
- key={key}
71
- message={message}
72
- shouldShowHeader={previousMessage?.role !== message.role}
68
+ {/* Static blocks */}
69
+ {staticBlocks.length > 0 && (
70
+ <Static items={staticBlocks}>
71
+ {(item) => (
72
+ <MessageBlockItem
73
+ key={item.key}
74
+ block={item.block}
75
+ message={item.message}
73
76
  isExpanded={isExpanded}
77
+ paddingTop={1}
74
78
  />
75
- );
76
- }}
77
- </Static>
79
+ )}
80
+ </Static>
81
+ )}
78
82
 
79
- {/* Dynamic messages */}
80
- {dynamicMessages.map((message, index) => {
81
- const messageIndex = staticMessages.length + index;
82
- const previousMessage =
83
- messageIndex > 0 ? displayMessages[messageIndex - 1] : undefined;
84
- return (
85
- <Box key={`dynamic-${index}`}>
86
- <MessageItem
87
- message={message}
88
- shouldShowHeader={previousMessage?.role !== message.role}
83
+ {/* Dynamic blocks */}
84
+ {dynamicBlocks.length > 0 && (
85
+ <Box flexDirection="column">
86
+ {dynamicBlocks.map((item) => (
87
+ <MessageBlockItem
88
+ key={item.key}
89
+ block={item.block}
90
+ message={item.message}
89
91
  isExpanded={isExpanded}
92
+ paddingTop={1}
90
93
  />
91
- </Box>
92
- );
93
- })}
94
+ ))}
95
+ </Box>
96
+ )}
94
97
  </Box>
95
98
  );
96
99
  },
@@ -36,42 +36,41 @@ export const PluginDetail: React.FC = () => {
36
36
  );
37
37
  actions.setView(isFromDiscover ? "DISCOVER" : "INSTALLED");
38
38
  } else if (key.upArrow) {
39
- if (isInstalledAndEnabled) {
40
- setSelectedActionIndex((prev) =>
41
- prev > 0 ? prev - 1 : INSTALLED_ACTIONS.length - 1,
42
- );
43
- } else {
44
- setSelectedScopeIndex((prev) =>
45
- prev > 0 ? prev - 1 : SCOPES.length - 1,
46
- );
47
- }
39
+ setSelectedActionIndex((prev) =>
40
+ prev > 0 ? prev - 1 : INSTALLED_ACTIONS.length - 1,
41
+ );
42
+ setSelectedScopeIndex((prev) =>
43
+ prev > 0 ? prev - 1 : SCOPES.length - 1,
44
+ );
48
45
  } else if (key.downArrow) {
49
- if (isInstalledAndEnabled) {
50
- setSelectedActionIndex((prev) =>
51
- prev < INSTALLED_ACTIONS.length - 1 ? prev + 1 : 0,
52
- );
53
- } else {
54
- setSelectedScopeIndex((prev) =>
55
- prev < SCOPES.length - 1 ? prev + 1 : 0,
56
- );
57
- }
46
+ setSelectedActionIndex((prev) =>
47
+ prev < INSTALLED_ACTIONS.length - 1 ? prev + 1 : 0,
48
+ );
49
+ setSelectedScopeIndex((prev) =>
50
+ prev < SCOPES.length - 1 ? prev + 1 : 0,
51
+ );
58
52
  } else if (key.return && plugin) {
59
53
  if (isInstalledAndEnabled) {
60
- const action = INSTALLED_ACTIONS[selectedActionIndex].id;
61
- if (action === "uninstall") {
62
- actions.uninstallPlugin(plugin.name, plugin.marketplace);
63
- } else {
64
- actions.updatePlugin(plugin.name, plugin.marketplace);
65
- }
66
- actions.setView("INSTALLED");
54
+ setSelectedActionIndex((prev) => {
55
+ const action = INSTALLED_ACTIONS[prev].id;
56
+ if (action === "uninstall") {
57
+ actions.uninstallPlugin(plugin.name, plugin.marketplace);
58
+ } else {
59
+ actions.updatePlugin(plugin.name, plugin.marketplace);
60
+ }
61
+ return prev;
62
+ });
67
63
  } else {
68
- actions.installPlugin(
69
- plugin.name,
70
- plugin.marketplace,
71
- SCOPES[selectedScopeIndex].id,
72
- );
73
- actions.setView("INSTALLED");
64
+ setSelectedScopeIndex((prev) => {
65
+ actions.installPlugin(
66
+ plugin.name,
67
+ plugin.marketplace,
68
+ SCOPES[prev].id,
69
+ );
70
+ return prev;
71
+ });
74
72
  }
73
+ actions.setView("INSTALLED");
75
74
  }
76
75
  });
77
76
 
@@ -17,9 +17,12 @@ export const SessionSelector: React.FC<SessionSelectorProps> = ({
17
17
 
18
18
  useInput((input, key) => {
19
19
  if (key.return) {
20
- if (sessions.length > 0 && selectedIndex < sessions.length) {
21
- onSelect(sessions[selectedIndex].id);
22
- }
20
+ setSelectedIndex((prev) => {
21
+ if (sessions.length > 0 && prev < sessions.length) {
22
+ onSelect(sessions[prev].id);
23
+ }
24
+ return prev;
25
+ });
23
26
  return;
24
27
  }
25
28
 
@@ -29,12 +32,12 @@ export const SessionSelector: React.FC<SessionSelectorProps> = ({
29
32
  }
30
33
 
31
34
  if (key.upArrow) {
32
- setSelectedIndex(Math.max(0, selectedIndex - 1));
35
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
33
36
  return;
34
37
  }
35
38
 
36
39
  if (key.downArrow) {
37
- setSelectedIndex(Math.min(sessions.length - 1, selectedIndex + 1));
40
+ setSelectedIndex((prev) => Math.min(sessions.length - 1, prev + 1));
38
41
  return;
39
42
  }
40
43
  });
@@ -11,10 +11,7 @@ export const TaskList: React.FC = () => {
11
11
  return null;
12
12
  }
13
13
 
14
- const getStatusIcon = (status: string, isBlocked: boolean) => {
15
- if (isBlocked) {
16
- return <Text color="red">🔒</Text>;
17
- }
14
+ const getStatusIcon = (status: string) => {
18
15
  switch (status) {
19
16
  case "pending":
20
17
  return <Text color="gray">□</Text>;
@@ -48,7 +45,7 @@ export const TaskList: React.FC = () => {
48
45
 
49
46
  return (
50
47
  <Box key={task.id} gap={1}>
51
- {getStatusIcon(task.status, isBlocked)}
48
+ {getStatusIcon(task.status)}
52
49
  <Text dimColor={isDimmed}>{fullText}</Text>
53
50
  </Box>
54
51
  );
@@ -131,7 +131,11 @@ export const ToolDisplay: React.FC<ToolDisplayProps> = ({
131
131
 
132
132
  {/* Diff display - only show after tool execution completes and was successful */}
133
133
  {stage === "end" && success && (
134
- <DiffDisplay toolName={name} parameters={parameters} />
134
+ <DiffDisplay
135
+ toolName={name}
136
+ parameters={parameters}
137
+ startLineNumber={block.startLineNumber}
138
+ />
135
139
  )}
136
140
  </Box>
137
141
  );
@@ -108,12 +108,14 @@ export interface ChatProviderProps {
108
108
  children: React.ReactNode;
109
109
  bypassPermissions?: boolean;
110
110
  pluginDirs?: string[];
111
+ tools?: string[];
111
112
  }
112
113
 
113
114
  export const ChatProvider: React.FC<ChatProviderProps> = ({
114
115
  children,
115
116
  bypassPermissions,
116
117
  pluginDirs,
118
+ tools,
117
119
  }) => {
118
120
  const { restoreSessionId, continueLastSession } = useAppConfig();
119
121
 
@@ -129,6 +131,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
129
131
 
130
132
  // AI State
131
133
  const [messages, setMessages] = useState<Message[]>([]);
134
+ const messagesUpdateTimerRef = useRef<NodeJS.Timeout | null>(null);
135
+
132
136
  const [isLoading, setIsLoading] = useState(false);
133
137
  const [latestTotalTokens, setlatestTotalTokens] = useState(0);
134
138
  const [sessionId, setSessionId] = useState("");
@@ -225,9 +229,16 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
225
229
  useEffect(() => {
226
230
  const initializeAgent = async () => {
227
231
  const callbacks: AgentCallbacks = {
228
- onMessagesChange: (newMessages) => {
232
+ onMessagesChange: () => {
229
233
  if (!isExpandedRef.current) {
230
- setMessages([...newMessages]);
234
+ if (!messagesUpdateTimerRef.current) {
235
+ messagesUpdateTimerRef.current = setTimeout(() => {
236
+ if (agentRef.current) {
237
+ setMessages([...agentRef.current.messages]);
238
+ }
239
+ messagesUpdateTimerRef.current = null;
240
+ }, 50);
241
+ }
231
242
  }
232
243
  },
233
244
  onServersChange: (servers) => {
@@ -304,6 +315,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
304
315
  canUseTool: permissionCallback,
305
316
  stream: false, // 关闭流式模式
306
317
  plugins: pluginDirs?.map((path) => ({ type: "local", path })),
318
+ tools,
307
319
  });
308
320
 
309
321
  agentRef.current = agent;
@@ -336,11 +348,15 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
336
348
  bypassPermissions,
337
349
  showConfirmation,
338
350
  pluginDirs,
351
+ tools,
339
352
  ]);
340
353
 
341
354
  // Cleanup on unmount
342
355
  useEffect(() => {
343
356
  return () => {
357
+ if (messagesUpdateTimerRef.current) {
358
+ clearTimeout(messagesUpdateTimerRef.current);
359
+ }
344
360
  if (agentRef.current) {
345
361
  try {
346
362
  // Display usage summary before cleanup
@@ -526,6 +542,10 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
526
542
  setIsExpanded((prev) => {
527
543
  const newExpanded = !prev;
528
544
  if (newExpanded) {
545
+ if (messagesUpdateTimerRef.current) {
546
+ clearTimeout(messagesUpdateTimerRef.current);
547
+ messagesUpdateTimerRef.current = null;
548
+ }
529
549
  // Transitioning to EXPANDED: Freeze the current view
530
550
  // Deep copy the last message to ensure it doesn't update if the agent is still writing to it
531
551
  setMessages((currentMessages) => {
@@ -1,9 +1,6 @@
1
1
  import { useState, useCallback, useEffect, useMemo } from "react";
2
2
  import {
3
- MarketplaceService,
4
- PluginScopeManager,
5
- ConfigurationService,
6
- PluginManager,
3
+ PluginCore,
7
4
  KnownMarketplace,
8
5
  InstalledPlugin,
9
6
  MarketplacePluginEntry,
@@ -35,25 +32,7 @@ export function usePluginManager(): PluginManagerContextType {
35
32
  })[]
36
33
  >([]);
37
34
 
38
- const marketplaceService = useMemo(() => new MarketplaceService(), []);
39
- const configurationService = useMemo(() => new ConfigurationService(), []);
40
- const pluginManager = useMemo(
41
- () =>
42
- new PluginManager({
43
- workdir: process.cwd(),
44
- configurationService,
45
- }),
46
- [configurationService],
47
- );
48
- const pluginScopeManager = useMemo(
49
- () =>
50
- new PluginScopeManager({
51
- workdir: process.cwd(),
52
- configurationService,
53
- pluginManager,
54
- }),
55
- [configurationService, pluginManager],
56
- );
35
+ const pluginCore = useMemo(() => new PluginCore(), []);
57
36
 
58
37
  const refresh = useCallback(async () => {
59
38
  setState((prev: PluginManagerState) => ({
@@ -63,9 +42,9 @@ export function usePluginManager(): PluginManagerContextType {
63
42
  }));
64
43
  try {
65
44
  const [mks, installed, enabledMap] = await Promise.all([
66
- marketplaceService.listMarketplaces(),
67
- marketplaceService.getInstalledPlugins(),
68
- Promise.resolve(pluginScopeManager.getMergedEnabledPlugins()),
45
+ pluginCore.listMarketplaces(),
46
+ pluginCore.getInstalledPlugins(),
47
+ Promise.resolve(pluginCore.getMergedEnabledPlugins()),
69
48
  ]);
70
49
 
71
50
  setMarketplaces(mks);
@@ -74,7 +53,7 @@ export function usePluginManager(): PluginManagerContextType {
74
53
  return {
75
54
  ...p,
76
55
  enabled: !!enabledMap[pluginId],
77
- scope: pluginScopeManager.findPluginScope(pluginId) || undefined,
56
+ scope: pluginCore.findPluginScope(pluginId) || undefined,
78
57
  };
79
58
  });
80
59
 
@@ -88,8 +67,8 @@ export function usePluginManager(): PluginManagerContextType {
88
67
  })[] = [];
89
68
  for (const mk of mks) {
90
69
  try {
91
- const manifest = await marketplaceService.loadMarketplaceManifest(
92
- marketplaceService.getMarketplacePath(mk),
70
+ const manifest = await pluginCore.loadMarketplaceManifest(
71
+ pluginCore.getMarketplacePath(mk),
93
72
  );
94
73
  manifest.plugins.forEach((p) => {
95
74
  const pluginId = `${p.name}@${mk.name}`;
@@ -120,7 +99,7 @@ export function usePluginManager(): PluginManagerContextType {
120
99
  error: error instanceof Error ? error.message : String(error),
121
100
  }));
122
101
  }
123
- }, [marketplaceService, pluginScopeManager]);
102
+ }, [pluginCore]);
124
103
 
125
104
  useEffect(() => {
126
105
  refresh();
@@ -142,7 +121,7 @@ export function usePluginManager(): PluginManagerContextType {
142
121
  error: null,
143
122
  }));
144
123
  try {
145
- await marketplaceService.addMarketplace(source);
124
+ await pluginCore.addMarketplace(source);
146
125
  await refresh();
147
126
  } catch (error) {
148
127
  setState((prev: PluginManagerState) => ({
@@ -152,7 +131,7 @@ export function usePluginManager(): PluginManagerContextType {
152
131
  }));
153
132
  }
154
133
  },
155
- [marketplaceService, refresh],
134
+ [pluginCore, refresh],
156
135
  );
157
136
 
158
137
  const removeMarketplace = useCallback(
@@ -163,7 +142,7 @@ export function usePluginManager(): PluginManagerContextType {
163
142
  error: null,
164
143
  }));
165
144
  try {
166
- await marketplaceService.removeMarketplace(name);
145
+ await pluginCore.removeMarketplace(name);
167
146
  await refresh();
168
147
  } catch (error) {
169
148
  setState((prev: PluginManagerState) => ({
@@ -173,7 +152,7 @@ export function usePluginManager(): PluginManagerContextType {
173
152
  }));
174
153
  }
175
154
  },
176
- [marketplaceService, refresh],
155
+ [pluginCore, refresh],
177
156
  );
178
157
 
179
158
  const updateMarketplace = useCallback(
@@ -184,7 +163,7 @@ export function usePluginManager(): PluginManagerContextType {
184
163
  error: null,
185
164
  }));
186
165
  try {
187
- await marketplaceService.updateMarketplace(name);
166
+ await pluginCore.updateMarketplace(name);
188
167
  await refresh();
189
168
  } catch (error) {
190
169
  setState((prev: PluginManagerState) => ({
@@ -194,7 +173,7 @@ export function usePluginManager(): PluginManagerContextType {
194
173
  }));
195
174
  }
196
175
  },
197
- [marketplaceService, refresh],
176
+ [pluginCore, refresh],
198
177
  );
199
178
 
200
179
  const installPlugin = useCallback(
@@ -210,9 +189,7 @@ export function usePluginManager(): PluginManagerContextType {
210
189
  }));
211
190
  try {
212
191
  const pluginId = `${name}@${marketplace}`;
213
- const workdir = process.cwd();
214
- await marketplaceService.installPlugin(pluginId, workdir);
215
- await pluginScopeManager.enablePlugin(scope, pluginId);
192
+ await pluginCore.installPlugin(pluginId, scope);
216
193
  await refresh();
217
194
  } catch (error) {
218
195
  setState((prev: PluginManagerState) => ({
@@ -222,7 +199,7 @@ export function usePluginManager(): PluginManagerContextType {
222
199
  }));
223
200
  }
224
201
  },
225
- [marketplaceService, pluginScopeManager, refresh],
202
+ [pluginCore, refresh],
226
203
  );
227
204
 
228
205
  const uninstallPlugin = useCallback(
@@ -234,20 +211,7 @@ export function usePluginManager(): PluginManagerContextType {
234
211
  }));
235
212
  try {
236
213
  const pluginId = `${name}@${marketplace}`;
237
- const workdir = process.cwd();
238
-
239
- // 1. Remove from global registry and potentially clean up cache
240
- await marketplaceService.uninstallPlugin(pluginId, workdir);
241
-
242
- // 2. Find the scope where it's currently enabled and remove it from there
243
- const scope = pluginScopeManager.findPluginScope(pluginId);
244
- if (scope) {
245
- await configurationService.removeEnabledPlugin(
246
- workdir,
247
- scope,
248
- pluginId,
249
- );
250
- }
214
+ await pluginCore.uninstallPlugin(pluginId);
251
215
  await refresh();
252
216
  } catch (error) {
253
217
  setState((prev: PluginManagerState) => ({
@@ -257,7 +221,7 @@ export function usePluginManager(): PluginManagerContextType {
257
221
  }));
258
222
  }
259
223
  },
260
- [configurationService, marketplaceService, pluginScopeManager, refresh],
224
+ [pluginCore, refresh],
261
225
  );
262
226
 
263
227
  const updatePlugin = useCallback(
@@ -269,7 +233,7 @@ export function usePluginManager(): PluginManagerContextType {
269
233
  }));
270
234
  try {
271
235
  const pluginId = `${name}@${marketplace}`;
272
- await marketplaceService.updatePlugin(pluginId);
236
+ await pluginCore.updatePlugin(pluginId);
273
237
  await refresh();
274
238
  } catch (error) {
275
239
  setState((prev: PluginManagerState) => ({
@@ -279,7 +243,7 @@ export function usePluginManager(): PluginManagerContextType {
279
243
  }));
280
244
  }
281
245
  },
282
- [marketplaceService, refresh],
246
+ [pluginCore, refresh],
283
247
  );
284
248
 
285
249
  return {