wave-code 0.15.1 → 0.15.3

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":"agent.d.ts","sourceRoot":"","sources":["../../src/acp/agent.ts"],"names":[],"mappings":"AAqBA,OAAO,EACL,KAAK,KAAK,IAAI,QAAQ,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAUzB,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,8BAA8B,EAMpC,MAAM,0BAA0B,CAAC;AAElC,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,UAAU,CAAsB;gBAE5B,UAAU,EAAE,mBAAmB;IAI3C,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,uBAAuB;YAmCjB,gBAAgB;IASxB,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAwBzC,YAAY,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;YAI5C,WAAW;IAmEnB,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAalE,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAWrE,YAAY,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,oBAAoB,CAAC;IAuB1B,qBAAqB,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAc7B,SAAS,CACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAO7B,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D,sBAAsB,CAC1B,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,8BAA8B,CAAC;IAuBpC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAyDtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD,OAAO,CAAC,kBAAkB;YA2BZ,uBAAuB;IA8LrC,OAAO,CAAC,cAAc;IAwGtB,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,eAAe;CAwNxB"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/acp/agent.ts"],"names":[],"mappings":"AAqBA,OAAO,EACL,KAAK,KAAK,IAAI,QAAQ,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAUzB,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,8BAA8B,EAOpC,MAAM,0BAA0B,CAAC;AAGlC,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,UAAU,CAAsB;gBAE5B,UAAU,EAAE,mBAAmB;IAI3C,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,uBAAuB;YAmCjB,gBAAgB;IASxB,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAyBzC,YAAY,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;YAI5C,WAAW;IA0EnB,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAalE,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAWrE,YAAY,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,oBAAoB,CAAC;IAuB1B,qBAAqB,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAc7B,SAAS,CACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAO7B,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D,sBAAsB,CAC1B,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,8BAA8B,CAAC;IAuBpC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAyDtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD,OAAO,CAAC,kBAAkB;YA2BZ,uBAAuB;IA8LrC,OAAO,CAAC,cAAc;IAwGtB,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,eAAe;CAyOxB"}
package/dist/acp/agent.js CHANGED
@@ -89,6 +89,7 @@ export class WaveAcpAgent {
89
89
  },
