reasonix 0.40.0 → 0.41.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.
Files changed (130) hide show
  1. package/README.md +21 -13
  2. package/README.zh-CN.md +19 -13
  3. package/dashboard/app.css +8 -4
  4. package/dashboard/dist/app.js +279 -224
  5. package/dashboard/dist/app.js.map +1 -1
  6. package/dist/cli/acp-64VQZLDJ.js +708 -0
  7. package/dist/cli/acp-64VQZLDJ.js.map +1 -0
  8. package/dist/cli/chat-ZAGX52RV.js +46 -0
  9. package/dist/cli/{chunk-UCMTWZKU.js → chunk-2CXPDAWX.js} +2 -2
  10. package/dist/cli/{chunk-CLAN6PVH.js → chunk-4H3ZRJ2U.js} +19 -7
  11. package/dist/cli/chunk-4H3ZRJ2U.js.map +1 -0
  12. package/dist/cli/{chunk-A5LSGEEK.js → chunk-4W2CICFQ.js} +21 -10
  13. package/dist/cli/{chunk-A5LSGEEK.js.map → chunk-4W2CICFQ.js.map} +1 -1
  14. package/dist/cli/{chunk-CZSJILQP.js → chunk-65Q5HQ26.js} +39 -1
  15. package/dist/cli/chunk-65Q5HQ26.js.map +1 -0
  16. package/dist/cli/{chunk-XHQIK7B6.js → chunk-7SPOFTMT.js} +2 -2
  17. package/dist/cli/{chunk-5GKJLNP2.js → chunk-7VFNPMKG.js} +2 -2
  18. package/dist/cli/{chunk-UVRXTSK3.js → chunk-A3LL4XDV.js} +8 -2
  19. package/dist/cli/chunk-A3LL4XDV.js.map +1 -0
  20. package/dist/cli/{chunk-VLNRQMCI.js → chunk-A7VHMMDE.js} +2 -2
  21. package/dist/cli/{chunk-R4YTW7PR.js → chunk-ARF3N2SY.js} +56 -12
  22. package/dist/cli/chunk-ARF3N2SY.js.map +1 -0
  23. package/dist/cli/{chunk-AVB3WZWU.js → chunk-AT6GGIBV.js} +10 -10
  24. package/dist/cli/{chunk-RFX7TYVV.js → chunk-BOFL3T45.js} +14 -1
  25. package/dist/cli/chunk-BOFL3T45.js.map +1 -0
  26. package/dist/cli/{chunk-SZH34P45.js → chunk-BYZGO3BX.js} +43 -17
  27. package/dist/cli/chunk-BYZGO3BX.js.map +1 -0
  28. package/dist/cli/{chunk-7DLHHBGN.js → chunk-CD4SCQL4.js} +6 -4
  29. package/dist/cli/chunk-CD4SCQL4.js.map +1 -0
  30. package/dist/cli/{chunk-HCC42PEI.js → chunk-CFY2XLY6.js} +6 -2
  31. package/dist/cli/chunk-CFY2XLY6.js.map +1 -0
  32. package/dist/cli/{chunk-26UDIXLD.js → chunk-F2AV2QDK.js} +493 -460
  33. package/dist/cli/chunk-F2AV2QDK.js.map +1 -0
  34. package/dist/cli/{chunk-KMWKGPFZ.js → chunk-H4OLWRSX.js} +10 -1
  35. package/dist/cli/chunk-H4OLWRSX.js.map +1 -0
  36. package/dist/cli/{chunk-4YV2GBYG.js → chunk-IEA6JOIP.js} +291 -98
  37. package/dist/cli/chunk-IEA6JOIP.js.map +1 -0
  38. package/dist/cli/{chunk-WKOMCPXP.js → chunk-KZYLMMU5.js} +21 -13
  39. package/dist/cli/chunk-KZYLMMU5.js.map +1 -0
  40. package/dist/cli/{chunk-JWCTX5S4.js → chunk-L7W3HJZQ.js} +2 -2
  41. package/dist/cli/{chunk-MRLXEMZ7.js → chunk-LN27AKV3.js} +1 -1
  42. package/dist/cli/chunk-LN27AKV3.js.map +1 -0
  43. package/dist/cli/{chunk-IYF36OCJ.js → chunk-LTXADNCO.js} +2 -2
  44. package/dist/cli/{chunk-H7PHYVPM.js → chunk-MHGPBJ2T.js} +44 -8
  45. package/dist/cli/chunk-MHGPBJ2T.js.map +1 -0
  46. package/dist/cli/{chunk-ULBW7DYL.js → chunk-RAUPWSYA.js} +2 -2
  47. package/dist/cli/chunk-SXLJBFIV.js +245 -0
  48. package/dist/cli/chunk-SXLJBFIV.js.map +1 -0
  49. package/dist/cli/{chunk-4X3NY5ZM.js → chunk-UV7XJUJH.js} +2 -2
  50. package/dist/cli/{chunk-XJLZ4HKU.js → chunk-VFG4GIT3.js} +2 -2
  51. package/dist/cli/{chunk-FFNOMR32.js → chunk-WE3YZULK.js} +2 -2
  52. package/dist/cli/chunk-Y5XNV3NX.js +25 -0
  53. package/dist/cli/chunk-Y5XNV3NX.js.map +1 -0
  54. package/dist/cli/{chunk-XST7BSZJ.js → chunk-YJFKFTAL.js} +7 -1
  55. package/dist/cli/chunk-YJFKFTAL.js.map +1 -0
  56. package/dist/cli/{code-YQGVLIT2.js → code-X3M6ENTQ.js} +38 -35
  57. package/dist/cli/{code-YQGVLIT2.js.map → code-X3M6ENTQ.js.map} +1 -1
  58. package/dist/cli/{commands-FQZOBLLZ.js → commands-QY7MSQG7.js} +4 -4
  59. package/dist/cli/{commit-ZS24SHPG.js → commit-BRCQ3OQO.js} +3 -3
  60. package/dist/cli/{desktop-6OLENOOO.js → desktop-ZTMHQR2Y.js} +247 -28
  61. package/dist/cli/desktop-ZTMHQR2Y.js.map +1 -0
  62. package/dist/cli/{diff-2VUKNGEI.js → diff-YASCB7PU.js} +7 -7
  63. package/dist/cli/{doctor-JO2WNN6C.js → doctor-XCN5ETVP.js} +9 -9
  64. package/dist/cli/{events-APSVNROZ.js → events-2AJTXR7I.js} +3 -3
  65. package/dist/cli/index.js +69 -35
  66. package/dist/cli/index.js.map +1 -1
  67. package/dist/cli/{mcp-DCKOE5RF.js → mcp-YMWBLRR7.js} +2 -2
  68. package/dist/cli/{mcp-browse-D6GBP5RQ.js → mcp-browse-XLDUE6SB.js} +7 -3
  69. package/dist/cli/mcp-browse-XLDUE6SB.js.map +1 -0
  70. package/dist/cli/{mcp-inspect-KFGFPJ3E.js → mcp-inspect-H4D2HSJP.js} +5 -7
  71. package/dist/cli/{mcp-inspect-KFGFPJ3E.js.map → mcp-inspect-H4D2HSJP.js.map} +1 -1
  72. package/dist/cli/{prompt-PKCCLLAD.js → prompt-RSIHN62V.js} +4 -3
  73. package/dist/cli/{prune-sessions-LV33R47N.js → prune-sessions-4N3BVST2.js} +2 -2
  74. package/dist/cli/{replay-WFCYX7XF.js → replay-3GTWM75X.js} +8 -8
  75. package/dist/cli/{run-IUJYEPMT.js → run-BLZPTRDX.js} +19 -21
  76. package/dist/cli/{run-IUJYEPMT.js.map → run-BLZPTRDX.js.map} +1 -1
  77. package/dist/cli/{server-CN4QPPVJ.js → server-DRFPXXSH.js} +16 -12
  78. package/dist/cli/{server-CN4QPPVJ.js.map → server-DRFPXXSH.js.map} +1 -1
  79. package/dist/cli/{sessions-F5GPGTJN.js → sessions-BOWFPTXT.js} +13 -13
  80. package/dist/cli/{setup-WWMDBPSB.js → setup-FQL2JJC2.js} +5 -5
  81. package/dist/cli/version-XQXYSJ5L.js +30 -0
  82. package/dist/index.d.ts +148 -103
  83. package/dist/index.js +468 -134
  84. package/dist/index.js.map +1 -1
  85. package/package.json +2 -1
  86. package/dist/cli/chat-G7CUW4ZI.js +0 -45
  87. package/dist/cli/chunk-26UDIXLD.js.map +0 -1
  88. package/dist/cli/chunk-4YV2GBYG.js.map +0 -1
  89. package/dist/cli/chunk-7DLHHBGN.js.map +0 -1
  90. package/dist/cli/chunk-CLAN6PVH.js.map +0 -1
  91. package/dist/cli/chunk-CPTZ5OHX.js +0 -18
  92. package/dist/cli/chunk-CPTZ5OHX.js.map +0 -1
  93. package/dist/cli/chunk-CZSJILQP.js.map +0 -1
  94. package/dist/cli/chunk-H7PHYVPM.js.map +0 -1
  95. package/dist/cli/chunk-HCC42PEI.js.map +0 -1
  96. package/dist/cli/chunk-KMWKGPFZ.js.map +0 -1
  97. package/dist/cli/chunk-MRLXEMZ7.js.map +0 -1
  98. package/dist/cli/chunk-R4YTW7PR.js.map +0 -1
  99. package/dist/cli/chunk-RFX7TYVV.js.map +0 -1
  100. package/dist/cli/chunk-SZH34P45.js.map +0 -1
  101. package/dist/cli/chunk-UVRXTSK3.js.map +0 -1
  102. package/dist/cli/chunk-WKOMCPXP.js.map +0 -1
  103. package/dist/cli/chunk-XST7BSZJ.js.map +0 -1
  104. package/dist/cli/desktop-6OLENOOO.js.map +0 -1
  105. package/dist/cli/mcp-browse-D6GBP5RQ.js.map +0 -1
  106. package/dist/cli/version-KQUPV6T5.js +0 -30
  107. /package/dist/cli/{chat-G7CUW4ZI.js.map → chat-ZAGX52RV.js.map} +0 -0
  108. /package/dist/cli/{chunk-UCMTWZKU.js.map → chunk-2CXPDAWX.js.map} +0 -0
  109. /package/dist/cli/{chunk-XHQIK7B6.js.map → chunk-7SPOFTMT.js.map} +0 -0
  110. /package/dist/cli/{chunk-5GKJLNP2.js.map → chunk-7VFNPMKG.js.map} +0 -0
  111. /package/dist/cli/{chunk-VLNRQMCI.js.map → chunk-A7VHMMDE.js.map} +0 -0
  112. /package/dist/cli/{chunk-AVB3WZWU.js.map → chunk-AT6GGIBV.js.map} +0 -0
  113. /package/dist/cli/{chunk-JWCTX5S4.js.map → chunk-L7W3HJZQ.js.map} +0 -0
  114. /package/dist/cli/{chunk-IYF36OCJ.js.map → chunk-LTXADNCO.js.map} +0 -0
  115. /package/dist/cli/{chunk-ULBW7DYL.js.map → chunk-RAUPWSYA.js.map} +0 -0
  116. /package/dist/cli/{chunk-4X3NY5ZM.js.map → chunk-UV7XJUJH.js.map} +0 -0
  117. /package/dist/cli/{chunk-XJLZ4HKU.js.map → chunk-VFG4GIT3.js.map} +0 -0
  118. /package/dist/cli/{chunk-FFNOMR32.js.map → chunk-WE3YZULK.js.map} +0 -0
  119. /package/dist/cli/{commands-FQZOBLLZ.js.map → commands-QY7MSQG7.js.map} +0 -0
  120. /package/dist/cli/{commit-ZS24SHPG.js.map → commit-BRCQ3OQO.js.map} +0 -0
  121. /package/dist/cli/{diff-2VUKNGEI.js.map → diff-YASCB7PU.js.map} +0 -0
  122. /package/dist/cli/{doctor-JO2WNN6C.js.map → doctor-XCN5ETVP.js.map} +0 -0
  123. /package/dist/cli/{events-APSVNROZ.js.map → events-2AJTXR7I.js.map} +0 -0
  124. /package/dist/cli/{mcp-DCKOE5RF.js.map → mcp-YMWBLRR7.js.map} +0 -0
  125. /package/dist/cli/{prompt-PKCCLLAD.js.map → prompt-RSIHN62V.js.map} +0 -0
  126. /package/dist/cli/{prune-sessions-LV33R47N.js.map → prune-sessions-4N3BVST2.js.map} +0 -0
  127. /package/dist/cli/{replay-WFCYX7XF.js.map → replay-3GTWM75X.js.map} +0 -0
  128. /package/dist/cli/{sessions-F5GPGTJN.js.map → sessions-BOWFPTXT.js.map} +0 -0
  129. /package/dist/cli/{setup-WWMDBPSB.js.map → setup-FQL2JJC2.js.map} +0 -0
  130. /package/dist/cli/{version-KQUPV6T5.js.map → version-XQXYSJ5L.js.map} +0 -0
