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,245 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ formatMcpLifecycleEvent,
4
+ formatMcpSlowToast
5
+ } from "./chunk-LTXADNCO.js";
6
+ import {
7
+ buildTransportFromSpec,
8
+ preflightStdioSpec
9
+ } from "./chunk-BOFL3T45.js";
10
+ import {
11
+ bridgeMcpTools
12
+ } from "./chunk-IEA6JOIP.js";
13
+ import {
14
+ McpClient,
15
+ inspectMcpServer,
16
+ parseMcpSpec
17
+ } from "./chunk-CFY2XLY6.js";
18
+ import {
19
+ mcpEnvFor,
20
+ readConfig
21
+ } from "./chunk-65Q5HQ26.js";
22
+
23
+ // src/mcp/summary.ts
24
+ function buildMcpServerSummary(opts) {
25
+ return {
26
+ label: opts.label,
27
+ spec: opts.spec,
28
+ toolCount: opts.toolCount,
29
+ report: opts.report,
30
+ host: opts.host,
31
+ bridgeEnv: opts.bridgeEnv,
32
+ readResource(uri) {
33
+ return opts.host.client.readResource(uri);
34
+ },
35
+ getPrompt(name, args) {
36
+ return args !== void 0 ? opts.host.client.getPrompt(name, args) : opts.host.client.getPrompt(name);
37
+ }
38
+ };
39
+ }
40
+
41
+ // src/cli/commands/mcp-runtime.ts
42
+ var stderrLifecycleSink = (n) => {
43
+ if (n.kind === "slow") {
44
+ process.stderr.write(
45
+ `${formatMcpSlowToast({ name: n.serverName, p95Ms: n.p95Ms, sampleSize: n.sampleSize })}
46
+ `
47
+ );
48
+ return;
49
+ }
50
+ if (n.kind === "failed") {
51
+ process.stderr.write(
52
+ `${formatMcpLifecycleEvent({ state: "failed", name: n.name, reason: n.reason })}
53
+ \u2192 run \`reasonix setup\` to remove this entry, or fix the underlying issue (missing npm package, network, etc.).
54
+ `
55
+ );
56
+ return;
57
+ }
58
+ if (n.kind === "connected") {
59
+ process.stderr.write(
60
+ `${formatMcpLifecycleEvent({
61
+ state: "connected",
62
+ name: n.name,
63
+ tools: n.tools,
64
+ resources: n.resources,
65
+ prompts: n.prompts,
66
+ ms: n.ms
67
+ })}
68
+ `
69
+ );
70
+ return;
71
+ }
72
+ process.stderr.write(`${formatMcpLifecycleEvent({ state: n.kind, name: n.name })}
73
+ `);
74
+ };
75
+ function createMcpRuntime(ctx) {
76
+ const records = /* @__PURE__ */ new Map();
77
+ const insertionOrder = [];
78
+ let sink = stderrLifecycleSink;
79
+ async function addSpec(raw, loop) {
80
+ if (records.has(raw)) {
81
+ return { ok: true, summary: records.get(raw).summary };
82
+ }
83
+ const tools = ctx.getTools();
84
+ if (!tools) return { ok: false, reason: "no tool registry available" };
85
+ const disabledNames = new Set(readConfig().mcpDisabled ?? []);
86
+ let label = "anon";
87
+ let mcp;
88
+ let resolveReady;
89
+ let rejectReady;
90
+ const ready = new Promise((resolve, reject) => {
91
+ resolveReady = resolve;
92
+ rejectReady = reject;
93
+ });
94
+ ready.catch(() => void 0);
95
+ try {
96
+ const spec = parseMcpSpec(raw);
97
+ label = spec.name ?? "anon";
98
+ if (spec.name && disabledNames.has(spec.name)) {
99
+ sink({ kind: "disabled", name: label });
100
+ rejectReady(new Error(`MCP server "${label}" is disabled`));
101
+ return { ok: false, reason: "disabled by user" };
102
+ }
103
+ sink({ kind: "handshake", name: label });
104
+ const t0 = Date.now();
105
+ const namePrefix = spec.name ? `${spec.name}_` : ctx.getRequestedCount() === 1 && ctx.getMcpPrefix() ? ctx.getMcpPrefix() : "";
106
+ if (spec.transport === "stdio") preflightStdioSpec(spec);
107
+ const transport = buildTransportFromSpec(spec, { env: mcpEnvFor(spec.name, readConfig()) });
108
+ mcp = new McpClient({ transport });
109
+ await mcp.initialize();
110
+ const host = { client: mcp };
111
+ const bridge = await bridgeMcpTools(mcp, {
112
+ registry: tools,
113
+ namePrefix,
114
+ serverName: label,
115
+ host,
116
+ ready,
117
+ onProgress: (info) => ctx.progressSink.current?.(info),
118
+ onSlow: (info) => sink({
119
+ kind: "slow",
120
+ serverName: info.serverName,
121
+ p95Ms: info.p95Ms,
122
+ sampleSize: info.sampleSize
123
+ })
124
+ });
125
+ let report;
126
+ try {
127
+ report = await inspectMcpServer(mcp);
128
+ } catch {
129
+ report = {
130
+ protocolVersion: mcp.protocolVersion,
131
+ serverInfo: mcp.serverInfo,
132
+ capabilities: mcp.serverCapabilities ?? {},
133
+ tools: { supported: true, items: [] },
134
+ resources: { supported: false, reason: "inspect failed" },
135
+ prompts: { supported: false, reason: "inspect failed" },
136
+ elapsedMs: 0
137
+ };
138
+ }
139
+ const ms = Date.now() - t0;
140
+ const resourceCount = report.resources.supported ? report.resources.items.length : 0;
141
+ const promptCount = report.prompts.supported ? report.prompts.items.length : 0;
142
+ sink({
143
+ kind: "connected",
144
+ name: label,
145
+ tools: bridge.registeredNames.length,
146
+ resources: resourceCount,
147
+ prompts: promptCount,
148
+ ms
149
+ });
150
+ resolveReady();
151
+ const summary = buildMcpServerSummary({
152
+ label,
153
+ spec: raw,
154
+ toolCount: bridge.registeredNames.length,
155
+ report,
156
+ host,
157
+ bridgeEnv: bridge.env
158
+ });
159
+ const allSpecs = tools.specs();
160
+ const registeredSpecs = allSpecs.filter(
161
+ (s) => bridge.registeredNames.includes(s.function.name)
162
+ );
163
+ records.set(raw, {
164
+ spec: raw,
165
+ client: mcp,
166
+ summary,
167
+ registeredNames: bridge.registeredNames,
168
+ registeredSpecs
169
+ });
170
+ insertionOrder.push(raw);
171
+ if (loop) for (const s of registeredSpecs) loop.prefix.addTool(s);
172
+ return { ok: true, summary };
173
+ } catch (err) {
174
+ await mcp?.close().catch(() => void 0);
175
+ const reason = err.message;
176
+ sink({ kind: "failed", name: label, reason });
177
+ rejectReady(new Error(`MCP server "${label}" failed to start: ${reason}`));
178
+ return { ok: false, reason };
179
+ }
180
+ }
181
+ async function removeSpec(raw, loop) {
182
+ const record = records.get(raw);
183
+ if (!record) return false;
184
+ await record.client.close().catch(() => void 0);
185
+ const tools = ctx.getTools();
186
+ for (const name of record.registeredNames) {
187
+ tools?.unregister(name);
188
+ loop?.prefix.removeTool(name);
189
+ }
190
+ records.delete(raw);
191
+ const idx = insertionOrder.indexOf(raw);
192
+ if (idx >= 0) insertionOrder.splice(idx, 1);
193
+ return true;
194
+ }
195
+ async function reloadFromConfig(loop) {
196
+ const desired = readConfig().mcp ?? [];
197
+ const desiredSet = new Set(desired);
198
+ const currentSet = new Set(records.keys());
199
+ const added = [];
200
+ const removed = [];
201
+ const failed = [];
202
+ for (const spec of [...currentSet]) {
203
+ if (!desiredSet.has(spec)) {
204
+ await removeSpec(spec, loop);
205
+ removed.push(spec);
206
+ }
207
+ }
208
+ for (const spec of desired) {
209
+ if (currentSet.has(spec)) continue;
210
+ const result = await addSpec(spec, loop);
211
+ if (result.ok) added.push(spec);
212
+ else failed.push({ spec, reason: result.reason });
213
+ }
214
+ return { added, removed, failed, summaries: summaries() };
215
+ }
216
+ function specs() {
217
+ return [...insertionOrder];
218
+ }
219
+ function summaries() {
220
+ return insertionOrder.map((s) => records.get(s)?.summary).filter((s) => Boolean(s));
221
+ }
222
+ async function closeAll() {
223
+ for (const r of records.values()) await r.client.close().catch(() => void 0);
224
+ records.clear();
225
+ insertionOrder.length = 0;
226
+ }
227
+ function setLifecycleSink(s) {
228
+ sink = s;
229
+ }
230
+ return {
231
+ size: () => records.size,
232
+ specs,
233
+ summaries,
234
+ addSpec,
235
+ removeSpec,
236
+ reloadFromConfig,
237
+ closeAll,
238
+ setLifecycleSink
239
+ };
240
+ }
241
+
242
+ export {
243
+ createMcpRuntime
244
+ };
245
+ //# sourceMappingURL=chunk-SXLJBFIV.js.map
@@ -0,0 +1 @@
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 { mcpEnvFor, readConfig } from \"../../config.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 { parseMcpSpec } 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 { 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\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 → run \\`reasonix setup\\` to remove this entry, or fix the underlying issue (missing npm package, network, etc.).\\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 process.stderr.write(`${formatMcpLifecycleEvent({ state: n.kind, name: n.name })}\\n`);\n};\n\nexport interface McpRuntime {\n size(): number;\n specs(): string[];\n summaries(): McpServerSummary[];\n addSpec(\n raw: string,\n loop?: CacheFirstLoop,\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 let sink: McpLifecycleSink = stderrLifecycleSink;\n\n async function addSpec(\n raw: string,\n loop?: CacheFirstLoop,\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 const tools = ctx.getTools();\n if (!tools) return { ok: false, reason: \"no tool registry available\" };\n const disabledNames = new Set(readConfig().mcpDisabled ?? []);\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 spec = parseMcpSpec(raw);\n label = spec.name ?? \"anon\";\n if (spec.name && disabledNames.has(spec.name)) {\n sink({ kind: \"disabled\", name: label });\n rejectReady(new Error(`MCP server \"${label}\" is disabled`));\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, { env: mcpEnvFor(spec.name, readConfig()) });\n mcp = new McpClient({ transport });\n await mcp.initialize();\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 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 ms = Date.now() - t0;\n const resourceCount = report.resources.supported ? report.resources.items.length : 0;\n const promptCount = report.prompts.supported ? report.prompts.items.length : 0;\n sink({\n kind: \"connected\",\n name: label,\n tools: bridge.registeredNames.length,\n resources: resourceCount,\n prompts: promptCount,\n ms,\n });\n resolveReady();\n const summary = buildMcpServerSummary({\n label,\n spec: raw,\n toolCount: bridge.registeredNames.length,\n report,\n host,\n bridgeEnv: bridge.env,\n });\n // Snapshot tool specs AFTER bridge so hot-add can replay them into loop.prefix.\n const allSpecs = tools.specs();\n const registeredSpecs = allSpecs.filter((s) =>\n bridge.registeredNames.includes(s.function.name),\n );\n records.set(raw, {\n spec: raw,\n client: mcp,\n summary,\n registeredNames: bridge.registeredNames,\n registeredSpecs,\n });\n insertionOrder.push(raw);\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) for (const s of registeredSpecs) loop.prefix.addTool(s);\n return { ok: true, summary };\n } catch (err) {\n await mcp?.close().catch(() => undefined);\n const reason = (err as Error).message;\n sink({ kind: \"failed\", name: label, reason });\n rejectReady(new Error(`MCP server \"${label}\" failed to start: ${reason}`));\n return { ok: false, reason };\n }\n }\n\n async function removeSpec(raw: string, loop?: CacheFirstLoop): Promise<boolean> {\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 desired = readConfig().mcp ?? [];\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 }\n function setLifecycleSink(s: McpLifecycleSink): void {\n sink = s;\n }\n return {\n size: () => records.size,\n specs,\n summaries,\n addSpec,\n removeSpec,\n reloadFromConfig,\n closeAll,\n setLifecycleSink,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAeO,SAAS,sBAAsB,MAOjB;AACnB,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,MAAM,KAAK;AAAA,IACX,WAAW,KAAK;AAAA,IAChB,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,WAAW,KAAK;AAAA,IAChB,aAAa,KAAK;AAChB,aAAO,KAAK,KAAK,OAAO,aAAa,GAAG;AAAA,IAC1C;AAAA,IACA,UAAU,MAAM,MAAM;AACpB,aAAO,SAAS,SACZ,KAAK,KAAK,OAAO,UAAU,MAAM,IAAI,IACrC,KAAK,KAAK,OAAO,UAAU,IAAI;AAAA,IACrC;AAAA,EACF;AACF;;;ACgBO,IAAM,sBAAwC,CAAC,MAAM;AAC1D,MAAI,EAAE,SAAS,QAAQ;AACrB,YAAQ,OAAO;AAAA,MACb,GAAG,mBAAmB,EAAE,MAAM,EAAE,YAAY,OAAO,EAAE,OAAO,YAAY,EAAE,WAAW,CAAC,CAAC;AAAA;AAAA,IACzF;AACA;AAAA,EACF;AACA,MAAI,EAAE,SAAS,UAAU;AACvB,YAAQ,OAAO;AAAA,MACb,GAAG,wBAAwB,EAAE,OAAO,UAAU,MAAM,EAAE,MAAM,QAAQ,EAAE,OAAO,CAAC,CAAC;AAAA;AAAA;AAAA,IACjF;AACA;AAAA,EACF;AACA,MAAI,EAAE,SAAS,aAAa;AAC1B,YAAQ,OAAO;AAAA,MACb,GAAG,wBAAwB;AAAA,QACzB,OAAO;AAAA,QACP,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,QACT,WAAW,EAAE;AAAA,QACb,SAAS,EAAE;AAAA,QACX,IAAI,EAAE;AAAA,MACR,CAAC,CAAC;AAAA;AAAA,IACJ;AACA;AAAA,EACF;AACA,UAAQ,OAAO,MAAM,GAAG,wBAAwB,EAAE,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,CAAC,CAAC;AAAA,CAAI;AACtF;AAsBO,SAAS,iBAAiB,KAAiC;AAChE,QAAM,UAAU,oBAAI,IAAwB;AAC5C,QAAM,iBAA2B,CAAC;AAClC,MAAI,OAAyB;AAE7B,iBAAe,QACb,KACA,MACkF;AAClF,QAAI,QAAQ,IAAI,GAAG,GAAG;AACpB,aAAO,EAAE,IAAI,MAAM,SAAS,QAAQ,IAAI,GAAG,EAAG,QAAQ;AAAA,IACxD;AACA,UAAM,QAAQ,IAAI,SAAS;AAC3B,QAAI,CAAC,MAAO,QAAO,EAAE,IAAI,OAAO,QAAQ,6BAA6B;AACrE,UAAM,gBAAgB,IAAI,IAAI,WAAW,EAAE,eAAe,CAAC,CAAC;AAC5D,QAAI,QAAQ;AACZ,QAAI;AAMJ,QAAI;AACJ,QAAI;AACJ,UAAM,QAAQ,IAAI,QAAc,CAAC,SAAS,WAAW;AACnD,qBAAe;AACf,oBAAc;AAAA,IAChB,CAAC;AAED,UAAM,MAAM,MAAM,MAAS;AAC3B,QAAI;AACF,YAAM,OAAO,aAAa,GAAG;AAC7B,cAAQ,KAAK,QAAQ;AACrB,UAAI,KAAK,QAAQ,cAAc,IAAI,KAAK,IAAI,GAAG;AAC7C,aAAK,EAAE,MAAM,YAAY,MAAM,MAAM,CAAC;AACtC,oBAAY,IAAI,MAAM,eAAe,KAAK,eAAe,CAAC;AAC1D,eAAO,EAAE,IAAI,OAAO,QAAQ,mBAAmB;AAAA,MACjD;AACA,WAAK,EAAE,MAAM,aAAa,MAAM,MAAM,CAAC;AACvC,YAAM,KAAK,KAAK,IAAI;AACpB,YAAM,aAAa,KAAK,OACpB,GAAG,KAAK,IAAI,MACZ,IAAI,kBAAkB,MAAM,KAAK,IAAI,aAAa,IAC/C,IAAI,aAAa,IAClB;AACN,UAAI,KAAK,cAAc,QAAS,oBAAmB,IAAI;AACvD,YAAM,YAAY,uBAAuB,MAAM,EAAE,KAAK,UAAU,KAAK,MAAM,WAAW,CAAC,EAAE,CAAC;AAC1F,YAAM,IAAI,UAAU,EAAE,UAAU,CAAC;AACjC,YAAM,IAAI,WAAW;AACrB,YAAM,OAAsB,EAAE,QAAQ,IAAI;AAC1C,YAAM,SAAS,MAAM,eAAe,KAAK;AAAA,QACvC,UAAU;AAAA,QACV;AAAA,QACA,YAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA,YAAY,CAAC,SAAS,IAAI,aAAa,UAAU,IAAI;AAAA,QACrD,QAAQ,CAAC,SACP,KAAK;AAAA,UACH,MAAM;AAAA,UACN,YAAY,KAAK;AAAA,UACjB,OAAO,KAAK;AAAA,UACZ,YAAY,KAAK;AAAA,QACnB,CAAC;AAAA,MACL,CAAC;AACD,UAAI;AACJ,UAAI;AACF,iBAAS,MAAM,iBAAiB,GAAG;AAAA,MACrC,QAAQ;AACN,iBAAS;AAAA,UACP,iBAAiB,IAAI;AAAA,UACrB,YAAY,IAAI;AAAA,UAChB,cAAc,IAAI,sBAAsB,CAAC;AAAA,UACzC,OAAO,EAAE,WAAW,MAAM,OAAO,CAAC,EAAE;AAAA,UACpC,WAAW,EAAE,WAAW,OAAO,QAAQ,iBAAiB;AAAA,UACxD,SAAS,EAAE,WAAW,OAAO,QAAQ,iBAAiB;AAAA,UACtD,WAAW;AAAA,QACb;AAAA,MACF;AACA,YAAM,KAAK,KAAK,IAAI,IAAI;AACxB,YAAM,gBAAgB,OAAO,UAAU,YAAY,OAAO,UAAU,MAAM,SAAS;AACnF,YAAM,cAAc,OAAO,QAAQ,YAAY,OAAO,QAAQ,MAAM,SAAS;AAC7E,WAAK;AAAA,QACH,MAAM;AAAA,QACN,MAAM;AAAA,QACN,OAAO,OAAO,gBAAgB;AAAA,QAC9B,WAAW;AAAA,QACX,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AACD,mBAAa;AACb,YAAM,UAAU,sBAAsB;AAAA,QACpC;AAAA,QACA,MAAM;AAAA,QACN,WAAW,OAAO,gBAAgB;AAAA,QAClC;AAAA,QACA;AAAA,QACA,WAAW,OAAO;AAAA,MACpB,CAAC;AAED,YAAM,WAAW,MAAM,MAAM;AAC7B,YAAM,kBAAkB,SAAS;AAAA,QAAO,CAAC,MACvC,OAAO,gBAAgB,SAAS,EAAE,SAAS,IAAI;AAAA,MACjD;AACA,cAAQ,IAAI,KAAK;AAAA,QACf,MAAM;AAAA,QACN,QAAQ;AAAA,QACR;AAAA,QACA,iBAAiB,OAAO;AAAA,QACxB;AAAA,MACF,CAAC;AACD,qBAAe,KAAK,GAAG;AAGvB,UAAI,KAAM,YAAW,KAAK,gBAAiB,MAAK,OAAO,QAAQ,CAAC;AAChE,aAAO,EAAE,IAAI,MAAM,QAAQ;AAAA,IAC7B,SAAS,KAAK;AACZ,YAAM,KAAK,MAAM,EAAE,MAAM,MAAM,MAAS;AACxC,YAAM,SAAU,IAAc;AAC9B,WAAK,EAAE,MAAM,UAAU,MAAM,OAAO,OAAO,CAAC;AAC5C,kBAAY,IAAI,MAAM,eAAe,KAAK,sBAAsB,MAAM,EAAE,CAAC;AACzE,aAAO,EAAE,IAAI,OAAO,OAAO;AAAA,IAC7B;AAAA,EACF;AAEA,iBAAe,WAAW,KAAa,MAAyC;AAC9E,UAAM,SAAS,QAAQ,IAAI,GAAG;AAC9B,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,OAAO,OAAO,MAAM,EAAE,MAAM,MAAM,MAAS;AACjD,UAAM,QAAQ,IAAI,SAAS;AAC3B,eAAW,QAAQ,OAAO,iBAAiB;AACzC,aAAO,WAAW,IAAI;AACtB,YAAM,OAAO,WAAW,IAAI;AAAA,IAC9B;AACA,YAAQ,OAAO,GAAG;AAClB,UAAM,MAAM,eAAe,QAAQ,GAAG;AACtC,QAAI,OAAO,EAAG,gBAAe,OAAO,KAAK,CAAC;AAC1C,WAAO;AAAA,EACT;AAEA,iBAAe,iBAAiB,MAK7B;AACD,UAAM,UAAU,WAAW,EAAE,OAAO,CAAC;AACrC,UAAM,aAAa,IAAI,IAAI,OAAO;AAClC,UAAM,aAAa,IAAI,IAAI,QAAQ,KAAK,CAAC;AACzC,UAAM,QAAkB,CAAC;AACzB,UAAM,UAAoB,CAAC;AAC3B,UAAM,SAAkD,CAAC;AAEzD,eAAW,QAAQ,CAAC,GAAG,UAAU,GAAG;AAClC,UAAI,CAAC,WAAW,IAAI,IAAI,GAAG;AACzB,cAAM,WAAW,MAAM,IAAI;AAC3B,gBAAQ,KAAK,IAAI;AAAA,MACnB;AAAA,IACF;AACA,eAAW,QAAQ,SAAS;AAC1B,UAAI,WAAW,IAAI,IAAI,EAAG;AAC1B,YAAM,SAAS,MAAM,QAAQ,MAAM,IAAI;AACvC,UAAI,OAAO,GAAI,OAAM,KAAK,IAAI;AAAA,UACzB,QAAO,KAAK,EAAE,MAAM,QAAQ,OAAO,OAAO,CAAC;AAAA,IAClD;AACA,WAAO,EAAE,OAAO,SAAS,QAAQ,WAAW,UAAU,EAAE;AAAA,EAC1D;AAEA,WAAS,QAAkB;AACzB,WAAO,CAAC,GAAG,cAAc;AAAA,EAC3B;AACA,WAAS,YAAgC;AACvC,WAAO,eACJ,IAAI,CAAC,MAAM,QAAQ,IAAI,CAAC,GAAG,OAAO,EAClC,OAAO,CAAC,MAA6B,QAAQ,CAAC,CAAC;AAAA,EACpD;AACA,iBAAe,WAA0B;AACvC,eAAW,KAAK,QAAQ,OAAO,EAAG,OAAM,EAAE,OAAO,MAAM,EAAE,MAAM,MAAM,MAAS;AAC9E,YAAQ,MAAM;AACd,mBAAe,SAAS;AAAA,EAC1B;AACA,WAAS,iBAAiB,GAA2B;AACnD,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,MAAM,MAAM,QAAQ;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -9,7 +9,7 @@ import {
9
9
  TONE_ACTIVE,