90
90
  agentCapabilities: {
91
91
  loadSession: true,
92
+ mcpCapabilities: { http: true, sse: true },
92
93
  sessionCapabilities: {
93
94
  list: {},
94
95
  close: {},
@@ -103,13 +104,17 @@ export class WaveAcpAgent {
103
104
  async authenticate() {
104
105
  // No authentication required for now
105
106
  }
106
- async createAgent(sessionId, cwd) {
107
+ async createAgent(sessionId, cwd, mcpServers) {
107
108
  const callbacks = {};
108
109
  const agentRef = {};
110
+ const sdkMcpServers = mcpServers
111
+ ? convertAcpMcpServers(mcpServers)
112
+ : undefined;
109
113
  const agent = await WaveAgent.create({
110
114
  workdir: cwd,
111
115
  restoreSessionId: sessionId,
112
116
  stream: true,
117
+ mcpServers: sdkMcpServers,
113
118
  canUseTool: (context) => {
114
119
  if (!agentRef.instance) {
115
120
  throw new Error("Agent instance not yet initialized");
@@ -127,6 +132,7 @@ export class WaveAcpAgent {
127
132
  onPermissionModeChange: (mode) => callbacks.onPermissionModeChange?.(mode),
128
133
  onModelChange: (model) => callbacks.onModelChange?.(model),
129
134
  onUserMessageAdded: (params) => callbacks.onUserMessageAdded?.(params),
135
+ onMcpServersChange: (servers) => callbacks.onMcpServersChange?.(servers),
130
136
  },
131
137
  });
132
138
  agentRef.instance = agent;
@@ -154,9 +160,9 @@ export class WaveAcpAgent {
154
160
  return agent;
155
161
  }
156
162
  async newSession(params) {
157
- const { cwd } = params;
163
+ const { cwd, mcpServers } = params;
158
164
  logger.info(`Creating new session in ${cwd}`);
159
- const agent = await this.createAgent(undefined, cwd);
165
+ const agent = await this.createAgent(undefined, cwd, mcpServers);
160
166
  logger.info(`New session created with ID: ${agent.sessionId}`);
161
167
  return {
162
168
  sessionId: agent.sessionId,
@@ -165,9 +171,9 @@ export class WaveAcpAgent {
165
171
  };
166
172
  }
167
173
  async loadSession(params) {
168
- const { sessionId, cwd } = params;
174
+ const { sessionId, cwd, mcpServers } = params;
169
175
  logger.info(`Loading session: ${sessionId} in ${cwd}`);
170
- const agent = await this.createAgent(sessionId, cwd);
176
+ const agent = await this.createAgent(sessionId, cwd, mcpServers);
171
177
  return {
172
178
  modes: this.getSessionModeState(agent),
173
179
  configOptions: this.getSessionConfigOptions(agent),
@@ -787,6 +793,68 @@ export class WaveAcpAgent {
787
793
  },
788
794
  });
789
795
  },
796
+ onMcpServersChange: (servers) => {
797
+ for (const server of servers) {
798
+ this.connection.sessionUpdate({
799
+ sessionId: sessionId,
800
+ update: {
801
+ sessionUpdate: "ext_notification",
802
+ method: "mcp_server_status",
803
+ params: {
804
+ name: server.name,
805
+ status: server.status,
806
+ toolCount: server.toolCount,
807
+ error: server.error,
808
+ },
809
+ },
810
+ });
811
+ }
812
+ },
790
813
  };
791
814
  }
792
815
  }
816
+ /**
817
+ * Convert ACP McpServer[] to SDK Record<string, McpServerConfig>.
818
+ */
819
+ function convertAcpMcpServers(servers) {
820
+ const result = {};
821
+ for (const server of servers) {
822
+ const config = {};
823
+ if ("type" in server && server.type === "http") {
824
+ config.url = server.url;
825
+ config.headers = convertHttpHeaders(server.headers);
826
+ }
827
+ else if ("type" in server && server.type === "sse") {
828
+ config.url = server.url;
829
+ config.headers = convertHttpHeaders(server.headers);
830
+ }
831
+ else {
832
+ // stdio (no type discriminator)
833
+ config.command = server.command;
834
+ config.args = server.args;
835
+ config.env = convertEnvVariables(server.env);
836
+ }
837
+ result[server.name] = config;
838
+ }
839
+ return result;
840
+ }
841
+ /**
842
+ * Convert ACP EnvVariable[] to SDK Record<string, string>.
843
+ */
844
+ function convertEnvVariables(env) {
845
+ const result = {};
846
+ for (const entry of env) {
847
+ result[entry.name] = entry.value;
848
+ }
849
+ return result;
850
+ }
851
+ /**
852
+ * Convert ACP HttpHeader[] to SDK Record<string, string>.
853
+ */
854
+ function convertHttpHeaders(headers) {
855
+ const result = {};
856
+ for (const entry of headers) {
857
+ result[entry.name] = entry.value;
858
+ }
859
+ return result;
860
+ }
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgEjE"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkEjE"}
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { App } from "./components/App.js";
4
4
  import { cleanupLogs } from "./utils/logger.js";
5
5
  import { removeWorktree } from "./utils/worktree.js";
6
6
  export async function startCli(options) {
7
- const { restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, } = options;
7
+ const { restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, mcpServers, } = options;
8
8
  // Continue with ink-based UI for normal mode
9
9
  let shouldRemoveWorktree = false;
10
10
  const handleExit = (shouldRemove) => {
@@ -12,7 +12,7 @@ export async function startCli(options) {
12
12
  unmount();
13
13
  };
14
14
  // Render the application
15
- const { unmount, waitUntilExit } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, onExit: handleExit }), { exitOnCtrlC: false });
15
+ const { unmount, waitUntilExit } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, mcpServers: mcpServers, onExit: handleExit }), { exitOnCtrlC: false });
16
16
  // Wait for the app to finish unmounting
17
17
  await waitUntilExit();
18
18
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAWhE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,UAAU,QAAS,SAAQ,YAAY;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AAiGD,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAmClC,CAAC"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAWhE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,UAAU,QAAS,SAAQ,YAAY;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AAwID,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAqClC,CAAC"}
@@ -2,34 +2,31 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useState, useEffect, useCallback } from "react";
3
3
  import { useInput } from "ink";
4
4
  import { ChatInterface } from "./ChatInterface.js";
