reasonix 0.47.2 → 0.48.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 (129) hide show
  1. package/README.md +14 -26
  2. package/README.zh-CN.md +5 -26
  3. package/dist/cli/{acp-GEOAKSTU.js → acp-QJGGHQLA.js} +52 -135
  4. package/dist/cli/acp-QJGGHQLA.js.map +1 -0
  5. package/dist/cli/{chat-YTPATMMG.js → chat-ZXF227MP.js} +25 -25
  6. package/dist/cli/{chunk-DN4B5S6Y.js → chunk-3FULTFRB.js} +2 -2
  7. package/dist/cli/chunk-43ROGEX2.js +5190 -0
  8. package/dist/cli/chunk-43ROGEX2.js.map +1 -0
  9. package/dist/cli/{chunk-DQ6K5ZQ7.js → chunk-4E2BHJU4.js} +4 -4
  10. package/dist/cli/chunk-4E2BHJU4.js.map +1 -0
  11. package/dist/cli/{chunk-T5A7EY6B.js → chunk-5AW6NIHU.js} +2 -2
  12. package/dist/cli/{chunk-DWPAKZTY.js → chunk-5U5LMMFF.js} +2 -2
  13. package/dist/cli/{chunk-TRSAHHCL.js → chunk-6FRNXWDZ.js} +321 -76
  14. package/dist/cli/chunk-6FRNXWDZ.js.map +1 -0
  15. package/dist/cli/{chunk-KYQVQ5X4.js → chunk-B5CZL2SE.js} +9 -4
  16. package/dist/cli/chunk-B5CZL2SE.js.map +1 -0
  17. package/dist/cli/{chunk-XMHP7BEE.js → chunk-DABAOQSV.js} +2273 -2517
  18. package/dist/cli/chunk-DABAOQSV.js.map +1 -0
  19. package/dist/cli/chunk-EO6RPTJG.js +831 -0
  20. package/dist/cli/chunk-EO6RPTJG.js.map +1 -0
  21. package/dist/cli/{chunk-BQ6HC66J.js → chunk-FD7SNDWW.js} +4 -14
  22. package/dist/cli/chunk-FD7SNDWW.js.map +1 -0
  23. package/dist/cli/chunk-FPME5QOO.js +17747 -0
  24. package/dist/cli/chunk-FPME5QOO.js.map +1 -0
  25. package/dist/cli/{chunk-6QC5RQLE.js → chunk-H2F4LDNH.js} +2 -2
  26. package/dist/cli/{chunk-QCFLPSPH.js → chunk-IKSYVBBZ.js} +2 -2
  27. package/dist/cli/{chunk-5QCB62C4.js → chunk-J2TQAWOM.js} +135 -18
  28. package/dist/cli/{chunk-5QCB62C4.js.map → chunk-J2TQAWOM.js.map} +1 -1
  29. package/dist/cli/{chunk-JBH5RM7X.js → chunk-JFBGSWQB.js} +395 -85
  30. package/dist/cli/chunk-JFBGSWQB.js.map +1 -0
  31. package/dist/cli/{chunk-CCJAP7G3.js → chunk-KH5JIJJD.js} +2 -2
  32. package/dist/cli/{chunk-TDHXB2ER.js → chunk-NQZ5U37J.js} +2 -2
  33. package/dist/cli/{chunk-CNG32VAB.js → chunk-O3AGYTG2.js} +2 -2
  34. package/dist/cli/{chunk-NRQ5UP5T.js → chunk-PIC5HJRD.js} +234 -40
  35. package/dist/cli/chunk-PIC5HJRD.js.map +1 -0
  36. package/dist/cli/{chunk-GH7DC2Y5.js → chunk-PJIQIYTV.js} +6 -3
  37. package/dist/cli/chunk-PJIQIYTV.js.map +1 -0
  38. package/dist/cli/{chunk-KVZZ5U75.js → chunk-R7U44O3Y.js} +2 -2
  39. package/dist/cli/{chunk-ZXSCAODE.js → chunk-RCLS63KE.js} +71 -3
  40. package/dist/cli/chunk-RCLS63KE.js.map +1 -0
  41. package/dist/cli/{chunk-FY4S7TJZ.js → chunk-SLAFMXAZ.js} +10 -2
  42. package/dist/cli/chunk-SLAFMXAZ.js.map +1 -0
  43. package/dist/cli/{chunk-TRWHTFG7.js → chunk-SWUMD2LX.js} +2 -2
  44. package/dist/cli/{chunk-2XY77LW7.js → chunk-TIJ4ZHD6.js} +56 -24
  45. package/dist/cli/chunk-TIJ4ZHD6.js.map +1 -0
  46. package/dist/cli/{chunk-4MFCAZ2W.js → chunk-WKOXKCF3.js} +3 -3
  47. package/dist/cli/{chunk-HUILPCYX.js → chunk-XMR2VCGT.js} +3 -3
  48. package/dist/cli/{code-Q4NRVEDG.js → code-OKA5YPOH.js} +31 -32
  49. package/dist/cli/code-OKA5YPOH.js.map +1 -0
  50. package/dist/cli/{commands-4CDI4GFM.js → commands-3U6PUVSS.js} +4 -4
  51. package/dist/cli/{commit-GW7LDQP5.js → commit-HFB7SRBU.js} +3 -3
  52. package/dist/cli/{desktop-EG6P5SF2.js → desktop-G7UMW3CJ.js} +503 -48
  53. package/dist/cli/desktop-G7UMW3CJ.js.map +1 -0
  54. package/dist/cli/{diff-VI2YX4FN.js → diff-PGXW4YZD.js} +8 -8
  55. package/dist/cli/{doctor-CQTTZP27.js → doctor-WWJFLVCB.js} +9 -9
  56. package/dist/cli/index.js +53 -41
  57. package/dist/cli/index.js.map +1 -1
  58. package/dist/cli/{mcp-J2UCD4RZ.js → mcp-Y3VKIK3T.js} +2 -2
  59. package/dist/cli/{mcp-browse-GSX34JEK.js → mcp-browse-4IN2QIFR.js} +2 -2
  60. package/dist/cli/{mcp-inspect-RRFYF4ZV.js → mcp-inspect-BUXFXDHB.js} +2 -2
  61. package/dist/cli/{prompt-5TQPIVHV.js → prompt-US57R6BA.js} +5 -4
  62. package/dist/cli/{replay-MJCEMODU.js → replay-EQJMZRB3.js} +8 -8
  63. package/dist/cli/{run-P4D5VDYE.js → run-KVEI66TR.js} +14 -14
  64. package/dist/cli/{server-C25JNNZV.js → server-D6C4GHWN.js} +18 -15
  65. package/dist/cli/server-D6C4GHWN.js.map +1 -0
  66. package/dist/cli/{sessions-QIONZJQ6.js → sessions-TGVS2RQZ.js} +13 -13
  67. package/dist/cli/{setup-NLQ6G5G4.js → setup-WLKX6GGG.js} +5 -5
  68. package/dist/cli/{stats-DFZEXHP4.js → stats-TCD7Q6MB.js} +6 -6
  69. package/dist/cli/{version-GR3X3MPI.js → version-BCWWS2OU.js} +13 -13
  70. package/dist/grammars/tree-sitter-go.wasm +0 -0
  71. package/dist/grammars/tree-sitter-java.wasm +0 -0
  72. package/dist/grammars/tree-sitter-javascript.wasm +0 -0
  73. package/dist/grammars/tree-sitter-python.wasm +0 -0
  74. package/dist/grammars/tree-sitter-rust.wasm +0 -0
  75. package/dist/grammars/tree-sitter-tsx.wasm +0 -0
  76. package/dist/grammars/tree-sitter-typescript.wasm +0 -0
  77. package/dist/grammars/web-tree-sitter.wasm +0 -0
  78. package/dist/index.d.ts +46 -12
  79. package/dist/index.js +684 -129
  80. package/dist/index.js.map +1 -1
  81. package/package.json +16 -4
  82. package/dist/cli/acp-GEOAKSTU.js.map +0 -1
  83. package/dist/cli/chunk-2XY77LW7.js.map +0 -1
  84. package/dist/cli/chunk-6CRPCJAU.js +0 -3141
  85. package/dist/cli/chunk-6CRPCJAU.js.map +0 -1
  86. package/dist/cli/chunk-BQ6HC66J.js.map +0 -1
  87. package/dist/cli/chunk-DQ6K5ZQ7.js.map +0 -1
  88. package/dist/cli/chunk-FY4S7TJZ.js.map +0 -1
  89. package/dist/cli/chunk-GH7DC2Y5.js.map +0 -1
  90. package/dist/cli/chunk-JBH5RM7X.js.map +0 -1
  91. package/dist/cli/chunk-KYQVQ5X4.js.map +0 -1
  92. package/dist/cli/chunk-NRQ5UP5T.js.map +0 -1
  93. package/dist/cli/chunk-TRSAHHCL.js.map +0 -1
  94. package/dist/cli/chunk-XD6P7AFH.js +0 -375
  95. package/dist/cli/chunk-XD6P7AFH.js.map +0 -1
  96. package/dist/cli/chunk-XMHP7BEE.js.map +0 -1
  97. package/dist/cli/chunk-YFP3MYMY.js +0 -323
  98. package/dist/cli/chunk-YFP3MYMY.js.map +0 -1
  99. package/dist/cli/chunk-ZXSCAODE.js.map +0 -1
  100. package/dist/cli/code-Q4NRVEDG.js.map +0 -1
  101. package/dist/cli/desktop-EG6P5SF2.js.map +0 -1
  102. package/dist/cli/server-C25JNNZV.js.map +0 -1
  103. /package/dist/cli/{chat-YTPATMMG.js.map → chat-ZXF227MP.js.map} +0 -0
  104. /package/dist/cli/{chunk-DN4B5S6Y.js.map → chunk-3FULTFRB.js.map} +0 -0
  105. /package/dist/cli/{chunk-T5A7EY6B.js.map → chunk-5AW6NIHU.js.map} +0 -0
  106. /package/dist/cli/{chunk-DWPAKZTY.js.map → chunk-5U5LMMFF.js.map} +0 -0
  107. /package/dist/cli/{chunk-6QC5RQLE.js.map → chunk-H2F4LDNH.js.map} +0 -0
  108. /package/dist/cli/{chunk-QCFLPSPH.js.map → chunk-IKSYVBBZ.js.map} +0 -0
  109. /package/dist/cli/{chunk-CCJAP7G3.js.map → chunk-KH5JIJJD.js.map} +0 -0
  110. /package/dist/cli/{chunk-TDHXB2ER.js.map → chunk-NQZ5U37J.js.map} +0 -0
  111. /package/dist/cli/{chunk-CNG32VAB.js.map → chunk-O3AGYTG2.js.map} +0 -0
  112. /package/dist/cli/{chunk-KVZZ5U75.js.map → chunk-R7U44O3Y.js.map} +0 -0
  113. /package/dist/cli/{chunk-TRWHTFG7.js.map → chunk-SWUMD2LX.js.map} +0 -0
  114. /package/dist/cli/{chunk-4MFCAZ2W.js.map → chunk-WKOXKCF3.js.map} +0 -0
  115. /package/dist/cli/{chunk-HUILPCYX.js.map → chunk-XMR2VCGT.js.map} +0 -0
  116. /package/dist/cli/{commands-4CDI4GFM.js.map → commands-3U6PUVSS.js.map} +0 -0
  117. /package/dist/cli/{commit-GW7LDQP5.js.map → commit-HFB7SRBU.js.map} +0 -0
  118. /package/dist/cli/{diff-VI2YX4FN.js.map → diff-PGXW4YZD.js.map} +0 -0
  119. /package/dist/cli/{doctor-CQTTZP27.js.map → doctor-WWJFLVCB.js.map} +0 -0
  120. /package/dist/cli/{mcp-J2UCD4RZ.js.map → mcp-Y3VKIK3T.js.map} +0 -0
  121. /package/dist/cli/{mcp-browse-GSX34JEK.js.map → mcp-browse-4IN2QIFR.js.map} +0 -0
  122. /package/dist/cli/{mcp-inspect-RRFYF4ZV.js.map → mcp-inspect-BUXFXDHB.js.map} +0 -0
  123. /package/dist/cli/{prompt-5TQPIVHV.js.map → prompt-US57R6BA.js.map} +0 -0
  124. /package/dist/cli/{replay-MJCEMODU.js.map → replay-EQJMZRB3.js.map} +0 -0
  125. /package/dist/cli/{run-P4D5VDYE.js.map → run-KVEI66TR.js.map} +0 -0
  126. /package/dist/cli/{sessions-QIONZJQ6.js.map → sessions-TGVS2RQZ.js.map} +0 -0
  127. /package/dist/cli/{setup-NLQ6G5G4.js.map → setup-WLKX6GGG.js.map} +0 -0
  128. /package/dist/cli/{stats-DFZEXHP4.js.map → stats-TCD7Q6MB.js.map} +0 -0
  129. /package/dist/cli/{version-GR3X3MPI.js.map → version-BCWWS2OU.js.map} +0 -0