10
10
  resolveThemeName,
11
11
  setActiveTheme
12
- } from "./chunk-CZSJILQP.js";
12
+ } from "./chunk-65Q5HQ26.js";
13
13
 
14
14
  // src/cli/ui/theme/context.tsx
15
15
  import React from "react";
@@ -150,4 +150,4 @@ export {
150
150
  COLOR,
151
151
  GLYPH
152
152
  };
153
- //# sourceMappingURL=chunk-4X3NY5ZM.js.map
153
+ //# sourceMappingURL=chunk-UV7XJUJH.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  computeReplayStats
4
- } from "./chunk-XHQIK7B6.js";
4
+ } from "./chunk-7SPOFTMT.js";
5
5
 
6
6
  // src/transcript/diff.ts
7
7
  function findNextDivergence(pairs, fromIdx) {
@@ -304,4 +304,4 @@ export {
304
304
  renderSummaryTable,
305
305
  renderMarkdown
306
306
  };
307
- //# sourceMappingURL=chunk-XJLZ4HKU.js.map
307
+ //# sourceMappingURL=chunk-VFG4GIT3.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  t
4
- } from "./chunk-H7PHYVPM.js";
4
+ } from "./chunk-MHGPBJ2T.js";
5
5
 
6
6
  // src/hooks.ts