5
- import { ChatProvider } from "../contexts/useChat.js";
5
+ import { ChatProvider, useChat } from "../contexts/useChat.js";
6
6
  import { AppProvider } from "../contexts/useAppConfig.js";
7
7
  import { WorktreeExitPrompt } from "./WorktreeExitPrompt.js";
8
8
  import { hasUncommittedChanges, hasNewCommits, getDefaultRemoteBranch, } from "wave-agent-sdk";
9
- const AppWithProviders = ({ bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, onExit, }) => {
9
+ /** Wraps ChatInterface with worktree exit handling, using useChat() for hook access. */
10
+ const ChatWithExitPrompt = ({ worktreeSession, onExit }) => {
11
+ const { triggerWorktreeRemoveHook } = useChat();
10
12
  const [isExiting, setIsExiting] = useState(false);
11
13
  const [worktreeStatus, setWorktreeStatus] = useState(null);
12
14
  const handleSignal = useCallback(async () => {
13
- if (worktreeSession) {
14
- const cwd = workdir || worktreeSession.path;
15
- const baseBranch = getDefaultRemoteBranch(cwd);
16
- const hasChanges = hasUncommittedChanges(cwd);
17
- const hasCommits = hasNewCommits(cwd, baseBranch);
18
- if (hasChanges || hasCommits) {
19
- setWorktreeStatus({
20
- hasUncommittedChanges: hasChanges,
21
- hasNewCommits: hasCommits,
22
- });
23
- setIsExiting(true);
24
- }
25
- else {
26
- onExit(true);
27
- }
15
+ const cwd = worktreeSession.path;
16
+ const baseBranch = getDefaultRemoteBranch(cwd);
17
+ const hasChanges = hasUncommittedChanges(cwd);
18
+ const hasCommits = hasNewCommits(cwd, baseBranch);
19
+ if (hasChanges || hasCommits) {
20
+ setWorktreeStatus({
21
+ hasUncommittedChanges: hasChanges,
22
+ hasNewCommits: hasCommits,
23
+ });
24
+ setIsExiting(true);
28
25
  }
29
26
  else {
30
- onExit(false);
27
+ onExit(true);
31
28
  }
32
- }, [worktreeSession, workdir, onExit]);
29
+ }, [worktreeSession, onExit]);
33
30
  useInput((input, key) => {
34
31
  if (input === "c" && key.ctrl) {
35
32
  handleSignal();
@@ -45,11 +42,28 @@ const AppWithProviders = ({ bypassPermissions, permissionMode, pluginDirs, tools
45
42
  process.off("SIGTERM", onSigTerm);
46
43
  };
47
44
  }, [handleSignal]);
48
- if (isExiting && worktreeSession && worktreeStatus) {
49
- return (_jsx(WorktreeExitPrompt, { name: worktreeSession.name, path: worktreeSession.path, hasUncommittedChanges: worktreeStatus.hasUncommittedChanges, hasNewCommits: worktreeStatus.hasNewCommits, onKeep: () => onExit(false), onRemove: () => onExit(true), onCancel: () => setIsExiting(false) }));
45
+ if (isExiting && worktreeStatus) {
46
+ return (_jsx(WorktreeExitPrompt, { name: worktreeSession.name, path: worktreeSession.path, hasUncommittedChanges: worktreeStatus.hasUncommittedChanges, hasNewCommits: worktreeStatus.hasNewCommits, onKeep: () => onExit(false), onRemove: async () => {
47
+ await triggerWorktreeRemoveHook(worktreeSession.path);
48
+ onExit(true);
49
+ }, onCancel: () => setIsExiting(false) }));
50
+ }
51
+ return _jsx(ChatInterface, {});
52
+ };
53
+ const AppWithProviders = ({ bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, mcpServers, onExit, }) => {
54
+ // Handle Ctrl-C for non-worktree sessions (immediate exit)
55
+ // Ink runs terminal in raw mode, so Ctrl+C arrives as useInput event, not SIGINT
56
+ useInput((input, key) => {
57
+ if (!worktreeSession && input === "c" && key.ctrl) {
58
+ onExit(false);
59
+ return true;
60
+ }
61
+ });
62
+ if (worktreeSession) {
63
+ return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, workdir: workdir, worktreeSession: worktreeSession, version: version, model: model, mcpServers: mcpServers, children: _jsx(ChatWithExitPrompt, { worktreeSession: worktreeSession, onExit: onExit }) }));
50
64
  }
51
- return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, workdir: workdir, worktreeSession: worktreeSession, version: version, model: model, children: _jsx(ChatInterface, {}) }));
65
+ return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, workdir: workdir, worktreeSession: worktreeSession, version: version, model: model, mcpServers: mcpServers, children: _jsx(ChatInterface, {}) }));
52
66
  };
