wave-code 1.0.10 → 1.1.1

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.
Files changed (248) hide show
  1. package/bin/wave-code.js +8 -2
  2. package/dist/bundle/wave.mjs +3231 -0
  3. package/package.json +24 -25
  4. package/src/cli.tsx +6 -1
  5. package/src/commands/update.ts +2 -7
  6. package/src/components/App.tsx +3 -7
  7. package/src/components/BtwDisplay.tsx +10 -1
  8. package/src/components/ChatInterface.tsx +21 -52
  9. package/src/components/ConfirmationDetails.tsx +144 -37
  10. package/src/components/DiffDisplay.tsx +335 -301
  11. package/src/components/InputBox.tsx +17 -2
  12. package/src/components/LoadingIndicator.tsx +16 -2
  13. package/src/components/MessageBlockItem.tsx +2 -4
  14. package/src/components/MessageList.tsx +75 -14
  15. package/src/components/ReasoningDisplay.tsx +2 -4
  16. package/src/components/SessionSelector.tsx +82 -11
  17. package/src/components/SkillsManager.tsx +312 -0
  18. package/src/components/StatusCommand.tsx +2 -9
  19. package/src/components/ToolDisplay.tsx +2 -4
  20. package/src/constants/commands.ts +6 -0
  21. package/src/contexts/useChat.tsx +245 -301
  22. package/src/daemon/commands.ts +57 -27
  23. package/src/daemon/jsonRpcClient.ts +1 -1
  24. package/src/daemon/socketClient.ts +2 -2
  25. package/src/hooks/useInputManager.ts +7 -1
  26. package/src/index.ts +57 -10
  27. package/src/managers/inputHandlers.ts +2 -0
  28. package/src/managers/inputReducer.ts +195 -104
  29. package/src/print-cli.ts +25 -17
  30. package/src/reducers/selectorReducer.ts +10 -0
  31. package/src/reducers/skillsManagerReducer.ts +91 -0
  32. package/src/session-selector-cli.tsx +269 -28
  33. package/src/stdio/agentBridge.ts +30 -21
  34. package/src/stdio/daemonServer.ts +3 -1
  35. package/src/stdio/protocol.ts +2 -0
  36. package/src/utils/clipboard.ts +21 -0
  37. package/src/utils/highlightUtils.ts +46 -1
  38. package/src/utils/readPackageJson.ts +29 -0
  39. package/src/utils/streamingText.ts +11 -0
  40. package/src/utils/worktree.ts +191 -43
  41. package/dist/cli.d.ts +0 -6
  42. package/dist/cli.js +0 -53
  43. package/dist/commands/plugin/disable.d.ts +0 -5
  44. package/dist/commands/plugin/disable.js +0 -15
  45. package/dist/commands/plugin/enable.d.ts +0 -5
  46. package/dist/commands/plugin/enable.js +0 -15
  47. package/dist/commands/plugin/install.d.ts +0 -5
  48. package/dist/commands/plugin/install.js +0 -21
  49. package/dist/commands/plugin/list.d.ts +0 -1
  50. package/dist/commands/plugin/list.js +0 -31
  51. package/dist/commands/plugin/marketplace.d.ts +0 -10
  52. package/dist/commands/plugin/marketplace.js +0 -90
  53. package/dist/commands/plugin/uninstall.d.ts +0 -3
  54. package/dist/commands/plugin/uninstall.js +0 -16
  55. package/dist/commands/plugin/update.d.ts +0 -3
  56. package/dist/commands/plugin/update.js +0 -15
  57. package/dist/commands/update.d.ts +0 -1
  58. package/dist/commands/update.js +0 -97
  59. package/dist/components/AgentsManager.d.ts +0 -7
  60. package/dist/components/AgentsManager.js +0 -109
  61. package/dist/components/App.d.ts +0 -9
  62. package/dist/components/App.js +0 -76
  63. package/dist/components/BackgroundTaskManager.d.ts +0 -5
  64. package/dist/components/BackgroundTaskManager.js +0 -99
  65. package/dist/components/BangDisplay.d.ts +0 -8
  66. package/dist/components/BangDisplay.js +0 -17
  67. package/dist/components/BtwDisplay.d.ts +0 -7
  68. package/dist/components/BtwDisplay.js +0 -19
  69. package/dist/components/ChatInterface.d.ts +0 -2
  70. package/dist/components/ChatInterface.js +0 -61
  71. package/dist/components/CommandSelector.d.ts +0 -10
  72. package/dist/components/CommandSelector.js +0 -66
  73. package/dist/components/CompactDisplay.d.ts +0 -8
  74. package/dist/components/CompactDisplay.js +0 -13
  75. package/dist/components/ConfirmationDetails.d.ts +0 -9
  76. package/dist/components/ConfirmationDetails.js +0 -45
  77. package/dist/components/ConfirmationSelector.d.ts +0 -13
  78. package/dist/components/ConfirmationSelector.js +0 -127
  79. package/dist/components/DiffDisplay.d.ts +0 -8
  80. package/dist/components/DiffDisplay.js +0 -201
  81. package/dist/components/DiscoverView.d.ts +0 -2
  82. package/dist/components/DiscoverView.js +0 -37
  83. package/dist/components/FileSelector.d.ts +0 -11
  84. package/dist/components/FileSelector.js +0 -50
  85. package/dist/components/HelpView.d.ts +0 -7
  86. package/dist/components/HelpView.js +0 -74
  87. package/dist/components/HistorySearch.d.ts +0 -8
  88. package/dist/components/HistorySearch.js +0 -66
  89. package/dist/components/InputBox.d.ts +0 -24
  90. package/dist/components/InputBox.js +0 -149
  91. package/dist/components/InstalledView.d.ts +0 -2
  92. package/dist/components/InstalledView.js +0 -45
  93. package/dist/components/LoadingIndicator.d.ts +0 -10
  94. package/dist/components/LoadingIndicator.js +0 -6
  95. package/dist/components/LoginCommand.d.ts +0 -5
  96. package/dist/components/LoginCommand.js +0 -153
  97. package/dist/components/Markdown.d.ts +0 -5
  98. package/dist/components/Markdown.js +0 -127
  99. package/dist/components/MarketplaceAddForm.d.ts +0 -2
  100. package/dist/components/MarketplaceAddForm.js +0 -55
  101. package/dist/components/MarketplaceDetail.d.ts +0 -2
  102. package/dist/components/MarketplaceDetail.js +0 -74
  103. package/dist/components/MarketplaceList.d.ts +0 -8
  104. package/dist/components/MarketplaceList.js +0 -17
  105. package/dist/components/MarketplaceView.d.ts +0 -2
  106. package/dist/components/MarketplaceView.js +0 -41
  107. package/dist/components/McpManager.d.ts +0 -9
  108. package/dist/components/McpManager.js +0 -88
  109. package/dist/components/MessageBlockItem.d.ts +0 -8
  110. package/dist/components/MessageBlockItem.js +0 -15
  111. package/dist/components/MessageList.d.ts +0 -10
  112. package/dist/components/MessageList.js +0 -80
  113. package/dist/components/ModelSelector.d.ts +0 -8
  114. package/dist/components/ModelSelector.js +0 -45
  115. package/dist/components/Notifications.d.ts +0 -7
  116. package/dist/components/Notifications.js +0 -9
  117. package/dist/components/PlanDisplay.d.ts +0 -7
  118. package/dist/components/PlanDisplay.js +0 -6
  119. package/dist/components/PluginDetail.d.ts +0 -2
  120. package/dist/components/PluginDetail.js +0 -87
  121. package/dist/components/PluginList.d.ts +0 -13
  122. package/dist/components/PluginList.js +0 -15
  123. package/dist/components/PluginManagerShell.d.ts +0 -6
  124. package/dist/components/PluginManagerShell.js +0 -92
  125. package/dist/components/PluginManagerTypes.d.ts +0 -35
  126. package/dist/components/PluginManagerTypes.js +0 -1
  127. package/dist/components/QueuedMessageList.d.ts +0 -2
  128. package/dist/components/QueuedMessageList.js +0 -18
  129. package/dist/components/ReasoningDisplay.d.ts +0 -8
  130. package/dist/components/ReasoningDisplay.js +0 -13
  131. package/dist/components/RewindCommand.d.ts +0 -12
  132. package/dist/components/RewindCommand.js +0 -78
  133. package/dist/components/SessionSelector.d.ts +0 -12
  134. package/dist/components/SessionSelector.js +0 -47
  135. package/dist/components/StatusCommand.d.ts +0 -5
  136. package/dist/components/StatusCommand.js +0 -28
  137. package/dist/components/StatusLine.d.ts +0 -6
  138. package/dist/components/StatusLine.js +0 -9
  139. package/dist/components/TaskList.d.ts +0 -5
  140. package/dist/components/TaskList.js +0 -197
  141. package/dist/components/TaskNotificationMessage.d.ts +0 -5
  142. package/dist/components/TaskNotificationMessage.js +0 -12
  143. package/dist/components/ToolDisplay.d.ts +0 -9
  144. package/dist/components/ToolDisplay.js +0 -55
  145. package/dist/components/WorkflowManager.d.ts +0 -5
  146. package/dist/components/WorkflowManager.js +0 -102
  147. package/dist/components/WorktreeExitPrompt.d.ts +0 -12
  148. package/dist/components/WorktreeExitPrompt.js +0 -35
  149. package/dist/constants/commands.d.ts +0 -2
  150. package/dist/constants/commands.js +0 -92
  151. package/dist/contexts/PluginManagerContext.d.ts +0 -3
  152. package/dist/contexts/PluginManagerContext.js +0 -9
  153. package/dist/contexts/useAppConfig.d.ts +0 -10
  154. package/dist/contexts/useAppConfig.js +0 -13
  155. package/dist/contexts/useChat.d.ts +0 -101
  156. package/dist/contexts/useChat.js +0 -993
  157. package/dist/contracts/status.d.ts +0 -7
  158. package/dist/contracts/status.js +0 -1
  159. package/dist/daemon/commands.d.ts +0 -49
  160. package/dist/daemon/commands.js +0 -341
  161. package/dist/daemon/jsonRpcClient.d.ts +0 -38
  162. package/dist/daemon/jsonRpcClient.js +0 -129
  163. package/dist/daemon/socketClient.d.ts +0 -13
  164. package/dist/daemon/socketClient.js +0 -26
  165. package/dist/daemon-cli.d.ts +0 -10
  166. package/dist/daemon-cli.js +0 -15
  167. package/dist/hooks/useInputManager.d.ts +0 -75
  168. package/dist/hooks/useInputManager.js +0 -583
  169. package/dist/hooks/usePluginManager.d.ts +0 -4
  170. package/dist/hooks/usePluginManager.js +0 -265
  171. package/dist/hooks/useTasks.d.ts +0 -1
  172. package/dist/hooks/useTasks.js +0 -5
  173. package/dist/index.d.ts +0 -4
  174. package/dist/index.js +0 -447
  175. package/dist/managers/inputHandlers.d.ts +0 -30
  176. package/dist/managers/inputHandlers.js +0 -625
  177. package/dist/managers/inputReducer.d.ts +0 -271
  178. package/dist/managers/inputReducer.js +0 -1121
  179. package/dist/plugin-manager-cli.d.ts +0 -5
  180. package/dist/plugin-manager-cli.js +0 -12
  181. package/dist/print-cli.d.ts +0 -10
  182. package/dist/print-cli.js +0 -209
  183. package/dist/reducers/agentsManagerReducer.d.ts +0 -26
  184. package/dist/reducers/agentsManagerReducer.js +0 -54
  185. package/dist/reducers/backgroundTaskManagerReducer.d.ts +0 -62
  186. package/dist/reducers/backgroundTaskManagerReducer.js +0 -106
  187. package/dist/reducers/confirmationReducer.d.ts +0 -37
  188. package/dist/reducers/confirmationReducer.js +0 -193
  189. package/dist/reducers/helpSelectorReducer.d.ts +0 -25
  190. package/dist/reducers/helpSelectorReducer.js +0 -52
  191. package/dist/reducers/marketplaceAddFormReducer.d.ts +0 -24
  192. package/dist/reducers/marketplaceAddFormReducer.js +0 -58
  193. package/dist/reducers/mcpManagerReducer.d.ts +0 -37
  194. package/dist/reducers/mcpManagerReducer.js +0 -74
  195. package/dist/reducers/pluginDetailReducer.d.ts +0 -32
  196. package/dist/reducers/pluginDetailReducer.js +0 -70
  197. package/dist/reducers/questionReducer.d.ts +0 -82
  198. package/dist/reducers/questionReducer.js +0 -375
  199. package/dist/reducers/rewindSelectorReducer.d.ts +0 -21
  200. package/dist/reducers/rewindSelectorReducer.js +0 -37
  201. package/dist/reducers/selectorReducer.d.ts +0 -23
  202. package/dist/reducers/selectorReducer.js +0 -42
  203. package/dist/reducers/workflowManagerReducer.d.ts +0 -40
  204. package/dist/reducers/workflowManagerReducer.js +0 -100
  205. package/dist/session-selector-cli.d.ts +0 -3
  206. package/dist/session-selector-cli.js +0 -25
  207. package/dist/stdio/agentBridge.d.ts +0 -139
  208. package/dist/stdio/agentBridge.js +0 -999
  209. package/dist/stdio/daemonServer.d.ts +0 -67
  210. package/dist/stdio/daemonServer.js +0 -191
  211. package/dist/stdio/index.d.ts +0 -5
  212. package/dist/stdio/index.js +0 -5
  213. package/dist/stdio/jsonRpcConnection.d.ts +0 -39
  214. package/dist/stdio/jsonRpcConnection.js +0 -135
  215. package/dist/stdio/protocol.d.ts +0 -41
  216. package/dist/stdio/protocol.js +0 -26
  217. package/dist/stdio/stdioServer.d.ts +0 -36
  218. package/dist/stdio/stdioServer.js +0 -51
  219. package/dist/stdio-cli.d.ts +0 -8
  220. package/dist/stdio-cli.js +0 -15
  221. package/dist/types.d.ts +0 -20
  222. package/dist/types.js +0 -1
  223. package/dist/utils/bracketedPaste.d.ts +0 -39
  224. package/dist/utils/bracketedPaste.js +0 -122
  225. package/dist/utils/clipboard.d.ts +0 -21
  226. package/dist/utils/clipboard.js +0 -347
  227. package/dist/utils/constants.d.ts +0 -16
  228. package/dist/utils/constants.js +0 -18
  229. package/dist/utils/highlightUtils.d.ts +0 -1
  230. package/dist/utils/highlightUtils.js +0 -93
  231. package/dist/utils/inputUtils.d.ts +0 -17
  232. package/dist/utils/inputUtils.js +0 -67
  233. package/dist/utils/logger.d.ts +0 -71
  234. package/dist/utils/logger.js +0 -259
  235. package/dist/utils/markdownTable.d.ts +0 -34
  236. package/dist/utils/markdownTable.js +0 -302
  237. package/dist/utils/rewindCheckpoints.d.ts +0 -8
  238. package/dist/utils/rewindCheckpoints.js +0 -17
  239. package/dist/utils/throttle.d.ts +0 -14
  240. package/dist/utils/throttle.js +0 -55
  241. package/dist/utils/toolParameterTransforms.d.ts +0 -18
  242. package/dist/utils/toolParameterTransforms.js +0 -73
  243. package/dist/utils/usageSummary.d.ts +0 -28
  244. package/dist/utils/usageSummary.js +0 -121
  245. package/dist/utils/version.d.ts +0 -1
  246. package/dist/utils/version.js +0 -4
  247. package/dist/utils/worktree.d.ts +0 -35
  248. package/dist/utils/worktree.js +0 -219
