wave-code 0.9.6 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ import type { Agent as AcpAgent, AgentSideConnection, InitializeResponse, NewSessionRequest, NewSessionResponse, LoadSessionRequest, LoadSessionResponse, PromptRequest, PromptResponse, CancelNotification, AuthenticateResponse } from "@agentclientprotocol/sdk";
2
+ export declare class WaveAcpAgent implements AcpAgent {
3
+ private agents;
4
+ private connection;
5
+ constructor(connection: AgentSideConnection);
6
+ initialize(): Promise<InitializeResponse>;
7
+ authenticate(): Promise<AuthenticateResponse | void>;
8
+ newSession(params: NewSessionRequest): Promise<NewSessionResponse>;
9
+ loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse>;
10
+ prompt(params: PromptRequest): Promise<PromptResponse>;
11
+ cancel(params: CancelNotification): Promise<void>;
12
+ private createCallbacks;
13
+ }
14
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/acp/agent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,KAAK,IAAI,QAAQ,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EAIrB,MAAM,0BAA0B,CAAC;AAElC,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,UAAU,CAAsB;gBAE5B,UAAU,EAAE,mBAAmB;IAIrC,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAczC,YAAY,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAIpD,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAsClE,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAmCrE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAuDtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD,OAAO,CAAC,eAAe;CAuFxB"}
@@ -0,0 +1,209 @@
1
+ import { Agent as WaveAgent } from "wave-agent-sdk";
2
+ import { logger } from "../utils/logger.js";
3
+ export class WaveAcpAgent {
4
+ constructor(connection) {
5
+ this.agents = new Map();
6
+ this.connection = connection;
7
+ }
8
+ async initialize() {
9
+ logger.info("Initializing WaveAcpAgent");
10
+ return {
11
+ protocolVersion: 1,
12
+ agentInfo: {
13
+ name: "wave-agent",
14
+ version: "0.1.0",
15
+ },
16
+ agentCapabilities: {
17
+ loadSession: true,
18
+ },
19
+ };
20
+ }
21
+ async authenticate() {
22
+ // No authentication required for now
23
+ }
24
+ async newSession(params) {
25
+ const { cwd } = params;
26
+ logger.info(`Creating new session in ${cwd}`);
27
+ const callbacks = {};
28
+ const agent = await WaveAgent.create({
29
+ workdir: cwd,
30
+ callbacks: {
31
+ onAssistantContentUpdated: (chunk) => callbacks.onAssistantContentUpdated?.(chunk, ""),
32
+ onAssistantReasoningUpdated: (chunk) => callbacks.onAssistantReasoningUpdated?.(chunk, ""),
33
+ onToolBlockUpdated: (params) => {
34
+ const cb = callbacks.onToolBlockUpdated;
35
+ cb?.(params);
36
+ },
37
+ onTasksChange: (tasks) => {
38
+ const cb = callbacks.onTasksChange;
39
+ cb?.(tasks);
40
+ },
41
+ },
42
+ });
43
+ const sessionId = agent.sessionId;
44
+ logger.info(`New session created: ${sessionId}`);
45
+ this.agents.set(sessionId, agent);
46
+ // Update the callbacks object with the correct sessionId
47
+ Object.assign(callbacks, this.createCallbacks(sessionId));
48
+ return {
49
+ sessionId: sessionId,
50
+ };
51
+ }
52
+ async loadSession(params) {
53
+ const { sessionId } = params;
54
+ logger.info(`Loading session: ${sessionId}`);
55
+ const callbacks = {};
56
+ const agent = await WaveAgent.create({
57
+ restoreSessionId: sessionId,
58
+ callbacks: {
59
+ onAssistantContentUpdated: (chunk) => callbacks.onAssistantContentUpdated?.(chunk, ""),
60
+ onAssistantReasoningUpdated: (chunk) => callbacks.onAssistantReasoningUpdated?.(chunk, ""),
61
+ onToolBlockUpdated: (params) => {
62
+ const cb = callbacks.onToolBlockUpdated;
63
+ cb?.(params);
64
+ },
65
+ onTasksChange: (tasks) => {
66
+ const cb = callbacks.onTasksChange;
67
+ cb?.(tasks);
68
+ },
69
+ },
70
+ });
71
+ this.agents.set(sessionId, agent);
72
+ logger.info(`Session loaded: ${sessionId}`);
73
+ // Update the callbacks object with the correct sessionId
74
+ Object.assign(callbacks, this.createCallbacks(sessionId));
75
+ return {};
76
+ }
77
+ async prompt(params) {
78
+ const { sessionId, prompt } = params;
79
+ logger.info(`Received prompt for session ${sessionId}`);
80
+ const agent = this.agents.get(sessionId);
81
+ if (!agent) {
82
+ logger.error(`Session ${sessionId} not found`);
83
+ throw new Error(`Session ${sessionId} not found`);
84
+ }
85
+ // Map ACP prompt to Wave Agent sendMessage
86
+ const textContent = prompt
87
+ .filter((block) => block.type === "text")
88
+ .map((block) => block.text)
89
+ .join("\n");
90
+ const images = prompt
91
+ .filter((block) => block.type === "image")
92
+ .map((block) => {
93
+ const img = block;
94
+ return {
95
+ path: `data:${img.mimeType};base64,${img.data}`,
96
+ mimeType: img.mimeType,
97
+ };
98
+ });
99
+ try {
100
+ logger.info(`Sending message to agent: ${textContent.substring(0, 50)}...`);
101
+ await agent.sendMessage(textContent, images.length > 0 ? images : undefined);
102
+ // Force save session so it can be loaded later
103
+ await agent.messageManager.saveSession();
104
+ logger.info(`Message sent successfully for session ${sessionId}`);
105
+ return {
106
+ stopReason: "end_turn",
107
+ };
108
+ }
109
+ catch (error) {
110
+ if (error instanceof Error && error.message.includes("abort")) {
111
+ logger.info(`Message aborted for session ${sessionId}`);
112
+ return {
113
+ stopReason: "cancelled",
114
+ };
115
+ }
116
+ logger.error(`Error sending message for session ${sessionId}:`, error);
117
+ throw error;
118
+ }
119
+ }
120
+ async cancel(params) {
121
+ const { sessionId } = params;
122
+ logger.info(`Cancelling message for session ${sessionId}`);
123
+ const agent = this.agents.get(sessionId);
124
+ if (agent) {
125
+ agent.abortMessage();
126
+ }
127
+ }
128
+ createCallbacks(sessionId) {
129
+ return {
130
+ onAssistantContentUpdated: (chunk) => {
131
+ this.connection.sessionUpdate({
132
+ sessionId: sessionId,
133
+ update: {
134
+ sessionUpdate: "agent_message_chunk",
135
+ content: {
136
+ type: "text",
137
+ text: chunk,
138
+ },
139
+ },
140
+ });
141
+ },
142
+ onAssistantReasoningUpdated: (chunk) => {
143
+ this.connection.sessionUpdate({
144
+ sessionId: sessionId,
145
+ update: {
146
+ sessionUpdate: "agent_thought_chunk",
147
+ content: {
148
+ type: "text",
149
+ text: chunk,
150
+ },
151
+ },
152
+ });
153
+ },
154
+ onToolBlockUpdated: (params) => {
155
+ const { id, name, stage, success, error, result } = params;
156
+ if (stage === "start") {
157
+ this.connection.sessionUpdate({
158
+ sessionId: sessionId,
159
+ update: {
160
+ sessionUpdate: "tool_call",
161
+ toolCallId: id,
162
+ title: name || "Tool Call",
163
+ status: "pending",
164
+ },
165
+ });
166
+ return;
167
+ }
168
+ if (stage === "streaming") {
169
+ // We don't support streaming tool arguments in ACP yet
170
+ return;
171
+ }
172
+ const status = stage === "end"
173
+ ? success
174
+ ? "completed"
175
+ : "failed"
176
+ : stage === "running"
177
+ ? "in_progress"
178
+ : "pending";
179
+ this.connection.sessionUpdate({
180
+ sessionId: sessionId,
181
+ update: {
182
+ sessionUpdate: "tool_call_update",
183
+ toolCallId: id,
184
+ status,
185
+ title: name || "Tool Call",
186
+ rawOutput: result || error,
187
+ },
188
+ });
189
+ },
190
+ onTasksChange: (tasks) => {
191
+ this.connection.sessionUpdate({
192
+ sessionId: sessionId,
193
+ update: {
194
+ sessionUpdate: "plan",
195
+ entries: tasks.map((task) => ({
196
+ content: task.subject,
197
+ status: task.status === "completed"
198
+ ? "completed"
199
+ : task.status === "in_progress"
200
+ ? "in_progress"
201
+ : "pending",
202
+ priority: "medium",
203
+ })),
204
+ },
205
+ });
206
+ },
207
+ };
208
+ }
209
+ }
@@ -0,0 +1,2 @@
1
+ export declare function startAcpCli(): Promise<void>;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/acp/index.ts"],"names":[],"mappings":"AAKA,wBAAsB,WAAW,kBAsBhC"}
@@ -0,0 +1,22 @@
1
+ import { Readable, Writable } from "node:stream";
2
+ import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
3
+ import { WaveAcpAgent } from "./agent.js";
4
+ import { logger } from "../utils/logger.js";
5
+ export async function startAcpCli() {
6
+ // Redirect console.log to logger to avoid interfering with JSON-RPC over stdio
7
+ console.log = (...args) => {
8
+ logger.info(...args);
9
+ };
10
+ logger.info("Starting ACP bridge...");
11
+ // Convert Node.js stdio to Web streams
12
+ const stdin = Readable.toWeb(process.stdin);
13
+ const stdout = Writable.toWeb(process.stdout);
14
+ // Create ACP stream
15
+ const stream = ndJsonStream(stdout, stdin);
16
+ // Initialize AgentSideConnection
17
+ const connection = new AgentSideConnection((conn) => {
18
+ return new WaveAcpAgent(conn);
19
+ }, stream);
20
+ // Wait for connection to close
21
+ await connection.closed;
22
+ }
@@ -0,0 +1,2 @@
1
+ export declare function runAcp(): Promise<void>;
2
+ //# sourceMappingURL=acp-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acp-cli.d.ts","sourceRoot":"","sources":["../src/acp-cli.ts"],"names":[],"mappings":"AAEA,wBAAsB,MAAM,kBAE3B"}
@@ -0,0 +1,4 @@
1
+ import { startAcpCli } from "./acp/index.js";
2
+ export async function runAcp() {
3
+ await startAcpCli();
4
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"marketplace.d.ts","sourceRoot":"","sources":["../../../src/commands/plugin/marketplace.ts"],"names":[],"mappings":"AAEA,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,iBAsBlE;AAED,wBAAsB,uBAAuB,kBA8B5C;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,iBAWpE;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,iBAgBrE"}
1
+ {"version":3,"file":"marketplace.d.ts","sourceRoot":"","sources":["../../../src/commands/plugin/marketplace.ts"],"names":[],"mappings":"AAEA,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,iBAsBlE;AAED,wBAAsB,uBAAuB,kBAiC5C;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,iBAWpE;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,iBAgBrE"}
@@ -45,7 +45,10 @@ export async function listMarketplacesCommand() {
45
45
  sourceInfo = source.url + (source.ref ? `#${source.ref}` : "");
46
46
  }