7
7
  import { spawn } from "child_process";
@@ -205,4 +205,4 @@ export {
205
205
  formatHookOutcomeMessage,
206
206
  runHooks
207
207
  };
208
- //# sourceMappingURL=chunk-FFNOMR32.js.map
208
+ //# sourceMappingURL=chunk-WE3YZULK.js.map
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/mcp/marketplace-overlay/loader.ts
4
+ import { readFileSync } from "fs";
5
+ import { dirname, join } from "path";
6
+ import { fileURLToPath } from "url";
7
+ var cache = null;
8
+ var cachedLang = null;
9
+ function loadOverlay(lang) {
10
+ if (cachedLang === lang && cache) return cache;
11
+ try {
12
+ const dir = dirname(fileURLToPath(import.meta.url));
13
+ const raw = readFileSync(join(dir, `${lang}.json`), "utf8");
14
+ cache = JSON.parse(raw);
15
+ cachedLang = lang;
16
+ return cache;
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+
22
+ export {
23
+ loadOverlay
24
+ };
25
+ //# sourceMappingURL=chunk-Y5XNV3NX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/mcp/marketplace-overlay/loader.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport interface OverlayEntry {\n title: string;\n description: string;\n}\n\nlet cache: Record<string, OverlayEntry> | null = null;\nlet cachedLang: string | null = null;\n\nexport function loadOverlay(lang: string): Record<string, OverlayEntry> | null {\n if (cachedLang === lang && cache) return cache;\n try {\n const dir = dirname(fileURLToPath(import.meta.url));\n const raw = readFileSync(join(dir, `${lang}.json`), \"utf8\");\n cache = JSON.parse(raw) as Record<string, OverlayEntry>;\n cachedLang = lang;\n return cache;\n } catch {\n return null;\n }\n}\n"],"mappings":";;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAO9B,IAAI,QAA6C;AACjD,IAAI,aAA4B;AAEzB,SAAS,YAAY,MAAmD;AAC7E,MAAI,eAAe,QAAQ,MAAO,QAAO;AACzC,MAAI;AACF,UAAM,MAAM,QAAQ,cAAc,YAAY,GAAG,CAAC;AAClD,UAAM,MAAM,aAAa,KAAK,KAAK,GAAG,IAAI,OAAO,GAAG,MAAM;AAC1D,YAAQ,KAAK,MAAM,GAAG;AACtB,iBAAa;AACb,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -42,6 +42,11 @@ function sanitizeName(name) {
42
42
  function timestampSuffix() {
43
43
  return (/* @__PURE__ */ new Date()).toISOString().replace(/[^\d]/g, "").slice(0, 12);
44
44
  }
45
+ function freshSessionName(currentName) {
46
+ const base = currentName ? currentName.replace(/-\d{12,14}$/, "") : "default";
47
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[^\d]/g, "").slice(0, 14);
48
+ return `${base || "default"}-${stamp}`;
49
+ }
45
50
  function findSessionsByPrefix(prefix) {
46
51
  const dir = sessionsDir();
47
52
  if (!existsSync(dir)) return [];
@@ -247,6 +252,7 @@ export {
247
252
  sessionPath,
248
253
  sanitizeName,
249
254
  timestampSuffix,
255
+ freshSessionName,
250
256
  resolveSession,
251
257
  loadSessionMessages,
252
258
  appendSessionMessage,
@@ -260,4 +266,4 @@ export {
260
266
  rewriteSession,
261
267
  archiveSession
262
268
  };
263
- //# sourceMappingURL=chunk-XST7BSZJ.js.map
269
+ //# sourceMappingURL=chunk-YJFKFTAL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/memory/session.ts"],"sourcesContent":["/** JSONL append-only message log under `~/.reasonix/sessions/`; concurrent-write safe. */\n\nimport { execFileSync } from \"node:child_process\";\nimport {\n appendFileSync,\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { ChatMessage } from \"../types.js\";\n\n/** Best-effort git branch sniff; returns undefined if not a git repo or git missing. */\nexport function detectGitBranch(cwd: string): string | undefined {\n try {\n const out = execFileSync(\"git\", [\"branch\", \"--show-current\"], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 800,\n encoding: \"utf8\",\n }).trim();\n return out || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface SessionInfo {\n name: string;\n path: string;\n size: number;\n messageCount: number;\n mtime: Date;\n meta: SessionMeta;\n}\n\nexport interface SessionMeta {\n branch?: string;\n summary?: string;\n totalCostUsd?: number;\n turnCount?: number;\n /** Absolute path of the workspace root the session was created/used in. */\n workspace?: string;\n /** Wallet currency at last save — used to format `totalCostUsd` in the picker without re-fetching balance. */\n balanceCurrency?: string;\n /** Cumulative cache hit / miss tokens across the session — survives resume so /status cache% isn't 0 on a fresh boot. */\n cacheHitTokens?: number;\n cacheMissTokens?: number;\n /** Last turn's promptTokens — lets /status render the context bar before the next turn fires. */\n lastPromptTokens?: number;\n}\n\nexport function sessionsDir(): string {\n return join(homedir(), \".reasonix\", \"sessions\");\n}\n\nexport function sessionPath(name: string): string {\n return join(sessionsDir(), `${sanitizeName(name)}.jsonl`);\n}\n\nexport function sanitizeName(name: string): string {\n const cleaned = name.replace(/[^\\w\\-\\u4e00-\\u9fa5]/g, \"_\").slice(0, 64);\n return cleaned || \"default\";\n}\n\n/** Sortable timestamp `YYYYMMDDHHmm` — used as a session-name suffix. */\nexport function timestampSuffix(): string {\n return new Date().toISOString().replace(/[^\\d]/g, \"\").slice(0, 12);\n}\n\n/** Unique name for an in-app \"new session\" — strips a trailing 12/14-digit timestamp from the current name and re-stamps with seconds precision so back-to-back clicks don't collide. */\nexport function freshSessionName(currentName: string | undefined): string {\n const base = currentName ? currentName.replace(/-\\d{12,14}$/, \"\") : \"default\";\n const stamp = new Date().toISOString().replace(/[^\\d]/g, \"\").slice(0, 14);\n return `${base || \"default\"}-${stamp}`;\n}\n\n/** Names of `.jsonl` sessions starting with `prefix`, newest-first by filename. */\nexport function findSessionsByPrefix(prefix: string): string[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n try {\n const files = readdirSync(dir)\n .filter((f) => f.endsWith(\".jsonl\") && !f.endsWith(\".events.jsonl\") && f.startsWith(prefix))\n .sort()\n .reverse();\n return files.map((f) => f.replace(/\\.jsonl$/, \"\"));\n } catch {\n return [];\n }\n}\n\nexport interface SessionPreview {\n messageCount: number;\n lastActive: Date;\n}\n\n/** Resolve launch-time session: forceNew → timestamped suffix; else latest `${name}-*` if any, else base. Preview returned only on the default branch when messages exist. */\nexport function resolveSession(\n sessionName: string | undefined,\n forceNew?: boolean,\n forceResume?: boolean,\n): { resolved: string | undefined; preview: SessionPreview | undefined } {\n let resolved = sessionName;\n let preview: SessionPreview | undefined;\n\n if (sessionName && forceNew) {\n resolved = `${sessionName}-${timestampSuffix()}`;\n } else if (sessionName && !forceResume) {\n let sessionToCheck = sessionName;\n const prefixed = findSessionsByPrefix(`${sessionName}-`);\n if (prefixed.length > 0) {\n sessionToCheck = prefixed[0]!;\n }\n const prior = loadSessionMessages(sessionToCheck);\n if (prior.length > 0) {\n resolved = sessionToCheck;\n const p = sessionPath(sessionToCheck);\n const mtime = existsSync(p) ? statSync(p).mtime : new Date();\n preview = { messageCount: prior.length, lastActive: mtime };\n }\n } else if (sessionName && forceResume) {\n const prefixed = findSessionsByPrefix(`${sessionName}-`);\n if (prefixed.length > 0) {\n resolved = prefixed[0]!;\n }\n }\n\n return { resolved, preview };\n}\n\nexport function loadSessionMessages(name: string): ChatMessage[] {\n const path = sessionPath(name);\n if (!existsSync(path)) return [];\n try {\n const raw = readFileSync(path, \"utf8\");\n const out: ChatMessage[] = [];\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const msg = JSON.parse(trimmed) as ChatMessage;\n if (msg && typeof msg === \"object\" && \"role\" in msg) out.push(msg);\n } catch {\n /* skip malformed line */\n }\n }\n return out;\n } catch {\n return [];\n }\n}\n\nexport function appendSessionMessage(name: string, message: ChatMessage): void {\n const path = sessionPath(name);\n mkdirSync(dirname(path), { recursive: true });\n appendFileSync(path, `${JSON.stringify(message)}\\n`, \"utf8\");\n try {\n chmodSync(path, 0o600);\n } catch {\n /* chmod not supported on this platform */\n }\n}\n\nexport function listSessions(): SessionInfo[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n try {\n // Exclude `.events.jsonl` sidecars — they share the .jsonl suffix.\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".jsonl\") && !f.endsWith(\".events.jsonl\"),\n );\n return files\n .map((file) => {\n const path = join(dir, file);\n const stat = statSync(path);\n const name = file.replace(/\\.jsonl$/, \"\");\n const messageCount = countLines(path);\n return {\n name,\n path,\n size: stat.size,\n messageCount,\n mtime: stat.mtime,\n meta: loadSessionMeta(name),\n };\n })\n .sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n } catch {\n return [];\n }\n}\n\n/** Strict match — legacy sessions without meta.workspace are hidden; resume by name still works. */\nexport function listSessionsForWorkspace(workspace: string): SessionInfo[] {\n return listSessions().filter((s) => s.meta.workspace === workspace);\n}\n\nfunction metaPath(name: string): string {\n return join(sessionsDir(), `${sanitizeName(name)}.meta.json`);\n}\n\nexport function loadSessionMeta(name: string): SessionMeta {\n const p = metaPath(name);\n if (!existsSync(p)) return {};\n try {\n const raw = JSON.parse(readFileSync(p, \"utf8\")) as SessionMeta;\n return raw && typeof raw === \"object\" ? raw : {};\n } catch {\n return {};\n }\n}\n\nexport function patchSessionMeta(name: string, patch: Partial<SessionMeta>): SessionMeta {\n const cur = loadSessionMeta(name);\n const next: SessionMeta = { ...cur, ...patch };\n const p = metaPath(name);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, JSON.stringify(next), \"utf8\");\n try {\n chmodSync(p, 0o600);\n } catch {\n /* chmod not supported */\n }\n return next;\n}\n\n/** Renames the JSONL plus all known sidecars together; returns false if target already exists. */\nexport function renameSession(oldName: string, newName: string): boolean {\n const safeOld = sanitizeName(oldName);\n const safeNew = sanitizeName(newName);\n if (safeOld === safeNew) return false;\n const oldJsonl = sessionPath(oldName);\n const newJsonl = sessionPath(newName);\n if (!existsSync(oldJsonl) || existsSync(newJsonl)) return false;\n renameSync(oldJsonl, newJsonl);\n for (const ext of [\".events.jsonl\", \".meta.json\", \".pending.json\", \".plan.json\"]) {\n const oldP = oldJsonl.replace(/\\.jsonl$/, ext);\n const newP = newJsonl.replace(/\\.jsonl$/, ext);\n if (existsSync(oldP)) {\n try {\n renameSync(oldP, newP);\n } catch {\n /* sidecar rename failed — leave the jsonl rename in place */\n }\n }\n }\n return true;\n}\n\n/** Best-effort: per-file delete errors are swallowed so partial pruning still finishes. */\nexport function pruneStaleSessions(daysOld = 90): string[] {\n const cutoff = Date.now() - daysOld * 24 * 60 * 60 * 1000;\n const deleted: string[] = [];\n for (const s of listSessions()) {\n if (s.mtime.getTime() < cutoff) {\n if (deleteSession(s.name)) deleted.push(s.name);\n }\n }\n return deleted;\n}\n\nexport function deleteSession(name: string): boolean {\n const path = sessionPath(name);\n try {\n unlinkSync(path);\n for (const ext of [\".events.jsonl\", \".pending.json\", \".meta.json\", \".plan.json\"]) {\n const sidecar = path.replace(/\\.jsonl$/, ext);\n try {\n unlinkSync(sidecar);\n } catch {\n /* expected when the sidecar doesn't exist */\n }\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/** Non-atomic truncate+write window is acceptable — a concurrent crash leaves the session file empty, same end state as the user deleting it. */\nexport function rewriteSession(name: string, messages: ChatMessage[]): void {\n const path = sessionPath(name);\n mkdirSync(dirname(path), { recursive: true });\n const body = messages.map((m) => JSON.stringify(m)).join(\"\\n\");\n writeFileSync(path, body ? `${body}\\n` : \"\", \"utf8\");\n try {\n chmodSync(path, 0o600);\n } catch {\n /* chmod not supported */\n }\n}\n\n/** Rotate the live jsonl + sidecars to `<name>__archive_<ts>` so /new doesn't destroy history. Returns the archive name, or null if there was nothing to archive. */\nexport function archiveSession(name: string): string | null {\n const path = sessionPath(name);\n if (!existsSync(path)) return null;\n try {\n if (statSync(path).size === 0) return null;\n } catch {\n return null;\n }\n for (let attempt = 0; attempt < 5; attempt++) {\n const target = `${name}__archive_${timestampSuffix()}${attempt > 0 ? `_${attempt}` : \"\"}`;\n if (renameSession(name, target)) return target;\n }\n return null;\n}\n\nfunction countLines(path: string): number {\n try {\n const raw = readFileSync(path, \"utf8\");\n return raw.split(/\\r?\\n/).filter((l) => l.trim()).length;\n } catch {\n return 0;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,58 +1,59 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildCodeToolset
4
- } from "./chunk-AVB3WZWU.js";
5
- import "./chunk-ULBW7DYL.js";
4
+ } from "./chunk-AT6GGIBV.js";
5
+ import "./chunk-RAUPWSYA.js";
6
6
  import {
7
7
  chatCommand
8
- } from "./chunk-26UDIXLD.js";
9
- import "./chunk-IYF36OCJ.js";
10
- import "./chunk-CPTZ5OHX.js";
11
- import "./chunk-VLNRQMCI.js";
12
- import "./chunk-RFX7TYVV.js";
13
- import "./chunk-MRLXEMZ7.js";
8
+ } from "./chunk-F2AV2QDK.js";
9
+ import "./chunk-LN27AKV3.js";
10
+ import "./chunk-Y5XNV3NX.js";
11
+ import "./chunk-SXLJBFIV.js";
12
+ import "./chunk-A7VHMMDE.js";
13
+ import "./chunk-LTXADNCO.js";
14
+ import "./chunk-BOFL3T45.js";
14
15
  import {
15
16
  markPhase
16
17
  } from "./chunk-CPOV2O73.js";