@@ -1,67 +0,0 @@
1
- /**
2
- * DaemonServer — JSON-RPC server over a unix socket for remote background
3
- * sessions (spec: docs/specs/ui/desktop-app.md 「SSH 远程后台会话」).
4
- *
5
- * The desktop app launches `wave --daemon <socket>` on the remote host via
6
- * nohup/setsid, then tunnels the socket back with `ssh -L`. All connections
7
- * share one AgentBridge, so sessions and pending tool permissions survive
8
- * client detach/attach — the daemon keeps running (and generating) while no
9
- * desktop is connected. The daemon never exits on a client disconnect; it
10
- * only exits when killed (app quit / 删除会话 / remote reboot).
11
- *
12
- * Idle auto-exit (spec: 「远程 daemon 空闲自动退出」): once every session has
13
- * settled and no client is connected, the daemon mirrors `wave -p`'s exit
14
- * semantics — after a grace period it destroys the sessions (saving their
15
- * transcripts), closes the socket, and exits, so the remote process doesn't
16
- * linger forever after background work completes.
17
- */
18
- import { AgentBridge, type AgentBridgeOptions } from "./agentBridge.js";
19
- export interface DaemonServerOptions {
20
- socketPath: string;
21
- bridgeOptions?: AgentBridgeOptions;
22
- /** Idle grace period before the daemon auto-exits (default 60s). */
23
- graceMs?: number;
24
- }
25
- export declare class DaemonServer {
26
- static readonly DEFAULT_IDLE_GRACE_MS = 60000;
27
- private socketPath;
28
- private server;
29
- private bridge;
30
- private connections;
31
- private sockets;
32
- private graceMs;
33
- private idleTimer;
34
- private shuttingDown;
35
- private stopped;
36
- constructor(options: DaemonServerOptions);
37
- get agentBridge(): AgentBridge;
38
- /**
39
- * Listen on the socket path. Rejects when a live daemon already holds it. A
40
- * stale socket file left by a crashed daemon would otherwise block the
41
- * restart with EADDRINUSE, so it is cleaned up first: non-socket files are
42
- * unlinked outright; socket files are probe-connected — ECONNREFUSED means
43
- * no listener (stale → unlink and listen), anything else means a live
44
- * daemon owns the path (reject).
45
- */
46
- start(): Promise<void>;
47
- private listen;
48
- stop(): Promise<void>;
49
- private clearIdleTimer;
50
- /**
51
- * Re-evaluate the idle condition after any state transition: sessions busy
52
- * (loading / pending messages / background work) or any client attached →
53
- * cancel the timer. Fully idle + detached → arm the grace timer once; when
54
- * it fires, shut the daemon down. Evaluation is event-driven (every
55
- * busy→idle transition emits a notification, every attach/detach fires a
56
- * connection event), so nothing is polled. The failure mode is
57
- * conservative: a missed transition just leaves the daemon running.
58
- */
59
- private evaluateIdle;
60
- /**
61
- * Destroy the sessions (each agent saves its transcript and drains
62
- * auto-memory), close the listener, unlink the socket file, then exit.
63
- * `shuttingDown` guards against re-entry: new connections are refused and
64
- * further idle evaluations become no-ops.
65
- */
66
- private shutdown;
67
- }
@@ -1,191 +0,0 @@
1
- /**
2
- * DaemonServer — JSON-RPC server over a unix socket for remote background
3
- * sessions (spec: docs/specs/ui/desktop-app.md 「SSH 远程后台会话」).
4
- *
5
- * The desktop app launches `wave --daemon <socket>` on the remote host via
6
- * nohup/setsid, then tunnels the socket back with `ssh -L`. All connections
7
- * share one AgentBridge, so sessions and pending tool permissions survive
8
- * client detach/attach — the daemon keeps running (and generating) while no
9
- * desktop is connected. The daemon never exits on a client disconnect; it
10
- * only exits when killed (app quit / 删除会话 / remote reboot).
11
- *
12
- * Idle auto-exit (spec: 「远程 daemon 空闲自动退出」): once every session has
13
- * settled and no client is connected, the daemon mirrors `wave -p`'s exit
14
- * semantics — after a grace period it destroys the sessions (saving their
15
- * transcripts), closes the socket, and exits, so the remote process doesn't
16
- * linger forever after background work completes.
17
- */
18
- import net from "net";
19
- import * as fs from "fs";
20
- import { AgentBridge } from "./agentBridge.js";
21
- import { JsonRpcConnection } from "./jsonRpcConnection.js";
22
- export class DaemonServer {
23
- constructor(options) {
24
- this.connections = new Set();
25
- this.sockets = new Set();
26
- this.shuttingDown = false;
27
- this.stopped = false;
28
- this.socketPath = options.socketPath;
29
- this.graceMs = options.graceMs ?? DaemonServer.DEFAULT_IDLE_GRACE_MS;
30
- this.bridge = new AgentBridge({
31
- ...options.bridgeOptions,
32
- // Notifications go to every attached client; a fully detached daemon
33
- // has none, and the write is dropped silently (the attach snapshot
34
- // re-syncs state on reconnect).
35
- emit: (method, params, sessionId) => {
36
- for (const conn of this.connections) {
37
- conn.sendNotification(method, params, sessionId);
38
- }
39
- // Any session activity can change the idle state — re-evaluate.
40
- this.evaluateIdle();
41
- },
42
- });
43
- this.server = net.createServer((socket) => {
44
- if (this.shuttingDown) {
45
- socket.destroy();
46
- return;
47
- }
48
- const conn = new JsonRpcConnection(socket, socket, this.bridge);
49
- this.connections.add(conn);
50
- this.sockets.add(socket);
51
- // A (re)attached client cancels a pending idle exit.
52
- this.evaluateIdle();
53
- socket.on("error", () => {
54
- // The client (ssh tunnel) can reset the socket mid-detach; the daemon
55
- // must keep running — 'close' below cleans up the connection.
56
- });
57
- socket.on("close", () => {
58
- this.connections.delete(conn);
59
- this.sockets.delete(socket);
60
- // A client detach may leave the daemon idle — re-evaluate.
61
- this.evaluateIdle();
62
- });
63
- conn.start();
64
- });
65
- }
66
- get agentBridge() {
67
- return this.bridge;
68
- }
69
- /**
70
- * Listen on the socket path. Rejects when a live daemon already holds it. A
71
- * stale socket file left by a crashed daemon would otherwise block the
72
- * restart with EADDRINUSE, so it is cleaned up first: non-socket files are
73
- * unlinked outright; socket files are probe-connected — ECONNREFUSED means
74
- * no listener (stale → unlink and listen), anything else means a live
75
- * daemon owns the path (reject).
76
- */
77
- start() {
78
- return new Promise((resolve, reject) => {
79
- const server = this.server;
80
- if (!server)
81
- return resolve();
82
- try {
83
- const st = fs.statSync(this.socketPath);
84
- if (st.isSocket()) {
85
- const probe = net.connect(this.socketPath);
86
- probe.once("connect", () => {
87
- probe.destroy();
88
- reject(new Error(`另一个 wave daemon 已在 ${this.socketPath} 监听`));
89
- });
90
- probe.once("error", (err) => {
91
- probe.destroy();
92
- if (err.code === "ECONNREFUSED") {
93
- fs.unlinkSync(this.socketPath);
94
- this.listen(server, resolve, reject);
95
- }
96
- else {
97
- reject(err);
98
- }
99
- });
100
- return;
101
- }
102
- fs.unlinkSync(this.socketPath);
103
- }
104
- catch {
105
- // ENOENT — no stale socket, listen directly.
106
- }
107
- this.listen(server, resolve, reject);
108
- });
109
- }
110
- listen(server, resolve, reject) {
111
- server.once("error", reject);
112
- server.listen(this.socketPath, () => {
113
- server.removeListener("error", reject);
114
- resolve();
115
- // A freshly started daemon may already be idle (no sessions) — start the
116
- // idle watch so a zero-session daemon also auto-exits.
117
- this.evaluateIdle();
118
- });
119
- }
120
- stop() {
121
- this.stopped = true;
122
- this.clearIdleTimer();
123
- return new Promise((resolve) => {
124
- const server = this.server;
125
- if (!server)
126
- return resolve();
127
- this.server = undefined;
128
- server.close(() => resolve());
129
- });
130
- }
131
- // ── Idle auto-exit ────────────────────────────────────────────
132
- clearIdleTimer() {
133
- if (this.idleTimer) {
134
- clearTimeout(this.idleTimer);
135
- this.idleTimer = undefined;
136
- }
137
- }
138
- /**
139
- * Re-evaluate the idle condition after any state transition: sessions busy
140
- * (loading / pending messages / background work) or any client attached →
141
- * cancel the timer. Fully idle + detached → arm the grace timer once; when
142
- * it fires, shut the daemon down. Evaluation is event-driven (every
143
- * busy→idle transition emits a notification, every attach/detach fires a
144
- * connection event), so nothing is polled. The failure mode is
145
- * conservative: a missed transition just leaves the daemon running.
146
- */
147
- evaluateIdle() {
148
- // A stopped/shutting-down daemon never (re)arms the idle timer — late
149
- // socket 'close' events (which fire after server.close resolves) must not
150
- // resurrect a timer after stop().
151
- if (this.shuttingDown || this.stopped)
152
- return;
153
- if (this.connections.size > 0 || !this.bridge.isIdle()) {
154
- this.clearIdleTimer();
155
- return;
156
- }
157
- if (this.idleTimer)
158
- return;
159
- this.idleTimer = setTimeout(() => {
160
- this.idleTimer = undefined;
161
- void this.shutdown();
162
- }, this.graceMs);
163
- }
164
- /**
165
- * Destroy the sessions (each agent saves its transcript and drains
166
- * auto-memory), close the listener, unlink the socket file, then exit.
167
- * `shuttingDown` guards against re-entry: new connections are refused and
168
- * further idle evaluations become no-ops.
169
- */
170
- async shutdown() {
171
- if (this.shuttingDown)
172
- return;
173
- this.shuttingDown = true;
174
- this.clearIdleTimer();
175
- // Destroy client sockets first so server.close() can complete (an open
176
- // socket keeps the close callback pending).
177
- for (const socket of this.sockets)
178
- socket.destroy();
179
- this.sockets.clear();
180
- await this.bridge.destroyAll();
181
- await this.stop();
182
- try {
183
- fs.unlinkSync(this.socketPath);
184
- }
185
- catch {
186
- // Already gone — a stale file would be probed/unlinked on next start.
187
- }
188
- process.exit(0);
189
- }
190
- }
191
- DaemonServer.DEFAULT_IDLE_GRACE_MS = 60000;
@@ -1,5 +0,0 @@
1
- export { StdioServer, type StdioServerOptions } from "./stdioServer.js";
2
- export { JsonRpcConnection } from "./jsonRpcConnection.js";
3
- export { DaemonServer, type DaemonServerOptions } from "./daemonServer.js";
4
- export { AgentBridge, type AgentBridgeOptions, RpcError, } from "./agentBridge.js";
5
- export * from "./protocol.js";
@@ -1,5 +0,0 @@
1
- export { StdioServer } from "./stdioServer.js";
2
- export { JsonRpcConnection } from "./jsonRpcConnection.js";
3
- export { DaemonServer } from "./daemonServer.js";
4
- export { AgentBridge, RpcError, } from "./agentBridge.js";
5
- export * from "./protocol.js";
@@ -1,39 +0,0 @@
1
- /**
2
- * JsonRpcConnection — one JSON-RPC connection over a Readable/Writable pair,
3
- * dispatching to a shared AgentBridge.
4
- *
5
- * Shared by StdioServer (process stdin/stdout) and DaemonServer (each unix
6
- * socket connection). The AgentBridge owns all session/agent state, so any
7
- * number of connections can share it — a detached client loses nothing and
8
- * every session keeps running on the daemon side.
9
- */
10
- import type { Readable, Writable } from "stream";
11
- import { AgentBridge } from "./agentBridge.js";
12
- export interface JsonRpcConnectionOptions {
13
- /** Called when the input stream reaches EOF (parent closed the pipe). Only
14
- * stdio mode passes it — it must exit the process when its client dies;
15
- * daemon mode never passes it (a detached client must not kill the daemon,
16
- * see daemonServer.ts). */
17
- onClose?: () => void;
18
- }
19
- export declare class JsonRpcConnection {
20
- private input;
21
- private output;
22
- private bridge;
23
- private rl;
24
- private started;
25
- private stoppedByOwner;
26
- private onClose?;
27
- constructor(input: Readable, output: Writable, bridge: AgentBridge, options?: JsonRpcConnectionOptions);
28
- start(): void;
29
- stop(): void;
30
- handleLine(line: string): Promise<void>;
31
- private handleRequest;
32
- private handleNotification;
33
- sendResponse(id: number | string | null, result?: unknown, error?: {
34
- code: number;
35
- message: string;
36
- }): void;
37
- sendNotification(method: string, params?: unknown, sessionId?: string): void;
38
- private write;
39
- }
@@ -1,135 +0,0 @@
1
- /**
2
- * JsonRpcConnection — one JSON-RPC connection over a Readable/Writable pair,
3
- * dispatching to a shared AgentBridge.
4
- *
5
- * Shared by StdioServer (process stdin/stdout) and DaemonServer (each unix
6
- * socket connection). The AgentBridge owns all session/agent state, so any
7
- * number of connections can share it — a detached client loses nothing and
8
- * every session keeps running on the daemon side.
9
- */
10
- import readline from "readline";
11
- import { PARSE_ERROR, INVALID_REQUEST, INTERNAL_ERROR, isRequest, isNotification, } from "./protocol.js";
12
- export class JsonRpcConnection {
13
- constructor(input, output, bridge, options = {}) {
14
- this.input = input;
15
- this.output = output;
16
- this.bridge = bridge;
17
- this.started = false;
18
- this.stoppedByOwner = false;
19
- this.onClose = options.onClose;
20
- }
21
- start() {
22
- if (this.started)
23
- return;
24
- this.started = true;
25
- this.rl = readline.createInterface({
26
- input: this.input,
27
- crlfDelay: Infinity,
28
- });
29
- // readline re-emits input errors on the Interface; error handling on the
30
- // underlying stream is the owner's job (the daemon keeps running on a
31
- // client reset), so swallow them here.
32
- this.rl.on("error", () => { });
33
- this.rl.on("line", (line) => {
34
- this.handleLine(line).catch((err) => {
35
- // Should never reach here — handleLine catches internally
36
- this.sendResponse(null, undefined, {
37
- code: INTERNAL_ERROR,
38
- message: `Unhandled error: ${err.message}`,
39
- });
40
- });
41
- });
42
- this.rl.on("close", () => {
43
- this.started = false;
44
- // stdin EOF from the owning client — not a deliberate stop(). stdio
45
- // mode reacts by exiting the process (its parent is gone); daemon mode
46
- // has no onClose so a detached client reset never kills the daemon.
47
- if (!this.stoppedByOwner)
48
- this.onClose?.();
49
- });
50
- }
51
- stop() {
52
- this.stoppedByOwner = true;
53
- this.rl?.close();
54
- this.rl = undefined;
55
- this.started = false;
56
- }
57
- async handleLine(line) {
58
- const trimmed = line.trim();
59
- if (!trimmed)
60
- return;
61
- let msg;
62
- try {
63
- msg = JSON.parse(trimmed);
64
- }
65
- catch {
66
- this.sendResponse(null, undefined, {
67
- code: PARSE_ERROR,
68
- message: "Parse error: invalid JSON",
69
- });
70
- return;
71
- }
72
- if (isRequest(msg)) {
73
- await this.handleRequest(msg);
74
- }
75
- else if (isNotification(msg)) {
76
- this.handleNotification(msg);
77
- }
78
- else {
79
- // Echo back the id if the message has one, otherwise null
80
- const id = typeof msg === "object" &&
81
- msg !== null &&
82
- "id" in msg &&
83
- (typeof msg.id === "number" ||
84
- typeof msg.id === "string")
85
- ? msg.id
86
- : null;
87
- this.sendResponse(id, undefined, {
88
- code: INVALID_REQUEST,
89
- message: "Invalid request: must have 'method' field",
90
- });
91
- }
92
- }
93
- async handleRequest(msg) {
94
- try {
95
- const result = await this.bridge.handleRequest(msg.method, msg.params, msg.sessionId);
96
- this.sendResponse(msg.id, result);
97
- }
98
- catch (err) {
99
- const code = err && typeof err === "object" && "code" in err
100
- ? err.code
101
- : INTERNAL_ERROR;
102
- const message = err instanceof Error ? err.message : String(err);
103
- this.sendResponse(msg.id, undefined, { code, message });
104
- }
105
- }
106
- handleNotification(msg) {
107
- try {
108
- this.bridge.handleNotification(msg.method, msg.params);
109
- }
110
- catch (err) {
111
- // Notifications don't get responses, but we log to stderr
112
- process.stderr.write(`Error handling notification ${msg.method}: ${err.message}\n`);
113
- }
114
- }
115
- // ── Output helpers ────────────────────────────────────────────
116
- sendResponse(id, result, error) {
117
- const response = { id };
118
- if (error) {
119
- response.error = error;
120
- }
121
- else {
122
- response.result = result ?? null;
123
- }
124
- this.write(response);
125
- }
126
- sendNotification(method, params, sessionId) {
127
- const notification = { method, params };
128
- if (sessionId)
129
- notification.sessionId = sessionId;
130
- this.write(notification);
131
- }
132
- write(obj) {
133
- this.output.write(JSON.stringify(obj) + "\n");
134
- }
135
- }
@@ -1,41 +0,0 @@
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
- /** Session-scoped requests carry sessionId for routing to the right Agent. */
14
- sessionId?: string;
15
- }
16
- export interface JsonRpcResponse {
17
- id: number | string | null;
18
- result?: unknown;
19
- error?: JsonRpcError;
20
- }
21
- export interface JsonRpcError {
22
- code: number;
23
- message: string;
24
- data?: unknown;
25
- }
26
- export interface JsonRpcNotification {
27
- method: string;
28
- params?: unknown;
29
- /** Session-scoped notifications carry sessionId for demultiplexing on the client. */
30
- sessionId?: string;
31
- }
32
- export declare const PARSE_ERROR = -32700;
33
- export declare const INVALID_REQUEST = -32600;
34
- export declare const METHOD_NOT_FOUND = -32601;
35
- export declare const INVALID_PARAMS = -32602;
36
- export declare const INTERNAL_ERROR = -32603;
37
- export type RequestMethod = "initialize" | "destroy" | "restoreSession" | "listSessions" | "getSessionInfo" | "sendMessage" | "bang" | "askBtw" | "abortMessage" | "clearMessages" | "rewindToMessage" | "listRewindCheckpoints" | "deleteQueuedMessage" | "updateQueuedMessage" | "deleteQueuedMessageById" | "getMessages" | "getFullMessageThread" | "setPermissionMode" | "getPermissionMode" | "getMcpServers" | "connectMcpServer" | "disconnectMcpServer" | "getSlashCommands" | "searchFiles" | "writeArtifactFile" | "getPromptHistory" | "searchPromptHistory" | "updateConfig" | "getConfiguredModels" | "setModel" | "listPendingPermissions" | "listDaemonSessions" | "getAuthStatus" | "login" | "logout" | "listPlugins" | "installPlugin" | "uninstallPlugin" | "enablePlugin" | "disablePlugin" | "updatePlugin" | "listMarketplaces" | "addMarketplace" | "removeMarketplace" | "updateMarketplace" | "compact" | "getBackgroundTaskOutput" | "stopBackgroundTask" | "getWorkflowRuns" | "stopWorkflowRun" | "listGitBranches" | "createWorktree" | "removeWorktree";
38
- export type ClientNotificationMethod = "permissionResponse";
39
- export type ServerNotificationMethod = "userMessageAdded" | "assistantMessageAdded" | "assistantContentUpdated" | "assistantReasoningUpdated" | "toolBlockUpdated" | "errorBlockAdded" | "loadingChange" | "commandRunningChange" | "queuedMessagesChange" | "tasksChange" | "sessionIdChange" | "permissionModeChange" | "mcpServersChange" | "workdirChange" | "bangMessageAdded" | "bangMessageUpdated" | "bangMessageCompleted" | "notificationMessageAdded" | "permissionRequest" | "authUrl" | "compactBlockAdded" | "compactionStateChange" | "backgroundTasksChange" | "btwContent";
40
- export declare function isRequest(msg: unknown): msg is JsonRpcRequest;
41
- export declare function isNotification(msg: unknown): msg is JsonRpcNotification;
@@ -1,26 +0,0 @@
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
- }
@@ -1,36 +0,0 @@
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
- * Line handling lives in JsonRpcConnection (shared with DaemonServer).
7
- */
8
- import type { Readable, Writable } from "stream";
9
- import { AgentBridge, type AgentBridgeOptions } from "./agentBridge.js";
10
- export interface StdioServerOptions {
11
- input?: Readable;
12
- output?: Writable;
13
- bridgeOptions?: AgentBridgeOptions;
14
- }
15
- export declare class StdioServer {
16
- private bridge;
17
- private conn;
18
- constructor(options?: StdioServerOptions);
19
- get agentBridge(): AgentBridge;
20
- start(): void;
21
- stop(): void;
22
- /**
23
- * The owning client closed stdin (EOF) — it's gone, so this process must
24
- * follow it. destroyAll() saves each session's transcript and drains
25
- * auto-memory first; a timeout bounds it so a stuck agent can't orphan the
26
- * exit. This is the real-world "parent died" path: without it the process
27
- * lingers forever whenever an agent keeps event-loop handles alive.
28
- */
29
- private onConnectionClosed;
30
- handleLine(line: string): Promise<void>;
31
- sendResponse(id: number | string | null, result?: unknown, error?: {
32
- code: number;
33
- message: string;
34
- }): void;
35
- sendNotification(method: string, params?: unknown, sessionId?: string): void;
36
- }
@@ -1,51 +0,0 @@
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
- * Line handling lives in JsonRpcConnection (shared with DaemonServer).
7
- */
8
- import { AgentBridge } from "./agentBridge.js";
9
- import { JsonRpcConnection } from "./jsonRpcConnection.js";
10
- export class StdioServer {
11
- constructor(options = {}) {
12
- this.bridge = new AgentBridge({
13
- ...options.bridgeOptions,
14
- emit: (method, params, sessionId) => this.sendNotification(method, params, sessionId),
15
- });
16
- this.conn = new JsonRpcConnection(options.input ?? process.stdin, options.output ?? process.stdout, this.bridge, { onClose: () => this.onConnectionClosed() });
17
- }
18
- get agentBridge() {
19
- return this.bridge;
20
- }
21
- start() {
22
- this.conn.start();
23
- }
24
- stop() {
25
- this.conn.stop();
26
- }
27
- /**
28
- * The owning client closed stdin (EOF) — it's gone, so this process must
29
- * follow it. destroyAll() saves each session's transcript and drains
30
- * auto-memory first; a timeout bounds it so a stuck agent can't orphan the
31
- * exit. This is the real-world "parent died" path: without it the process
32
- * lingers forever whenever an agent keeps event-loop handles alive.
33
- */
34
- async onConnectionClosed() {
35
- const SHUTDOWN_TIMEOUT_MS = 5000;
36
- await Promise.race([
37
- this.bridge.destroyAll(),
38
- new Promise((resolve) => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS)),
39
- ]);
40
- process.exit(0);
41
- }
42
- handleLine(line) {
43
- return this.conn.handleLine(line);
44
- }
45
- sendResponse(id, result, error) {
46
- this.conn.sendResponse(id, result, error);
47
- }
48
- sendNotification(method, params, sessionId) {
49
- this.conn.sendNotification(method, params, sessionId);
50
- }
51
- }
@@ -1,8 +0,0 @@
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>;
package/dist/stdio-cli.js DELETED
@@ -1,15 +0,0 @@
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/dist/types.d.ts DELETED
@@ -1,20 +0,0 @@
1
- import { WorktreeSession } from "./utils/worktree.js";
2
- import { PermissionMode, McpServerConfig } from "wave-agent-sdk";
3
- export interface BaseAppProps {
4
- bypassPermissions?: boolean;
5
- permissionMode?: PermissionMode;
6
- pluginDirs?: string[];
7
- /** Additional directories to add to the session Safe Zone (from --add-dir). */
8
- additionalDirectories?: string[];
9
- tools?: string[];
10
- allowedTools?: string[];
11
- disallowedTools?: string[];
12
- worktreeSession?: WorktreeSession;
13
- workdir?: string;
14
- /** The working directory before entering a worktree (CLI -w); injected into the agent's container. */
15
- originalCwd?: string;
16
- version?: string;
17
- model?: string;
18
- /** Optional MCP server configs to pass to Agent.create() */
19
- mcpServers?: Record<string, McpServerConfig>;
20
- }
package/dist/types.js DELETED
@@ -1 +0,0 @@
1
- export {};