@@ -0,0 +1,708 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ buildCodeToolset
4
+ } from "./chunk-AT6GGIBV.js";
5
+ import "./chunk-RAUPWSYA.js";
6
+ import {
7
+ Eventizer,
8
+ autoResolveVerdict
9
+ } from "./chunk-A7VHMMDE.js";
10
+ import {
11
+ formatMcpLifecycleEvent,
12
+ formatMcpSlowToast
13
+ } from "./chunk-LTXADNCO.js";
14
+ import {
15
+ buildTransportFromSpec,
16
+ preflightStdioSpec
17
+ } from "./chunk-BOFL3T45.js";
18
+ import {
19
+ CacheFirstLoop,
20
+ ImmutablePrefix,
21
+ bridgeMcpTools
22
+ } from "./chunk-IEA6JOIP.js";
23
+ import "./chunk-VFG4GIT3.js";
24
+ import {
25
+ openTranscriptFile,
26
+ recordFromLoopEvent,
27
+ writeRecord
28
+ } from "./chunk-7SPOFTMT.js";
29
+ import {
30
+ McpClient,
31
+ parseMcpSpec
32
+ } from "./chunk-CFY2XLY6.js";
33
+ import {
34
+ codeSystemPrompt
35
+ } from "./chunk-ARF3N2SY.js";
36
+ import {
37
+ canonicalPresetName,
38
+ resolvePreset
39
+ } from "./chunk-E46ECXJD.js";
40
+ import "./chunk-DAEAAVDF.js";
41
+ import {
42
+ DeepSeekClient
43
+ } from "./chunk-H4OLWRSX.js";
44
+ import {
45
+ loadDotenv
46
+ } from "./chunk-3Q3C4W66.js";
47
+ import {
48
+ pauseGate
49
+ } from "./chunk-BYZGO3BX.js";
50
+ import "./chunk-CD4SCQL4.js";
51
+ import "./chunk-FM57FNPJ.js";
52
+ import "./chunk-4H3ZRJ2U.js";
53
+ import "./chunk-WE3YZULK.js";
54
+ import "./chunk-5X7LZJDE.js";
55
+ import {
56
+ timestampSuffix
57
+ } from "./chunk-YJFKFTAL.js";
58
+ import "./chunk-MHGPBJ2T.js";
59
+ import {
60
+ loadApiKey,
61
+ loadBaseUrl,
62
+ loadEditMode,
63
+ loadPreset,
64
+ loadReasoningEffort,
65
+ mcpEnvFor,
66
+ readConfig
67
+ } from "./chunk-65Q5HQ26.js";
68
+ import "./chunk-ZTLZO42A.js";
69
+ import "./chunk-ORM6PK57.js";
70
+ import {
71
+ VERSION
72
+ } from "./chunk-CRPQUBP6.js";
73
+
74
+ // src/cli/commands/acp.ts
75
+ import { AsyncLocalStorage } from "async_hooks";
76
+ import { existsSync, statSync } from "fs";
77
+ import { resolve } from "path";
78
+
79
+ // src/acp/dispatch.ts
80
+ var READ_TOOLS = /* @__PURE__ */ new Set([
81
+ "read_file",
82
+ "list_directory",
83
+ "directory_tree",
84
+ "get_file_info",
85
+ "glob"
86
+ ]);
87
+ var EDIT_TOOLS = /* @__PURE__ */ new Set([
88
+ "write_file",
89
+ "edit_file",
90
+ "multi_edit",
91
+ "create_directory",
92
+ "delete_file",
93
+ "delete_directory",
94
+ "move_file",
95
+ "copy_file"
96
+ ]);
97
+ var SEARCH_TOOLS = /* @__PURE__ */ new Set(["search_content", "search_files"]);
98
+ var EXECUTE_TOOLS = /* @__PURE__ */ new Set(["run_command", "run_background"]);
99
+ function toolKindFor(name) {
100
+ if (READ_TOOLS.has(name)) return "read";
101
+ if (EDIT_TOOLS.has(name)) return "edit";
102
+ if (SEARCH_TOOLS.has(name)) return "search";
103
+ if (EXECUTE_TOOLS.has(name)) return "execute";
104
+ return "other";
105
+ }
106
+ function tryParseJson(raw) {
107
+ if (!raw) return void 0;
108
+ try {
109
+ return JSON.parse(raw);
110
+ } catch {
111
+ return raw;
112
+ }
113
+ }
114
+ function dispatchKernelEvent(server, sessionId, ev) {
115
+ switch (ev.type) {
116
+ case "model.delta": {
117
+ if (!ev.text) return;
118
+ const variant = ev.channel === "reasoning" ? "agent_thought_chunk" : "agent_message_chunk";
119
+ emit(server, {
120
+ sessionId,
121
+ update: { sessionUpdate: variant, content: { type: "text", text: ev.text } }
122
+ });
123
+ return;
124
+ }
125
+ case "tool.preparing": {
126
+ emit(server, {
127
+ sessionId,
128
+ update: {
129
+ sessionUpdate: "tool_call",
130
+ toolCallId: ev.callId,
131
+ title: ev.name,
132
+ kind: toolKindFor(ev.name),
133
+ status: "pending"
134
+ }
135
+ });
136
+ return;
137
+ }
138
+ case "tool.intent": {
139
+ emit(server, {
140
+ sessionId,
141
+ update: {
142
+ sessionUpdate: "tool_call_update",
143
+ toolCallId: ev.callId,
144
+ status: "in_progress"
145
+ }
146
+ });
147
+ const rawInput = tryParseJson(ev.args);
148
+ if (rawInput !== void 0) {
149
+ emit(server, {
150
+ sessionId,
151
+ update: {
152
+ sessionUpdate: "tool_call",
153
+ toolCallId: ev.callId,
154
+ title: ev.name,
155
+ kind: toolKindFor(ev.name),
156
+ status: "in_progress",
157
+ rawInput
158
+ }
159
+ });
160
+ }
161
+ return;
162
+ }
163
+ case "tool.result": {
164
+ emit(server, {
165
+ sessionId,
166
+ update: {
167
+ sessionUpdate: "tool_call_update",
168
+ toolCallId: ev.callId,
169
+ status: ev.ok ? "completed" : "failed",
170
+ content: [
171
+ {
172
+ type: "content",
173
+ content: { type: "text", text: clip(ev.output) }
174
+ }
175
+ ]
176
+ }
177
+ });
178
+ return;
179
+ }
180
+ default:
181
+ return;
182
+ }
183
+ }
184
+ var MAX_RESULT_CHARS = 8e3;
185
+ function clip(text) {
186
+ if (text.length <= MAX_RESULT_CHARS) return text;
187
+ return `${text.slice(0, MAX_RESULT_CHARS)}
188
+ \u2026(${text.length - MAX_RESULT_CHARS} more chars truncated)`;
189
+ }
190
+ function emit(server, params) {
191
+ server.sendNotification("session/update", params);
192
+ }
193
+
194
+ // src/acp/gates.ts
195
+ var ID_ALLOW_ONCE = "allow_once";
196
+ var ID_ALLOW_ALWAYS = "allow_always";
197
+ var ID_REJECT = "reject";
198
+ var ID_REFINE = "refine";
199
+ var ID_REVISE = "revise";
200
+ var ID_STOP = "stop";
201
+ var ID_CANCEL = "cancel";
202
+ var ID_ACCEPT = "accept";
203
+ function permissionOptionsFor(req) {
204
+ switch (req.kind) {
205
+ case "run_command":
206
+ case "run_background":
207
+ case "path_access":
208
+ return [
209
+ { optionId: ID_ALLOW_ONCE, name: "Allow once", kind: "allow_once" },
210
+ { optionId: ID_ALLOW_ALWAYS, name: "Allow always", kind: "allow_always" },
211
+ { optionId: ID_REJECT, name: "Reject", kind: "reject_once" }
212
+ ];
213
+ case "plan_proposed":
214
+ return [
215
+ { optionId: ID_ALLOW_ONCE, name: "Approve plan", kind: "allow_once" },
216
+ { optionId: ID_REFINE, name: "Refine", kind: "allow_once" },
217
+ { optionId: ID_CANCEL, name: "Cancel", kind: "reject_once" }
218
+ ];
219
+ case "plan_checkpoint":
220
+ return [
221
+ { optionId: ID_ALLOW_ONCE, name: "Continue", kind: "allow_once" },
222
+ { optionId: ID_REVISE, name: "Revise", kind: "allow_once" },
223
+ { optionId: ID_STOP, name: "Stop", kind: "reject_once" }
224
+ ];
225
+ case "plan_revision":
226
+ return [
227
+ { optionId: ID_ACCEPT, name: "Accept revision", kind: "allow_once" },
228
+ { optionId: ID_REJECT, name: "Keep original plan", kind: "reject_once" }
229
+ ];
230
+ case "choice": {
231
+ const payload = req.payload;
232
+ const opts = (payload.options ?? []).map((o) => ({
233
+ optionId: o.id,
234
+ name: o.title ?? o.id,
235
+ kind: "allow_once"
236
+ }));
237
+ opts.push({ optionId: ID_CANCEL, name: "Cancel", kind: "reject_once" });
238
+ return opts;
239
+ }
240
+ }
241
+ }
242
+ function commandPrefix(command) {
243
+ const first = command.trim().split(/\s+/)[0] ?? command.trim();
244
+ return `${first} *`;
245
+ }
246
+ function pathPrefix(p) {
247
+ return p;
248
+ }
249
+ function verdictFor(req, result) {
250
+ const cancelled = result.outcome.outcome === "cancelled";
251
+ const optionId = result.outcome.outcome === "selected" ? result.outcome.optionId : null;
252
+ switch (req.kind) {
253
+ case "run_command":
254
+ case "run_background": {
255
+ if (cancelled || optionId === ID_REJECT) return { type: "deny" };
256
+ if (optionId === ID_ALLOW_ALWAYS) {
257
+ const payload = req.payload;
258
+ return { type: "always_allow", prefix: commandPrefix(payload.command ?? "") };
259
+ }
260
+ return { type: "run_once" };
261
+ }
262
+ case "path_access": {
263
+ if (cancelled || optionId === ID_REJECT) return { type: "deny" };
264
+ if (optionId === ID_ALLOW_ALWAYS) {
265
+ const payload = req.payload;
266
+ return { type: "always_allow", prefix: pathPrefix(payload.allowPrefix) };
267
+ }
268
+ return { type: "run_once" };
269
+ }
270
+ case "plan_proposed": {
271
+ if (cancelled || optionId === ID_CANCEL) return { type: "cancel" };
272
+ if (optionId === ID_REFINE) return { type: "refine" };
273
+ return { type: "approve" };
274
+ }
275
+ case "plan_checkpoint": {
276
+ if (cancelled || optionId === ID_STOP) return { type: "stop" };
277
+ if (optionId === ID_REVISE) return { type: "revise" };
278
+ return { type: "continue" };
279
+ }
280
+ case "plan_revision": {
281
+ if (cancelled) return { type: "cancelled" };
282
+ if (optionId === ID_ACCEPT) return { type: "accepted" };
283
+ return { type: "rejected" };
284
+ }
285
+ case "choice": {
286
+ if (cancelled || optionId === ID_CANCEL || !optionId) return { type: "cancel" };
287
+ return { type: "pick", optionId };
288
+ }
289
+ }
290
+ }
291
+ function permissionTitleFor(req) {
292
+ switch (req.kind) {
293
+ case "run_command":
294
+ case "run_background":
295
+ return `Run command \u2014 ${(req.payload.command ?? "").slice(0, 80)}`;
296
+ case "path_access":
297
+ return `Access path \u2014 ${req.payload.path}`;
298
+ case "plan_proposed":
299
+ return "Approve plan";
300
+ case "plan_checkpoint":
301
+ return `Checkpoint \u2014 ${req.payload.title ?? "step complete"}`;
302
+ case "plan_revision":
303
+ return "Approve plan revision";
304
+ case "choice":
305
+ return req.payload.question ?? "Choose an option";
306
+ }
307
+ }
308
+ function permissionKindFor(req) {
309
+ if (req.kind === "run_command" || req.kind === "run_background") return "execute";
310
+ if (req.kind === "path_access") {
311
+ return req.payload.intent === "write" ? "edit" : "other";
312
+ }
313
+ return "other";
314
+ }
315
+ async function requestPermissionForGate(server, sessionId, req) {
316
+ const params = {
317
+ sessionId,
318
+ toolCall: {
319
+ toolCallId: `gate-${req.id}`,
320
+ title: permissionTitleFor(req),
321
+ kind: permissionKindFor(req),
322
+ status: "pending",
323
+ rawInput: req.payload
324
+ },
325
+ options: permissionOptionsFor(req)
326
+ };
327
+ let result;
328
+ try {
329
+ result = await server.sendRequest(
330
+ "session/request_permission",
331
+ params
332
+ );
333
+ } catch {
334
+ result = { outcome: { outcome: "cancelled" } };
335
+ }
336
+ return verdictFor(req, result);
337
+ }
338
+
339
+ // src/acp/protocol.ts
340
+ var ACP_PROTOCOL_VERSION = 1;
341
+ var ERR_PARSE = -32700;
342
+ var ERR_METHOD_NOT_FOUND = -32601;
343
+ var ERR_INVALID_PARAMS = -32602;
344
+ var ERR_INTERNAL = -32603;
345
+ function flattenPrompt(blocks) {
346
+ const parts = [];
347
+ for (const b of blocks) {
348
+ if (b.type === "text") parts.push(b.text);
349
+ else if (b.type === "resource" && b.resource.text) parts.push(b.resource.text);
350
+ }
351
+ return parts.join("\n\n").trim();
352
+ }
353
+
354
+ // src/acp/server.ts
355
+ import { createInterface } from "readline";
356
+ var AcpServer = class {
357
+ requestHandlers = /* @__PURE__ */ new Map();
358
+ notificationHandlers = /* @__PURE__ */ new Map();
359
+ pending = /* @__PURE__ */ new Map();
360
+ nextOutboundId = 1;
361
+ output;
362
+ rl;
363
+ closed = false;
364
+ constructor(opts = {}) {
365
+ this.output = opts.output ?? process.stdout;
366
+ const input = opts.input ?? process.stdin;
367
+ this.rl = createInterface({ input });
368
+ this.rl.on("line", (line) => {
369
+ void this.handleLine(line);
370
+ });
371
+ }
372
+ onRequest(method, handler) {
373
+ this.requestHandlers.set(method, handler);
374
+ }
375
+ onNotification(method, handler) {
376
+ this.notificationHandlers.set(method, handler);
377
+ }
378
+ sendNotification(method, params) {
379
+ this.write({ jsonrpc: "2.0", method, params });
380
+ }
381
+ /** Send an outbound JSON-RPC request and resolve when the peer responds. */
382
+ sendRequest(method, params) {
383
+ const id = this.nextOutboundId++;
384
+ return new Promise((resolve2, reject) => {
385
+ this.pending.set(id, {
386
+ resolve: resolve2,
387
+ reject
388
+ });
389
+ this.write({ jsonrpc: "2.0", id, method, params });
390
+ });
391
+ }
392
+ close() {
393
+ if (this.closed) return;
394
+ this.closed = true;
395
+ for (const p of this.pending.values()) p.reject(new Error("server closed"));
396
+ this.pending.clear();
397
+ this.rl.close();
398
+ }
399
+ /** Wait for the input stream to end. */
400
+ done() {
401
+ return new Promise((resolve2) => this.rl.once("close", () => resolve2()));
402
+ }
403
+ write(msg) {
404
+ this.output.write(`${JSON.stringify(msg)}
405
+ `);
406
+ }
407
+ writeError(id, code, message) {
408
+ this.write({ jsonrpc: "2.0", id, error: { code, message } });
409
+ }
410
+ async handleLine(raw) {
411
+ const line = raw.trim();
412
+ if (!line) return;
413
+ let parsed;
414
+ try {
415
+ parsed = JSON.parse(line);
416
+ } catch {
417
+ this.writeError(null, ERR_PARSE, "parse error");
418
+ return;
419
+ }
420
+ if (!parsed || typeof parsed !== "object") {
421
+ this.writeError(null, ERR_PARSE, "expected JSON object");
422
+ return;
423
+ }
424
+ const msg = parsed;
425
+ if (typeof msg.method === "string" && msg.id !== void 0) {
426
+ const id = msg.id;
427
+ const handler = this.requestHandlers.get(msg.method);
428
+ if (!handler) {
429
+ this.writeError(id, ERR_METHOD_NOT_FOUND, `method not found: ${msg.method}`);
430
+ return;
431
+ }
432
+ try {
433
+ const result = await handler(msg.params);
434
+ this.write({ jsonrpc: "2.0", id, result });
435
+ } catch (err) {
436
+ this.writeError(id, ERR_INTERNAL, err.message);
437
+ }
438
+ return;
439
+ }
440
+ if (typeof msg.method === "string" && msg.id === void 0) {
441
+ const handler = this.notificationHandlers.get(msg.method);
442
+ if (!handler) return;
443
+ try {
444
+ await handler(msg.params);
445
+ } catch {
446
+ }
447
+ return;
448
+ }
449
+ if (msg.id !== void 0 && msg.method === void 0) {
450
+ const response = parsed;
451
+ const pending = this.pending.get(response.id);
452
+ if (!pending) return;
453
+ this.pending.delete(response.id);
454
+ if (response.error) {
455
+ pending.reject(new Error(response.error.message));
456
+ } else {
457
+ pending.resolve(response.result);
458
+ }
459
+ }
460
+ }
461
+ };
462
+
463
+ // src/cli/commands/acp.ts
464
+ function resolveMcpPrefix(specName, specCount, globalPrefix) {
465
+ if (specName) return `${specName}_`;
466
+ if (specCount === 1 && globalPrefix) return globalPrefix;
467
+ return "";
468
+ }
469
+ async function loadMcpServers(tools, specs, globalPrefix) {
470
+ const clients = [];
471
+ if (specs.length === 0) return clients;
472
+ const cfg = readConfig();
473
+ const disabledNames = new Set(cfg.mcpDisabled ?? []);
474
+ for (const raw of specs) {
475
+ let label = "anon";
476
+ let mcp;
477
+ try {
478
+ const spec = parseMcpSpec(raw);
479
+ label = spec.name ?? "anon";
480
+ if (spec.name && disabledNames.has(spec.name)) {
481
+ process.stderr.write(`${formatMcpLifecycleEvent({ state: "disabled", name: label })}
482
+ `);
483
+ continue;
484
+ }
485
+ process.stderr.write(`${formatMcpLifecycleEvent({ state: "handshake", name: label })}
486
+ `);
487
+ const t0 = Date.now();
488
+ const prefix = resolveMcpPrefix(spec.name, specs.length, globalPrefix);
489
+ if (spec.transport === "stdio") preflightStdioSpec(spec);
490
+ const transport = buildTransportFromSpec(spec, { env: mcpEnvFor(spec.name, cfg) });
491
+ mcp = new McpClient({ transport });
492
+ await mcp.initialize();
493
+ const bridge = await bridgeMcpTools(mcp, {
494
+ registry: tools,
495
+ namePrefix: prefix,
496
+ serverName: label,
497
+ onSlow: (info) => process.stderr.write(
498
+ `${formatMcpSlowToast({ name: info.serverName, p95Ms: info.p95Ms, sampleSize: info.sampleSize })}
499
+ `
500
+ )
501
+ });
502
+ process.stderr.write(
503
+ `${formatMcpLifecycleEvent({
504
+ state: "connected",
505
+ name: label,
506
+ tools: bridge.registeredNames.length,
507
+ ms: Date.now() - t0
508
+ })}
509
+ `
510
+ );
511
+ clients.push(mcp);
512
+ } catch (err) {
513
+ await mcp?.close().catch(() => void 0);
514
+ process.stderr.write(
515
+ `${formatMcpLifecycleEvent({ state: "failed", name: label, reason: err.message })}
516
+ \u2192 run \`reasonix setup\` to remove broken entries from your saved config.
517
+ `
518
+ );
519
+ }
520
+ }
521
+ return clients;
522
+ }
523
+ function resolveDir(raw, fallback) {
524
+ if (!raw) return fallback;
525
+ const abs = resolve(raw);
526
+ if (!existsSync(abs) || !statSync(abs).isDirectory()) {
527
+ throw new Error(`workspace directory not found: ${abs}`);
528
+ }
529
+ return abs;
530
+ }
531
+ async function buildSession(opts) {
532
+ const preset = canonicalPresetName(loadPreset());
533
+ const resolved = resolvePreset(preset);
534
+ const model = opts.modelOverride || resolved.model;
535
+ const toolset = await buildCodeToolset({ rootDir: opts.rootDir });
536
+ const mcpClients = await loadMcpServers(toolset.tools, opts.mcpSpecs ?? [], opts.mcpPrefix);
537
+ const system = codeSystemPrompt(opts.rootDir, {
538
+ hasSemanticSearch: toolset.semantic.enabled,
539
+ modelId: model
540
+ });
541
+ const client = new DeepSeekClient({ baseUrl: loadBaseUrl() });
542
+ const prefix = new ImmutablePrefix({ system, toolSpecs: toolset.tools.specs() });
543
+ const loop = new CacheFirstLoop({
544
+ client,
545
+ prefix,
546
+ tools: toolset.tools,
547
+ model,
548
+ budgetUsd: opts.budgetUsd,
549
+ session: `acp-${timestampSuffix()}`
550
+ });
551
+ return {
552
+ id: `sess_${timestampSuffix()}-${Math.random().toString(36).slice(2, 8)}`,
553
+ rootDir: opts.rootDir,
554
+ model,
555
+ toolset,
556
+ mcpClients,
557
+ loop,
558
+ eventizer: new Eventizer(),
559
+ ctx: {
560
+ model,
561
+ prefixHash: prefix.fingerprint,
562
+ reasoningEffort: loadReasoningEffort()
563
+ },
564
+ aborter: null
565
+ };
566
+ }
567
+ async function acpCommand(opts) {
568
+ loadDotenv();
569
+ if (loadApiKey()) {
570
+ process.env.DEEPSEEK_API_KEY = loadApiKey();
571
+ }
572
+ const defaultDir = resolveDir(opts.dir, process.cwd());
573
+ const sessions = /* @__PURE__ */ new Map();
574
+ const sessionContext = new AsyncLocalStorage();
575
+ const server = new AcpServer();
576
+ let transcriptStream = null;
577
+ if (opts.transcript) {
578
+ const defaultModel = opts.model || resolvePreset(canonicalPresetName(loadPreset())).model;
579
+ transcriptStream = openTranscriptFile(opts.transcript, {
580
+ version: 1,
581
+ source: "reasonix acp",
582
+ model: defaultModel,
583
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
584
+ });
585
+ }
586
+ pauseGate.on((req) => {
587
+ const editMode = opts.yolo ? "yolo" : loadEditMode();
588
+ const auto = autoResolveVerdict(req, editMode);
589
+ if (auto !== null) {
590
+ pauseGate.resolve(req.id, auto);
591
+ return;
592
+ }
593
+ const activeSessionId = sessionContext.getStore();
594
+ if (!activeSessionId || !sessions.has(activeSessionId)) {
595
+ pauseGate.cancel(req.id);
596
+ return;
597
+ }
598
+ void (async () => {
599
+ const verdict = await requestPermissionForGate(server, activeSessionId, req);
600
+ pauseGate.resolve(req.id, verdict);
601
+ })();
602
+ });
603
+ server.onRequest("initialize", (params) => {
604
+ if (!params || typeof params !== "object") {
605
+ throw Object.assign(new Error("initialize: missing params"), { code: ERR_INVALID_PARAMS });
606
+ }
607
+ return {
608
+ protocolVersion: ACP_PROTOCOL_VERSION,
609
+ agentCapabilities: {
610
+ loadSession: false,
611
+ promptCapabilities: { image: false, audio: false, embeddedContext: true },
612
+ mcpCapabilities: { http: false, sse: false }
613
+ },
614
+ agentInfo: { name: "reasonix", title: "Reasonix", version: VERSION },
615
+ authMethods: []
616
+ };
617
+ });
618
+ server.onRequest("session/new", async (params) => {
619
+ const rootDir = resolveDir(params?.cwd, defaultDir);
620
+ const session = await buildSession({
621
+ rootDir,
622
+ modelOverride: opts.model,
623
+ budgetUsd: opts.budgetUsd,
624
+ mcpSpecs: opts.mcpSpecs,
625
+ mcpPrefix: opts.mcpPrefix
626
+ });
627
+ sessions.set(session.id, session);
628
+ return { sessionId: session.id };
629
+ });
630
+ server.onRequest("session/prompt", async (params) => {
631
+ if (!params?.sessionId) {
632
+ throw Object.assign(new Error("session/prompt: missing sessionId"), {
633
+ code: ERR_INVALID_PARAMS
634
+ });
635
+ }
636
+ const session = sessions.get(params.sessionId);
637
+ if (!session) {
638
+ throw Object.assign(new Error(`session/prompt: unknown session ${params.sessionId}`), {
639
+ code: ERR_INVALID_PARAMS
640
+ });
641
+ }
642
+ const text = flattenPrompt(params.prompt);
643
+ if (!text) {
644
+ throw Object.assign(new Error("session/prompt: empty prompt"), { code: ERR_INVALID_PARAMS });
645
+ }
646
+ session.aborter = new AbortController();
647
+ let stopReason = "end_turn";
648
+ try {
649
+ await sessionContext.run(session.id, async () => {
650
+ for await (const ev of session.loop.step(text)) {
651
+ if (session.aborter?.signal.aborted) {
652
+ stopReason = "cancelled";
653
+ break;
654
+ }
655
+ if (transcriptStream) {
656
+ writeRecord(
657
+ transcriptStream,
658
+ recordFromLoopEvent(ev, {
659
+ model: session.ctx.model,
660
+ prefixHash: session.ctx.prefixHash
661
+ })
662
+ );
663
+ }
664
+ for (const kev of session.eventizer.consume(ev, session.ctx)) {
665
+ dispatchKernelEvent(server, session.id, kev);
666
+ if (kev.type === "error") stopReason = "error";
667
+ }
668
+ }
669
+ });
670
+ } catch (err) {
671
+ const message = err.message;
672
+ server.sendNotification("session/update", {
673
+ sessionId: session.id,
674
+ update: {
675
+ sessionUpdate: "agent_message_chunk",
676
+ content: { type: "text", text: `
677
+
678
+ [error] ${message}` }
679
+ }
680
+ });
681
+ stopReason = "error";
682
+ } finally {
683
+ session.aborter = null;
684
+ }
685
+ return { stopReason };
686
+ });
687
+ server.onNotification("session/cancel", (params) => {
688
+ const session = params?.sessionId ? sessions.get(params.sessionId) : void 0;
689
+ session?.aborter?.abort();
690
+ });
691
+ try {
692
+ await server.done();
693
+ } finally {
694
+ transcriptStream?.end();
695
+ const closes = [];
696
+ for (const session of sessions.values()) {
697
+ for (const mcp of session.mcpClients) {
698
+ closes.push(mcp.close().catch(() => void 0));
699
+ }
700
+ }
701
+ await Promise.all(closes);
702
+ }
703
+ }
704
+ export {
705
+ acpCommand,
706
+ loadMcpServers
707
+ };
708
+ //# sourceMappingURL=acp-64VQZLDJ.js.map