wave-code 0.19.1 → 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.
@@ -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"}
@@ -0,0 +1,26 @@
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
+ // ── Error codes (JSON-RPC 2.0 standard) ────────────────────────
10
+ export const PARSE_ERROR = -32700;
11
+ export const INVALID_REQUEST = -32600;
12
+ export const METHOD_NOT_FOUND = -32601;
13
+ export const INVALID_PARAMS = -32602;
14
+ export const INTERNAL_ERROR = -32603;
15
+ // ── Helper: is this a request (has id)? ─────────────────────────
16
+ export function isRequest(msg) {
17
+ return (typeof msg === "object" &&
18
+ msg !== null &&
19
+ "method" in msg &&
20
+ "id" in msg &&
21
+ (typeof msg.id === "number" ||
22
+ typeof msg.id === "string"));
23
+ }
24
+ export function isNotification(msg) {
25
+ return (typeof msg === "object" && msg !== null && "method" in msg && !("id" in msg));
26
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * StdioServer — reads JSON-RPC messages from stdin, dispatches to AgentBridge,
3
+ * and writes responses / notifications to stdout.
4
+ *
5
+ * One JSON object per line. stderr is reserved for logger output.
6
+ */
7
+ import type { Readable, Writable } from "stream";
8
+ import { AgentBridge, type AgentBridgeOptions } from "./agentBridge.js";
9
+ export interface StdioServerOptions {
10
+ input?: Readable;
11
+ output?: Writable;
12
+ bridgeOptions?: AgentBridgeOptions;
13
+ }
14
+ export declare class StdioServer {
15
+ private rl;
16
+ private bridge;
17
+ private input;
18
+ private output;
19
+ private started;
20
+ constructor(options?: StdioServerOptions);
21
+ get agentBridge(): AgentBridge;
22
+ start(): void;
23
+ stop(): void;
24
+ handleLine(line: string): Promise<void>;
25
+ private handleRequest;
26
+ private handleNotification;
27
+ sendResponse(id: number | string | null, result?: unknown, error?: {
28
+ code: number;
29
+ message: string;
30
+ }): void;
31
+ sendNotification(method: string, params?: unknown): void;
32
+ private write;
33
+ }
34
+ //# sourceMappingURL=stdioServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdioServer.d.ts","sourceRoot":"","sources":["../../src/stdio/stdioServer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAYxE,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACpC;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAAiC;IAC3C,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE,kBAAuB;IAS5C,IAAI,WAAW,IAAI,WAAW,CAE7B;IAED,KAAK,IAAI,IAAI;IAwBb,IAAI,IAAI,IAAI;IAMN,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAoC/B,aAAa;IAc3B,OAAO,CAAC,kBAAkB;IAa1B,YAAY,CACV,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAC1B,MAAM,CAAC,EAAE,OAAO,EAChB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GACxC,IAAI;IAUP,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI;IAKxD,OAAO,CAAC,KAAK;CAGd"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * StdioServer — reads JSON-RPC messages from stdin, dispatches to AgentBridge,
3
+ * and writes responses / notifications to stdout.
4
+ *
5
+ * One JSON object per line. stderr is reserved for logger output.
6
+ */
7
+ import readline from "readline";
8
+ import { AgentBridge } from "./agentBridge.js";
9
+ import { PARSE_ERROR, INVALID_REQUEST, INTERNAL_ERROR, isRequest, isNotification, } from "./protocol.js";
10
+ export class StdioServer {
11
+ constructor(options = {}) {
12
+ this.started = false;
13
+ this.input = options.input ?? process.stdin;
14
+ this.output = options.output ?? process.stdout;
15
+ this.bridge = new AgentBridge({
16
+ ...options.bridgeOptions,
17
+ emit: (method, params) => this.sendNotification(method, params),
18
+ });
19
+ }
20
+ get agentBridge() {
21
+ return this.bridge;
22
+ }
23
+ start() {
24
+ if (this.started)
25
+ return;
26
+ this.started = true;
27
+ this.rl = readline.createInterface({
28
+ input: this.input,
29
+ crlfDelay: Infinity,
30
+ });
31
+ this.rl.on("line", (line) => {
32
+ this.handleLine(line).catch((err) => {
33
+ // Should never reach here — handleLine catches internally
34
+ this.sendResponse(null, undefined, {
35
+ code: INTERNAL_ERROR,
36
+ message: `Unhandled error: ${err.message}`,
37
+ });
38
+ });
39
+ });
40
+ this.rl.on("close", () => {
41
+ this.started = false;
42
+ });
43
+ }
44
+ stop() {
45
+ this.rl?.close();
46
+ this.rl = undefined;
47
+ this.started = false;
48
+ }
49
+ async handleLine(line) {
50
+ const trimmed = line.trim();
51
+ if (!trimmed)
52
+ return;
53
+ let msg;
54
+ try {
55
+ msg = JSON.parse(trimmed);
56
+ }
57
+ catch {
58
+ this.sendResponse(null, undefined, {
59
+ code: PARSE_ERROR,
60
+ message: "Parse error: invalid JSON",
61
+ });
62
+ return;
63
+ }
64
+ if (isRequest(msg)) {
65
+ await this.handleRequest(msg);
66
+ }
67
+ else if (isNotification(msg)) {
68
+ this.handleNotification(msg);
69
+ }
70
+ else {
71
+ // Echo back the id if the message has one, otherwise null
72
+ const id = typeof msg === "object" &&
73
+ msg !== null &&
74
+ "id" in msg &&
75
+ (typeof msg.id === "number" ||
76
+ typeof msg.id === "string")
77
+ ? msg.id
78
+ : null;
79
+ this.sendResponse(id, undefined, {
80
+ code: INVALID_REQUEST,
81
+ message: "Invalid request: must have 'method' field",
82
+ });
83
+ }
84
+ }
85
+ async handleRequest(msg) {
86
+ try {
87
+ const result = await this.bridge.handleRequest(msg.method, msg.params);
88
+ this.sendResponse(msg.id, result);
89
+ }
90
+ catch (err) {
91
+ const code = err && typeof err === "object" && "code" in err
92
+ ? err.code
93
+ : INTERNAL_ERROR;
94
+ const message = err instanceof Error ? err.message : String(err);
95
+ this.sendResponse(msg.id, undefined, { code, message });
96
+ }
97
+ }
98
+ handleNotification(msg) {
99
+ try {
100
+ this.bridge.handleNotification(msg.method, msg.params);
101
+ }
102
+ catch (err) {
103
+ // Notifications don't get responses, but we log to stderr
104
+ process.stderr.write(`Error handling notification ${msg.method}: ${err.message}\n`);
105
+ }
106
+ }
107
+ // ── Output helpers ────────────────────────────────────────────
108
+ sendResponse(id, result, error) {
109
+ const response = { id };
110
+ if (error) {
111
+ response.error = error;
112
+ }
113
+ else {
114
+ response.result = result ?? null;
115
+ }
116
+ this.write(response);
117
+ }
118
+ sendNotification(method, params) {
119
+ const notification = { method, params };
120
+ this.write(notification);
121
+ }
122
+ write(obj) {
123
+ this.output.write(JSON.stringify(obj) + "\n");
124
+ }
125
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * stdio-cli.ts — Entry point for `wave --stdio` mode.
3
+ *
4
+ * Starts a StdioServer that reads JSON-RPC messages from stdin and writes
5
+ * responses/notifications to stdout. The server creates an Agent lazily when
6
+ * the client sends an "initialize" request.
7
+ */
8
+ export declare function startStdioCli(): Promise<void>;
9
+ //# sourceMappingURL=stdio-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-cli.d.ts","sourceRoot":"","sources":["../src/stdio-cli.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAOnD"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * stdio-cli.ts — Entry point for `wave --stdio` mode.
3
+ *
4
+ * Starts a StdioServer that reads JSON-RPC messages from stdin and writes
5
+ * responses/notifications to stdout. The server creates an Agent lazily when
6
+ * the client sends an "initialize" request.
7
+ */
8
+ import { StdioServer } from "./stdio/stdioServer.js";
9
+ export async function startStdioCli() {
10
+ const server = new StdioServer();
11
+ server.start();
12
+ // Keep the process alive — readline on stdin handles the event loop.
13
+ // When stdin closes (EOF), the readline interface emits 'close' and
14
+ // the process will exit naturally.
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.19.1",
3
+ "version": "0.19.3",
4
4
  "description": "CLI-based code assistant powered by AI, built with React and Ink",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,7 +29,6 @@
29
29
  "README.md"
30
30
  ],
31
31
  "dependencies": {
32
- "@agentclientprotocol/sdk": "0.17.1",
33
32
  "chalk": "^5.6.2",
34
33
  "diff": "^8.0.2",
35
34
  "glob": "^13.0.0",
@@ -42,7 +41,7 @@
42
41
  "semver": "^7.7.4",
43
42
  "yargs": "^17.7.2",
44
43
  "zod": "^3.23.8",
45
- "wave-agent-sdk": "0.19.1"
44
+ "wave-agent-sdk": "0.19.3"
46
45
  },
47
46
  "devDependencies": {
48
47
  "@types/react": "^19.1.8",
@@ -61,7 +60,7 @@
61
60
  "react": ">=18.0.0"
62
61
  },
63
62
  "engines": {
64
- "node": ">=22.0.0"
63
+ "node": ">=20"
65
64
  },
66
65
  "license": "MIT",
67
66
  "scripts": {
@@ -125,12 +125,7 @@ export const LoginCommand: React.FC<LoginCommandProps> = ({ onCancel }) => {
125
125
 
126
126
  const isAuthenticated = authService.isSSOAuthenticated();
127
127
  const token = authService.getSSOToken();
128
- let serverUrl: string | undefined;
129
- try {
130
- serverUrl = authService.getServerUrl();
131
- } catch {
132
- // serverUrl not configured, skip display
133
- }
128
+ const serverUrl = authService.getServerUrl();
134
129
 
135
130
  const truncatedToken =
136
131
  token && token.length > 14
package/src/index.ts CHANGED
@@ -47,6 +47,12 @@ export async function main() {
47
47
  type: "string",
48
48
  global: false,
49
49
  })
50
+ .option("stdio", {
51
+ description: "Start in stdio mode (JSON-RPC over stdin/stdout)",
52
+ type: "boolean",
53
+ default: false,
54
+ global: false,
55
+ })
50
56
  .option("show-stats", {
51
57
  description: "Show timing and usage statistics in print mode",
52
58
  type: "boolean",
@@ -105,11 +111,6 @@ export async function main() {
105
111
  type: "string",
106
112
  global: false,
107
113
  })
108
- .option("acp", {
109
- description: "Run as an ACP bridge",
110
- type: "boolean",
111
- global: false,
112
- })
113
114
  .command("plugin", "Manage plugins and marketplaces", (yargs) => {
114
115
  return yargs
115
116
  .help()
@@ -343,12 +344,6 @@ export async function main() {
343
344
  process.chdir(workdir);
344
345
  }
345
346
 
346
- // Handle ACP mode
347
- if (argv.acp) {
348
- const { runAcp } = await import("./acp-cli.js");
349
- return runAcp();
350
- }
351
-
352
347
  // Handle restore session command
353
348
  if (
354
349
  argv.restore === "" ||
@@ -404,6 +399,12 @@ export async function main() {
404
399
  });
405
400
  }
406
401
 
402
+ // Handle stdio mode
403
+ if (argv.stdio) {
404
+ const { startStdioCli } = await import("./stdio-cli.js");
405
+ return startStdioCli();
406
+ }
407
+
407
408
  await startCli({
408
409
  restoreSessionId: argv.restore as string | undefined,
409
410
  continueLastSession: argv.continue as boolean | undefined,