17
- import "./chunk-4YV2GBYG.js";
18
- import "./chunk-XJLZ4HKU.js";
19
- import "./chunk-HCC42PEI.js";
20
- import "./chunk-XHQIK7B6.js";
21
- import "./chunk-R4YTW7PR.js";
22
- import "./chunk-A5LSGEEK.js";
23
- import "./chunk-4X3NY5ZM.js";
18
+ import "./chunk-IEA6JOIP.js";
19
+ import "./chunk-VFG4GIT3.js";
20
+ import "./chunk-7SPOFTMT.js";
21
+ import "./chunk-CFY2XLY6.js";
22
+ import "./chunk-ARF3N2SY.js";
23
+ import "./chunk-4W2CICFQ.js";
24
+ import "./chunk-UV7XJUJH.js";
24
25
  import "./chunk-E46ECXJD.js";
25
- import "./chunk-WKOMCPXP.js";
26
+ import "./chunk-KZYLMMU5.js";
26
27
  import "./chunk-AFFZF3MW.js";
27
28
  import "./chunk-DAEAAVDF.js";
28
- import "./chunk-KMWKGPFZ.js";
29
+ import "./chunk-H4OLWRSX.js";
29
30
  import {
30
31
  loadDotenv
31
32
  } from "./chunk-3Q3C4W66.js";