47
47
  const builtinLabel = m.isBuiltin ? " [builtin]" : "";
48
- console.log(`- ${m.name}${builtinLabel}: ${sourceInfo} (${m.source.source})`);
48
+ const lastUpdatedLabel = m.lastUpdated
49
+ ? ` (Last updated: ${new Date(m.lastUpdated).toLocaleString()})`
50
+ : "";
51
+ console.log(`- ${m.name}${builtinLabel}: ${sourceInfo} (${m.source.source})${lastUpdatedLabel}`);
49
52
  });
50
53
  }
51
54
  process.exit(0);
@@ -1 +1 @@
1
- {"version":3,"file":"DiffDisplay.d.ts","sourceRoot":"","sources":["../../src/components/DiffDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAMvC,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA8VlD,CAAC"}
1
+ {"version":3,"file":"DiffDisplay.d.ts","sourceRoot":"","sources":["../../src/components/DiffDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAMvC,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA0VlD,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useMemo } from "react";
2
+ import { useMemo } from "react";
3
3
  import { Box, Text } from "ink";
4
4
  import { WRITE_TOOL_NAME, EDIT_TOOL_NAME } from "wave-agent-sdk";
5
5
  import { transformToolBlockToChanges } from "../utils/toolParameterTransforms.js";
@@ -85,26 +85,46 @@ export const DiffDisplay = ({ toolName, parameters, startLineNumber, }) => {
85
85
  let newLineNum = change.startLineNumber || 1;
86
86
  // Process line diffs
87
87
  const diffElements = [];
88
- lineDiffs.forEach((part, partIndex) => {
88
+ for (let i = 0; i < lineDiffs.length; i++) {
89
+ const part = lineDiffs[i];
89
90
  const lines = part.value.split("\n");
90
91
  // diffLines might return a trailing empty string if the content ends with a newline
91
92
  if (lines[lines.length - 1] === "") {
92
93
  lines.pop();
93
94
  }
94
- if (part.added) {
95
+ if (part.removed) {
96
+ // Look ahead for an added block
97
+ if (i + 1 < lineDiffs.length && lineDiffs[i + 1].added) {
98
+ const nextPart = lineDiffs[i + 1];
99
+ const addedLines = nextPart.value.split("\n");
100
+ if (addedLines[addedLines.length - 1] === "") {
101
+ addedLines.pop();
102
+ }
103
+ if (lines.length === addedLines.length) {
104
+ // Word-level diffing
105
+ lines.forEach((line, lineIndex) => {
106
+ const { removedParts, addedParts } = renderWordLevelDiff(line, addedLines[lineIndex], `word-${changeIndex}-${i}-${lineIndex}`);
107
+ diffElements.push(renderLine(oldLineNum++, null, "-", removedParts, "red", `remove-${changeIndex}-${i}-${lineIndex}`));
108
+ diffElements.push(renderLine(null, newLineNum++, "+", addedParts, "green", `add-${changeIndex}-${i}-${lineIndex}`));
109
+ });
110
+ i++; // Skip the added block
111
+ continue;
112
+ }
113
+ }
114
+ // Fallback to standard removed rendering
95
115
  lines.forEach((line, lineIndex) => {
96
- diffElements.push(renderLine(null, newLineNum++, "+", line, "green", `add-${changeIndex}-${partIndex}-${lineIndex}`));
116
+ diffElements.push(renderLine(oldLineNum++, null, "-", line, "red", `remove-${changeIndex}-${i}-${lineIndex}`));
97
117
  });
98
118
  }
99
- else if (part.removed) {
119
+ else if (part.added) {
100
120
  lines.forEach((line, lineIndex) => {
101
- diffElements.push(renderLine(oldLineNum++, null, "-", line, "red", `remove-${changeIndex}-${partIndex}-${lineIndex}`));
121
+ diffElements.push(renderLine(null, newLineNum++, "+", line, "green", `add-${changeIndex}-${i}-${lineIndex}`));
102
122
  });
103
123
  }
104
124
  else {
105
125
  // Context lines - show unchanged content
106
- const isFirstBlock = partIndex === 0;
107
- const isLastBlock = partIndex === lineDiffs.length - 1;
126
+ const isFirstBlock = i === 0;
127
+ const isLastBlock = i === lineDiffs.length - 1;
108
128
  let linesToDisplay = lines;
109
129
  let showEllipsisTop = false;
110
130
  let showEllipsisBottom = false;
@@ -133,7 +153,7 @@ export const DiffDisplay = ({ toolName, parameters, startLineNumber, }) => {
133
153
  }
134
154
  }
135
155
  if (showEllipsisTop) {
136
- diffElements.push(_jsx(Box, { children: _jsxs(Text, { color: "gray", children: [" ".repeat(maxDigits * 2 + 2), "..."] }) }, `ellipsis-top-${changeIndex}-${partIndex}`));
156
+ diffElements.push(_jsx(Box, { children: _jsxs(Text, { color: "gray", children: [" ".repeat(maxDigits * 2 + 2), "..."] }) }, `ellipsis-top-${changeIndex}-${i}`));
137
157
  }
138
158
  linesToDisplay.forEach((line, lineIndex) => {
139
159
  // If it's a middle block and we are at the split point
@@ -144,9 +164,9 @@ export const DiffDisplay = ({ toolName, parameters, startLineNumber, }) => {
144
164
  const skipCount = lines.length - 6;
145
165
  oldLineNum += skipCount;
146
166
  newLineNum += skipCount;
147
- diffElements.push(_jsx(Box, { children: _jsxs(Text, { color: "gray", children: [" ".repeat(maxDigits * 2 + 2), "..."] }) }, `ellipsis-mid-${changeIndex}-${partIndex}`));
167
+ diffElements.push(_jsx(Box, { children: _jsxs(Text, { color: "gray", children: [" ".repeat(maxDigits * 2 + 2), "..."] }) }, `ellipsis-mid-${changeIndex}-${i}`));
148
168
  }
149
- diffElements.push(renderLine(oldLineNum++, newLineNum++, " ", line, "white", `context-${changeIndex}-${partIndex}-${lineIndex}`));
169
+ diffElements.push(renderLine(oldLineNum++, newLineNum++, " ", line, "white", `context-${changeIndex}-${i}-${lineIndex}`));
150
170
  });
151
171
  if (showEllipsisBottom) {
152
172
  const skipCount = lines.length - linesToDisplay.length;
@@ -154,34 +174,11 @@ export const DiffDisplay = ({ toolName, parameters, startLineNumber, }) => {
154
174
  // But we need to account for the lines we skipped at the end of this block
155
175
  oldLineNum += skipCount;
156
176
  newLineNum += skipCount;
157
- diffElements.push(_jsx(Box, { children: _jsxs(Text, { color: "gray", children: [" ".repeat(maxDigits * 2 + 2), "..."] }) }, `ellipsis-bottom-${changeIndex}-${partIndex}`));
177
+ diffElements.push(_jsx(Box, { children: _jsxs(Text, { color: "gray", children: [" ".repeat(maxDigits * 2 + 2), "..."] }) }, `ellipsis-bottom-${changeIndex}-${i}`));
158
178
  }
159
179
  }
160
- });
161
- // If it's a single line change (one removed, one added), use word-level diff
162
- if (diffElements.length === 2 &&
163
- React.isValidElement(diffElements[0]) &&
164
- React.isValidElement(diffElements[1]) &&
165
- typeof diffElements[0].key === "string" &&
166
- diffElements[0].key.includes("remove-") &&
167
- typeof diffElements[1].key === "string" &&
168
- diffElements[1].key.includes("add-")) {
169
- const removedText = extractTextFromElement(diffElements[0]);
170
- const addedText = extractTextFromElement(diffElements[1]);
171
- const oldLineNumVal = extractOldLineNumFromElement(diffElements[0]);
172
- const newLineNumVal = extractNewLineNumFromElement(diffElements[1]);
173
- if (removedText && addedText) {
174
- const { removedParts, addedParts } = renderWordLevelDiff(removedText, addedText, `word-${changeIndex}`);
175
- allElements.push(renderLine(oldLineNumVal, null, "-", removedParts, "red", `word-diff-removed-${changeIndex}`));
176
- allElements.push(renderLine(null, newLineNumVal, "+", addedParts, "green", `word-diff-added-${changeIndex}`));
177
- }
178
- else {
179
- allElements.push(...diffElements);
180
- }
181
- }
182
- else {
183
- allElements.push(...diffElements);
184
180
  }
181
+ allElements.push(...diffElements);
185
182
  }
186
183
  catch (error) {
187
184
  console.warn(`Error rendering diff for change ${changeIndex}:`, error);
@@ -202,56 +199,3 @@ export const DiffDisplay = ({ toolName, parameters, startLineNumber, }) => {
202
199
  }
203
200
  return (_jsx(Box, { flexDirection: "column", children: _jsx(Box, { paddingLeft: 2, borderLeft: true, borderColor: "cyan", flexDirection: "column", children: renderExpandedDiff() }) }));
204
201
  };
205
- // Helper function to extract text content from a React element
206
- const extractTextFromElement = (element) => {
207
- if (!React.isValidElement(element))
208
- return null;
209
- // Navigate through Box -> Text structure
210
- // Our new structure is: Box -> Text (old), Text (new), Text (|), Text (prefix), Text (content)
211
- const children = element.props.children;
212
- if (Array.isArray(children) && children.length >= 5) {
213
- const textElement = children[4]; // Fifth child should be the Text with content
214
- if (React.isValidElement(textElement)) {
215
- const textChildren = textElement.props
216
- .children;
217
- return Array.isArray(textChildren)
218
- ? textChildren.join("")
219
- : String(textChildren || "");
220
- }
221
- }
222
- return null;
223
- };
224
- const extractOldLineNumFromElement = (element) => {
225
- if (!React.isValidElement(element))
226
- return null;
227
- const children = element.props.children;
228
- if (Array.isArray(children) && children.length >= 1) {
229
- const textElement = children[0];
230
- if (React.isValidElement(textElement)) {
231
- const textChildren = textElement.props
232
- .children;
233
- const val = (Array.isArray(textChildren)
234
- ? textChildren.join("")
235
- : String(textChildren || "")).trim();
236
- return val ? parseInt(val, 10) : null;
237
- }
238
- }
239
- return null;
240
- };
241
- const extractNewLineNumFromElement = (element) => {
242
- if (!React.isValidElement(element))
243
- return null;
244
- const children = element.props.children;
245
- if (Array.isArray(children) && children.length >= 2) {
246
- const textElement = children[1];
247
- if (React.isValidElement(textElement)) {
248
- const textChildren = textElement.props
249
- .children;
250
- const val = (Array.isArray(textChildren)
251
- ? textChildren.join("")
252
- : String(textChildren || "")).trim();
253
- return val ? parseInt(val, 10) : null;
254
- }
255
- }
256
- return null;
257
- };
@@ -1 +1 @@
1
- {"version":3,"file":"FileSelector.d.ts","sourceRoot":"","sources":["../../src/components/FileSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA8HpD,CAAC"}
1
+ {"version":3,"file":"FileSelector.d.ts","sourceRoot":"","sources":["../../src/components/FileSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAuHpD,CAAC"}
@@ -26,22 +26,21 @@ export const FileSelector = ({ files, searchQuery, isLoading = false, onSelect,
26
26
  if (files.length === 0) {
27
27
  return (_jsx(Box, { flexDirection: "column", borderStyle: "single", borderColor: isLoading ? "cyan" : "yellow", borderBottom: false, borderLeft: false, borderRight: false, children: isLoading ? (_jsx(Text, { color: "cyan", bold: true, children: "Select File/Directory..." })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "yellow", children: ["No files found for \"", searchQuery, "\""] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] })) }));
28
28
  }
29
- const maxDisplay = 10;
29
+ const maxDisplay = 5;
30
30
  // Calculate display window start and end positions
31
31
  const getDisplayWindow = () => {
32
- const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(maxDisplay / 2), files.length - maxDisplay));
32
+ const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(maxDisplay / 2), Math.max(0, files.length - maxDisplay)));
33
33
  const endIndex = Math.min(files.length, startIndex + maxDisplay);
34
- const adjustedStartIndex = Math.max(0, endIndex - maxDisplay);
35
34
  return {
36
- startIndex: adjustedStartIndex,
37
- endIndex: endIndex,
38
- displayFiles: files.slice(adjustedStartIndex, endIndex),
35
+ startIndex,
36
+ endIndex,
37
+ displayFiles: files.slice(startIndex, endIndex),
39
38
  };
40
39
  };
41
- const { startIndex, endIndex, displayFiles } = getDisplayWindow();
42
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, children: [_jsxs(Text, { color: "cyan", bold: true, children: ["Select File/Directory ", searchQuery && `(filtering: "${searchQuery}")`] }), startIndex > 0 && (_jsxs(Text, { dimColor: true, children: ["... ", startIndex, " more files above"] })), displayFiles.map((fileItem, displayIndex) => {
43
- const actualIndex = startIndex + displayIndex;
44
- const isSelected = actualIndex === selectedIndex;
45
- return (_jsx(Box, { children: _jsx(Text, { color: isSelected ? "black" : "white", backgroundColor: isSelected ? "cyan" : undefined, children: fileItem.path }) }, fileItem.path));
46
- }), endIndex < files.length && (_jsxs(Text, { dimColor: true, children: ["... ", files.length - endIndex, " more files below"] })), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter/Tab to select, Escape to cancel" }) })] }));
40
+ const { startIndex, displayFiles } = getDisplayWindow();
41
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["Select File/Directory ", searchQuery && `(filtering: "${searchQuery}")`] }) }), _jsx(Box, { flexDirection: "column", children: displayFiles.map((fileItem, displayIndex) => {
42
+ const actualIndex = startIndex + displayIndex;
43
+ const isSelected = actualIndex === selectedIndex;
44
+ return (_jsx(Box, { children: _jsxs(Text, { color: isSelected ? "black" : "white", backgroundColor: isSelected ? "cyan" : undefined, children: [isSelected ? "▶ " : " ", fileItem.path] }) }, fileItem.path));
45
+ }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u2022 Enter/Tab select \u2022 Esc cancel" }) })] }));
47
46
  };
@@ -1 +1 @@
1
- {"version":3,"file":"MarketplaceDetail.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceDetail.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAwGrC,CAAC"}
1
+ {"version":3,"file":"MarketplaceDetail.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceDetail.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAmHrC,CAAC"}
@@ -40,7 +40,7 @@ export const MarketplaceDetail = () => {
40
40
  if (!marketplace) {
41
41
  return (_jsx(Box, { children: _jsx(Text, { color: "red", children: "Marketplace not found." }) }));
42
42
  }
43
- return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: marketplace.name }), marketplace.isBuiltin && _jsx(Text, { dimColor: true, children: " (Built-in)" })] }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { children: ["Source: ", JSON.stringify(marketplace.source)] }) }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { children: ["Auto-update:", " ", _jsx(Text, { color: marketplace.autoUpdate ? "green" : "red", children: marketplace.autoUpdate ? "Enabled" : "Disabled" })] }) }), state.isLoading && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "yellow", children: "\u231B Processing operation..." }) })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Marketplace Actions:" }), ACTIONS.map((action, index) => (_jsxs(Text, { color: index === selectedActionIndex
43
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: marketplace.name }), marketplace.isBuiltin && _jsx(Text, { dimColor: true, children: " (Built-in)" })] }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { children: ["Source: ", JSON.stringify(marketplace.source)] }) }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { children: ["Auto-update:", " ", _jsx(Text, { color: marketplace.autoUpdate ? "green" : "red", children: marketplace.autoUpdate ? "Enabled" : "Disabled" })] }) }), marketplace.lastUpdated && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { children: ["Last updated:", " ", _jsx(Text, { color: "cyan", children: new Date(marketplace.lastUpdated).toLocaleString() })] }) })), state.isLoading && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "yellow", children: "\u231B Processing operation..." }) })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Marketplace Actions:" }), ACTIONS.map((action, index) => (_jsxs(Text, { color: index === selectedActionIndex
44
44
  ? state.isLoading