53
- export const App = ({ restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, onExit, }) => {
54
- return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, onExit: onExit }) }));
67
+ export const App = ({ restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, mcpServers, onExit, }) => {
68
+ return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, mcpServers: mcpServers, onExit: onExit }) }));
55
69
  };
@@ -65,6 +65,7 @@ export interface ChatContextType {
65
65
  version?: string;
66
66
  workdir?: string;
67
67
  recreateAgent: () => void;
68
+ triggerWorktreeRemoveHook: (worktreePath: string) => Promise<void>;
68
69
  }
69
70
  export declare const useChat: () => ChatContextType;
70
71
  export interface ChatProviderProps extends BaseAppProps {
@@ -1 +1 @@
1
- {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"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"}
@@ -15,7 +15,7 @@ export const useChat = () => {
15
15
  }
16
16
  return context;
17
17
  };
18
- export const ChatProvider = ({ children, bypassPermissions, permissionMode: initialPermissionMode, pluginDirs, tools, allowedTools, disallowedTools, workdir, worktreeSession, version, model, }) => {
18
+ export const ChatProvider = ({ children, bypassPermissions, permissionMode: initialPermissionMode, pluginDirs, tools, allowedTools, disallowedTools, workdir, worktreeSession, version, model, mcpServers, }) => {
19
19
  const { restoreSessionId, continueLastSession } = useAppConfig();
20
20
  const { stdout } = useStdout();
21
21
  // Message Display State
@@ -50,7 +50,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
50
50
  const [configuredModels, setConfiguredModels] = useState([]);
51
51
  const [queuedMessages, setQueuedMessages] = useState([]);
52
52
  // MCP State
53
- const [mcpServers, setMcpServers] = useState([]);
53
+ const [mcpServerStatuses, setMcpServerStatuses] = useState([]);
54
54
  // Background tasks state
55
55
  const [backgroundTasks, setBackgroundTasks] = useState([]);
56
56
  // Tasks state
@@ -116,8 +116,8 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
116
116
  onMessagesChange: () => {
117
117
  throttledSetMessages();
118
118
  },
119
- onServersChange: (servers) => {
120
- setMcpServers([...servers]);
119
+ onMcpServersChange: (servers) => {
120
+ setMcpServerStatuses([...servers]);
121
121
  },
122
122
  onSessionIdChange: (sessionId) => {
123
123
  setSessionId(sessionId);
@@ -181,6 +181,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
181
181
  worktreeName: worktreeSession?.name,
182
182
  isNewWorktree: worktreeSession?.isNew,
183
183
  model,
184
+ mcpServers,
184
185
  });
185
186
  agentRef.current = agent;
186
187
  // Get initial state
@@ -195,8 +196,8 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
195
196
  setCurrentModelState(agent.getModelConfig().model);
196
197
  setConfiguredModels(agent.getConfiguredModels());
197
198
  // Get initial MCP servers state
198
- const mcpServers = agent.getMcpServers?.() || [];
199
- setMcpServers(mcpServers);
199
+ const initialMcpServers = agent.getMcpServers?.() || [];
200
+ setMcpServerStatuses(initialMcpServers);
200
201
  // Get initial commands
201
202
  const agentSlashCommands = agent.getSlashCommands?.() || [];
202
203
  setSlashCommands(agentSlashCommands);
@@ -218,6 +219,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
218
219
  model,
219
220
  initialPermissionMode,
220
221
  throttledSetMessages,
222
+ mcpServers,
221
223
  ]);
222
224
  // Recreate agent (e.g. after plugin install) — destroys current agent and reinitializes
223
225
  const recreateAgent = useCallback(() => {
@@ -232,7 +234,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
232
234
  }
233
235
  agentRef.current = null;
234
236
  setMessages([]);
235
- setMcpServers([]);
237
+ setMcpServerStatuses([]);
236
238
  setSlashCommands([]);
237
239
  setSessionId("");
238
240
  setIsLoading(false);
@@ -264,6 +266,10 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
264
266
  }
