wave-code 0.19.2 → 0.19.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.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -10
- package/dist/stdio/agentBridge.d.ts +74 -0
- package/dist/stdio/agentBridge.d.ts.map +1 -0
- package/dist/stdio/agentBridge.js +486 -0
- package/dist/stdio/index.d.ts +4 -0
- package/dist/stdio/index.d.ts.map +1 -0
- package/dist/stdio/index.js +3 -0
- package/dist/stdio/protocol.d.ts +38 -0
- package/dist/stdio/protocol.d.ts.map +1 -0
- package/dist/stdio/protocol.js +26 -0
- package/dist/stdio/stdioServer.d.ts +34 -0
- package/dist/stdio/stdioServer.d.ts.map +1 -0
- package/dist/stdio/stdioServer.js +125 -0
- package/dist/stdio-cli.d.ts +9 -0
- package/dist/stdio-cli.d.ts.map +1 -0
- package/dist/stdio-cli.js +15 -0
- package/package.json +3 -4
- package/src/index.ts +12 -11
- package/src/stdio/agentBridge.ts +756 -0
- package/src/stdio/index.ts +7 -0
- package/src/stdio/protocol.ts +130 -0
- package/src/stdio/stdioServer.ts +163 -0
- package/src/stdio-cli.ts +18 -0
- package/dist/acp/agent.d.ts +0 -32
- package/dist/acp/agent.d.ts.map +0 -1
- package/dist/acp/agent.js +0 -1163
- package/dist/acp/index.d.ts +0 -2
- package/dist/acp/index.d.ts.map +0 -1
- package/dist/acp/index.js +0 -22
- package/dist/acp-cli.d.ts +0 -2
- package/dist/acp-cli.d.ts.map +0 -1
- package/dist/acp-cli.js +0 -4
- package/src/acp/agent.ts +0 -1501
- package/src/acp/index.ts +0 -28
- package/src/acp-cli.ts +0 -5
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,wBAAsB,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,wBAAsB,IAAI,kBAsZzB;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
|
@@ -38,6 +38,12 @@ export async function main() {
|
|
|
38
38
|
description: "Print response without interactive mode",
|
|
39
39
|
type: "string",
|
|
40
40
|
global: false,
|
|
41
|
+
})
|
|
42
|
+
.option("stdio", {
|
|
43
|
+
description: "Start in stdio mode (JSON-RPC over stdin/stdout)",
|
|
44
|
+
type: "boolean",
|
|
45
|
+
default: false,
|
|
46
|
+
global: false,
|
|
41
47
|
})
|
|
42
48
|
.option("show-stats", {
|
|
43
49
|
description: "Show timing and usage statistics in print mode",
|
|
@@ -92,11 +98,6 @@ export async function main() {
|
|
|
92
98
|
description: "MCP server configuration as JSON string (same format as .mcp.json)",
|
|
93
99
|
type: "string",
|
|
94
100
|
global: false,
|
|
95
|
-
})
|
|
96
|
-
.option("acp", {
|
|
97
|
-
description: "Run as an ACP bridge",
|
|
98
|
-
type: "boolean",
|
|
99
|
-
global: false,
|
|
100
101
|
})
|
|
101
102
|
.command("plugin", "Manage plugins and marketplaces", (yargs) => {
|
|
102
103
|
return yargs
|
|
@@ -250,11 +251,6 @@ export async function main() {
|
|
|
250
251
|
if (worktreeSession) {
|
|
251
252
|
process.chdir(workdir);
|
|
252
253
|
}
|
|
253
|
-
// Handle ACP mode
|
|
254
|
-
if (argv.acp) {
|
|
255
|
-
const { runAcp } = await import("./acp-cli.js");
|
|
256
|
-
return runAcp();
|
|
257
|
-
}
|
|
258
254
|
// Handle restore session command
|
|
259
255
|
if (argv.restore === "" ||
|
|
260
256
|
(process.argv.includes("-r") && argv.restore === undefined) ||
|
|
@@ -302,6 +298,11 @@ export async function main() {
|
|
|
302
298
|
mcpServers,
|
|
303
299
|
});
|
|
304
300
|
}
|
|
301
|
+
// Handle stdio mode
|
|
302
|
+
if (argv.stdio) {
|
|
303
|
+
const { startStdioCli } = await import("./stdio-cli.js");
|
|
304
|
+
return startStdioCli();
|
|
305
|
+
}
|
|
305
306
|
await startCli({
|
|
306
307
|
restoreSessionId: argv.restore,
|
|
307
308
|
continueLastSession: argv.continue,
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentBridge — wraps the SDK Agent and translates between the JSON-RPC-like
|
|
3
|
+
* stdio protocol and Agent method calls / callbacks.
|
|
4
|
+
*
|
|
5
|
+
* Responsibilities:
|
|
6
|
+
* - Route incoming requests to the appropriate Agent method
|
|
7
|
+
* - Translate AgentCallbacks into outgoing notifications
|
|
8
|
+
* - Implement the canUseTool permission flow over the stdio protocol
|
|
9
|
+
* - Handle config updates by destroying and recreating the Agent
|
|
10
|
+
*/
|
|
11
|
+
import { type JsonRpcError } from "./protocol.js";
|
|
12
|
+
export type NotificationEmitter = (method: string, params: unknown) => void;
|
|
13
|
+
export interface AgentBridgeOptions {
|
|
14
|
+
emit: NotificationEmitter;
|
|
15
|
+
}
|
|
16
|
+
export declare class AgentBridge {
|
|
17
|
+
private agent;
|
|
18
|
+
private pendingPermissions;
|
|
19
|
+
private permissionCounter;
|
|
20
|
+
private storedConfig;
|
|
21
|
+
private emit;
|
|
22
|
+
private pluginCore;
|
|
23
|
+
private pluginCoreWorkdir;
|
|
24
|
+
constructor(options: AgentBridgeOptions);
|
|
25
|
+
handleRequest(method: string, params: unknown): Promise<unknown>;
|
|
26
|
+
handleNotification(method: string, params: unknown): void;
|
|
27
|
+
private initialize;
|
|
28
|
+
private destroy;
|
|
29
|
+
private restoreSession;
|
|
30
|
+
private listSessions;
|
|
31
|
+
private getSessionInfo;
|
|
32
|
+
private updateConfig;
|
|
33
|
+
private sendMessage;
|
|
34
|
+
private bang;
|
|
35
|
+
private abortMessage;
|
|
36
|
+
private clearMessages;
|
|
37
|
+
private rewindToMessage;
|
|
38
|
+
private deleteQueuedMessage;
|
|
39
|
+
private getMessages;
|
|
40
|
+
private getFullMessageThread;
|
|
41
|
+
private setPermissionMode;
|
|
42
|
+
private getPermissionMode;
|
|
43
|
+
private getMcpServers;
|
|
44
|
+
private connectMcpServer;
|
|
45
|
+
private disconnectMcpServer;
|
|
46
|
+
private getSlashCommands;
|
|
47
|
+
private searchFiles;
|
|
48
|
+
private getPromptHistory;
|
|
49
|
+
private searchPromptHistory;
|
|
50
|
+
private canUseTool;
|
|
51
|
+
private getAuthStatus;
|
|
52
|
+
private login;
|
|
53
|
+
private logout;
|
|
54
|
+
private getPluginCore;
|
|
55
|
+
private listPlugins;
|
|
56
|
+
private installPlugin;
|
|
57
|
+
private uninstallPlugin;
|
|
58
|
+
private enablePlugin;
|
|
59
|
+
private disablePlugin;
|
|
60
|
+
private updatePlugin;
|
|
61
|
+
private listMarketplaces;
|
|
62
|
+
private addMarketplace;
|
|
63
|
+
private removeMarketplace;
|
|
64
|
+
private updateMarketplace;
|
|
65
|
+
private createCallbacks;
|
|
66
|
+
private findLastUserMessage;
|
|
67
|
+
private requireAgent;
|
|
68
|
+
}
|
|
69
|
+
export declare class RpcError extends Error {
|
|
70
|
+
code: number;
|
|
71
|
+
constructor(code: number, message: string);
|
|
72
|
+
toJsonRpcError(): JsonRpcError;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=agentBridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentBridge.d.ts","sourceRoot":"","sources":["../../src/stdio/agentBridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAuBH,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;AAE5E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,mBAAmB,CAAC;CAC3B;AAoCD,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,kBAAkB,CAGtB;IACJ,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,UAAU,CAAyB;IAC3C,OAAO,CAAC,iBAAiB,CAAqB;gBAElC,OAAO,EAAE,kBAAkB;IAMjC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAyItE,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;YAgB3C,UAAU;YAuCV,OAAO;YAQP,cAAc;YAMd,YAAY;IAS1B,OAAO,CAAC,cAAc;YAiBR,YAAY;YAmBZ,WAAW;YAwBX,IAAI;YAMJ,YAAY;YAMZ,aAAa;YAMb,eAAe;IAoB7B,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,WAAW;YAKL,oBAAoB;YAUpB,iBAAiB;IAM/B,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,aAAa;YAKP,gBAAgB;YAQhB,mBAAmB;IAUjC,OAAO,CAAC,gBAAgB;YAOV,WAAW;YAWX,gBAAgB;YAShB,mBAAmB;IAcjC,OAAO,CAAC,UAAU;YA0BJ,aAAa;YAWb,KAAK;YAaL,MAAM;IAQpB,OAAO,CAAC,aAAa;YAUP,WAAW;YAoBX,aAAa;YAQb,eAAe;YAKf,YAAY;YAQZ,aAAa;YAQb,YAAY;YAIZ,gBAAgB;YAIhB,cAAc;YAId,iBAAiB;YASjB,iBAAiB;IAO/B,OAAO,CAAC,eAAe;IA4EvB,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,YAAY;CAKrB;AAID,qBAAa,QAAS,SAAQ,KAAK;IACjC,IAAI,EAAE,MAAM,CAAC;gBACD,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAKzC,cAAc,IAAI,YAAY;CAG/B"}
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentBridge — wraps the SDK Agent and translates between the JSON-RPC-like
|
|
3
|
+
* stdio protocol and Agent method calls / callbacks.
|
|
4
|
+
*
|
|
5
|
+
* Responsibilities:
|
|
6
|
+
* - Route incoming requests to the appropriate Agent method
|
|
7
|
+
* - Translate AgentCallbacks into outgoing notifications
|
|
8
|
+
* - Implement the canUseTool permission flow over the stdio protocol
|
|
9
|
+
* - Handle config updates by destroying and recreating the Agent
|
|
10
|
+
*/
|
|
11
|
+
import { Agent, listSessions, searchFiles, PromptHistoryManager, AuthService, PluginCore, } from "wave-agent-sdk";
|
|
12
|
+
import { INTERNAL_ERROR as PROTOCOL_INTERNAL_ERROR, METHOD_NOT_FOUND as PROTOCOL_METHOD_NOT_FOUND, } from "./protocol.js";
|
|
13
|
+
export class AgentBridge {
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.pendingPermissions = new Map();
|
|
16
|
+
this.permissionCounter = 0;
|
|
17
|
+
this.storedConfig = {};
|
|
18
|
+
this.emit = options.emit;
|
|
19
|
+
}
|
|
20
|
+
// ── Public API ────────────────────────────────────────────────
|
|
21
|
+
async handleRequest(method, params) {
|
|
22
|
+
const p = (params ?? {});
|
|
23
|
+
switch (method) {
|
|
24
|
+
// ── Lifecycle ──
|
|
25
|
+
case "initialize":
|
|
26
|
+
return this.initialize(p);
|
|
27
|
+
case "destroy":
|
|
28
|
+
return this.destroy();
|
|
29
|
+
case "restoreSession":
|
|
30
|
+
return this.restoreSession(p.sessionId);
|
|
31
|
+
case "listSessions":
|
|
32
|
+
return this.listSessions(p.workdir);
|
|
33
|
+
case "getSessionInfo":
|
|
34
|
+
return this.getSessionInfo();
|
|
35
|
+
case "updateConfig":
|
|
36
|
+
return this.updateConfig(p);
|
|
37
|
+
// ── Messages ──
|
|
38
|
+
case "sendMessage":
|
|
39
|
+
return this.sendMessage(p);
|
|
40
|
+
case "bang":
|
|
41
|
+
return this.bang(p.command);
|
|
42
|
+
case "abortMessage":
|
|
43
|
+
return this.abortMessage();
|
|
44
|
+
case "clearMessages":
|
|
45
|
+
return this.clearMessages();
|
|
46
|
+
case "rewindToMessage":
|
|
47
|
+
return this.rewindToMessage(p.messageId);
|
|
48
|
+
case "deleteQueuedMessage":
|
|
49
|
+
return this.deleteQueuedMessage(p.index);
|
|
50
|
+
case "getMessages":
|
|
51
|
+
return this.getMessages();
|
|
52
|
+
case "getFullMessageThread":
|
|
53
|
+
return this.getFullMessageThread();
|
|
54
|
+
// ── Permissions ──
|
|
55
|
+
case "setPermissionMode":
|
|
56
|
+
return this.setPermissionMode(p.mode);
|
|
57
|
+
case "getPermissionMode":
|
|
58
|
+
return this.getPermissionMode();
|
|
59
|
+
// ── MCP ──
|
|
60
|
+
case "getMcpServers":
|
|
61
|
+
return this.getMcpServers();
|
|
62
|
+
case "connectMcpServer":
|
|
63
|
+
return this.connectMcpServer(p.serverName);
|
|
64
|
+
case "disconnectMcpServer":
|
|
65
|
+
return this.disconnectMcpServer(p.serverName);
|
|
66
|
+
// ── Commands ──
|
|
67
|
+
case "getSlashCommands":
|
|
68
|
+
return this.getSlashCommands();
|
|
69
|
+
// ── File / History ──
|
|
70
|
+
case "searchFiles":
|
|
71
|
+
return this.searchFiles(p);
|
|
72
|
+
case "getPromptHistory":
|
|
73
|
+
return this.getPromptHistory(p.workdir);
|
|
74
|
+
case "searchPromptHistory":
|
|
75
|
+
return this.searchPromptHistory(p.query, p.workdir);
|
|
76
|
+
// ── Auth ──
|
|
77
|
+
case "getAuthStatus":
|
|
78
|
+
return this.getAuthStatus();
|
|
79
|
+
case "login":
|
|
80
|
+
return this.login(p.serverUrl);
|
|
81
|
+
case "logout":
|
|
82
|
+
return this.logout();
|
|
83
|
+
// ── Plugins ──
|
|
84
|
+
case "listPlugins":
|
|
85
|
+
return this.listPlugins(p.workdir);
|
|
86
|
+
case "installPlugin":
|
|
87
|
+
return this.installPlugin(p.pluginId, p.scope, p.workdir);
|
|
88
|
+
case "uninstallPlugin":
|
|
89
|
+
return this.uninstallPlugin(p.pluginId, p.workdir);
|
|
90
|
+
case "enablePlugin":
|
|
91
|
+
return this.enablePlugin(p.pluginId, p.scope, p.workdir);
|
|
92
|
+
case "disablePlugin":
|
|
93
|
+
return this.disablePlugin(p.pluginId, p.scope, p.workdir);
|
|
94
|
+
case "updatePlugin":
|
|
95
|
+
return this.updatePlugin(p.pluginId, p.workdir);
|
|
96
|
+
case "listMarketplaces":
|
|
97
|
+
return this.listMarketplaces(p.workdir);
|
|
98
|
+
case "addMarketplace":
|
|
99
|
+
return this.addMarketplace(p.input, p.scope, p.workdir);
|
|
100
|
+
case "removeMarketplace":
|
|
101
|
+
return this.removeMarketplace(p.name, p.scope, p.workdir);
|
|
102
|
+
case "updateMarketplace":
|
|
103
|
+
return this.updateMarketplace(p.name, p.workdir);
|
|
104
|
+
default:
|
|
105
|
+
throw new RpcError(PROTOCOL_METHOD_NOT_FOUND, `Method not found: ${method}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
handleNotification(method, params) {
|
|
109
|
+
if (method === "permissionResponse") {
|
|
110
|
+
const p = params;
|
|
111
|
+
const resolve = this.pendingPermissions.get(p.requestId);
|
|
112
|
+
if (resolve) {
|
|
113
|
+
this.pendingPermissions.delete(p.requestId);
|
|
114
|
+
resolve(p.decision);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// ── Lifecycle ─────────────────────────────────────────────────
|
|
119
|
+
async initialize(params) {
|
|
120
|
+
// Merge with stored config (CLI defaults can be overridden by client)
|
|
121
|
+
this.storedConfig = { ...this.storedConfig, ...params };
|
|
122
|
+
const callbacks = this.createCallbacks();
|
|
123
|
+
const options = {
|
|
124
|
+
callbacks,
|
|
125
|
+
workdir: params.workdir,
|
|
126
|
+
restoreSessionId: params.restoreSessionId,
|
|
127
|
+
apiKey: params.apiKey,
|
|
128
|
+
baseURL: params.baseURL,
|
|
129
|
+
defaultHeaders: params.defaultHeaders,
|
|
130
|
+
model: params.model,
|
|
131
|
+
fastModel: params.fastModel,
|
|
132
|
+
language: params.language,
|
|
133
|
+
permissionMode: params.permissionMode,
|
|
134
|
+
tools: params.tools,
|
|
135
|
+
allowedTools: params.allowedTools,
|
|
136
|
+
disallowedTools: params.disallowedTools,
|
|
137
|
+
plugins: params.pluginDirs?.map((path) => ({ type: "local", path })),
|
|
138
|
+
mcpServers: params.mcpServers,
|
|
139
|
+
canUseTool: (context) => this.canUseTool(context),
|
|
140
|
+
};
|
|
141
|
+
this.agent = await Agent.create(options);
|
|
142
|
+
return {
|
|
143
|
+
sessionId: this.agent.sessionId,
|
|
144
|
+
workingDirectory: this.agent.workingDirectory,
|
|
145
|
+
permissionMode: this.agent.getPermissionMode(),
|
|
146
|
+
latestTotalTokens: this.agent.latestTotalTokens,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
async destroy() {
|
|
150
|
+
if (this.agent) {
|
|
151
|
+
await this.agent.destroy();
|
|
152
|
+
this.agent = undefined;
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
async restoreSession(sessionId) {
|
|
157
|
+
this.requireAgent();
|
|
158
|
+
await this.agent.restoreSession(sessionId);
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
async listSessions(workdir) {
|
|
162
|
+
const sessions = await listSessions(workdir || this.agent?.workingDirectory || process.cwd());
|
|
163
|
+
return { sessions };
|
|
164
|
+
}
|
|
165
|
+
getSessionInfo() {
|
|
166
|
+
this.requireAgent();
|
|
167
|
+
return {
|
|
168
|
+
sessionId: this.agent.sessionId,
|
|
169
|
+
workingDirectory: this.agent.workingDirectory,
|
|
170
|
+
latestTotalTokens: this.agent.latestTotalTokens,
|
|
171
|
+
permissionMode: this.agent.getPermissionMode(),
|
|
172
|
+
availableTools: this.agent.getAvailableToolNames(),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
async updateConfig(params) {
|
|
176
|
+
this.requireAgent();
|
|
177
|
+
const currentSessionId = this.agent.sessionId;
|
|
178
|
+
// Merge new config into stored config
|
|
179
|
+
this.storedConfig = { ...this.storedConfig, ...params };
|
|
180
|
+
// Destroy and recreate
|
|
181
|
+
await this.agent.destroy();
|
|
182
|
+
this.agent = undefined;
|
|
183
|
+
await this.initialize({
|
|
184
|
+
...this.storedConfig,
|
|
185
|
+
restoreSessionId: currentSessionId,
|
|
186
|
+
});
|
|
187
|
+
return { sessionId: this.agent.sessionId };
|
|
188
|
+
}
|
|
189
|
+
// ── Messages ──────────────────────────────────────────────────
|
|
190
|
+
async sendMessage(params) {
|
|
191
|
+
this.requireAgent();
|
|
192
|
+
if (params.force) {
|
|
193
|
+
this.agent.abortMessage();
|
|
194
|
+
}
|
|
195
|
+
// Save prompt to history (mirrors VSCE chatSession.ts:236-242)
|
|
196
|
+
try {
|
|
197
|
+
await PromptHistoryManager.addEntry(params.text, this.agent.sessionId, {}, this.agent.workingDirectory);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// Best-effort; don't block message sending on history save failure
|
|
201
|
+
}
|
|
202
|
+
await this.agent.sendMessage(params.text, params.images);
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
async bang(command) {
|
|
206
|
+
this.requireAgent();
|
|
207
|
+
await this.agent.bang(command);
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
async abortMessage() {
|
|
211
|
+
this.requireAgent();
|
|
212
|
+
this.agent.abortMessage();
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
async clearMessages() {
|
|
216
|
+
this.requireAgent();
|
|
217
|
+
this.agent.clearMessages();
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
async rewindToMessage(messageId) {
|
|
221
|
+
this.requireAgent();
|
|
222
|
+
const { messages } = await this.agent.getFullMessageThread();
|
|
223
|
+
const index = messages.findIndex((m) => m.id === messageId);
|
|
224
|
+
if (index === -1) {
|
|
225
|
+
throw new RpcError(PROTOCOL_INTERNAL_ERROR, `Message not found: ${messageId}`);
|
|
226
|
+
}
|
|
227
|
+
const message = messages[index];
|
|
228
|
+
const textBlock = message.blocks.find((b) => b.type === "text");
|
|
229
|
+
await this.agent.truncateHistory(index);
|
|
230
|
+
return { inputContent: textBlock?.content || "" };
|
|
231
|
+
}
|
|
232
|
+
deleteQueuedMessage(index) {
|
|
233
|
+
this.requireAgent();
|
|
234
|
+
this.agent.removeQueuedMessage(index);
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
getMessages() {
|
|
238
|
+
this.requireAgent();
|
|
239
|
+
return { messages: this.agent.messages };
|
|
240
|
+
}
|
|
241
|
+
async getFullMessageThread() {
|
|
242
|
+
this.requireAgent();
|
|
243
|
+
return this.agent.getFullMessageThread();
|
|
244
|
+
}
|
|
245
|
+
// ── Permissions ───────────────────────────────────────────────
|
|
246
|
+
async setPermissionMode(mode) {
|
|
247
|
+
this.requireAgent();
|
|
248
|
+
await this.agent.setPermissionMode(mode);
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
getPermissionMode() {
|
|
252
|
+
this.requireAgent();
|
|
253
|
+
return { mode: this.agent.getPermissionMode() };
|
|
254
|
+
}
|
|
255
|
+
// ── MCP ───────────────────────────────────────────────────────
|
|
256
|
+
getMcpServers() {
|
|
257
|
+
this.requireAgent();
|
|
258
|
+
return { servers: this.agent.getMcpServers() };
|
|
259
|
+
}
|
|
260
|
+
async connectMcpServer(serverName) {
|
|
261
|
+
this.requireAgent();
|
|
262
|
+
const success = await this.agent.connectMcpServer(serverName);
|
|
263
|
+
return { success };
|
|
264
|
+
}
|
|
265
|
+
async disconnectMcpServer(serverName) {
|
|
266
|
+
this.requireAgent();
|
|
267
|
+
const success = await this.agent.disconnectMcpServer(serverName);
|
|
268
|
+
return { success };
|
|
269
|
+
}
|
|
270
|
+
// ── Commands ──────────────────────────────────────────────────
|
|
271
|
+
getSlashCommands() {
|
|
272
|
+
this.requireAgent();
|
|
273
|
+
return { commands: this.agent.getSlashCommands() };
|
|
274
|
+
}
|
|
275
|
+
// ── File / History ────────────────────────────────────────────
|
|
276
|
+
async searchFiles(params) {
|
|
277
|
+
const files = await searchFiles(params.query, {
|
|
278
|
+
maxResults: params.maxResults,
|
|
279
|
+
workingDirectory: params.workdir || this.agent?.workingDirectory || process.cwd(),
|
|
280
|
+
});
|
|
281
|
+
return { files };
|
|
282
|
+
}
|
|
283
|
+
async getPromptHistory(workdir) {
|
|
284
|
+
const history = await PromptHistoryManager.getHistory({
|
|
285
|
+
workdir: workdir || this.agent?.workingDirectory,
|
|
286
|
+
});
|
|
287
|
+
return { history };
|
|
288
|
+
}
|
|
289
|
+
async searchPromptHistory(query, workdir) {
|
|
290
|
+
const history = await PromptHistoryManager.searchHistory(query, {
|
|
291
|
+
workdir: workdir || this.agent?.workingDirectory,
|
|
292
|
+
});
|
|
293
|
+
return { history };
|
|
294
|
+
}
|
|
295
|
+
// ── canUseTool flow ───────────────────────────────────────────
|
|
296
|
+
canUseTool(context) {
|
|
297
|
+
const requestId = `perm_${++this.permissionCounter}`;
|
|
298
|
+
return new Promise((resolve) => {
|
|
299
|
+
this.pendingPermissions.set(requestId, resolve);
|
|
300
|
+
this.emit("permissionRequest", { requestId, context });
|
|
301
|
+
// 5-minute timeout → auto-deny
|
|
302
|
+
setTimeout(() => {
|
|
303
|
+
if (this.pendingPermissions.has(requestId)) {
|
|
304
|
+
this.pendingPermissions.delete(requestId);
|
|
305
|
+
resolve({
|
|
306
|
+
behavior: "deny",
|
|
307
|
+
message: "Permission request timed out",
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}, 5 * 60 * 1000);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
// ── Auth ─────────────────────────────────────────────────────
|
|
314
|
+
async getAuthStatus() {
|
|
315
|
+
const authService = AuthService.getInstance();
|
|
316
|
+
return {
|
|
317
|
+
isAuthenticated: authService.isSSOAuthenticated(),
|
|
318
|
+
user: authService.getAuthUser(),
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
async login(serverUrl) {
|
|
322
|
+
const authService = AuthService.getInstance();
|
|
323
|
+
await authService.login({
|
|
324
|
+
onAuthUrl: (url) => {
|
|
325
|
+
this.emit("authUrl", { url });
|
|
326
|
+
},
|
|
327
|
+
serverUrl,
|
|
328
|
+
});
|
|
329
|
+
return { user: authService.getAuthUser() };
|
|
330
|
+
}
|
|
331
|
+
async logout() {
|
|
332
|
+
const authService = AuthService.getInstance();
|
|
333
|
+
await authService.clearAuth();
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
// ── Plugins ──────────────────────────────────────────────────
|
|
337
|
+
getPluginCore(workdir) {
|
|
338
|
+
const resolvedWorkdir = workdir || this.agent?.workingDirectory || process.cwd();
|
|
339
|
+
if (!this.pluginCore || this.pluginCoreWorkdir !== resolvedWorkdir) {
|
|
340
|
+
this.pluginCore = new PluginCore(resolvedWorkdir);
|
|
341
|
+
this.pluginCoreWorkdir = resolvedWorkdir;
|
|
342
|
+
}
|
|
343
|
+
return this.pluginCore;
|
|
344
|
+
}
|
|
345
|
+
async listPlugins(workdir) {
|
|
346
|
+
const core = this.getPluginCore(workdir);
|
|
347
|
+
const { plugins, mergedEnabled } = await core.listPlugins();
|
|
348
|
+
return {
|
|
349
|
+
plugins: plugins.map((p) => {
|
|
350
|
+
const pluginId = `${p.name}@${p.marketplace}`;
|
|
351
|
+
return {
|
|
352
|
+
id: pluginId,
|
|
353
|
+
name: p.name,
|
|
354
|
+
description: p.description,
|
|
355
|
+
marketplace: p.marketplace,
|
|
356
|
+
installed: p.installed,
|
|
357
|
+
version: p.version,
|
|
358
|
+
enabled: mergedEnabled[pluginId] !== false,
|
|
359
|
+
scope: p.scope,
|
|
360
|
+
};
|
|
361
|
+
}),
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
async installPlugin(pluginId, scope, workdir) {
|
|
365
|
+
return this.getPluginCore(workdir).installPlugin(pluginId, scope);
|
|
366
|
+
}
|
|
367
|
+
async uninstallPlugin(pluginId, workdir) {
|
|
368
|
+
await this.getPluginCore(workdir).uninstallPlugin(pluginId);
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
async enablePlugin(pluginId, scope, workdir) {
|
|
372
|
+
return this.getPluginCore(workdir).enablePlugin(pluginId, scope);
|
|
373
|
+
}
|
|
374
|
+
async disablePlugin(pluginId, scope, workdir) {
|
|
375
|
+
return this.getPluginCore(workdir).disablePlugin(pluginId, scope);
|
|
376
|
+
}
|
|
377
|
+
async updatePlugin(pluginId, workdir) {
|
|
378
|
+
return this.getPluginCore(workdir).updatePlugin(pluginId);
|
|
379
|
+
}
|
|
380
|
+
async listMarketplaces(workdir) {
|
|
381
|
+
return this.getPluginCore(workdir).listMarketplaces();
|
|
382
|
+
}
|
|
383
|
+
async addMarketplace(input, scope, workdir) {
|
|
384
|
+
return this.getPluginCore(workdir).addMarketplace(input, scope);
|
|
385
|
+
}
|
|
386
|
+
async removeMarketplace(name, scope, workdir) {
|
|
387
|
+
await this.getPluginCore(workdir).removeMarketplace(name, scope);
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
async updateMarketplace(name, workdir) {
|
|
391
|
+
await this.getPluginCore(workdir).updateMarketplace(name);
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
// ── Callbacks → Notifications ─────────────────────────────────
|
|
395
|
+
createCallbacks() {
|
|
396
|
+
return {
|
|
397
|
+
onMessagesChange: (messages) => {
|
|
398
|
+
this.emit("messagesChange", { messages });
|
|
399
|
+
},
|
|
400
|
+
onUserMessageAdded: () => {
|
|
401
|
+
const msg = this.findLastUserMessage();
|
|
402
|
+
if (msg)
|
|
403
|
+
this.emit("userMessageAdded", { message: msg });
|
|
404
|
+
},
|
|
405
|
+
onAssistantMessageAdded: (messageId) => {
|
|
406
|
+
const msg = this.agent?.messages.find((m) => m.id === messageId);
|
|
407
|
+
if (msg)
|
|
408
|
+
this.emit("assistantMessageAdded", { message: msg });
|
|
409
|
+
},
|
|
410
|
+
onAssistantContentUpdated: (params) => {
|
|
411
|
+
this.emit("assistantContentUpdated", params);
|
|
412
|
+
},
|
|
413
|
+
onAssistantReasoningUpdated: (params) => {
|
|
414
|
+
this.emit("assistantReasoningUpdated", params);
|
|
415
|
+
},
|
|
416
|
+
onToolBlockUpdated: (params) => {
|
|
417
|
+
this.emit("toolBlockUpdated", params);
|
|
418
|
+
},
|
|
419
|
+
onErrorBlockAdded: (error) => {
|
|
420
|
+
this.emit("errorBlockAdded", { error });
|
|
421
|
+
},
|
|
422
|
+
onLoadingChange: (loading) => {
|
|
423
|
+
this.emit("loadingChange", {
|
|
424
|
+
loading,
|
|
425
|
+
latestTotalTokens: this.agent?.latestTotalTokens,
|
|
426
|
+
});
|
|
427
|
+
},
|
|
428
|
+
onCommandRunningChange: (running) => {
|
|
429
|
+
this.emit("commandRunningChange", { running });
|
|
430
|
+
},
|
|
431
|
+
onQueuedMessagesChange: (messages) => {
|
|
432
|
+
this.emit("queuedMessagesChange", { messages });
|
|
433
|
+
},
|
|
434
|
+
onTasksChange: (tasks) => {
|
|
435
|
+
this.emit("tasksChange", { tasks });
|
|
436
|
+
},
|
|
437
|
+
onSessionIdChange: (sessionId) => {
|
|
438
|
+
this.emit("sessionIdChange", { sessionId });
|
|
439
|
+
},
|
|
440
|
+
onPermissionModeChange: (mode) => {
|
|
441
|
+
this.emit("permissionModeChange", { mode });
|
|
442
|
+
},
|
|
443
|
+
onMcpServersChange: (servers) => {
|
|
444
|
+
this.emit("mcpServersChange", { servers });
|
|
445
|
+
},
|
|
446
|
+
onAddBangMessage: () => {
|
|
447
|
+
this.emit("bangMessageAdded", {});
|
|
448
|
+
},
|
|
449
|
+
onUpdateBangMessage: () => {
|
|
450
|
+
this.emit("bangMessageUpdated", {});
|
|
451
|
+
},
|
|
452
|
+
onCompleteBangMessage: () => {
|
|
453
|
+
this.emit("bangMessageCompleted", {});
|
|
454
|
+
},
|
|
455
|
+
onNotificationMessageAdded: (params) => {
|
|
456
|
+
const msg = this.agent?.messages.find((m) => m.role === "user" &&
|
|
457
|
+
m.blocks.some((b) => b.type === "task_notification" &&
|
|
458
|
+
b.taskId === params.taskId));
|
|
459
|
+
this.emit("notificationMessageAdded", {
|
|
460
|
+
...params,
|
|
461
|
+
message: msg,
|
|
462
|
+
});
|
|
463
|
+
},
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
findLastUserMessage() {
|
|
467
|
+
const userMessages = this.agent?.messages.filter((m) => m.role === "user") ?? [];
|
|
468
|
+
return userMessages[userMessages.length - 1];
|
|
469
|
+
}
|
|
470
|
+
// ── Utils ─────────────────────────────────────────────────────
|
|
471
|
+
requireAgent() {
|
|
472
|
+
if (!this.agent) {
|
|
473
|
+
throw new RpcError(PROTOCOL_INTERNAL_ERROR, "Agent not initialized");
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
// ── Error class for protocol errors ─────────────────────────────
|
|
478
|
+
export class RpcError extends Error {
|
|
479
|
+
constructor(code, message) {
|
|
480
|
+
super(message);
|
|
481
|
+
this.code = code;
|
|
482
|
+
}
|
|
483
|
+
toJsonRpcError() {
|
|
484
|
+
return { code: this.code, message: this.message };
|
|
485
|
+
}
|
|
486
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stdio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EACL,WAAW,EACX,KAAK,kBAAkB,EACvB,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAC1B,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0-compatible protocol types for stdio communication.
|
|
3
|
+
*
|
|
4
|
+
* Each line on stdin/stdout is one JSON object.
|
|
5
|
+
* - Requests have `id` (number|string) and expect a response.
|
|
6
|
+
* - Responses match the request `id` with either `result` or `error`.
|
|
7
|
+
* - Notifications have no `id` and expect no response.
|
|
8
|
+
*/
|
|
9
|
+
export interface JsonRpcRequest {
|
|
10
|
+
id: number | string;
|
|
11
|
+
method: string;
|
|
12
|
+
params?: unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface JsonRpcResponse {
|
|
15
|
+
id: number | string | null;
|
|
16
|
+
result?: unknown;
|
|
17
|
+
error?: JsonRpcError;
|
|
18
|
+
}
|
|
19
|
+
export interface JsonRpcError {
|
|
20
|
+
code: number;
|
|
21
|
+
message: string;
|
|
22
|
+
data?: unknown;
|
|
23
|
+
}
|
|
24
|
+
export interface JsonRpcNotification {
|
|
25
|
+
method: string;
|
|
26
|
+
params?: unknown;
|
|
27
|
+
}
|
|
28
|
+
export declare const PARSE_ERROR = -32700;
|
|
29
|
+
export declare const INVALID_REQUEST = -32600;
|
|
30
|
+
export declare const METHOD_NOT_FOUND = -32601;
|
|
31
|
+
export declare const INVALID_PARAMS = -32602;
|
|
32
|
+
export declare const INTERNAL_ERROR = -32603;
|
|
33
|
+
export type RequestMethod = "initialize" | "destroy" | "restoreSession" | "listSessions" | "getSessionInfo" | "sendMessage" | "bang" | "abortMessage" | "clearMessages" | "rewindToMessage" | "deleteQueuedMessage" | "getMessages" | "getFullMessageThread" | "setPermissionMode" | "getPermissionMode" | "getMcpServers" | "connectMcpServer" | "disconnectMcpServer" | "getSlashCommands" | "searchFiles" | "getPromptHistory" | "searchPromptHistory" | "updateConfig" | "getAuthStatus" | "login" | "logout" | "listPlugins" | "installPlugin" | "uninstallPlugin" | "enablePlugin" | "disablePlugin" | "updatePlugin" | "listMarketplaces" | "addMarketplace" | "removeMarketplace" | "updateMarketplace";
|
|
34
|
+
export type ClientNotificationMethod = "permissionResponse";
|
|
35
|
+
export type ServerNotificationMethod = "messagesChange" | "userMessageAdded" | "assistantMessageAdded" | "assistantContentUpdated" | "assistantReasoningUpdated" | "toolBlockUpdated" | "errorBlockAdded" | "loadingChange" | "commandRunningChange" | "queuedMessagesChange" | "tasksChange" | "sessionIdChange" | "permissionModeChange" | "mcpServersChange" | "bangMessageAdded" | "bangMessageUpdated" | "bangMessageCompleted" | "notificationMessageAdded" | "permissionRequest" | "authUrl";
|
|
36
|
+
export declare function isRequest(msg: unknown): msg is JsonRpcRequest;
|
|
37
|
+
export declare function isNotification(msg: unknown): msg is JsonRpcNotification;
|
|
38
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/stdio/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAID,eAAO,MAAM,WAAW,SAAS,CAAC;AAClC,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,eAAO,MAAM,cAAc,SAAS,CAAC;AAIrC,MAAM,MAAM,aAAa,GACrB,YAAY,GACZ,SAAS,GACT,gBAAgB,GAChB,cAAc,GACd,gBAAgB,GAChB,aAAa,GACb,MAAM,GACN,cAAc,GACd,eAAe,GACf,iBAAiB,GACjB,qBAAqB,GACrB,aAAa,GACb,sBAAsB,GACtB,mBAAmB,GACnB,mBAAmB,GACnB,eAAe,GACf,kBAAkB,GAClB,qBAAqB,GACrB,kBAAkB,GAClB,aAAa,GACb,kBAAkB,GAClB,qBAAqB,GACrB,cAAc,GAEd,eAAe,GACf,OAAO,GACP,QAAQ,GAER,aAAa,GACb,eAAe,GACf,iBAAiB,GACjB,cAAc,GACd,eAAe,GACf,cAAc,GACd,kBAAkB,GAClB,gBAAgB,GAChB,mBAAmB,GACnB,mBAAmB,CAAC;AAIxB,MAAM,MAAM,wBAAwB,GAAG,oBAAoB,CAAC;AAI5D,MAAM,MAAM,wBAAwB,GAChC,gBAAgB,GAChB,kBAAkB,GAClB,uBAAuB,GACvB,yBAAyB,GACzB,2BAA2B,GAC3B,kBAAkB,GAClB,iBAAiB,GACjB,eAAe,GACf,sBAAsB,GACtB,sBAAsB,GACtB,aAAa,GACb,iBAAiB,GACjB,sBAAsB,GACtB,kBAAkB,GAClB,kBAAkB,GAClB,oBAAoB,GACpB,sBAAsB,GACtB,0BAA0B,GAC1B,mBAAmB,GACnB,SAAS,CAAC;AAId,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,cAAc,CAS7D;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,mBAAmB,CAIvE"}
|