45
45
  ? "gray"
46
46
  : "yellow"
@@ -1 +1 @@
1
- {"version":3,"file":"MarketplaceList.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,UAAU,oBAAoB;IAC5B,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA0C1D,CAAC"}
1
+ {"version":3,"file":"MarketplaceList.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,UAAU,oBAAoB;IAC5B,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgD1D,CAAC"}
@@ -11,6 +11,6 @@ export const MarketplaceList = ({ marketplaces, selectedIndex, }) => {
11
11
  : marketplace.source.source === "github"
12
12
  ? marketplace.source.repo
13
13
  : marketplace.source.url;
14
- return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: isSelected ? "cyan" : undefined, children: [isSelected ? "> " : " ", _jsx(Text, { bold: true, children: marketplace.name }), marketplace.isBuiltin && (_jsx(Text, { color: "yellow", children: " [Built-in]" }))] }) }), _jsx(Box, { marginLeft: 4, children: _jsxs(Text, { dimColor: true, children: ["Source: ", sourceStr] }) })] }, marketplace.name));
14
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: isSelected ? "cyan" : undefined, children: [isSelected ? "> " : " ", _jsx(Text, { bold: true, children: marketplace.name }), marketplace.isBuiltin && (_jsx(Text, { color: "yellow", children: " [Built-in]" }))] }) }), _jsxs(Box, { marginLeft: 4, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["Source: ", sourceStr] }), marketplace.lastUpdated && (_jsxs(Text, { dimColor: true, children: ["Last updated:", " ", new Date(marketplace.lastUpdated).toLocaleString()] }))] })] }, marketplace.name));
15
15
  }) }));