265
267
  };
266
268
  }, []);
269
+ // Trigger WorktreeRemove hook BEFORE agent destruction
270
+ const triggerWorktreeRemoveHook = useCallback(async (worktreePath) => {
271
+ await agentRef.current?.triggerWorktreeRemoveHook(worktreePath);
272
+ }, []);
267
273
  // Send message function (including judgment logic)
268
274
  const sendMessage = useCallback(async (content, images, longTextMap) => {
269
275
  // Check if there's content to send (text content or image attachments)
@@ -472,7 +478,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
472
478
  getConfiguredModels,
473
479
  setModel,
474
480
  isCompacting,
475
- mcpServers,
481
+ mcpServers: mcpServerStatuses,
476
482
  connectMcpServer,
477
483
  disconnectMcpServer,
478
484
  backgroundTasks,
@@ -501,6 +507,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
501
507
  version,
502
508
  workdir,
503
509
  recreateAgent,
510
+ triggerWorktreeRemoveHook,
504
511
  };
505
512
  return (_jsx(ChatContext.Provider, { value: contextValue, children: children }));
506
513
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,wBAAsB,IAAI,kBAoXzB;AAGD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGpC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,wBAAsB,IAAI,kBAqZzB;AAGD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGpC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import yargs from "yargs";
2
2
  import { hideBin } from "yargs/helpers";
3
3
  import { startCli } from "./cli.js";
4
- import { generateRandomName } from "wave-agent-sdk";
4
+ import { generateRandomName, setCurrentWorktreeSession, } from "wave-agent-sdk";
5
5
  import { createWorktree } from "./utils/worktree.js";
6
6
  import path from "path";
7
7
  import { readFileSync } from "fs";
@@ -87,6 +87,11 @@ export async function main() {
87
87
  description: "Specify the AI model to use",
88
88
  type: "string",
89
89
  global: false,
90
+ })
91
+ .option("mcp-config", {
92
+ description: "MCP server configuration as JSON string (same format as .mcp.json)",
93
+ type: "string",
94
+ global: false,
90
95
  })
91
96
  .option("acp", {
92
97
  description: "Run as an ACP bridge",
@@ -208,6 +213,18 @@ export async function main() {
208
213
  const tools = parseTools(argv.tools);
209
214
  const allowedTools = parseTools(argv.allowedTools);
210
215
  const disallowedTools = parseTools(argv.disallowedTools);
216
+ // Parse MCP server configuration from --mcp-config JSON string
217
+ let mcpServers;
218
+ if (argv.mcpConfig) {
219
+ try {
220
+ const parsed = JSON.parse(argv.mcpConfig);
221
+ mcpServers = parsed.mcpServers || parsed;
222
+ }
223
+ catch {
224
+ console.error("Failed to parse --mcp-config as JSON");
225
+ process.exit(1);
226
+ }
227
+ }
211
228
  // Resolve plugin directories to absolute paths before any worktree logic
212
229
  const pluginDirs = argv.pluginDir?.map((dir) => path.resolve(originalCwd, dir));
213
230
  let worktreeSession;
@@ -219,6 +236,15 @@ export async function main() {
219
236
  name = generateRandomName();
220
237
  }
221
238
  worktreeSession = createWorktree(name, originalCwd);
239
+ // Register worktree session so system prompt includes worktree warnings
240
+ setCurrentWorktreeSession({
241
+ originalCwd,
242
+ worktreePath: worktreeSession.path,
243
+ worktreeBranch: worktreeSession.branch,
244
+ worktreeName: worktreeSession.name,
245
+ isNew: worktreeSession.isNew,
246
+ repoRoot: worktreeSession.repoRoot,
247
+ });
222
248
  }
223
249
  const workdir = worktreeSession?.path || originalCwd;
224
250
  if (worktreeSession) {
@@ -252,6 +278,7 @@ export async function main() {
252
278
  workdir,
253
279
  version,
254
280
  model: argv.model,
281
+ mcpServers,
255
282
  });
256
283
  }
257
284
  // Handle print mode directly
@@ -272,6 +299,7 @@ export async function main() {
272
299
  workdir,
273
300
  version,
274
301
  model: argv.model,
302
+ mcpServers,
275
303
  });
