wave-code 0.15.0 → 0.15.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.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjE,MAAM,WAAW,YAAY;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC9C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.15.0",
3
+ "version": "0.15.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.15.0"
45
+ "wave-agent-sdk": "0.15.2"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/react": "^19.1.8",
package/src/acp/agent.ts CHANGED
@@ -49,8 +49,10 @@ import {
49
49
  type ResourceLink,
50
50
  type EmbeddedResource,
51
51
  type ImageContent,
52
+ type McpServer,
52
53
  AGENT_METHODS,
53
54
  } from "@agentclientprotocol/sdk";
55
+ import type { McpServerConfig, McpServerStatus } from "wave-agent-sdk";
54
56
 
55
57
  export class WaveAcpAgent implements AcpAgent {
56
58
  private agents: Map<string, WaveAgent> = new Map();
@@ -150,6 +152,7 @@ export class WaveAcpAgent implements AcpAgent {
150
152
  },
151
153
  agentCapabilities: {
152
154
  loadSession: true,
155
+ mcpCapabilities: { http: true, sse: true },
153
156
  sessionCapabilities: {
154
157
  list: {},
155
158
  close: {},
@@ -169,14 +172,20 @@ export class WaveAcpAgent implements AcpAgent {
169
172
  private async createAgent(
170
173
  sessionId: string | undefined,
171
174
  cwd: string,
175
+ mcpServers?: McpServer[],
172
176
  ): Promise<WaveAgent> {
173
177
  const callbacks: AgentOptions["callbacks"] = {};
174
178
  const agentRef: { instance?: WaveAgent } = {};
175
179
 
180
+ const sdkMcpServers = mcpServers
181
+ ? convertAcpMcpServers(mcpServers)
182
+ : undefined;
183
+
176
184
  const agent = await WaveAgent.create({
177
185
  workdir: cwd,
178
186
  restoreSessionId: sessionId,
179
187
  stream: true,
188
+ mcpServers: sdkMcpServers,
180
189
  canUseTool: (context) => {
181
190
  if (!agentRef.instance) {
182
191
  throw new Error("Agent instance not yet initialized");
@@ -202,6 +211,7 @@ export class WaveAcpAgent implements AcpAgent {
202
211
  callbacks.onPermissionModeChange?.(mode),
203
212
  onModelChange: (model) => callbacks.onModelChange?.(model),
204
213
  onUserMessageAdded: (params) => callbacks.onUserMessageAdded?.(params),
214
+ onMcpServersChange: (servers) => callbacks.onMcpServersChange?.(servers),
205
215
  },
206
216
  });
207
217
 
@@ -234,9 +244,9 @@ export class WaveAcpAgent implements AcpAgent {
234
244
  }
235
245
 
236
246
  async newSession(params: NewSessionRequest): Promise<NewSessionResponse> {
237
- const { cwd } = params;
247
+ const { cwd, mcpServers } = params;
238
248
  logger.info(`Creating new session in ${cwd}`);
239
- const agent = await this.createAgent(undefined, cwd);
249
+ const agent = await this.createAgent(undefined, cwd, mcpServers);
240
250
  logger.info(`New session created with ID: ${agent.sessionId}`);
241
251
 
242
252
  return {
@@ -247,9 +257,9 @@ export class WaveAcpAgent implements AcpAgent {
247
257
  }
248
258
 
249
259
  async loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {
250
- const { sessionId, cwd } = params;
260
+ const { sessionId, cwd, mcpServers } = params;
251
261
  logger.info(`Loading session: ${sessionId} in ${cwd}`);
252
- const agent = await this.createAgent(sessionId, cwd);
262
+ const agent = await this.createAgent(sessionId, cwd, mcpServers);
253
263
 
254
264
  return {
255
265
  modes: this.getSessionModeState(agent),
@@ -1002,6 +1012,75 @@ export class WaveAcpAgent implements AcpAgent {
1002
1012
  },
1003
1013
  });
1004
1014
  },
1015
+ onMcpServersChange: (servers: McpServerStatus[]) => {
1016
+ for (const server of servers) {
1017
+ this.connection.sessionUpdate({
1018
+ sessionId: sessionId as AcpSessionId,
1019
+ update: {
1020
+ sessionUpdate: "ext_notification" as const,
1021
+ method: "mcp_server_status",
1022
+ params: {
1023
+ name: server.name,
1024
+ status: server.status,
1025
+ toolCount: server.toolCount,
1026
+ error: server.error,
1027
+ },
1028
+ },
1029
+ });
1030
+ }
1031
+ },
1005
1032
  };
1006
1033
  }
1007
1034
  }
1035
+
1036
+ /**
1037
+ * Convert ACP McpServer[] to SDK Record<string, McpServerConfig>.
1038
+ */
1039
+ function convertAcpMcpServers(
1040
+ servers: McpServer[],
1041
+ ): Record<string, McpServerConfig> {
1042
+ const result: Record<string, McpServerConfig> = {};
1043
+ for (const server of servers) {
1044
+ const config: McpServerConfig = {};
1045
+ if ("type" in server && server.type === "http") {
1046
+ config.url = server.url;
1047
+ config.headers = convertHttpHeaders(server.headers);
1048
+ } else if ("type" in server && server.type === "sse") {
1049
+ config.url = server.url;
1050
+ config.headers = convertHttpHeaders(server.headers);
1051
+ } else {
1052
+ // stdio (no type discriminator)
1053
+ config.command = server.command;
1054
+ config.args = server.args;
1055
+ config.env = convertEnvVariables(server.env);
1056
+ }
1057
+ result[server.name] = config;
1058
+ }
1059
+ return result;
1060
+ }
1061
+
1062
+ /**
1063
+ * Convert ACP EnvVariable[] to SDK Record<string, string>.
1064
+ */
1065
+ function convertEnvVariables(
1066
+ env: Array<{ name: string; value: string }>,
1067
+ ): Record<string, string> {
1068
+ const result: Record<string, string> = {};
1069
+ for (const entry of env) {
1070
+ result[entry.name] = entry.value;
1071
+ }
1072
+ return result;
1073
+ }
1074
+
1075
+ /**
1076
+ * Convert ACP HttpHeader[] to SDK Record<string, string>.
1077
+ */
1078
+ function convertHttpHeaders(
1079
+ headers: Array<{ name: string; value: string }>,
1080
+ ): Record<string, string> {
1081
+ const result: Record<string, string> = {};
1082
+ for (const entry of headers) {
1083
+ result[entry.name] = entry.value;
1084
+ }
1085
+ return result;
1086
+ }
package/src/cli.tsx CHANGED
@@ -24,6 +24,7 @@ export async function startCli(options: CliOptions): Promise<void> {
24
24
  workdir,
25
25
  version,
26
26
  model,
27
+ mcpServers,
27
28
  } = options;
28
29
 
29
30
  // Continue with ink-based UI for normal mode
@@ -49,6 +50,7 @@ export async function startCli(options: CliOptions): Promise<void> {
49
50
  workdir={workdir}
50
51
  version={version}
51
52
  model={model}
53
+ mcpServers={mcpServers}
52
54
  onExit={handleExit}
53
55
  />,
54
56
  { exitOnCtrlC: false },
@@ -1,7 +1,7 @@
1
1
  import React, { useState, useEffect, useCallback } from "react";
2
2
  import { useInput } from "ink";
3
3
  import { ChatInterface } from "./ChatInterface.js";
4
- import { ChatProvider } from "../contexts/useChat.js";
4
+ import { ChatProvider, useChat } from "../contexts/useChat.js";
5
5
  import { AppProvider } from "../contexts/useAppConfig.js";
6
6
  import { WorktreeExitPrompt } from "./WorktreeExitPrompt.js";
7
7
  import {
@@ -21,19 +21,12 @@ interface AppWithProvidersProps extends BaseAppProps {
21
21
  onExit: (shouldRemove: boolean) => void;
22
22
  }
23
23
 
24
- const AppWithProviders: React.FC<AppWithProvidersProps> = ({
25
- bypassPermissions,
26
- permissionMode,
27
- pluginDirs,
28
- tools,
29
- allowedTools,
30
- disallowedTools,
31
- worktreeSession,
32
- workdir,
33
- version,
34
- model,
35
- onExit,
36
- }) => {
24
+ /** Wraps ChatInterface with worktree exit handling, using useChat() for hook access. */
25
+ const ChatWithExitPrompt: React.FC<{
26
+ worktreeSession: NonNullable<BaseAppProps["worktreeSession"]>;
27
+ onExit: (shouldRemove: boolean) => void;
28
+ }> = ({ worktreeSession, onExit }) => {
29
+ const { triggerWorktreeRemoveHook } = useChat();
37
30
  const [isExiting, setIsExiting] = useState(false);
38
31
  const [worktreeStatus, setWorktreeStatus] = useState<{
39
32
  hasUncommittedChanges: boolean;
@@ -41,25 +34,21 @@ const AppWithProviders: React.FC<AppWithProvidersProps> = ({
41
34
  } | null>(null);
42
35
 
43
36
  const handleSignal = useCallback(async () => {
44
- if (worktreeSession) {
45
- const cwd = workdir || worktreeSession.path;
46
- const baseBranch = getDefaultRemoteBranch(cwd);
47
- const hasChanges = hasUncommittedChanges(cwd);
48
- const hasCommits = hasNewCommits(cwd, baseBranch);
37
+ const cwd = worktreeSession.path;
38
+ const baseBranch = getDefaultRemoteBranch(cwd);
39
+ const hasChanges = hasUncommittedChanges(cwd);
40
+ const hasCommits = hasNewCommits(cwd, baseBranch);
49
41
 
50
- if (hasChanges || hasCommits) {
51
- setWorktreeStatus({
52
- hasUncommittedChanges: hasChanges,
53
- hasNewCommits: hasCommits,
54
- });
55
- setIsExiting(true);
56
- } else {
57
- onExit(true);
58
- }
42
+ if (hasChanges || hasCommits) {
43
+ setWorktreeStatus({
44
+ hasUncommittedChanges: hasChanges,
45
+ hasNewCommits: hasCommits,
46
+ });
47
+ setIsExiting(true);
59
48
  } else {
60
- onExit(false);
49
+ onExit(true);
61
50
  }
62
- }, [worktreeSession, workdir, onExit]);
51
+ }, [worktreeSession, onExit]);
63
52
 
64
53
  useInput((input, key) => {
65
54
  if (input === "c" && key.ctrl) {
@@ -80,7 +69,7 @@ const AppWithProviders: React.FC<AppWithProvidersProps> = ({
80
69
  };
81
70
  }, [handleSignal]);
82
71
 
83
- if (isExiting && worktreeSession && worktreeStatus) {
72
+ if (isExiting && worktreeStatus) {
84
73
  return (
85
74
  <WorktreeExitPrompt
86
75
  name={worktreeSession.name}
@@ -88,12 +77,61 @@ const AppWithProviders: React.FC<AppWithProvidersProps> = ({
88
77
  hasUncommittedChanges={worktreeStatus.hasUncommittedChanges}
89
78
  hasNewCommits={worktreeStatus.hasNewCommits}
90
79
  onKeep={() => onExit(false)}
91
- onRemove={() => onExit(true)}
80
+ onRemove={async () => {
81
+ await triggerWorktreeRemoveHook(worktreeSession.path);
82
+ onExit(true);
83
+ }}
92
84
  onCancel={() => setIsExiting(false)}
93
85
  />
94
86
  );
95
87
  }
96
88
 
89
+ return <ChatInterface />;
90
+ };
91
+
92
+ const AppWithProviders: React.FC<AppWithProvidersProps> = ({
93
+ bypassPermissions,
94
+ permissionMode,
95
+ pluginDirs,
96
+ tools,
97
+ allowedTools,
98
+ disallowedTools,
99
+ worktreeSession,
100
+ workdir,
101
+ version,
102
+ model,
103
+ mcpServers,
104
+ onExit,
105
+ }) => {
106
+ // Handle Ctrl-C for non-worktree sessions (immediate exit)
107
+ // Ink runs terminal in raw mode, so Ctrl+C arrives as useInput event, not SIGINT
108
+ useInput((input, key) => {
109
+ if (!worktreeSession && input === "c" && key.ctrl) {
110
+ onExit(false);
111
+ return true;
112
+ }
113
+ });
114
+
115
+ if (worktreeSession) {
116
+ return (
117
+ <ChatProvider
118
+ bypassPermissions={bypassPermissions}
119
+ permissionMode={permissionMode}
120
+ pluginDirs={pluginDirs}
121
+ tools={tools}
122
+ allowedTools={allowedTools}
123
+ disallowedTools={disallowedTools}
124
+ workdir={workdir}
125
+ worktreeSession={worktreeSession}
126
+ version={version}
127
+ model={model}
128
+ mcpServers={mcpServers}
129
+ >
130
+ <ChatWithExitPrompt worktreeSession={worktreeSession} onExit={onExit} />
131
+ </ChatProvider>
132
+ );
133
+ }
134
+
97
135
  return (
98
136
  <ChatProvider
99
137
  bypassPermissions={bypassPermissions}
@@ -106,6 +144,7 @@ const AppWithProviders: React.FC<AppWithProvidersProps> = ({
106
144
  worktreeSession={worktreeSession}
107
145
  version={version}
108
146
  model={model}
147
+ mcpServers={mcpServers}
109
148
  >
110
149
  <ChatInterface />
111
150
  </ChatProvider>
@@ -125,6 +164,7 @@ export const App: React.FC<AppProps> = ({
125
164
  workdir,
126
165
  version,
127
166
  model,
167
+ mcpServers,
128
168
  onExit,
129
169
  }) => {
130
170
  return (
@@ -143,6 +183,7 @@ export const App: React.FC<AppProps> = ({
143
183
  workdir={workdir}
144
184
  version={version}
145
185
  model={model}
186
+ mcpServers={mcpServers}
146
187
  onExit={onExit}
147
188
  />
148
189
  </AppProvider>
@@ -119,6 +119,8 @@ export interface ChatContextType {
119
119
  workdir?: string;
120
120
  // Agent recreation (e.g. after plugin install)
121
121
  recreateAgent: () => void;
122
+ // Trigger WorktreeRemove hook BEFORE agent destruction
123
+ triggerWorktreeRemoveHook: (worktreePath: string) => Promise<void>;
122
124
  }
123
125
 
124
126
  const ChatContext = createContext<ChatContextType | null>(null);
@@ -147,6 +149,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
147
149
  worktreeSession,
148
150
  version,
149
151
  model,
152
+ mcpServers,
150
153
  }) => {
151
154
  const { restoreSessionId, continueLastSession } = useAppConfig();
152
155
  const { stdout } = useStdout();
@@ -198,7 +201,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
198
201
  const [queuedMessages, setQueuedMessages] = useState<QueuedMessage[]>([]);
199
202
 
200
203
  // MCP State
201
- const [mcpServers, setMcpServers] = useState<McpServerStatus[]>([]);
204
+ const [mcpServerStatuses, setMcpServerStatuses] = useState<McpServerStatus[]>(
205
+ [],
206
+ );
202
207
 
203
208
  // Background tasks state
204
209
  const [backgroundTasks, setBackgroundTasks] = useState<BackgroundTask[]>([]);
@@ -328,8 +333,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
328
333
  onMessagesChange: () => {
329
334
  throttledSetMessages();
330
335
  },
331
- onServersChange: (servers) => {
332
- setMcpServers([...servers]);
336
+ onMcpServersChange: (servers) => {
337
+ setMcpServerStatuses([...servers]);
333
338
  },
334
339
  onSessionIdChange: (sessionId) => {
335
340
  setSessionId(sessionId);
@@ -403,6 +408,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
403
408
  worktreeName: worktreeSession?.name,
404
409
  isNewWorktree: worktreeSession?.isNew,
405
410
  model,
411
+ mcpServers,
406
412
  });
407
413
 
408
414
  agentRef.current = agent;
@@ -420,8 +426,8 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
420
426
  setConfiguredModels(agent.getConfiguredModels());
421
427
 
422
428
  // Get initial MCP servers state
423
- const mcpServers = agent.getMcpServers?.() || [];
424
- setMcpServers(mcpServers);
429
+ const initialMcpServers = agent.getMcpServers?.() || [];
430
+ setMcpServerStatuses(initialMcpServers);
425
431
 
426
432
  // Get initial commands
427
433
  const agentSlashCommands = agent.getSlashCommands?.() || [];
@@ -444,6 +450,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
444
450
  model,
445
451
  initialPermissionMode,
446
452
  throttledSetMessages,
453
+ mcpServers,
447
454
  ],
448
455
  );
449
456
 
@@ -459,7 +466,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
459
466
  }
460
467
  agentRef.current = null;
461
468
  setMessages([]);
462
- setMcpServers([]);
469
+ setMcpServerStatuses([]);
463
470
  setSlashCommands([]);
464
471
  setSessionId("");
465
472
  setIsLoading(false);
@@ -494,6 +501,14 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
494
501
  };
495
502
  }, []);
496
503
 
504
+ // Trigger WorktreeRemove hook BEFORE agent destruction
505
+ const triggerWorktreeRemoveHook = useCallback(
506
+ async (worktreePath: string) => {
507
+ await agentRef.current?.triggerWorktreeRemoveHook(worktreePath);
508
+ },
509
+ [],
510
+ );
511
+
497
512
  // Send message function (including judgment logic)
498
513
  const sendMessage = useCallback(
499
514
  async (
@@ -737,7 +752,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
737
752
  getConfiguredModels,
738
753
  setModel,
739
754
  isCompacting,
740
- mcpServers,
755
+ mcpServers: mcpServerStatuses,
741
756
  connectMcpServer,
742
757
  disconnectMcpServer,
743
758
  backgroundTasks,
@@ -767,6 +782,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
767
782
  version,
768
783
  workdir,
769
784
  recreateAgent,
785
+ triggerWorktreeRemoveHook,
770
786
  };
771
787
 
772
788
  return (
@@ -119,6 +119,14 @@ export const useInputManager = (
119
119
  effect.images,
120
120
  effect.longTextMap,
121
121
  );
122
+ PromptHistoryManager.addEntry(
123
+ effect.content,
124
+ sessionId,
125
+ effect.longTextMap,
126
+ workdir,
127
+ ).catch((err: unknown) => {
128
+ logger?.error("Failed to save prompt history", err);
129
+ });
122
130
  break;
123
131
  case "ABORT_MESSAGE":
124
132
  onAbortMessage?.();
@@ -148,16 +156,6 @@ export const useInputManager = (
148
156
  case "PERMISSION_MODE_CHANGE":
149
157
  onPermissionModeChange?.(effect.mode);
150
158
  break;
151
- case "SAVE_HISTORY":
152
- PromptHistoryManager.addEntry(
153
- effect.content,
154
- sessionId,
155
- effect.longTextMap,
156
- workdir,
157
- ).catch((err: unknown) => {
158
- logger?.error("Failed to save prompt history", err);
159
- });
160
- break;
161
159
  case "FETCH_HISTORY": {
162
160
  let sessionIds: string[] | undefined = sessionId
163
161
  ? [sessionId]
package/src/index.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import yargs from "yargs";
2
2
  import { hideBin } from "yargs/helpers";
3
3
  import { startCli } from "./cli.js";
4
- import { Scope, generateRandomName, type PermissionMode } from "wave-agent-sdk";
4
+ import {
5
+ Scope,
6
+ generateRandomName,
7
+ type PermissionMode,
8
+ setCurrentWorktreeSession,
9
+ } from "wave-agent-sdk";
5
10
  import { createWorktree, type WorktreeSession } from "./utils/worktree.js";
6
11
  import path from "path";
7
12
  import { readFileSync } from "fs";
@@ -94,6 +99,12 @@ export async function main() {
94
99
  type: "string",
95
100
  global: false,
96
101
  })
102
+ .option("mcp-config", {
103
+ description:
104
+ "MCP server configuration as JSON string (same format as .mcp.json)",
105
+ type: "string",
106
+ global: false,
107
+ })
97
108
  .option("acp", {
98
109
  description: "Run as an ACP bridge",
99
110
  type: "boolean",
@@ -284,6 +295,20 @@ export async function main() {
284
295
  argv.disallowedTools as string | undefined,
285
296
  );
286
297
 
298
+ // Parse MCP server configuration from --mcp-config JSON string
299
+ let mcpServers:
300
+ | Record<string, import("wave-agent-sdk").McpServerConfig>
301
+ | undefined;
302
+ if (argv.mcpConfig) {
303
+ try {
304
+ const parsed = JSON.parse(argv.mcpConfig as string);
305
+ mcpServers = parsed.mcpServers || parsed;
306
+ } catch {
307
+ console.error("Failed to parse --mcp-config as JSON");
308
+ process.exit(1);
309
+ }
310
+ }
311
+
287
312
  // Resolve plugin directories to absolute paths before any worktree logic
288
313
  const pluginDirs = (argv.pluginDir as string[] | undefined)?.map((dir) =>
289
314
  path.resolve(originalCwd, dir),
@@ -300,6 +325,16 @@ export async function main() {
300
325
  name = generateRandomName();
301
326
  }
302
327
  worktreeSession = createWorktree(name, originalCwd);
328
+
329
+ // Register worktree session so system prompt includes worktree warnings
330
+ setCurrentWorktreeSession({
331
+ originalCwd,
332
+ worktreePath: worktreeSession.path,
333
+ worktreeBranch: worktreeSession.branch,
334
+ worktreeName: worktreeSession.name,
335
+ isNew: worktreeSession.isNew,
336
+ repoRoot: worktreeSession.repoRoot,
337
+ });
303
338
  }
304
339
 
305
340
  const workdir = worktreeSession?.path || originalCwd;
@@ -341,6 +376,7 @@ export async function main() {
341
376
  workdir,
342
377
  version,
343
378
  model: argv.model as string | undefined,
379
+ mcpServers,
344
380
  });
345
381
  }
346
382
 
@@ -364,6 +400,7 @@ export async function main() {
364
400
  workdir,
365
401
  version,
366
402
  model: argv.model as string | undefined,
403
+ mcpServers,
367
404
  });
368
405
  }
369
406
 
@@ -380,6 +417,7 @@ export async function main() {
380
417
  workdir,
381
418
  version,
382
419
  model: argv.model as string | undefined,
420
+ mcpServers,
383
421
  });
384
422
  } catch (error) {
385
423
  console.error("Failed to start WAVE Code:", error);
@@ -125,7 +125,12 @@ export const cyclePermissionMode = (
125
125
  dispatch: React.Dispatch<InputAction>,
126
126
  callbacks: Partial<InputManagerCallbacks>,
127
127
  ) => {
128
- const modes: PermissionMode[] = ["default", "acceptEdits", "plan", "bypassPermissions"];
128
+ const modes: PermissionMode[] = [
129
+ "default",
130
+ "acceptEdits",
131
+ "bypassPermissions",
132
+ "plan",
133
+ ];
129
134
  const currentIndex = modes.indexOf(currentMode);
130
135
  const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % modes.length;
131
136
  const nextMode = modes[nextIndex];
@@ -760,11 +765,7 @@ export const handleInput = async (
760
765
  }
761
766
 
762
767
  if (key.tab && key.shift) {
763
- cyclePermissionMode(
764
- state.permissionMode,
765
- dispatch,
766
- callbacks,
767
- );
768
+ cyclePermissionMode(state.permissionMode, dispatch, callbacks);
768
769
  return true;
769
770
  }
770
771
 
@@ -38,11 +38,6 @@ export type PendingEffect =
38
38
  | { type: "BACKGROUND_CURRENT_TASK" }
39
39
  | { type: "ASK_BTW"; question: string }
40
40
  | { type: "PERMISSION_MODE_CHANGE"; mode: PermissionMode }
41
- | {
42
- type: "SAVE_HISTORY";
43
- content: string;
44
- longTextMap: Record<string, string>;
45
- }
46
41
  | { type: "FETCH_HISTORY" }
47
42
  | { type: "PASTE_IMAGE" }
48
43
  | { type: "EXECUTE_COMMAND"; command: string };
@@ -768,8 +763,8 @@ export function inputReducer(
768
763
  const modes: PermissionMode[] = [
769
764
  "default",
770
765
  "acceptEdits",
771
- "plan",
772
766
  "bypassPermissions",
767
+ "plan",
773
768
  ];
774
769
  const currentIndex = modes.indexOf(state.permissionMode);
775
770
  const nextIndex =
package/src/print-cli.ts CHANGED
@@ -14,6 +14,8 @@ export interface PrintCliOptions extends BaseAppProps {
14
14
  continueLastSession?: boolean;
15
15
  message?: string;
16
16
  showStats?: boolean;
17
+ /** MCP server config parsed from --mcp-config CLI argument */
18
+ mcpServers?: Record<string, import("wave-agent-sdk").McpServerConfig>;
17
19
  }
18
20
 
19
21
  function displayTimingInfo(startTime: Date, showStats: boolean): void {
@@ -46,6 +48,7 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
46
48
  worktreeSession,
47
49
  workdir,
48
50
  model,
51
+ mcpServers,
49
52
  } = options;
50
53
 
51
54
  if (
@@ -158,6 +161,7 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
158
161
  disallowedTools,
159
162
  workdir,
160
163
  model,
164
+ mcpServers,
161
165
  // 保持流式模式以获得更好的命令行用户体验
162
166
  });
163
167
 
@@ -167,6 +171,11 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
167
171
  process.stdout.write("\n");
168
172
  }
169
173
 
174
+ // Wait for running background tasks and subagents to complete
175
+ while (agent.hasRunningBackgroundWork) {
176
+ await new Promise((resolve) => setTimeout(resolve, 500));
177
+ }
178
+
170
179
  // Display usage summary before exit
171
180
  if (showStats) {
172
181
  try {
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { WorktreeSession } from "./utils/worktree.js";
2
- import { PermissionMode } from "wave-agent-sdk";
2
+ import { PermissionMode, McpServerConfig } from "wave-agent-sdk";
3
3
 
4
4
  export interface BaseAppProps {
5
5
  bypassPermissions?: boolean;
@@ -12,4 +12,6 @@ export interface BaseAppProps {
12
12
  workdir?: string;
13
13
  version?: string;
14
14
  model?: string;
15
+ /** Optional MCP server configs to pass to Agent.create() */
16
+ mcpServers?: Record<string, McpServerConfig>;
15
17
  }