16
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,wBAAsB,IAAI,kBAuSzB;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":"AAeA,wBAAsB,IAAI,kBAkTzB;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
@@ -65,6 +65,11 @@ export async function main() {
65
65
  description: "Specify the AI model to use",
66
66
  type: "string",
67
67
  global: false,
68
+ })
69
+ .option("acp", {
70
+ description: "Run as an ACP bridge",
71
+ type: "boolean",
72
+ global: false,
68
73
  })
69
74
  .command("plugin", "Manage plugins and marketplaces", (yargs) => {
70
75
  return yargs
@@ -170,6 +175,11 @@ export async function main() {
170
175
  if (worktreeSession) {
171
176
  process.chdir(workdir);
172
177
  }
178
+ // Handle ACP mode
179
+ if (argv.acp) {
180
+ const { runAcp } = await import("./acp-cli.js");
181
+ return runAcp();
182
+ }
173
183
  // Handle restore session command
174
184
  if (argv.restore === "" ||
175
185
  (process.argv.includes("-r") && argv.restore === undefined) ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.9.6",
3
+ "version": "0.10.0",
4
4
  "description": "CLI-based code assistant powered by AI, built with React and Ink",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,7 +39,9 @@
39
39
  "react": "^19.2.4",
40
40
  "react-dom": "19.2.4",
41
41
  "yargs": "^17.7.2",
42
- "wave-agent-sdk": "0.9.6"
42
+ "@agentclientprotocol/sdk": "0.15.0",
43
+ "zod": "^3.23.8",
44
+ "wave-agent-sdk": "0.10.0"
43
45
  },
44
46
  "devDependencies": {
45
47
  "@types/react": "^19.1.8",