@@ -1,323 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
- import {
4
- formatMcpLifecycleEvent,
5
- formatMcpSlowToast
6
- } from "./chunk-DQ6K5ZQ7.js";
7
- import {
8
- buildTransportFromSpec,
9
- preflightStdioSpec
10
- } from "./chunk-EQATK2L2.js";
11
- import {
12
- bridgeMcpTools
13
- } from "./chunk-JBH5RM7X.js";
14
- import {
15
- McpClient,
16
- inspectMcpServer
17
- } from "./chunk-HIYTRCSW.js";
18
- import {
19
- t
20
- } from "./chunk-NRQ5UP5T.js";
21
- import {
22
- normalizeMcpConfig,
23
- overlayMatchedSpec,
24
- parseMcpSpec,
25
- readConfig,
26
- specToRaw
27
- } from "./chunk-6CRPCJAU.js";
28
-
29
- // src/mcp/summary.ts
30
- function buildMcpServerSummary(opts) {
31
- return {
32
- label: opts.label,
33
- spec: opts.spec,
34
- toolCount: opts.toolCount,
35
- report: opts.report,
36
- host: opts.host,
37
- bridgeEnv: opts.bridgeEnv,
38
- readResource(uri) {
39
- return opts.host.client.readResource(uri);
40
- },
41
- getPrompt(name, args) {
42
- return args !== void 0 ? opts.host.client.getPrompt(name, args) : opts.host.client.getPrompt(name);
43
- }
44
- };
45
- }
46
-
47
- // src/cli/commands/mcp-runtime.ts
48
- var stderrLifecycleSink = (n) => {
49
- if (n.kind === "slow") {
50
- process.stderr.write(
51
- `${formatMcpSlowToast({ name: n.serverName, p95Ms: n.p95Ms, sampleSize: n.sampleSize })}
52
- `
53
- );
54
- return;
55
- }
56
- if (n.kind === "failed") {
57
- process.stderr.write(
58
- `${formatMcpLifecycleEvent({ state: "failed", name: n.name, reason: n.reason })}
59
- \u2192 ${t("mcpLifecycle.failedSetupHint")}
60
- `
61
- );
62
- return;
63
- }
64
- if (n.kind === "connected") {
65
- process.stderr.write(
66
- `${formatMcpLifecycleEvent({
67
- state: "connected",
68
- name: n.name,
69
- tools: n.tools,
70
- resources: n.resources,
71
- prompts: n.prompts,
72
- ms: n.ms
73
- })}
74
- `
75
- );
76
- return;
77
- }
78
- if (n.kind === "tools-ready") {
79
- process.stderr.write(
80
- `${formatMcpLifecycleEvent({ state: "tools-ready", name: n.name, tools: n.tools, ms: n.ms })}
81
- `
82
- );
83
- return;
84
- }
85
- if (n.kind === "warn") {
86
- process.stderr.write(
87
- `${formatMcpLifecycleEvent({ state: "warn", name: n.name, reason: n.reason })}
88
- `
89
- );
90
- return;
91
- }
92
- process.stderr.write(
93
- `${formatMcpLifecycleEvent({ state: n.kind, name: n.name })}
94
- `
95
- );
96
- };
97
- function createMcpRuntime(ctx) {
98
- const records = /* @__PURE__ */ new Map();
99
- const insertionOrder = [];
100
- const failureMap = /* @__PURE__ */ new Map();
101
- let sink = stderrLifecycleSink;
102
- async function addSpec(raw, loop, signal) {
103
- if (records.has(raw)) {
104
- return { ok: true, summary: records.get(raw).summary };
105
- }
106
- failureMap.delete(raw);
107
- const tools = ctx.getTools();
108
- if (!tools) return { ok: false, reason: "no tool registry available" };
109
- const cfg = readConfig();
110
- const normalized = normalizeMcpConfig(cfg);
111
- let label = "anon";
112
- let mcp;
113
- let resolveReady;
114
- let rejectReady;
115
- const ready = new Promise((resolve, reject) => {
116
- resolveReady = resolve;
117
- rejectReady = reject;
118
- });
119
- ready.catch(() => void 0);
120
- try {
121
- const parsed = parseMcpSpec(raw);
122
- label = parsed.name ?? "anon";
123
- const matched = parsed.name ? normalized.find((s) => s.name === parsed.name) : void 0;
124
- const spec = overlayMatchedSpec(parsed, matched);
125
- if (spec.disabled) {
126
- sink({ kind: "disabled", name: label });
127
- rejectReady(new Error(`MCP server "${label}" is disabled`));
128
- failureMap.set(raw, { spec: raw, name: label, reason: "disabled by user", at: Date.now() });
129
- return { ok: false, reason: "disabled by user" };
130
- }
131
- sink({ kind: "handshake", name: label });
132
- const t0 = Date.now();
133
- const namePrefix = spec.name ? `${spec.name}_` : ctx.getRequestedCount() === 1 && ctx.getMcpPrefix() ? ctx.getMcpPrefix() : "";
134
- if (spec.transport === "stdio") preflightStdioSpec(spec);
135
- const transport = buildTransportFromSpec(spec);
136
- mcp = new McpClient({ transport });
137
- await mcp.initialize({ signal });
138
- const host = { client: mcp };
139
- const bridge = await bridgeMcpTools(mcp, {
140
- registry: tools,
141
- namePrefix,
142
- serverName: label,
143
- host,
144
- ready,
145
- onProgress: (info) => ctx.progressSink.current?.(info),
146
- onSlow: (info) => sink({
147
- kind: "slow",
148
- serverName: info.serverName,
149
- p95Ms: info.p95Ms,
150
- sampleSize: info.sampleSize
151
- })
152
- });
153
- const ms = Date.now() - t0;
154
- const allSpecs = tools.specs();
155
- const registeredSpecs = allSpecs.filter(
156
- (s) => bridge.registeredNames.includes(s.function.name)
157
- );
158
- records.set(raw, {
159
- spec: raw,
160
- client: mcp,
161
- summary: buildMcpServerSummary({
162
- label,
163
- spec: raw,
164
- toolCount: bridge.registeredNames.length,
165
- report: {
166
- protocolVersion: mcp.protocolVersion,
167
- serverInfo: mcp.serverInfo,
168
- capabilities: mcp.serverCapabilities ?? {},
169
- tools: { supported: true, items: [] },
170
- resources: { supported: false, reason: "still inspecting" },
171
- prompts: { supported: false, reason: "still inspecting" },
172
- elapsedMs: ms
173
- },
174
- host,
175
- bridgeEnv: bridge.env
176
- }),
177
- registeredNames: bridge.registeredNames,
178
- registeredSpecs
179
- });
180
- insertionOrder.push(raw);
181
- resolveReady();
182
- sink({
183
- kind: "tools-ready",
184
- name: label,
185
- tools: bridge.registeredNames.length,
186
- ms
187
- });
188
- let report;
189
- try {
190
- report = await inspectMcpServer(mcp);
191
- } catch {
192
- report = {
193
- protocolVersion: mcp.protocolVersion,
194
- serverInfo: mcp.serverInfo,
195
- capabilities: mcp.serverCapabilities ?? {},
196
- tools: { supported: true, items: [] },
197
- resources: { supported: false, reason: "inspect failed" },
198
- prompts: { supported: false, reason: "inspect failed" },
199
- elapsedMs: 0
200
- };
201
- }
202
- const resourceCount = report.resources.supported ? report.resources.items.length : 0;
203
- const promptCount = report.prompts.supported ? report.prompts.items.length : 0;
204
- sink({
205
- kind: "connected",
206
- name: label,
207
- tools: bridge.registeredNames.length,
208
- resources: resourceCount,
209
- prompts: promptCount,
210
- ms
211
- });
212
- const summary = buildMcpServerSummary({
213
- label,
214
- spec: raw,
215
- toolCount: bridge.registeredNames.length,
216
- report,
217
- host,
218
- bridgeEnv: bridge.env
219
- });
220
- records.set(raw, {
221
- spec: raw,
222
- client: mcp,
223
- summary,
224
- registeredNames: bridge.registeredNames,
225
- registeredSpecs
226
- });
227
- if (loop)
228
- for (const s of registeredSpecs)
229
- try {
230
- loop.prefix.addTool(s);
231
- } catch (err) {
232
- sink({
233
- kind: "warn",
234
- name: label,
235
- reason: `addTool failed for ${s.function.name}: ${err.message}`
236
- });
237
- }
238
- return { ok: true, summary };
239
- } catch (err) {
240
- const reason = err.message;
241
- if (!records.has(raw)) {
242
- await mcp?.close().catch(() => void 0);
243
- rejectReady(new Error(`MCP server "${label}" failed to start: ${reason}`));
244
- sink({ kind: "failed", name: label, reason });
245
- failureMap.set(raw, { spec: raw, name: label, reason, at: Date.now() });
246
- return { ok: false, reason };
247
- }
248
- sink({ kind: "warn", name: label, reason });
249
- return { ok: true, summary: records.get(raw).summary };
250
- }
251
- }
252
- async function removeSpec(raw, loop) {
253
- failureMap.delete(raw);
254
- const record = records.get(raw);
255
- if (!record) return false;
256
- await record.client.close().catch(() => void 0);
257
- const tools = ctx.getTools();
258
- for (const name of record.registeredNames) {
259
- tools?.unregister(name);
260
- loop?.prefix.removeTool(name);
261
- }
262
- records.delete(raw);
263
- const idx = insertionOrder.indexOf(raw);
264
- if (idx >= 0) insertionOrder.splice(idx, 1);
265
- return true;
266
- }
267
- async function reloadFromConfig(loop) {
268
- const normalized = normalizeMcpConfig(readConfig());
269
- const desired = normalized.map(specToRaw);
270
- const desiredSet = new Set(desired);
271
- const currentSet = new Set(records.keys());
272
- const added = [];
273
- const removed = [];
274
- const failed = [];
275
- for (const spec of [...currentSet]) {
276
- if (!desiredSet.has(spec)) {
277
- await removeSpec(spec, loop);
278
- removed.push(spec);
279
- }
280
- }
281
- for (const spec of desired) {
282
- if (currentSet.has(spec)) continue;
283
- const result = await addSpec(spec, loop);
284
- if (result.ok) added.push(spec);
285
- else failed.push({ spec, reason: result.reason });
286
- }
287
- return { added, removed, failed, summaries: summaries() };
288
- }
289
- function specs() {
290
- return [...insertionOrder];
291
- }
292
- function summaries() {
293
- return insertionOrder.map((s) => records.get(s)?.summary).filter((s) => Boolean(s));
294
- }
295
- async function closeAll() {
296
- for (const r of records.values()) await r.client.close().catch(() => void 0);
297
- records.clear();
298
- insertionOrder.length = 0;
299
- failureMap.clear();
300
- }
301
- function failures() {
302
- return [...failureMap.values()];
303
- }
304
- function setLifecycleSink(s) {
305
- sink = s;
306
- }
307
- return {
308
- size: () => records.size,
309
- specs,
310
- summaries,
311
- failures,
312
- addSpec,
313
- removeSpec,
314
- reloadFromConfig,
315
- closeAll,
316
- setLifecycleSink
317
- };
318
- }
319
-
320
- export {
321
- createMcpRuntime
322
- };
323
- //# sourceMappingURL=chunk-YFP3MYMY.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/mcp/summary.ts","../../src/cli/commands/mcp-runtime.ts"],"sourcesContent":["import type { InspectionReport } from \"./inspect.js\";\nimport type { BridgeEnv, McpClientHost } from \"./registry.js\";\nimport type { GetPromptResult, ReadResourceResult } from \"./types.js\";\n\nexport interface McpServerSummary {\n label: string;\n spec: string;\n toolCount: number;\n report: InspectionReport;\n host: McpClientHost;\n bridgeEnv: BridgeEnv;\n readResource(uri: string): Promise<ReadResourceResult>;\n getPrompt(name: string, args?: Record<string, string>): Promise<GetPromptResult>;\n}\n\nexport function buildMcpServerSummary(opts: {\n label: string;\n spec: string;\n toolCount: number;\n report: InspectionReport;\n host: McpClientHost;\n bridgeEnv: BridgeEnv;\n}): McpServerSummary {\n return {\n label: opts.label,\n spec: opts.spec,\n toolCount: opts.toolCount,\n report: opts.report,\n host: opts.host,\n bridgeEnv: opts.bridgeEnv,\n readResource(uri) {\n return opts.host.client.readResource(uri);\n },\n getPrompt(name, args) {\n return args !== undefined\n ? opts.host.client.getPrompt(name, args)\n : opts.host.client.getPrompt(name);\n },\n };\n}\n","import { normalizeMcpConfig, readConfig } from \"../../config.js\";\nimport { t } from \"../../i18n/index.js\";\nimport type { CacheFirstLoop } from \"../../loop.js\";\nimport { McpClient } from \"../../mcp/client.js\";\nimport { type InspectionReport, inspectMcpServer } from \"../../mcp/inspect.js\";\nimport { preflightStdioSpec } from \"../../mcp/preflight.js\";\nimport { type McpClientHost, bridgeMcpTools } from \"../../mcp/registry.js\";\nimport { overlayMatchedSpec, parseMcpSpec, specToRaw } from \"../../mcp/spec.js\";\nimport { buildMcpServerSummary } from \"../../mcp/summary.js\";\nimport { buildTransportFromSpec } from \"../../mcp/transport-from-spec.js\";\nimport type { ToolRegistry } from \"../../tools.js\";\nimport type { ToolSpec } from \"../../types.js\";\nimport { type McpLifecycleEvent, formatMcpLifecycleEvent } from \"../ui/mcp-lifecycle.js\";\nimport { formatMcpSlowToast } from \"../ui/mcp-toast.js\";\nimport type { McpServerSummary } from \"../ui/slash.js\";\n\nexport interface ProgressInfo {\n toolName: string;\n progress: number;\n total?: number;\n message?: string;\n}\n\ninterface SpecRecord {\n spec: string;\n client: McpClient;\n summary: McpServerSummary;\n /** Names of bridged tools — used for hot-unbridge. */\n registeredNames: string[];\n /** ToolSpec snapshots captured AFTER bridge — handed to loop.prefix.addTool on hot-add. */\n registeredSpecs: ToolSpec[];\n}\n\nexport interface RuntimeContext {\n getTools: () => ToolRegistry | undefined;\n getMcpPrefix: () => string | undefined;\n getRequestedCount: () => number;\n progressSink: { current: ((info: ProgressInfo) => void) | null };\n}\n\nexport type McpLifecycleNotice =\n | { kind: \"handshake\"; name: string }\n | {\n kind: \"connected\";\n name: string;\n tools: number;\n resources: number;\n prompts: number;\n ms: number;\n }\n | { kind: \"disabled\"; name: string }\n | { kind: \"failed\"; name: string; reason: string }\n | { kind: \"slow\"; serverName: string; p95Ms: number; sampleSize: number }\n | { kind: \"tools-ready\"; name: string; tools: number; ms: number }\n | { kind: \"warn\"; name: string; reason: string };\n\nexport type McpLifecycleSink = (notice: McpLifecycleNotice) => void;\n\nexport const stderrLifecycleSink: McpLifecycleSink = (n) => {\n if (n.kind === \"slow\") {\n process.stderr.write(\n `${formatMcpSlowToast({ name: n.serverName, p95Ms: n.p95Ms, sampleSize: n.sampleSize })}\\n`,\n );\n return;\n }\n if (n.kind === \"failed\") {\n process.stderr.write(\n `${formatMcpLifecycleEvent({ state: \"failed\", name: n.name, reason: n.reason })}\\n → ${t(\"mcpLifecycle.failedSetupHint\")}\\n`,\n );\n return;\n }\n if (n.kind === \"connected\") {\n process.stderr.write(\n `${formatMcpLifecycleEvent({\n state: \"connected\",\n name: n.name,\n tools: n.tools,\n resources: n.resources,\n prompts: n.prompts,\n ms: n.ms,\n })}\\n`,\n );\n return;\n }\n if (n.kind === \"tools-ready\") {\n process.stderr.write(\n `${formatMcpLifecycleEvent({ state: \"tools-ready\", name: n.name, tools: n.tools, ms: n.ms })}\\n`,\n );\n return;\n }\n if (n.kind === \"warn\") {\n process.stderr.write(\n `${formatMcpLifecycleEvent({ state: \"warn\", name: n.name, reason: n.reason })}\\n`,\n );\n return;\n }\n // handshake / disabled — no extra fields needed\n process.stderr.write(\n `${formatMcpLifecycleEvent({ state: n.kind as \"handshake\" | \"disabled\", name: n.name })}\\n`,\n );\n};\n\nexport interface McpFailure {\n spec: string;\n name: string;\n reason: string;\n at: number;\n}\n\nexport interface McpRuntime {\n size(): number;\n specs(): string[];\n summaries(): McpServerSummary[];\n /** Last bridge failure per spec — drives the \"未桥接\" reason shown in the dashboard. */\n failures(): McpFailure[];\n addSpec(\n raw: string,\n loop?: CacheFirstLoop,\n signal?: AbortSignal,\n ): Promise<{ ok: true; summary: McpServerSummary } | { ok: false; reason: string }>;\n removeSpec(raw: string, loop?: CacheFirstLoop): Promise<boolean>;\n reloadFromConfig(loop?: CacheFirstLoop): Promise<{\n added: string[];\n removed: string[];\n failed: Array<{ spec: string; reason: string }>;\n summaries: McpServerSummary[];\n }>;\n closeAll(): Promise<void>;\n /** Replace the sink that lifecycle events flow through — App.tsx swaps this in on mount so toasts land in the alt-screen UI instead of corrupting it via stderr. */\n setLifecycleSink(sink: McpLifecycleSink): void;\n}\n\nexport function createMcpRuntime(ctx: RuntimeContext): McpRuntime {\n const records = new Map<string, SpecRecord>();\n const insertionOrder: string[] = [];\n const failureMap = new Map<string, McpFailure>();\n let sink: McpLifecycleSink = stderrLifecycleSink;\n\n async function addSpec(\n raw: string,\n loop?: CacheFirstLoop,\n signal?: AbortSignal,\n ): Promise<{ ok: true; summary: McpServerSummary } | { ok: false; reason: string }> {\n if (records.has(raw)) {\n return { ok: true, summary: records.get(raw)!.summary };\n }\n failureMap.delete(raw);\n const tools = ctx.getTools();\n if (!tools) return { ok: false, reason: \"no tool registry available\" };\n const cfg = readConfig();\n const normalized = normalizeMcpConfig(cfg);\n let label = \"anon\";\n let mcp: McpClient | undefined;\n // Per-server readiness gate — tool dispatches via the bridge await\n // this before calling into `live.callTool`. Resolved on `connected`,\n // rejected on `failed`, so a tool invoked mid-handshake waits\n // (capped by `bridgeMcpTools`'s `readyTimeoutMs`) instead of\n // surfacing a transport error.\n let resolveReady!: () => void;\n let rejectReady!: (err: Error) => void;\n const ready = new Promise<void>((resolve, reject) => {\n resolveReady = resolve;\n rejectReady = reject;\n });\n // Avoid unhandledRejection if no consumer awaits `ready` yet.\n ready.catch(() => undefined);\n try {\n const parsed = parseMcpSpec(raw);\n label = parsed.name ?? \"anon\";\n const matched = parsed.name ? normalized.find((s) => s.name === parsed.name) : undefined;\n const spec = overlayMatchedSpec(parsed, matched);\n if (spec.disabled) {\n sink({ kind: \"disabled\", name: label });\n rejectReady(new Error(`MCP server \"${label}\" is disabled`));\n failureMap.set(raw, { spec: raw, name: label, reason: \"disabled by user\", at: Date.now() });\n return { ok: false, reason: \"disabled by user\" };\n }\n sink({ kind: \"handshake\", name: label });\n const t0 = Date.now();\n const namePrefix = spec.name\n ? `${spec.name}_`\n : ctx.getRequestedCount() === 1 && ctx.getMcpPrefix()\n ? (ctx.getMcpPrefix() as string)\n : \"\";\n if (spec.transport === \"stdio\") preflightStdioSpec(spec);\n const transport = buildTransportFromSpec(spec);\n mcp = new McpClient({ transport });\n await mcp.initialize({ signal });\n const host: McpClientHost = { client: mcp };\n const bridge = await bridgeMcpTools(mcp, {\n registry: tools,\n namePrefix,\n serverName: label,\n host,\n ready,\n onProgress: (info) => ctx.progressSink.current?.(info),\n onSlow: (info) =>\n sink({\n kind: \"slow\",\n serverName: info.serverName,\n p95Ms: info.p95Ms,\n sampleSize: info.sampleSize,\n }),\n });\n // Tools are registered — record the bridge NOW so the UI shows\n // \"bridged\" even if later non-critical steps (inspect, hot-add) fail.\n const ms = Date.now() - t0;\n const allSpecs = tools.specs();\n const registeredSpecs = allSpecs.filter((s) =>\n bridge.registeredNames.includes(s.function.name),\n );\n // Create a provisional record immediately (tools already usable).\n records.set(raw, {\n spec: raw,\n client: mcp,\n summary: buildMcpServerSummary({\n label,\n spec: raw,\n toolCount: bridge.registeredNames.length,\n report: {\n protocolVersion: mcp.protocolVersion,\n serverInfo: mcp.serverInfo,\n capabilities: mcp.serverCapabilities ?? {},\n tools: { supported: true, items: [] },\n resources: { supported: false, reason: \"still inspecting\" },\n prompts: { supported: false, reason: \"still inspecting\" },\n elapsedMs: ms,\n },\n host,\n bridgeEnv: bridge.env,\n }),\n registeredNames: bridge.registeredNames,\n registeredSpecs,\n });\n insertionOrder.push(raw);\n resolveReady();\n sink({\n kind: \"tools-ready\",\n name: label,\n tools: bridge.registeredNames.length,\n ms,\n });\n\n // Non-critical: inspect + hot-add. Failures here don't un-bridge.\n let report: InspectionReport;\n try {\n report = await inspectMcpServer(mcp);\n } catch {\n report = {\n protocolVersion: mcp.protocolVersion,\n serverInfo: mcp.serverInfo,\n capabilities: mcp.serverCapabilities ?? {},\n tools: { supported: true, items: [] },\n resources: { supported: false, reason: \"inspect failed\" },\n prompts: { supported: false, reason: \"inspect failed\" },\n elapsedMs: 0,\n };\n }\n const resourceCount = report.resources.supported ? report.resources.items.length : 0;\n const promptCount = report.prompts.supported ? report.prompts.items.length : 0;\n // Re-emit with full inspection data (the provisional event reported 0).\n sink({\n kind: \"connected\",\n name: label,\n tools: bridge.registeredNames.length,\n resources: resourceCount,\n prompts: promptCount,\n ms,\n });\n const summary = buildMcpServerSummary({\n label,\n spec: raw,\n toolCount: bridge.registeredNames.length,\n report,\n host,\n bridgeEnv: bridge.env,\n });\n // Replace the provisional record with the fully-inspected summary.\n records.set(raw, {\n spec: raw,\n client: mcp,\n summary,\n registeredNames: bridge.registeredNames,\n registeredSpecs,\n });\n // Hot-add: shift the prefix so the live loop sees the new tools\n // on the very next turn. Each addTool is one cache-miss turn.\n if (loop)\n for (const s of registeredSpecs)\n try {\n loop.prefix.addTool(s);\n } catch (err) {\n sink({\n kind: \"warn\",\n name: label,\n reason: `addTool failed for ${s.function.name}: ${(err as Error).message}`,\n });\n }\n return { ok: true, summary };\n } catch (err) {\n // If we got far enough to create a provisional record, keep it —\n // tools are already registered and usable even after a late failure.\n const reason = (err as Error).message;\n if (!records.has(raw)) {\n await mcp?.close().catch(() => undefined);\n rejectReady(new Error(`MCP server \"${label}\" failed to start: ${reason}`));\n sink({ kind: \"failed\", name: label, reason });\n failureMap.set(raw, { spec: raw, name: label, reason, at: Date.now() });\n return { ok: false, reason };\n }\n sink({ kind: \"warn\", name: label, reason });\n return { ok: true, summary: records.get(raw)!.summary };\n }\n }\n\n async function removeSpec(raw: string, loop?: CacheFirstLoop): Promise<boolean> {\n failureMap.delete(raw);\n const record = records.get(raw);\n if (!record) return false;\n await record.client.close().catch(() => undefined);\n const tools = ctx.getTools();\n for (const name of record.registeredNames) {\n tools?.unregister(name);\n loop?.prefix.removeTool(name);\n }\n records.delete(raw);\n const idx = insertionOrder.indexOf(raw);\n if (idx >= 0) insertionOrder.splice(idx, 1);\n return true;\n }\n\n async function reloadFromConfig(loop?: CacheFirstLoop): Promise<{\n added: string[];\n removed: string[];\n failed: Array<{ spec: string; reason: string }>;\n summaries: McpServerSummary[];\n }> {\n const normalized = normalizeMcpConfig(readConfig());\n const desired = normalized.map(specToRaw);\n const desiredSet = new Set(desired);\n const currentSet = new Set(records.keys());\n const added: string[] = [];\n const removed: string[] = [];\n const failed: Array<{ spec: string; reason: string }> = [];\n\n for (const spec of [...currentSet]) {\n if (!desiredSet.has(spec)) {\n await removeSpec(spec, loop);\n removed.push(spec);\n }\n }\n for (const spec of desired) {\n if (currentSet.has(spec)) continue;\n const result = await addSpec(spec, loop);\n if (result.ok) added.push(spec);\n else failed.push({ spec, reason: result.reason });\n }\n return { added, removed, failed, summaries: summaries() };\n }\n\n function specs(): string[] {\n return [...insertionOrder];\n }\n function summaries(): McpServerSummary[] {\n return insertionOrder\n .map((s) => records.get(s)?.summary)\n .filter((s): s is McpServerSummary => Boolean(s));\n }\n async function closeAll(): Promise<void> {\n for (const r of records.values()) await r.client.close().catch(() => undefined);\n records.clear();\n insertionOrder.length = 0;\n failureMap.clear();\n }\n function failures(): McpFailure[] {\n return [...failureMap.values()];\n }\n function setLifecycleSink(s: McpLifecycleSink): void {\n sink = s;\n }\n return {\n size: () => records.size,\n specs,\n summaries,\n failures,\n addSpec,\n removeSpec,\n reloadFromConfig,\n closeAll,\n setLifecycleSink,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/core/event-redaction.ts","../../src/core/eventize.ts","../../src/core/pause-policy.ts","../../src/tools/skills.ts"],"sourcesContent":["const SECRET_KEY_RE =\n /(secret|token|password|passphrase|api[-_]?key|authorization|cookie|credential|passwd|pwd)/i;\n\nexport function redactEventValue<T>(value: T): T {\n return redactUnknown(value, null) as T;\n}\n\nfunction redactUnknown(value: unknown, key: string | null): unknown {\n if (Array.isArray(value)) return value.map((item) => redactUnknown(item, null));\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [childKey, childValue] of Object.entries(value)) {\n out[childKey] = redactUnknown(childValue, childKey);\n }\n return out;\n }\n if (typeof value === \"string\") {\n if ((key && SECRET_KEY_RE.test(key)) || /^Bearer\\s+/i.test(value)) return \"[redacted]\";\n }\n return value;\n}\n","import type { LoopEvent } from \"../loop.js\";\nimport type { ChatMessage, RawUsage, ToolCall } from \"../types.js\";\nimport { redactEventValue } from \"./event-redaction.js\";\nimport type {\n Event,\n ErrorEvent as KernelErrorEvent,\n ModelDeltaEvent,\n ModelFinalEvent,\n ModelTurnStartedEvent,\n SessionCompactedEvent,\n SessionOpenedEvent,\n SlashInvokedEvent,\n StatusEvent,\n ToolCallEvent,\n ToolConfirmAllowEvent,\n ToolConfirmAlwaysAllowEvent,\n ToolConfirmDenyEvent,\n ToolDispatchedEvent,\n ToolIntentEvent,\n ToolPreparingEvent,\n ToolResultEvent,\n UserMessageEvent,\n} from \"./events.js\";\n\nexport interface EventizeContext {\n model: string;\n prefixHash: string;\n reasoningEffort: \"high\" | \"max\";\n}\n\nexport class Eventizer {\n private nextId = 0;\n private lastTurn = -1;\n private nextToolSeq = 0;\n /** Tool calls announced via tool_call_delta but not yet dispatched. FIFO upgraded by tool_start. */\n private preparingCallIds: string[] = [];\n /** Tool calls dispatched but not yet finished. FIFO popped by tool result. */\n private inflightCallIds: string[] = [];\n /** Per-turn dedupe so each toolCallIndex emits exactly one tool.preparing. */\n private announcedToolIdx = new Set<string>();\n\n consume(ev: LoopEvent, ctx: EventizeContext): Event[] {\n const out: Event[] = [];\n if (ev.turn !== this.lastTurn) {\n this.lastTurn = ev.turn;\n this.announcedToolIdx.clear();\n out.push(this.turnStartedEvent(ev.turn, ctx));\n }\n switch (ev.role) {\n case \"assistant_delta\":\n if (ev.content) out.push(this.deltaEvent(ev.turn, \"content\", ev.content));\n if (ev.reasoningDelta) out.push(this.deltaEvent(ev.turn, \"reasoning\", ev.reasoningDelta));\n break;\n case \"tool_call_delta\": {\n const idx = ev.toolCallIndex;\n const name = ev.toolName;\n if (idx === undefined || !name) break;\n const key = `${ev.turn}:${idx}`;\n if (this.announcedToolIdx.has(key)) break;\n this.announcedToolIdx.add(key);\n const callId = `tc-${++this.nextToolSeq}`;\n this.preparingCallIds.push(callId);\n out.push(this.toolPreparingEvent(ev.turn, callId, name));\n break;\n }\n case \"assistant_final\":\n out.push(this.finalEvent(ev));\n break;\n case \"tool_start\": {\n const callId = this.preparingCallIds.shift() ?? `tc-${++this.nextToolSeq}`;\n this.inflightCallIds.push(callId);\n out.push(this.toolIntentEvent(ev.turn, callId, ev.toolName ?? \"\", ev.toolArgs ?? \"\"));\n out.push(this.toolDispatchedEvent(ev.turn, callId));\n break;\n }\n case \"tool\": {\n const callId = this.inflightCallIds.shift() ?? `tc-orphan-${++this.nextToolSeq}`;\n const ok = !looksLikeToolError(ev.content, ev.toolName);\n out.push(this.toolResultEvent(ev.turn, callId, ok, ev.content, 0));\n break;\n }\n case \"warning\":\n out.push(this.classifyWarning(ev));\n break;\n case \"error\":\n out.push(this.errorEvent(ev.turn, ev.error ?? ev.content, false));\n break;\n case \"status\":\n out.push(this.statusEvent(ev.turn, ev.content));\n break;\n // `done` / `branch_*` intentionally drop — no kernel-level event.\n default:\n break;\n }\n return out;\n }\n\n emitUserMessage(turn: number, text: string): UserMessageEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"user.message\",\n text,\n };\n }\n\n emitSlashInvoked(turn: number, name: string, args: string): SlashInvokedEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"slash.invoked\",\n name,\n args,\n };\n }\n\n emitSessionOpened(turn: number, name: string, resumedFromTurn: number): SessionOpenedEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"session.opened\",\n name,\n resumedFromTurn,\n };\n }\n\n emitSessionCompacted(\n turn: number,\n before: number,\n after: number,\n reason: \"user\" | \"auto-context-pressure\",\n replacementMessages: ReadonlyArray<ChatMessage>,\n ): SessionCompactedEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"session.compacted\",\n beforeMessages: before,\n afterMessages: after,\n reason,\n replacementMessages,\n };\n }\n\n emitToolCall(turn: number, name: string, args: Record<string, unknown>): ToolCallEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"tool.call\",\n name,\n args: redactEventValue(args),\n };\n }\n\n emitToolConfirmAllow(\n turn: number,\n kind: \"run_command\" | \"run_background\",\n payload: { command: string },\n ): ToolConfirmAllowEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"tool.confirm.allow\",\n kind,\n payload: redactEventValue(payload),\n };\n }\n\n emitToolConfirmDeny(\n turn: number,\n kind: \"run_command\" | \"run_background\",\n payload: { command: string },\n denyContext?: string,\n ): ToolConfirmDenyEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"tool.confirm.deny\",\n kind,\n payload: redactEventValue(payload),\n denyContext,\n };\n }\n\n emitToolConfirmAlwaysAllow(\n turn: number,\n kind: \"run_command\" | \"run_background\",\n payload: { command: string },\n prefix: string,\n ): ToolConfirmAlwaysAllowEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"tool.confirm.always_allow\",\n kind,\n payload: redactEventValue(payload),\n prefix,\n };\n }\n\n private turnStartedEvent(turn: number, ctx: EventizeContext): ModelTurnStartedEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"model.turn.started\",\n model: ctx.model,\n reasoningEffort: ctx.reasoningEffort,\n prefixHash: ctx.prefixHash,\n };\n }\n\n private deltaEvent(\n turn: number,\n channel: \"content\" | \"reasoning\" | \"tool_args\",\n text: string,\n ): ModelDeltaEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"model.delta\",\n channel,\n text,\n };\n }\n\n private finalEvent(ev: LoopEvent): ModelFinalEvent {\n const usage: RawUsage = ev.stats\n ? {\n prompt_tokens: ev.stats.usage.promptTokens,\n completion_tokens: ev.stats.usage.completionTokens,\n total_tokens: ev.stats.usage.totalTokens,\n prompt_cache_hit_tokens: ev.stats.usage.promptCacheHitTokens,\n prompt_cache_miss_tokens: ev.stats.usage.promptCacheMissTokens,\n }\n : {};\n const costUsd = ev.stats?.cost ?? 0;\n const out: ModelFinalEvent = {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn: ev.turn,\n type: \"model.final\",\n content: ev.content,\n // toolCalls land later via tool_start → tool.intent — not in this event.\n toolCalls: [] as ReadonlyArray<ToolCall>,\n usage,\n costUsd,\n };\n if (ev.forcedSummary) out.forcedSummary = true;\n return out;\n }\n\n private toolPreparingEvent(turn: number, callId: string, name: string): ToolPreparingEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"tool.preparing\",\n callId,\n name,\n };\n }\n\n private toolIntentEvent(\n turn: number,\n callId: string,\n name: string,\n args: string,\n ): ToolIntentEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"tool.intent\",\n callId,\n name,\n args,\n };\n }\n\n private toolDispatchedEvent(turn: number, callId: string): ToolDispatchedEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"tool.dispatched\",\n callId,\n };\n }\n\n private toolResultEvent(\n turn: number,\n callId: string,\n ok: boolean,\n output: string,\n durationMs: number,\n ): ToolResultEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"tool.result\",\n callId,\n ok,\n output,\n durationMs,\n };\n }\n\n private statusEvent(turn: number, text: string): StatusEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"status\",\n text,\n };\n }\n\n private errorEvent(turn: number, message: string, recoverable: boolean): KernelErrorEvent {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn,\n type: \"error\",\n message,\n recoverable,\n };\n }\n\n /** Pattern-match warning text since LoopEvent doesn't carry a typed kind. */\n private classifyWarning(ev: LoopEvent): Event {\n const c = ev.content;\n if (/\\bauto-escalating to\\b|\\barmed\\b.*pro|NEEDS_PRO/.test(c)) {\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn: ev.turn,\n type: \"policy.escalated\",\n fromModel: \"\",\n toModel: \"\",\n reason: c.includes(\"armed\") ? \"user-request\" : \"self-report\",\n };\n }\n if (/budget\\b.*\\$|\\$\\d.*\\/\\s*\\$\\d/.test(c)) {\n const blocked = /blocked|exceeded|refus/i.test(c);\n return {\n id: ++this.nextId,\n ts: new Date().toISOString(),\n turn: ev.turn,\n type: blocked ? \"policy.budget.blocked\" : \"policy.budget.warning\",\n spentUsd: 0,\n capUsd: 0,\n };\n }\n return this.errorEvent(ev.turn, c, true);\n }\n}\n\nfunction looksLikeToolError(content: string, _toolName: string | undefined): boolean {\n if (!content) return false;\n if (content.startsWith(\"ERROR:\")) return true;\n if (content.startsWith(\"[hook block]\")) return true;\n if (/^\\{\"error\"\\s*:/.test(content)) return true;\n if (/\\bConfirmationError:|\\bNeedsConfirmationError\\b/.test(content)) return true;\n return false;\n}\n","/** Shared editMode → auto-resolve rules so CLI TUI + Tauri desktop don't drift. */\n\nimport type { EditMode } from \"../config.js\";\nimport type { PauseRequest } from \"./pause-gate.js\";\n\n/** Mirrors shell.ts's allowAll bypass: only review still pauses on checkpoints. */\nexport function shouldAutoResolveCheckpoint(editMode: EditMode): boolean {\n return editMode === \"auto\" || editMode === \"yolo\";\n}\n\n/** null = surface to user; non-null = resolve gate immediately with this verdict. */\nexport function autoResolveVerdict(req: PauseRequest, editMode: EditMode): unknown | null {\n if (req.kind === \"plan_checkpoint\" && shouldAutoResolveCheckpoint(editMode)) {\n return { type: \"continue\" };\n }\n // yolo mirrors shell.ts's allowAll bypass — outside-sandbox reads/writes pass\n // through too. Stays \"run_once\" rather than \"always_allow\" so the YOLO session\n // doesn't pollute the on-disk allowlist with every transient path it touched.\n if (req.kind === \"path_access\" && editMode === \"yolo\") {\n return { type: \"run_once\" };\n }\n return null;\n}\n","/** runAs: inline appends the body to the parent log; subagent spawns an isolated child loop and only returns the final answer. */\n\nimport { type Skill, SkillStore } from \"../skills.js\";\nimport type { ToolRegistry } from \"../tools.js\";\n\n/** Returns serialized tool-result string — dispatch path is pure pass-through. */\nexport type SubagentRunner = (skill: Skill, task: string, signal?: AbortSignal) => Promise<string>;\n\n/** Fired after a successful `install_skill` write — host wires this to push a fresh `$skills` event so the desktop sidebar updates without a tab reload. */\nexport type SkillInstalledHook = (info: {\n name: string;\n path: string;\n scope: \"project\" | \"global\";\n}) => void;\n\nexport interface SkillToolsOptions {\n /** Override `$HOME` — tests set this to a tmpdir. */\n homeDir?: string;\n projectRoot?: string;\n customSkillPaths?: readonly string[];\n /** When omitted, subagent skills error rather than silently falling back to inline (loses isolation). */\n subagentRunner?: SubagentRunner;\n /** Hide built-in skills (test-only knob; production callers leave off). */\n disableBuiltins?: boolean;\n /** Called synchronously after `install_skill` successfully writes a new skill file. */\n onSkillInstalled?: SkillInstalledHook;\n}\n\nexport function registerSkillTools(\n registry: ToolRegistry,\n opts: SkillToolsOptions = {},\n): ToolRegistry {\n const store = new SkillStore({\n homeDir: opts.homeDir,\n projectRoot: opts.projectRoot,\n customSkillPaths: opts.customSkillPaths,\n disableBuiltins: opts.disableBuiltins,\n });\n const subagentRunner = opts.subagentRunner;\n const onSkillInstalled = opts.onSkillInstalled;\n const hasProjectScope = store.hasProjectScope();\n\n registry.register({\n name: \"run_skill\",\n description:\n \"Invoke a playbook from the Skills index pinned in the system prompt. Each entry is a self-contained instruction block. Pass `name` as the BARE skill identifier (e.g. 'explore'), NOT the `[🧬 subagent]` tag that appears after it in the index. Entries tagged `[🧬 subagent]` spawn an isolated subagent — only the final distilled answer comes back, the model's tool calls + reasoning during the run never enter your context. Plain skills are inlined: the body becomes a tool result you read and follow. For subagent skills, supply 'arguments' describing the concrete task — they'll be the only context the subagent has.\",\n readOnly: true,\n parallelSafe: true,\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n \"Skill identifier as it appears in the pinned Skills index (e.g. 'explore', 'review', 'security-review'). Case-sensitive.\",\n },\n arguments: {\n type: \"string\",\n description:\n \"Free-form arguments the skill should act on. For inline skills: appended to the body as an 'Arguments:' line; the skill's own instructions decide how to consume them. For `[🧬 subagent]` skills: REQUIRED — becomes the entire task description the subagent receives, since it has no other context.\",\n },\n },\n required: [\"name\"],\n },\n fn: async (args: { name?: unknown; arguments?: unknown }, ctx) => {\n const raw = typeof args.name === \"string\" ? args.name.trim() : \"\";\n if (!raw) {\n return JSON.stringify({ error: \"run_skill requires a 'name' argument\" });\n }\n // Defensive: The Skills index writes entries like\n // `explore [🧬 subagent]`, and models sometimes copy the\n // decoration verbatim into the `name` argument instead of just\n // the identifier. Rather than reject those calls:\n // 1. Drop any `[...]` bracketed tag (possibly containing\n // emoji + \"subagent\" label).\n // 2. Find the first whitespace-delimited token whose first\n // char is alphanumeric — that's the skill identifier,\n // whether the tag came before or after the name.\n const stripped = raw.replace(/\\[[^\\]]*\\]/g, \" \").trim();\n const tokens = stripped.split(/\\s+/).filter(Boolean);\n const name = tokens.find((t) => /^[a-zA-Z0-9]/.test(t)) ?? \"\";\n if (!name) {\n return JSON.stringify({\n error: \"run_skill requires a 'name' argument\",\n hint: `'${raw}' is just a marker/tag, not a skill name`,\n });\n }\n const skill = store.read(name);\n if (!skill) {\n const available = store\n .list()\n .map((s) => s.name)\n .join(\", \");\n return JSON.stringify({\n error: `unknown skill: ${JSON.stringify(name)}`,\n available: available || \"(none — user has not defined any skills)\",\n });\n }\n const rawArgs = typeof args.arguments === \"string\" ? args.arguments.trim() : \"\";\n\n if (skill.runAs === \"subagent\") {\n if (!subagentRunner) {\n return JSON.stringify({\n error: `run_skill: skill ${JSON.stringify(name)} is marked runAs=subagent but no subagent runner is configured for this session. Skill authors who need isolation should run inside reasonix code (or a library setup that passes subagentRunner to registerSkillTools).`,\n });\n }\n if (!rawArgs) {\n return JSON.stringify({\n error: `run_skill: skill ${JSON.stringify(name)} is a subagent and requires 'arguments' — the subagent has no other context, so describe the concrete task in the arguments field.`,\n });\n }\n return subagentRunner(skill, rawArgs, ctx?.signal);\n }\n\n const header = [\n `# Skill: ${skill.name}`,\n skill.description ? `> ${skill.description}` : \"\",\n `(scope: ${skill.scope} · ${skill.path})`,\n ]\n .filter(Boolean)\n .join(\"\\n\");\n const argsBlock = rawArgs ? `\\n\\nArguments: ${rawArgs}` : \"\";\n const inner = `${header}\\n\\n${skill.body}${argsBlock}`;\n // Sentinel-wrapped so ContextManager.fold preserves the body verbatim instead of paraphrasing it.\n return `<skill-pin name=${JSON.stringify(skill.name)}>\\n${inner}\\n</skill-pin>`;\n },\n });\n\n const installScopeDesc = hasProjectScope\n ? \"'project' (default) writes to <repo>/.reasonix/skills/, scoped to this workspace only; 'global' writes to ~/.reasonix/skills/, available in every project.\"\n : \"'global' (only option here — no project workspace) writes to ~/.reasonix/skills/.\";\n\n registry.register({\n name: \"install_skill\",\n description:\n \"Author and save a new skill — a reusable playbook future turns invoke via `run_skill`. Runnable immediately (same turn); appears in the pinned Skills index on next `/new` or launch. Skill bodies become prompts for future turns, so write what you'd want your future self to follow.\",\n parameters: {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n description:\n \"Identifier — letters/digits/_/-/., 1-64 chars, starts alnum. Becomes the filename.\",\n },\n description: {\n type: \"string\",\n description:\n \"≤120 char one-liner shown in the pinned Skills index — future agents read this to decide whether to invoke.\",\n },\n body: {\n type: \"string\",\n description:\n \"Markdown playbook. For subagent skills, write the subagent's persona/rules — it gets no context besides `arguments` at runtime.\",\n },\n scope: {\n type: \"string\",\n enum: [\"project\", \"global\"],\n description: installScopeDesc,\n },\n runAs: {\n type: \"string\",\n enum: [\"inline\", \"subagent\"],\n description:\n \"inline (default) appends body to parent log. subagent spawns isolated child loop; only final answer returns (use for context-heavy work).\",\n },\n model: {\n type: \"string\",\n description:\n \"Optional `deepseek-*` model override for runAs=subagent. Ignored otherwise.\",\n },\n allowedTools: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Optional tool allowlist for runAs=subagent (e.g. ['read_file','search_content']).\",\n },\n },\n required: [\"name\", \"description\", \"body\"],\n },\n fn: async (args: {\n name?: unknown;\n description?: unknown;\n body?: unknown;\n scope?: unknown;\n runAs?: unknown;\n model?: unknown;\n allowedTools?: unknown;\n }) => {\n const name = typeof args.name === \"string\" ? args.name.trim() : \"\";\n const description =\n typeof args.description === \"string\"\n ? args.description.replace(/[\\r\\n]+/g, \" \").trim()\n : \"\";\n const body = typeof args.body === \"string\" ? args.body : \"\";\n if (!name) return JSON.stringify({ error: \"install_skill requires a non-empty 'name'\" });\n if (!description) {\n return JSON.stringify({\n error:\n \"install_skill requires a non-empty 'description' — it is what appears in the Skills index and how future agents decide whether to invoke the skill\",\n });\n }\n if (!body.trim()) {\n return JSON.stringify({\n error:\n \"install_skill requires a non-empty 'body' — the playbook the skill executes when invoked\",\n });\n }\n\n const scopeRaw = typeof args.scope === \"string\" ? args.scope.trim() : \"\";\n let scope: \"project\" | \"global\";\n if (scopeRaw === \"global\") scope = \"global\";\n else if (scopeRaw === \"project\") scope = \"project\";\n else scope = hasProjectScope ? \"project\" : \"global\";\n if (scope === \"project\" && !hasProjectScope) {\n return JSON.stringify({\n error:\n \"install_skill: scope='project' requires a workspace — run from `reasonix code`, or use scope='global'\",\n });\n }\n\n const runAsRaw = typeof args.runAs === \"string\" ? args.runAs.trim() : \"\";\n const runAs: \"inline\" | \"subagent\" = runAsRaw === \"subagent\" ? \"subagent\" : \"inline\";\n\n const fmLines = [\"---\", `name: ${name}`, `description: ${description}`];\n if (runAs === \"subagent\") {\n fmLines.push(\"runAs: subagent\");\n const model = typeof args.model === \"string\" ? args.model.trim() : \"\";\n if (model) fmLines.push(`model: ${model}`);\n if (Array.isArray(args.allowedTools)) {\n const tools = args.allowedTools\n .filter((t): t is string => typeof t === \"string\")\n .map((t) => t.trim())\n .filter(Boolean);\n if (tools.length > 0) fmLines.push(`allowed-tools: ${tools.join(\", \")}`);\n }\n }\n fmLines.push(\"---\", \"\");\n const content = `${fmLines.join(\"\\n\")}${body.replace(/\\s+$/, \"\")}\\n`;\n\n const result = store.createWithContent(name, scope, content);\n if (\"error\" in result) {\n return JSON.stringify({ error: result.error });\n }\n\n try {\n onSkillInstalled?.({ name, path: result.path, scope });\n } catch {\n // host hook failure must not undo a successful write\n }\n\n return JSON.stringify({\n ok: true,\n name,\n scope,\n path: result.path,\n runAs,\n note: \"Skill is callable right now via run_skill({ name }). It will appear in the pinned Skills index after the next /new or launch.\",\n });\n },\n });\n\n return registry;\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/cli/commands/code.tsx"],"sourcesContent":["/**\n * `reasonix code [dir]` — opinionated wrapper around `reasonix chat` for\n * code-editing workflows.\n *\n * What it does differently from plain chat:\n * - Registers native filesystem tools rooted at the given directory\n * (CWD by default). No subprocess, no `npx install` step, R1-\n * friendly schemas. Replaced the old `@modelcontextprotocol/server-filesystem`\n * subprocess in 0.4.9 because its `edit_file` argv shape was the\n * biggest driver of R1 DSML hallucinations.\n * - Uses a coding-focused system prompt (src/code/prompt.ts) that\n * teaches the model to propose edits as SEARCH/REPLACE blocks.\n * - Defaults to the `smart` preset (reasoner + harvest) because\n * coding tasks pay back R1 thinking.\n * - Scopes its session to the directory so projects don't share\n * conversation history.\n * - Hooks `codeMode` into the TUI so assistant replies get parsed\n * for SEARCH/REPLACE blocks and applied on disk after each turn.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { buildCodeToolset } from \"../../code/setup.js\";\nimport { loadApiKey, loadEngineeringLifecycleMode, loadPreset, readConfig } from \"../../config.js\";\nimport { loadDotenv } from \"../../env.js\";\nimport { t } from \"../../i18n/index.js\";\nimport { detectForeignAgentPlatform } from \"../../memory/project.js\";\nimport { sanitizeName } from \"../../memory/session.js\";\nimport { markPhase } from \"../startup-profile.js\";\nimport { presetNameForSettings, resolvePreset } from \"../ui/presets.js\";\nimport { chatCommand } from \"./chat.js\";\n\nexport interface CodeOptions {\n /** Directory to root the filesystem tools at. Defaults to process.cwd(). */\n dir?: string;\n /** Override the default `smart` model. */\n model?: string;\n /** Disable session persistence. */\n noSession?: boolean;\n /** Transcript file for replay/diff. */\n transcript?: string;\n /** Skip the session picker — always resume prior messages. */\n forceResume?: boolean;\n /** Skip the session picker — always wipe prior messages and start fresh. */\n forceNew?: boolean;\n /**\n * Soft USD spend cap. Off by default. Same semantics as `chat`:\n * warns at 80%, refuses next turn at 100%. Mid-session adjustable\n * via `/budget <usd>` slash command.\n */\n budgetUsd?: number;\n /** Suppress the auto-launched embedded web dashboard. */\n noDashboard?: boolean;\n /** When true and the dashboard is enabled, open its URL in the system default browser as soon as the server is ready. */\n openDashboard?: boolean;\n /** Pin the dashboard to a fixed port. `undefined` keeps ephemeral assignment. */\n dashboardPort?: number;\n /** Dashboard bind address (#968). `undefined` keeps the default 127.0.0.1. */\n dashboardHost?: string;\n /** Stable dashboard URL token (#968). `undefined` mints a fresh per-boot token. */\n dashboardToken?: string;\n /** Inline string appended to the code system prompt after the generated base prompt. */\n systemAppend?: string;\n /** Path to a UTF-8 text file whose contents are appended to the code system prompt. */\n systemAppendFile?: string;\n}\n\nexport async function codeCommand(opts: CodeOptions = {}): Promise<void> {\n markPhase(\"code_command_enter\");\n const loadedPreset = loadPreset();\n const presetSettings = resolvePreset(loadedPreset);\n const resolvedModel = opts.model ?? presetSettings.model;\n // Bridge .env + ~/.reasonix/config.json into process.env so buildCodeToolset's\n // eager DeepSeekClient constructions (subagent client; semantic embedder) can\n // pick up a key the user already configured via `reasonix setup`. chatCommand\n // does the same dance — code.tsx wraps chatCommand but must also seed env\n // before buildCodeToolset runs, which is BEFORE chatCommand.\n loadDotenv();\n const cfgKey = loadApiKey();\n if (cfgKey && !process.env.DEEPSEEK_API_KEY) {\n process.env.DEEPSEEK_API_KEY = cfgKey;\n }\n const { codeSystemPrompt } = await import(\"../../code/prompt.js\");\n const rootDir = resolve(opts.dir ?? process.cwd());\n // Per-directory session so switching projects doesn't mix histories.\n // `code-<sanitized-basename>` fits the session name rules without\n // truncating most project names.\n const session = opts.noSession ? undefined : `code-${sanitizeName(basename(rootDir))}`;\n\n markPhase(\"semantic_bootstrap_start\");\n const { tools, jobs, registerRooted, reBootstrapSemantic, semantic } = await buildCodeToolset({\n rootDir,\n });\n markPhase(\n semantic.enabled ? \"semantic_bootstrap_done_enabled\" : \"semantic_bootstrap_done_skipped\",\n );\n\n process.stderr.write(\n `${t(\"startup.codeRooted\", {\n rootDir,\n session: session ?? t(\"startup.ephemeral\"),\n tools: tools.size,\n semantic: semantic.enabled ? t(\"startup.semanticOn\") : \"\",\n })}\\n`,\n );\n\n const foreign = detectForeignAgentPlatform(rootDir);\n if (foreign) {\n process.stderr.write(t(\"code.workspaceConflict\", { platforms: foreign.join(\", \") }));\n }\n\n // Belt-and-suspenders cleanup: even though spawn(detached:false)\n // should tie child processes to the parent's lifetime, Windows cmd.exe\n // wrappers occasionally leak. We DON'T install SIGINT/SIGTERM\n // handlers here — that overrode Node's default \"exit on Ctrl+C\" with\n // a silent no-op, which made Ctrl+C feel broken in the TUI. App.tsx\n // owns the SIGINT path now (it shows the quit-armed banner and calls\n // exit() on confirmation); this 'exit' hook just guarantees the job\n // registry is drained on the way out, regardless of which exit path\n // fired.\n process.once(\"exit\", () => {\n void jobs.shutdown();\n });\n\n let systemAppendFileContents: string | undefined;\n if (opts.systemAppend !== undefined && opts.systemAppend.trim().length === 0) {\n process.stderr.write(t(\"code.systemAppendEmpty\"));\n }\n if (opts.systemAppendFile) {\n const filePath = resolve(opts.systemAppendFile);\n try {\n systemAppendFileContents = readFileSync(filePath, \"utf8\");\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n const errorDetails = e.code ? `[${e.code}] ${e.message}` : e.message;\n process.stderr.write(t(\"code.systemAppendFileReadError\", { filePath, errorDetails }));\n process.exit(1);\n }\n }\n\n // The rebuilder is re-invoked on `/new` and `/cwd`. `currentRoot` is the live\n // pointer; `/cwd` updates it via `onRootChange` so the rebuild picks up the\n // new workspace's REASONIX.md / memory without restarting the loop.\n let currentRoot = rootDir;\n let semanticEnabled = semantic.enabled;\n const codeRebuildSystem = () =>\n codeSystemPrompt(currentRoot, {\n hasSemanticSearch: semanticEnabled,\n systemAppend: opts.systemAppend,\n systemAppendFile: systemAppendFileContents,\n modelId: resolvedModel,\n engineeringLifecycleMode: loadEngineeringLifecycleMode(),\n });\n await chatCommand({\n model: resolvedModel,\n preset: opts.model ? undefined : presetNameForSettings(presetSettings),\n autoEscalate: opts.model ? false : presetSettings.autoEscalate,\n budgetUsd: opts.budgetUsd,\n system: codeRebuildSystem(),\n rebuildSystem: codeRebuildSystem,\n transcript: opts.transcript,\n session,\n seedTools: tools,\n codeMode: {\n rootDir,\n jobs,\n reregisterTools: registerRooted,\n reBootstrapSemantic: async (root: string) => {\n const r = await reBootstrapSemantic(root);\n semanticEnabled = r.enabled;\n return r;\n },\n onRootChange: (newRoot: string) => {\n currentRoot = newRoot;\n },\n },\n mcp: readConfig().mcp,\n forceResume: opts.forceResume,\n forceNew: opts.forceNew,\n noDashboard: opts.noDashboard,\n openDashboard: opts.openDashboard,\n dashboardPort: opts.dashboardPort,\n dashboardHost: opts.dashboardHost,\n dashboardToken: opts.dashboardToken,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,SAAS,oBAAoB;AAC7B,SAAS,UAAU,eAAe;AA8ClC,eAAsB,YAAY,OAAoB,CAAC,GAAkB;AACvE,YAAU,oBAAoB;AAC9B,QAAM,eAAe,WAAW;AAChC,QAAM,iBAAiB,cAAc,YAAY;AACjD,QAAM,gBAAgB,KAAK,SAAS,eAAe;AAMnD,aAAW;AACX,QAAM,SAAS,WAAW;AAC1B,MAAI,UAAU,CAAC,QAAQ,IAAI,kBAAkB;AAC3C,YAAQ,IAAI,mBAAmB;AAAA,EACjC;AACA,QAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,sBAAsB;AAChE,QAAM,UAAU,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC;AAIjD,QAAM,UAAU,KAAK,YAAY,SAAY,QAAQ,aAAa,SAAS,OAAO,CAAC,CAAC;AAEpF,YAAU,0BAA0B;AACpC,QAAM,EAAE,OAAO,MAAM,gBAAgB,qBAAqB,SAAS,IAAI,MAAM,iBAAiB;AAAA,IAC5F;AAAA,EACF,CAAC;AACD;AAAA,IACE,SAAS,UAAU,oCAAoC;AAAA,EACzD;AAEA,UAAQ,OAAO;AAAA,IACb,GAAG,EAAE,sBAAsB;AAAA,MACzB;AAAA,MACA,SAAS,WAAW,EAAE,mBAAmB;AAAA,MACzC,OAAO,MAAM;AAAA,MACb,UAAU,SAAS,UAAU,EAAE,oBAAoB,IAAI;AAAA,IACzD,CAAC,CAAC;AAAA;AAAA,EACJ;AAEA,QAAM,UAAU,2BAA2B,OAAO;AAClD,MAAI,SAAS;AACX,YAAQ,OAAO,MAAM,EAAE,0BAA0B,EAAE,WAAW,QAAQ,KAAK,IAAI,EAAE,CAAC,CAAC;AAAA,EACrF;AAWA,UAAQ,KAAK,QAAQ,MAAM;AACzB,SAAK,KAAK,SAAS;AAAA,EACrB,CAAC;AAED,MAAI;AACJ,MAAI,KAAK,iBAAiB,UAAa,KAAK,aAAa,KAAK,EAAE,WAAW,GAAG;AAC5E,YAAQ,OAAO,MAAM,EAAE,wBAAwB,CAAC;AAAA,EAClD;AACA,MAAI,KAAK,kBAAkB;AACzB,UAAM,WAAW,QAAQ,KAAK,gBAAgB;AAC9C,QAAI;AACF,iCAA2B,aAAa,UAAU,MAAM;AAAA,IAC1D,SAAS,KAAK;AACZ,YAAM,IAAI;AACV,YAAM,eAAe,EAAE,OAAO,IAAI,EAAE,IAAI,KAAK,EAAE,OAAO,KAAK,EAAE;AAC7D,cAAQ,OAAO,MAAM,EAAE,kCAAkC,EAAE,UAAU,aAAa,CAAC,CAAC;AACpF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAKA,MAAI,cAAc;AAClB,MAAI,kBAAkB,SAAS;AAC/B,QAAM,oBAAoB,MACxB,iBAAiB,aAAa;AAAA,IAC5B,mBAAmB;AAAA,IACnB,cAAc,KAAK;AAAA,IACnB,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,0BAA0B,6BAA6B;AAAA,EACzD,CAAC;AACH,QAAM,YAAY;AAAA,IAChB,OAAO;AAAA,IACP,QAAQ,KAAK,QAAQ,SAAY,sBAAsB,cAAc;AAAA,IACrE,cAAc,KAAK,QAAQ,QAAQ,eAAe;AAAA,IAClD,WAAW,KAAK;AAAA,IAChB,QAAQ,kBAAkB;AAAA,IAC1B,eAAe;AAAA,IACf,YAAY,KAAK;AAAA,IACjB;AAAA,IACA,WAAW;AAAA,IACX,UAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,qBAAqB,OAAO,SAAiB;AAC3C,cAAM,IAAI,MAAM,oBAAoB,IAAI;AACxC,0BAAkB,EAAE;AACpB,eAAO;AAAA,MACT;AAAA,MACA,cAAc,CAAC,YAAoB;AACjC,sBAAc;AAAA,MAChB;AAAA,IACF;AAAA,IACA,KAAK,WAAW,EAAE;AAAA,IAClB,aAAa,KAAK;AAAA,IAClB,UAAU,KAAK;AAAA,IACf,aAAa,KAAK;AAAA,IAClB,eAAe,KAAK;AAAA,IACpB,eAAe,KAAK;AAAA,IACpB,eAAe,KAAK;AAAA,IACpB,gBAAgB,KAAK;AAAA,EACvB,CAAC;AACH;","names":[]}