276
304
  }
277
305
  await startCli({
@@ -287,6 +315,7 @@ export async function main() {
287
315
  workdir,
288
316
  version,
289
317
  model: argv.model,
318
+ mcpServers,
290
319
  });
291
320
  }
292
321
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"inputHandlers.d.ts","sourceRoot":"","sources":["../../src/managers/inputHandlers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"inputHandlers.d.ts","sourceRoot":"","sources":["../../src/managers/inputHandlers.ts"],"names":[],"mappings":"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"}
@@ -74,7 +74,12 @@ export const handlePasteImage = async (dispatch) => {
74
74
  }
75
75
  };
76
76
  export const cyclePermissionMode = (currentMode, dispatch, callbacks) => {
77
- const modes = ["default", "acceptEdits", "plan", "bypassPermissions"];
77
+ const modes = [
78
+ "default",
79
+ "acceptEdits",
80
+ "bypassPermissions",
81
+ "plan",
82
+ ];
78
83
  const currentIndex = modes.indexOf(currentMode);
79
84
  const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % modes.length;
80
85
  const nextMode = modes[nextIndex];
@@ -542,8 +542,8 @@ export function inputReducer(state, action) {
542
542
  const modes = [
543
543
  "default",
544
544
  "acceptEdits",
545
- "plan",
546
545
  "bypassPermissions",
546
+ "plan",
547
547
  ];
548
548
  const currentIndex = modes.indexOf(state.permissionMode);
549
549
  const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % modes.length;
@@ -4,6 +4,8 @@ export interface PrintCliOptions extends BaseAppProps {
4
4
  continueLastSession?: boolean;
5
5
  message?: string;
6
6
  showStats?: boolean;
7
+ /** MCP server config parsed from --mcp-config CLI argument */
8
+ mcpServers?: Record<string, import("wave-agent-sdk").McpServerConfig>;
7
9
  }
8
10
  export declare function startPrintCli(options: PrintCliOptions): Promise<void>;
9
11
  //# sourceMappingURL=print-cli.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"print-cli.d.ts","sourceRoot":"","sources":["../src/print-cli.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAgBD,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAqN3E"}
1
+ {"version":3,"file":"print-cli.d.ts","sourceRoot":"","sources":["../src/print-cli.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,gBAAgB,EAAE,eAAe,CAAC,CAAC;CACvE;AAgBD,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuN3E"}
package/dist/print-cli.js CHANGED
@@ -14,7 +14,7 @@ function displayTimingInfo(startTime, showStats) {
14
14
  }
15
15
  export async function startPrintCli(options) {
16
16
  const startTime = new Date();
17
- const { restoreSessionId, continueLastSession, message, showStats = false, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, model, } = options;
17
+ const { restoreSessionId, continueLastSession, message, showStats = false, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, model, mcpServers, } = options;
18
18
  if ((typeof message !== "string" || message.trim() === "") &&
19
19
  !continueLastSession &&
20
20
  !restoreSessionId) {
@@ -110,6 +110,7 @@ export async function startPrintCli(options) {
110
110
  disallowedTools,
111
111
  workdir,
112
112
  model,
113
+ mcpServers,
113
114
  // 保持流式模式以获得更好的命令行用户体验
114
115
  });
115
116
  // Send message if provided and not empty
package/dist/types.d.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
  export interface BaseAppProps {
4
4
  bypassPermissions?: boolean;
5
5
  permissionMode?: PermissionMode;
@@ -11,5 +11,7 @@ export interface BaseAppProps {
11
11
  workdir?: string;
12
12
  version?: string;
13
13
  model?: string;
14
+ /** Optional MCP server configs to pass to Agent.create() */
15
+ mcpServers?: Record<string, McpServerConfig>;
14
16
  }
15
17
  //# sourceMappingURL=types.d.ts.map
@@ -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.1",
3
+ "version": "0.15.3",
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.1"
45
+ "wave-agent-sdk": "0.15.3"
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 (
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
 
@@ -763,8 +763,8 @@ export function inputReducer(
763
763
  const modes: PermissionMode[] = [
764
764
  "default",
765
765
  "acceptEdits",
766
- "plan",
767
766
  "bypassPermissions",
767
+ "plan",
768
768
  ];
769
769
  const currentIndex = modes.indexOf(state.permissionMode);
770
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
 
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
  }