32
33
  import "./chunk-4DCHFFEY.js";
33
34
  import "./chunk-WJ3YX4PZ.js";
34
- import "./chunk-UVRXTSK3.js";
35
+ import "./chunk-A3LL4XDV.js";
35
36
  import "./chunk-SOZE7V7V.js";
36
- import "./chunk-5GKJLNP2.js";
37
- import "./chunk-SZH34P45.js";
37
+ import "./chunk-7VFNPMKG.js";
38
+ import "./chunk-BYZGO3BX.js";
38
39
  import {
39
40
  detectForeignAgentPlatform
40
- } from "./chunk-7DLHHBGN.js";
41
+ } from "./chunk-CD4SCQL4.js";
41
42
  import "./chunk-FM57FNPJ.js";
42
- import "./chunk-UCMTWZKU.js";
43
- import "./chunk-CLAN6PVH.js";
44
- import "./chunk-FFNOMR32.js";
43
+ import "./chunk-2CXPDAWX.js";
44
+ import "./chunk-4H3ZRJ2U.js";
45
+ import "./chunk-WE3YZULK.js";
45
46
  import "./chunk-5X7LZJDE.js";
46
47
  import {
47
48
  sanitizeName
48
- } from "./chunk-XST7BSZJ.js";
49
+ } from "./chunk-YJFKFTAL.js";
49
50
  import {
50
51
  t
51
- } from "./chunk-H7PHYVPM.js";
52
+ } from "./chunk-MHGPBJ2T.js";
52
53
  import {
53
54
  loadApiKey,
54
55
  readConfig
55
- } from "./chunk-CZSJILQP.js";
56
+ } from "./chunk-65Q5HQ26.js";
56
57
  import "./chunk-ZTLZO42A.js";
57
58
  import "./chunk-ORM6PK57.js";
58
59
  import "./chunk-CRPQUBP6.js";
@@ -67,7 +68,7 @@ async function codeCommand(opts = {}) {
67
68
  if (cfgKey && !process.env.DEEPSEEK_API_KEY) {
68
69
  process.env.DEEPSEEK_API_KEY = cfgKey;
69
70
  }
70
- const { codeSystemPrompt } = await import("./prompt-PKCCLLAD.js");
71
+ const { codeSystemPrompt } = await import("./prompt-RSIHN62V.js");
71
72
  const rootDir = resolve(opts.dir ?? process.cwd());
72
73
  const session = opts.noSession ? void 0 : `code-${sanitizeName(basename(rootDir))}`;
73
74
  markPhase("semantic_bootstrap_start");
@@ -113,16 +114,18 @@ async function codeCommand(opts = {}) {
113
114
  process.exit(1);
114
115
  }
115
116
  }
117
+ const codeRebuildSystem = () => codeSystemPrompt(rootDir, {
118
+ hasSemanticSearch: semantic.enabled,
119
+ systemAppend: opts.systemAppend,
120
+ systemAppendFile: systemAppendFileContents,
121
+ modelId: opts.model ?? "deepseek-v4-flash"
122
+ });
116
123
  await chatCommand({
117
124
  model: opts.model ?? "deepseek-v4-flash",
118
125
  budgetUsd: opts.budgetUsd,
119
126
  failureThreshold: opts.failureThreshold,
120
- system: codeSystemPrompt(rootDir, {
121
- hasSemanticSearch: semantic.enabled,
122
- systemAppend: opts.systemAppend,
123
- systemAppendFile: systemAppendFileContents,
124
- modelId: opts.model ?? "deepseek-v4-flash"
125
- }),
127
+ system: codeRebuildSystem(),
128
+ rebuildSystem: codeRebuildSystem,
126
129
  transcript: opts.transcript,
127
130
  session,
128
131
  seedTools: tools,
@@ -144,4 +147,4 @@ async function codeCommand(opts = {}) {
144
147
  export {
145
148
  codeCommand
146
149
  };
147
- //# sourceMappingURL=code-YQGVLIT2.js.map
150
+ //# sourceMappingURL=code-X3M6ENTQ.js.map
@@ -1 +1 @@
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, 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 { 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 /** Per-turn repair-signal count required to escalate flash→pro. Undefined → loop default (3). */\n failureThreshold?: number;\n /** Suppress the auto-launched embedded web dashboard. */\n noDashboard?: boolean;\n /** Pin the dashboard to a fixed port. `undefined` keeps ephemeral assignment. */\n dashboardPort?: number;\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 /** Default true. Pass false (CLI: `--no-alt-screen`) to keep chat output in shell scrollback. */\n altScreen?: boolean;\n /** Default true. Pass false (CLI: `--no-mouse`) to keep terminal-native drag-select unmodified. */\n mouse?: boolean;\n}\n\nexport async function codeCommand(opts: CodeOptions = {}): Promise<void> {\n markPhase(\"code_command_enter\");\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(\n `⚠ workspace contains another agent platform's files (${foreign.join(\", \")}). Reasonix Code may read them as project content; relaunch with --dir <your-project> if that's not what you want.\\n`,\n );\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(\"--system-append is empty — no prompt text will be appended\\n\");\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 process.stderr.write(\n `Error: cannot read --system-append-file \"${filePath}\": ${e.code ? `[${e.code}] ` : \"\"}${e.message}\\n`,\n );\n process.exit(1);\n }\n }\n\n await chatCommand({\n model: opts.model ?? \"deepseek-v4-flash\",\n budgetUsd: opts.budgetUsd,\n failureThreshold: opts.failureThreshold,\n system: codeSystemPrompt(rootDir, {\n hasSemanticSearch: semantic.enabled,\n systemAppend: opts.systemAppend,\n systemAppendFile: systemAppendFileContents,\n modelId: opts.model ?? \"deepseek-v4-flash\",\n }),\n transcript: opts.transcript,\n session,\n seedTools: tools,\n codeMode: {\n rootDir,\n jobs,\n reregisterTools: registerRooted,\n reBootstrapSemantic,\n },\n mcp: readConfig().mcp,\n forceResume: opts.forceResume,\n forceNew: opts.forceNew,\n noDashboard: opts.noDashboard,\n dashboardPort: opts.dashboardPort,\n altScreen: opts.altScreen,\n mouse: opts.mouse,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,SAAS,oBAAoB;AAC7B,SAAS,UAAU,eAAe;AA6ClC,eAAsB,YAAY,OAAoB,CAAC,GAAkB;AACvE,YAAU,oBAAoB;AAM9B,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;AAAA,MACb,6DAAwD,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA,IAC5E;AAAA,EACF;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,mEAA8D;AAAA,EACrF;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,cAAQ,OAAO;AAAA,QACb,4CAA4C,QAAQ,MAAM,EAAE,OAAO,IAAI,EAAE,IAAI,OAAO,EAAE,GAAG,EAAE,OAAO;AAAA;AAAA,MACpG;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,YAAY;AAAA,IAChB,OAAO,KAAK,SAAS;AAAA,IACrB,WAAW,KAAK;AAAA,IAChB,kBAAkB,KAAK;AAAA,IACvB,QAAQ,iBAAiB,SAAS;AAAA,MAChC,mBAAmB,SAAS;AAAA,MAC5B,cAAc,KAAK;AAAA,MACnB,kBAAkB;AAAA,MAClB,SAAS,KAAK,SAAS;AAAA,IACzB,CAAC;AAAA,IACD,YAAY,KAAK;AAAA,IACjB;AAAA,IACA,WAAW;AAAA,IACX,UAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB;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,WAAW,KAAK;AAAA,IAChB,OAAO,KAAK;AAAA,EACd,CAAC;AACH;","names":[]}
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, 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 { 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 /** Per-turn repair-signal count required to escalate flash→pro. Undefined → loop default (3). */\n failureThreshold?: number;\n /** Suppress the auto-launched embedded web dashboard. */\n noDashboard?: boolean;\n /** Pin the dashboard to a fixed port. `undefined` keeps ephemeral assignment. */\n dashboardPort?: number;\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 /** Default true. Pass false (CLI: `--no-alt-screen`) to keep chat output in shell scrollback. */\n altScreen?: boolean;\n /** Default true. Pass false (CLI: `--no-mouse`) to keep terminal-native drag-select unmodified. */\n mouse?: boolean;\n}\n\nexport async function codeCommand(opts: CodeOptions = {}): Promise<void> {\n markPhase(\"code_command_enter\");\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(\n `⚠ workspace contains another agent platform's files (${foreign.join(\", \")}). Reasonix Code may read them as project content; relaunch with --dir <your-project> if that's not what you want.\\n`,\n );\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(\"--system-append is empty — no prompt text will be appended\\n\");\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 process.stderr.write(\n `Error: cannot read --system-append-file \"${filePath}\": ${e.code ? `[${e.code}] ` : \"\"}${e.message}\\n`,\n );\n process.exit(1);\n }\n }\n\n const codeRebuildSystem = () =>\n codeSystemPrompt(rootDir, {\n hasSemanticSearch: semantic.enabled,\n systemAppend: opts.systemAppend,\n systemAppendFile: systemAppendFileContents,\n modelId: opts.model ?? \"deepseek-v4-flash\",\n });\n await chatCommand({\n model: opts.model ?? \"deepseek-v4-flash\",\n budgetUsd: opts.budgetUsd,\n failureThreshold: opts.failureThreshold,\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,\n },\n mcp: readConfig().mcp,\n forceResume: opts.forceResume,\n forceNew: opts.forceNew,\n noDashboard: opts.noDashboard,\n dashboardPort: opts.dashboardPort,\n altScreen: opts.altScreen,\n mouse: opts.mouse,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,SAAS,oBAAoB;AAC7B,SAAS,UAAU,eAAe;AA6ClC,eAAsB,YAAY,OAAoB,CAAC,GAAkB;AACvE,YAAU,oBAAoB;AAM9B,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;AAAA,MACb,6DAAwD,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA,IAC5E;AAAA,EACF;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,mEAA8D;AAAA,EACrF;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,cAAQ,OAAO;AAAA,QACb,4CAA4C,QAAQ,MAAM,EAAE,OAAO,IAAI,EAAE,IAAI,OAAO,EAAE,GAAG,EAAE,OAAO;AAAA;AAAA,MACpG;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,oBAAoB,MACxB,iBAAiB,SAAS;AAAA,IACxB,mBAAmB,SAAS;AAAA,IAC5B,cAAc,KAAK;AAAA,IACnB,kBAAkB;AAAA,IAClB,SAAS,KAAK,SAAS;AAAA,EACzB,CAAC;AACH,QAAM,YAAY;AAAA,IAChB,OAAO,KAAK,SAAS;AAAA,IACrB,WAAW,KAAK;AAAA,IAChB,kBAAkB,KAAK;AAAA,IACvB,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;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,WAAW,KAAK;AAAA,IAChB,OAAO,KAAK;AAAA,EACd,CAAC;AACH;","names":[]}
@@ -3,15 +3,15 @@ import {
3
3
  checkOllamaStatus,
4
4
  pullOllamaModel,
5
5
  startOllamaDaemon
6
- } from "./chunk-UCMTWZKU.js";
6
+ } from "./chunk-2CXPDAWX.js";
7
7
  import {
8
8
  buildIndex
9
- } from "./chunk-CLAN6PVH.js";
9
+ } from "./chunk-4H3ZRJ2U.js";
10
10
  import "./chunk-5X7LZJDE.js";
11
11
  import {
12
12
  loadIndexConfig,
13
13
  resolveSemanticEmbeddingConfig
14
- } from "./chunk-CZSJILQP.js";
14
+ } from "./chunk-65Q5HQ26.js";
15
15
 
16
16
  // src/cli/commands/index.ts
17
17
  import { resolve } from "path";
@@ -351,4 +351,4 @@ function makeTtyWriter() {
351
351
  export {
352
352
  indexCommand
353
353
  };
354
- //# sourceMappingURL=commands-FQZOBLLZ.js.map
354
+ //# sourceMappingURL=commands-QY7MSQG7.js.map
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  DeepSeekClient
4
- } from "./chunk-KMWKGPFZ.js";
4
+ } from "./chunk-H4OLWRSX.js";
5
5
  import {
6
6
  loadDotenv
7
7
  } from "./chunk-3Q3C4W66.js";
8
8
  import {
9
9
  loadApiKey,
10
10
  loadBaseUrl
11
- } from "./chunk-CZSJILQP.js";
11
+ } from "./chunk-65Q5HQ26.js";
12
12
 
13
13
  // src/cli/commands/commit.ts
14
14
  import { spawn, spawnSync } from "child_process";
@@ -286,4 +286,4 @@ async function commitCommand(opts = {}) {
286
286
  export {
287
287
  commitCommand
288
288
  };
289
- //# sourceMappingURL=commit-ZS24SHPG.js.map
289
+ //# sourceMappingURL=commit-BRCQ3OQO.js.map