reasonix 0.46.1 → 0.47.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 (131) hide show
  1. package/README.md +62 -13
  2. package/README.zh-CN.md +52 -10
  3. package/dashboard/dist/app.js +217 -60
  4. package/dashboard/dist/app.js.map +1 -1
  5. package/dist/cli/{acp-LKJU5DZX.js → acp-QK3DMC53.js} +22 -22
  6. package/dist/cli/chat-VV5UWY4V.js +51 -0
  7. package/dist/cli/{chunk-DGA5QYFM.js → chunk-24A7FHGJ.js} +42 -13
  8. package/dist/cli/chunk-24A7FHGJ.js.map +1 -0
  9. package/dist/cli/{chunk-K3AIFMI6.js → chunk-6J6BSUCR.js} +2 -2
  10. package/dist/cli/{chunk-C72TNHDE.js → chunk-BWYVFFKR.js} +2 -2
  11. package/dist/cli/{chunk-EAOL43HB.js → chunk-BYYVYJDX.js} +3 -3
  12. package/dist/cli/{chunk-HNXDZGC6.js → chunk-CI2PF5QX.js} +2 -2
  13. package/dist/cli/{chunk-JVQT5IYP.js → chunk-COWPEX54.js} +19 -9
  14. package/dist/cli/chunk-COWPEX54.js.map +1 -0
  15. package/dist/cli/{chunk-IYQ325V7.js → chunk-E5WCLUIU.js} +2 -2
  16. package/dist/cli/{chunk-YRLC2EDF.js → chunk-EQATK2L2.js} +2 -2
  17. package/dist/cli/{chunk-R2ASNSEO.js → chunk-FDKOUJKZ.js} +8 -8
  18. package/dist/cli/{chunk-TEUDEGX2.js → chunk-FY4S7TJZ.js} +19 -5
  19. package/dist/cli/chunk-FY4S7TJZ.js.map +1 -0
  20. package/dist/cli/{chunk-JVFEJAJX.js → chunk-GDKB2PPK.js} +2 -2
  21. package/dist/cli/{chunk-WQ6ZRDQM.js → chunk-HIYTRCSW.js} +16 -12
  22. package/dist/cli/chunk-HIYTRCSW.js.map +1 -0
  23. package/dist/cli/{chunk-ZOQHVQON.js → chunk-ICAFSZHS.js} +307 -30
  24. package/dist/cli/chunk-ICAFSZHS.js.map +1 -0
  25. package/dist/cli/{chunk-SPXN5JIT.js → chunk-ICSYGIPN.js} +1386 -1021
  26. package/dist/cli/chunk-ICSYGIPN.js.map +1 -0
  27. package/dist/cli/{chunk-XPAUNFOL.js → chunk-K6GUKSXH.js} +3 -2
  28. package/dist/cli/chunk-K6GUKSXH.js.map +1 -0
  29. package/dist/cli/{chunk-6VANO7KB.js → chunk-KDRUEXII.js} +147 -20
  30. package/dist/cli/chunk-KDRUEXII.js.map +1 -0
  31. package/dist/cli/{chunk-NCBP5D6E.js → chunk-LBLR4CUZ.js} +2 -2
  32. package/dist/cli/{chunk-2425HK6U.js → chunk-LGEKVMMV.js} +7 -2
  33. package/dist/cli/{chunk-2425HK6U.js.map → chunk-LGEKVMMV.js.map} +1 -1
  34. package/dist/cli/{chunk-7SGGXNB2.js → chunk-OJVITDGB.js} +2 -2
  35. package/dist/cli/{chunk-SE7C5ZSI.js → chunk-QVDWH2A2.js} +3 -3
  36. package/dist/cli/{chunk-WRONKNIH.js → chunk-QVUFWDD2.js} +2 -2
  37. package/dist/cli/{chunk-3AAG2CUT.js → chunk-R6GQKKBW.js} +2 -2
  38. package/dist/cli/{chunk-E7TAHQ4A.js → chunk-RRXUIPWG.js} +19 -18
  39. package/dist/cli/chunk-RRXUIPWG.js.map +1 -0
  40. package/dist/cli/{chunk-CXVWUPA3.js → chunk-TKVXTQ3T.js} +26 -26
  41. package/dist/cli/chunk-TKVXTQ3T.js.map +1 -0
  42. package/dist/cli/{chunk-DHRVZJ2D.js → chunk-UDVFBEXC.js} +3 -3
  43. package/dist/cli/{chunk-7YW6TPXK.js → chunk-VC2CQA5D.js} +9 -9
  44. package/dist/cli/{chunk-M4E5JK6S.js → chunk-VJMBISEI.js} +2 -2
  45. package/dist/cli/{chunk-TDSBASOF.js → chunk-VKYSZKH2.js} +2 -2
  46. package/dist/cli/{chunk-7LOJS3LV.js → chunk-VMUUFWFF.js} +2 -2
  47. package/dist/cli/{chunk-MIIZJD5O.js → chunk-VNQGCA3Q.js} +2 -2
  48. package/dist/cli/{chunk-2AASOSD5.js → chunk-WF7TPVZM.js} +2 -2
  49. package/dist/cli/{chunk-JLQDNLZF.js → chunk-YDPLF7XR.js} +26 -14
  50. package/dist/cli/chunk-YDPLF7XR.js.map +1 -0
  51. package/dist/cli/{code-2JIHL5M2.js → code-C24TUAE5.js} +39 -34
  52. package/dist/cli/code-C24TUAE5.js.map +1 -0
  53. package/dist/cli/{commands-OPT5AJNH.js → commands-RR3GIYOK.js} +4 -4
  54. package/dist/cli/{commit-KA37H6GM.js → commit-FSHPIINM.js} +3 -3
  55. package/dist/cli/{desktop-5ONTRU3C.js → desktop-7NCHPEFB.js} +263 -36
  56. package/dist/cli/desktop-7NCHPEFB.js.map +1 -0
  57. package/dist/cli/{diff-SOIA7AKH.js → diff-RAAHHLHV.js} +8 -8
  58. package/dist/cli/{doctor-RCUP4XRV.js → doctor-PKVQIXRT.js} +9 -9
  59. package/dist/cli/{events-6KHITNX4.js → events-VRYXOSKI.js} +3 -3
  60. package/dist/cli/index.js +81 -40
  61. package/dist/cli/index.js.map +1 -1
  62. package/dist/cli/{mcp-JP5OWD6R.js → mcp-CRJ26PP4.js} +2 -2
  63. package/dist/cli/{mcp-browse-ONCJJPJN.js → mcp-browse-QPAOWZOP.js} +2 -2
  64. package/dist/cli/{mcp-inspect-TPLHW5JA.js → mcp-inspect-CVCLABRS.js} +4 -4
  65. package/dist/cli/{prompt-RJDNCQAP.js → prompt-SKYXERSI.js} +4 -4
  66. package/dist/cli/{prune-sessions-MKEATRVL.js → prune-sessions-SEWX7GP6.js} +2 -2
  67. package/dist/cli/{replay-4NILJG4U.js → replay-KPDW2ZMJ.js} +9 -9
  68. package/dist/cli/{run-WFGXB4SB.js → run-WIKDIXTG.js} +17 -17
  69. package/dist/cli/{server-5VFQP3PV.js → server-P6V2G3P6.js} +82 -34
  70. package/dist/cli/server-P6V2G3P6.js.map +1 -0
  71. package/dist/cli/{sessions-5XDJDALO.js → sessions-2NULRMSA.js} +15 -15
  72. package/dist/cli/{setup-F6XSWLRA.js → setup-Y5WDBQFL.js} +6 -6
  73. package/dist/cli/{stats-ALHBZICE.js → stats-T7BL2YOR.js} +6 -6
  74. package/dist/cli/{version-JVRAHBMM.js → version-3KWDNWLN.js} +15 -15
  75. package/dist/index.d.ts +31 -10
  76. package/dist/index.js +505 -66
  77. package/dist/index.js.map +1 -1
  78. package/package.json +1 -1
  79. package/dist/cli/chat-W7LAWEN6.js +0 -51
  80. package/dist/cli/chunk-6VANO7KB.js.map +0 -1
  81. package/dist/cli/chunk-CXVWUPA3.js.map +0 -1
  82. package/dist/cli/chunk-DGA5QYFM.js.map +0 -1
  83. package/dist/cli/chunk-E7TAHQ4A.js.map +0 -1
  84. package/dist/cli/chunk-JLQDNLZF.js.map +0 -1
  85. package/dist/cli/chunk-JVQT5IYP.js.map +0 -1
  86. package/dist/cli/chunk-SPXN5JIT.js.map +0 -1
  87. package/dist/cli/chunk-TEUDEGX2.js.map +0 -1
  88. package/dist/cli/chunk-WQ6ZRDQM.js.map +0 -1
  89. package/dist/cli/chunk-XPAUNFOL.js.map +0 -1
  90. package/dist/cli/chunk-ZOQHVQON.js.map +0 -1
  91. package/dist/cli/code-2JIHL5M2.js.map +0 -1
  92. package/dist/cli/desktop-5ONTRU3C.js.map +0 -1
  93. package/dist/cli/server-5VFQP3PV.js.map +0 -1
  94. /package/dist/cli/{acp-LKJU5DZX.js.map → acp-QK3DMC53.js.map} +0 -0
  95. /package/dist/cli/{chat-W7LAWEN6.js.map → chat-VV5UWY4V.js.map} +0 -0
  96. /package/dist/cli/{chunk-K3AIFMI6.js.map → chunk-6J6BSUCR.js.map} +0 -0
  97. /package/dist/cli/{chunk-C72TNHDE.js.map → chunk-BWYVFFKR.js.map} +0 -0
  98. /package/dist/cli/{chunk-EAOL43HB.js.map → chunk-BYYVYJDX.js.map} +0 -0
  99. /package/dist/cli/{chunk-HNXDZGC6.js.map → chunk-CI2PF5QX.js.map} +0 -0
  100. /package/dist/cli/{chunk-IYQ325V7.js.map → chunk-E5WCLUIU.js.map} +0 -0
  101. /package/dist/cli/{chunk-YRLC2EDF.js.map → chunk-EQATK2L2.js.map} +0 -0
  102. /package/dist/cli/{chunk-R2ASNSEO.js.map → chunk-FDKOUJKZ.js.map} +0 -0
  103. /package/dist/cli/{chunk-JVFEJAJX.js.map → chunk-GDKB2PPK.js.map} +0 -0
  104. /package/dist/cli/{chunk-NCBP5D6E.js.map → chunk-LBLR4CUZ.js.map} +0 -0
  105. /package/dist/cli/{chunk-7SGGXNB2.js.map → chunk-OJVITDGB.js.map} +0 -0
  106. /package/dist/cli/{chunk-SE7C5ZSI.js.map → chunk-QVDWH2A2.js.map} +0 -0
  107. /package/dist/cli/{chunk-WRONKNIH.js.map → chunk-QVUFWDD2.js.map} +0 -0
  108. /package/dist/cli/{chunk-3AAG2CUT.js.map → chunk-R6GQKKBW.js.map} +0 -0
  109. /package/dist/cli/{chunk-DHRVZJ2D.js.map → chunk-UDVFBEXC.js.map} +0 -0
  110. /package/dist/cli/{chunk-7YW6TPXK.js.map → chunk-VC2CQA5D.js.map} +0 -0
  111. /package/dist/cli/{chunk-M4E5JK6S.js.map → chunk-VJMBISEI.js.map} +0 -0
  112. /package/dist/cli/{chunk-TDSBASOF.js.map → chunk-VKYSZKH2.js.map} +0 -0
  113. /package/dist/cli/{chunk-7LOJS3LV.js.map → chunk-VMUUFWFF.js.map} +0 -0
  114. /package/dist/cli/{chunk-MIIZJD5O.js.map → chunk-VNQGCA3Q.js.map} +0 -0
  115. /package/dist/cli/{chunk-2AASOSD5.js.map → chunk-WF7TPVZM.js.map} +0 -0
  116. /package/dist/cli/{commands-OPT5AJNH.js.map → commands-RR3GIYOK.js.map} +0 -0
  117. /package/dist/cli/{commit-KA37H6GM.js.map → commit-FSHPIINM.js.map} +0 -0
  118. /package/dist/cli/{diff-SOIA7AKH.js.map → diff-RAAHHLHV.js.map} +0 -0
  119. /package/dist/cli/{doctor-RCUP4XRV.js.map → doctor-PKVQIXRT.js.map} +0 -0
  120. /package/dist/cli/{events-6KHITNX4.js.map → events-VRYXOSKI.js.map} +0 -0
  121. /package/dist/cli/{mcp-JP5OWD6R.js.map → mcp-CRJ26PP4.js.map} +0 -0
  122. /package/dist/cli/{mcp-browse-ONCJJPJN.js.map → mcp-browse-QPAOWZOP.js.map} +0 -0
  123. /package/dist/cli/{mcp-inspect-TPLHW5JA.js.map → mcp-inspect-CVCLABRS.js.map} +0 -0
  124. /package/dist/cli/{prompt-RJDNCQAP.js.map → prompt-SKYXERSI.js.map} +0 -0
  125. /package/dist/cli/{prune-sessions-MKEATRVL.js.map → prune-sessions-SEWX7GP6.js.map} +0 -0
  126. /package/dist/cli/{replay-4NILJG4U.js.map → replay-KPDW2ZMJ.js.map} +0 -0
  127. /package/dist/cli/{run-WFGXB4SB.js.map → run-WIKDIXTG.js.map} +0 -0
  128. /package/dist/cli/{sessions-5XDJDALO.js.map → sessions-2NULRMSA.js.map} +0 -0
  129. /package/dist/cli/{setup-F6XSWLRA.js.map → setup-Y5WDBQFL.js.map} +0 -0
  130. /package/dist/cli/{stats-ALHBZICE.js.map → stats-T7BL2YOR.js.map} +0 -0
  131. /package/dist/cli/{version-JVRAHBMM.js.map → version-3KWDNWLN.js.map} +0 -0
@@ -19316,7 +19316,16 @@ var en = {
19316
19316
  resumeDesc: "Mid-session swap requires a restart so the message log can rewind cleanly. Quit your current session, then run:",
19317
19317
  loadingTranscript: "loading transcript\u2026",
19318
19318
  emptyTranscript: "empty transcript.",
19319
- messages: "{count} message{s}"
19319
+ messages: "{count} message{s}",
19320
+ newBtn: "New session",
19321
+ newHint: "Archive the current conversation and start a fresh one",
19322
+ switchBtn: "Switch to this session",
19323
+ deleteBtn: "Delete",
19324
+ deleteConfirm: 'Delete session "{name}"? This removes the transcript file and cannot be undone.',
19325
+ cantDeleteActive: "Switch to a different session before deleting this one.",
19326
+ attachRequired: "Live session operations need an attached CLI session. Launch via reasonix chat or open the dashboard from inside a TUI session.",
19327
+ activeChip: "active",
19328
+ activePill: "active"
19320
19329
  },
19321
19330
  tools: {
19322
19331
  loading: "loading tools\u2026",
@@ -19410,6 +19419,9 @@ var en = {
19410
19419
  whyUnbridged: "Why unbridged?",
19411
19420
  whyUnbridgedDesc: "This spec lives in your config.json but isn't bridged into the live session. MCP servers attach when reasonix code starts; the dashboard alone can't spawn the child process.",
19412
19421
  whyUnbridgedHint: "To activate: restart reasonix code, then refresh this dashboard.",
19422
+ bridgeFailed: "Bridge failed",
19423
+ bridgeFailedTitle: "bridge failed \xB7 in config",
19424
+ bridgeFailedHint: "Reasonix tried to bridge this server and the attempt errored. Common causes: wrong URL, missing auth header, upstream 404/5xx, missing local command. Fix and restart reasonix code to retry.",
19413
19425
  pickHint: "Pick an MCP server on the left to inspect tools / resources / prompts.",
19414
19426
  toolsTitle: "Tools \xB7 {count}",
19415
19427
  resourcesTitle: "Resources \xB7 {count}",
@@ -19585,6 +19597,7 @@ var en = {
19585
19597
  customRequestBodyMustBeObject: "Custom request body must be a JSON object.",
19586
19598
  saveBeforeIndex: "Save semantic settings before starting an index.",
19587
19599
  extraBody: "extra body",
19600
+ batchSize: "batch size",
19588
19601
  keepExistingKey: "leave blank to keep existing key",
19589
19602
  remoteProvider: "Remote embedding provider",
19590
19603
  remoteProviderDesc: "Configure the full OpenAI-compatible embeddings URL here. Reasonix will send requests exactly to the URL you provide.",
@@ -20014,7 +20027,16 @@ var zhCN = {
20014
20027
  resumeDesc: "\u4F1A\u8BDD\u4E2D\u9014\u5207\u6362\u9700\u8981\u91CD\u542F\uFF0C\u4EE5\u4FBF\u6D88\u606F\u65E5\u5FD7\u53EF\u4EE5\u5E72\u51C0\u5730\u56DE\u9000\u3002\u8BF7\u9000\u51FA\u5F53\u524D\u4F1A\u8BDD\uFF0C\u7136\u540E\u8FD0\u884C\uFF1A",
20015
20028
  loadingTranscript: "\u52A0\u8F7D\u8F6C\u5F55\u7A3F\u2026",
20016
20029
  emptyTranscript: "\u7A7A\u7684\u8F6C\u5F55\u7A3F\u3002",
20017
- messages: "{count} \u6761\u6D88\u606F"
20030
+ messages: "{count} \u6761\u6D88\u606F",
20031
+ newBtn: "\u65B0\u5EFA\u4F1A\u8BDD",
20032
+ newHint: "\u5F52\u6863\u5F53\u524D\u4F1A\u8BDD\u5E76\u5F00\u542F\u65B0\u4F1A\u8BDD",
20033
+ switchBtn: "\u5207\u6362\u5230\u6B64\u4F1A\u8BDD",
20034
+ deleteBtn: "\u5220\u9664",
20035
+ deleteConfirm: "\u786E\u5B9A\u5220\u9664\u4F1A\u8BDD\u300C{name}\u300D\uFF1F\u8F6C\u5F55\u6587\u4EF6\u5C06\u88AB\u79FB\u9664\uFF0C\u65E0\u6CD5\u64A4\u9500\u3002",
20036
+ cantDeleteActive: "\u8BF7\u5148\u5207\u6362\u5230\u5176\u4ED6\u4F1A\u8BDD\uFF0C\u518D\u5220\u9664\u5F53\u524D\u4F1A\u8BDD\u3002",
20037
+ attachRequired: "\u5B9E\u65F6\u4F1A\u8BDD\u64CD\u4F5C\u9700\u8981\u5DF2\u8FDE\u63A5\u7684 CLI \u4F1A\u8BDD\u3002\u8BF7\u901A\u8FC7 reasonix chat \u542F\u52A8\uFF0C\u6216\u5728 TUI \u4F1A\u8BDD\u4E2D\u6253\u5F00\u4EEA\u8868\u76D8\u3002",
20038
+ activeChip: "\u5F53\u524D",
20039
+ activePill: "\u5F53\u524D"
20018
20040
  },
20019
20041
  tools: {
20020
20042
  loading: "\u52A0\u8F7D\u5DE5\u5177\u2026",
@@ -20108,6 +20130,9 @@ var zhCN = {
20108
20130
  whyUnbridged: "\u4E3A\u4EC0\u4E48\u672A\u6865\u63A5\uFF1F",
20109
20131
  whyUnbridgedDesc: "\u6B64\u89C4\u683C\u5B58\u5728\u4E8E\u60A8\u7684 config.json \u4E2D\uFF0C\u4F46\u672A\u6865\u63A5\u5230\u5B9E\u65F6\u4F1A\u8BDD\u3002MCP \u670D\u52A1\u5668\u5728 reasonix code \u542F\u52A8\u65F6\u8FDE\u63A5\uFF1B\u4EEA\u8868\u76D8\u672C\u8EAB\u65E0\u6CD5\u751F\u6210\u5B50\u8FDB\u7A0B\u3002",
20110
20132
  whyUnbridgedHint: "\u6FC0\u6D3B\u65B9\u6CD5\uFF1A\u91CD\u542F reasonix code\uFF0C\u7136\u540E\u5237\u65B0\u6B64\u4EEA\u8868\u76D8\u3002",
20133
+ bridgeFailed: "\u6865\u63A5\u5931\u8D25",
20134
+ bridgeFailedTitle: "\u6865\u63A5\u5931\u8D25 \xB7 \u5728\u914D\u7F6E\u4E2D",
20135
+ bridgeFailedHint: "\u5DF2\u5C1D\u8BD5\u6865\u63A5\u4F46\u5931\u8D25\u3002\u5E38\u89C1\u539F\u56E0\uFF1AURL \u9519\u8BEF\u3001\u9700\u8981\u9274\u6743\u3001\u4E0A\u6E38 404 / 5xx\u3001\u672C\u5730\u547D\u4EE4\u7F3A\u5931\u3002\u4FEE\u590D\u540E\u91CD\u542F reasonix code \u91CD\u8BD5\u3002",
20111
20136
  pickHint: "\u9009\u62E9\u5DE6\u4FA7\u7684 MCP \u670D\u52A1\u5668\u4EE5\u68C0\u67E5\u5DE5\u5177 / \u8D44\u6E90 / \u63D0\u793A\u3002",
20112
20137
  toolsTitle: "\u5DE5\u5177 \xB7 {count}",
20113
20138
  resourcesTitle: "\u8D44\u6E90 \xB7 {count}",
@@ -20283,6 +20308,7 @@ var zhCN = {
20283
20308
  customRequestBodyMustBeObject: "\u81EA\u5B9A\u4E49\u8BF7\u6C42\u4F53\u5FC5\u987B\u662F JSON \u5BF9\u8C61\u3002",
20284
20309
  saveBeforeIndex: "\u8BF7\u5148\u4FDD\u5B58\u8BED\u4E49\u8BBE\u7F6E\uFF0C\u518D\u542F\u52A8\u7D22\u5F15\u3002",
20285
20310
  extraBody: "\u6269\u5C55\u8BF7\u6C42\u4F53",
20311
+ batchSize: "\u6279\u6B21\u5927\u5C0F",
20286
20312
  keepExistingKey: "\u7559\u7A7A\u5219\u4FDD\u7559\u73B0\u6709 Key",
20287
20313
  remoteProvider: "\u8FDC\u7A0B\u5411\u91CF\u670D\u52A1",
20288
20314
  remoteProviderDesc: "\u5728\u8FD9\u91CC\u914D\u7F6E OpenAI-Compatible embeddings \u7684\u5B8C\u6574 URL\u3002Reasonix \u4F1A\u4E25\u683C\u4F7F\u7528\u4F60\u63D0\u4F9B\u7684 URL \u53D1\u8D77\u8BF7\u6C42\u3002",
@@ -26721,6 +26747,7 @@ function McpPanel() {
26721
26747
  useLang();
26722
26748
  const [data, setData] = d2(null);
26723
26749
  const [specs, setSpecs] = d2(null);
26750
+ const [failures, setFailures] = d2([]);
26724
26751
  const [error, setError] = d2(null);
26725
26752
  const [info, setInfo] = d2(null);
26726
26753
  const [newSpec, setNewSpec] = d2("");
@@ -26792,6 +26819,22 @@ function McpPanel() {
26792
26819
  const specResponse = await api("/mcp/specs");
26793
26820
  const normalized = (Array.isArray(specResponse.specs) ? specResponse.specs : []).map(normalizeMcpSpec).filter((spec) => spec !== null && spec.length > 0);
26794
26821
  setSpecs(normalized);
26822
+ const rawFailures = Array.isArray(specResponse.failures) ? specResponse.failures : [];
26823
+ const validFailures = [];
26824
+ for (const f3 of rawFailures) {
26825
+ if (typeof f3 !== "object" || f3 === null) continue;
26826
+ const o3 = f3;
26827
+ const rawSpec = typeof o3.spec === "string" ? o3.spec : "";
26828
+ const norm = normalizeMcpSpec(rawSpec);
26829
+ if (!norm) continue;
26830
+ validFailures.push({
26831
+ spec: norm,
26832
+ name: typeof o3.name === "string" ? o3.name : "",
26833
+ reason: typeof o3.reason === "string" ? o3.reason : "",
26834
+ at: typeof o3.at === "number" ? o3.at : 0
26835
+ });
26836
+ }
26837
+ setFailures(validFailures);
26795
26838
  } catch (err) {
26796
26839
  setError(err.message);
26797
26840
  }
@@ -26927,8 +26970,9 @@ function McpPanel() {
26927
26970
  </div>
26928
26971
  `
26929
26972
  ) : null}
26930
- ${showUnbridged ? unbridgedSpecs.map(
26931
- (spec) => html4`
26973
+ ${showUnbridged ? unbridgedSpecs.map((spec) => {
26974
+ const failure = failures.find((f3) => f3.spec === spec);
26975
+ return html4`
26932
26976
  <div
26933
26977
  class=${`ssl-row ${openUnbridged === spec ? "sel" : ""}`}
26934
26978
  onClick=${() => {
@@ -26936,12 +26980,12 @@ function McpPanel() {
26936
26980
  setOpen(null);
26937
26981
  }}
26938
26982
  >
26939
- <span class="name">${mcpSpecLabel(spec)} <span class="pill">${t4("mcp.unbridged")}</span></span>
26983
+ <span class="name">${mcpSpecLabel(spec)} <span class=${`pill ${failure ? "err" : ""}`}>${failure ? t4("mcp.bridgeFailed") : t4("mcp.unbridged")}</span></span>
26940
26984
  <span class="preview">${mcpSpecCommand(spec)}</span>
26941
- <span class="meta"><span class="dim">${t4("mcp.inConfig")}</span></span>
26985
+ <span class="meta"><span class=${failure ? "" : "dim"} style=${failure ? "color:var(--c-err)" : ""}>${failure ? failure.reason : t4("mcp.inConfig")}</span></span>
26942
26986
  </div>
26943
- `
26944
- ) : null}
26987
+ `;
26988
+ }) : null}
26945
26989
  </div>
26946
26990
  </div>
26947
26991
 
@@ -26956,10 +27000,12 @@ function McpPanel() {
26956
27000
  onInstall: () => installFromRegistry(openRegistry),
26957
27001
  onUninstall: (spec) => removeSpec(spec),
26958
27002
  onClose: () => setOpenRegistry(null)
26959
- }) : openUnbridged != null ? html4`
27003
+ }) : openUnbridged != null ? (() => {
27004
+ const failure = failures.find((f3) => f3.spec === openUnbridged);
27005
+ return html4`
26960
27006
  <div class="sessions-detail-h">
26961
27007
  <span class="name">${mcpSpecLabel(openUnbridged)}</span>
26962
- <span class="ws"><span class="pill">${t4("mcp.unbridgedTitle")}</span></span>
27008
+ <span class="ws"><span class="pill">${failure ? t4("mcp.bridgeFailedTitle") : t4("mcp.unbridgedTitle")}</span></span>
26963
27009
  <span class="actions">
26964
27010
  <button class="btn" disabled=${busy} onClick=${() => removeSpec(openUnbridged)}
26965
27011
  style="border-color:var(--c-err);color:var(--c-err)">${t4("mcp.removeBtn")}</button>
@@ -26970,16 +27016,25 @@ function McpPanel() {
26970
27016
  <div class="card-h"><span class="title">${t4("mcp.spec")}</span></div>
26971
27017
  <code class="mono" style="font-size:11.5px;color:var(--fg-2);word-break:break-all">${openUnbridged}</code>
26972
27018
  </div>
26973
- <div class="card accent-warn">
26974
- <div class="card-h"><span class="title" style="color:var(--c-warn)">${t4("mcp.whyUnbridged")}</span></div>
26975
- <div class="card-b" style="font-size:13px;line-height:1.6">
26976
- ${t4("mcp.whyUnbridgedDesc")}
26977
- <div style="margin-top:10px;color:var(--fg-3);font-size:12px">
26978
- ${t4("mcp.whyUnbridgedHint")}
26979
- </div>
26980
- </div>
26981
- </div>
26982
- ` : open == null ? html4`<div style="color:var(--fg-3);font-size:13px;text-align:center;padding:60px 20px">
27019
+ ${failure ? html4`<div class="card accent-err">
27020
+ <div class="card-h"><span class="title" style="color:var(--c-err)">${t4("mcp.bridgeFailed")}</span></div>
27021
+ <div class="card-b" style="font-size:13px;line-height:1.6">
27022
+ <code class="mono" style="font-size:12px;color:var(--fg-1);word-break:break-word;white-space:pre-wrap">${failure.reason}</code>
27023
+ <div style="margin-top:10px;color:var(--fg-3);font-size:12px">
27024
+ ${t4("mcp.bridgeFailedHint")}
27025
+ </div>
27026
+ </div>
27027
+ </div>` : html4`<div class="card accent-warn">
27028
+ <div class="card-h"><span class="title" style="color:var(--c-warn)">${t4("mcp.whyUnbridged")}</span></div>
27029
+ <div class="card-b" style="font-size:13px;line-height:1.6">
27030
+ ${t4("mcp.whyUnbridgedDesc")}
27031
+ <div style="margin-top:10px;color:var(--fg-3);font-size:12px">
27032
+ ${t4("mcp.whyUnbridgedHint")}
27033
+ </div>
27034
+ </div>
27035
+ </div>`}
27036
+ `;
27037
+ })() : open == null ? html4`<div style="color:var(--fg-3);font-size:13px;text-align:center;padding:60px 20px">
26983
27038
  ${showMarketplace ? t4("mcp.marketplacePickHint") : t4("mcp.pickHint")}
26984
27039
  </div>` : html4`
26985
27040
  <div class="sessions-detail-h">
@@ -28032,7 +28087,8 @@ function SemanticPanel() {
28032
28087
  baseUrl: draft.openaiCompat.baseUrl,
28033
28088
  apiKey: draft.openaiCompat.apiKey,
28034
28089
  model: draft.openaiCompat.model,
28035
- extraBody
28090
+ extraBody,
28091
+ batchSize: draft.openaiCompat.batchSize
28036
28092
  }
28037
28093
  }
28038
28094
  });
@@ -28187,6 +28243,27 @@ function SemanticPanel() {
28187
28243
  model: e3.target.value
28188
28244
  }
28189
28245
  });
28246
+ }}
28247
+ />
28248
+ </div>
28249
+ <div class="form-row">
28250
+ <span class="lbl">${t4("semantic.batchSize")}</span>
28251
+ <input
28252
+ class="input mono"
28253
+ type="number"
28254
+ min="1"
28255
+ value=${draft.openaiCompat.batchSize}
28256
+ onInput=${(e3) => {
28257
+ const v3 = Number.parseInt(e3.target.value, 10);
28258
+ draftDirtyRef.current = true;
28259
+ setDraftDirty(true);
28260
+ setDraft({
28261
+ ...draft,
28262
+ openaiCompat: {
28263
+ ...draft.openaiCompat,
28264
+ batchSize: Number.isInteger(v3) && v3 > 0 ? v3 : 10
28265
+ }
28266
+ });
28190
28267
  }}
28191
28268
  />
28192
28269
  </div>
@@ -28322,6 +28399,7 @@ function SemanticPanel() {
28322
28399
  <div class="rail-kv"><span class="k">${t4("semantic.apiKey")}</span><span class="v">${remote?.apiKeySet ? html4`<span class="pill ok">${t4("semantic.found")}</span>` : html4`<span class="pill warn">${t4("semantic.missing")}</span>`}</span></div>
28323
28400
  <div class="rail-kv"><span class="k">${t4("semantic.model")}</span><span class="v" style="font-size:11px">${remote?.model ?? draft.openaiCompat.model}</span></div>
28324
28401
  <div class="rail-kv"><span class="k">${t4("semantic.extraBody")}</span><span class="v">${fmtNum(remote?.extraBodyKeys.length ?? 0)}</span></div>
28402
+ <div class="rail-kv"><span class="k">${t4("semantic.batchSize")}</span><span class="v">${remote?.batchSize ?? 10}</span></div>
28325
28403
  `}
28326
28404
  </div>
28327
28405
 
@@ -28342,6 +28420,7 @@ function toConfigDraft(config) {
28342
28420
  apiKey: "",
28343
28421
  model: config.openaiCompat.model,
28344
28422
  extraBodyText: JSON.stringify(config.openaiCompat.extraBody ?? {}, null, 2),
28423
+ batchSize: config.openaiCompat.batchSize,
28345
28424
  apiKeySet: config.openaiCompat.apiKeySet
28346
28425
  }
28347
28426
  };
@@ -28757,10 +28836,12 @@ function isPlainObject(value) {
28757
28836
  // dashboard/src/panels/sessions.ts
28758
28837
  function SessionsPanel() {
28759
28838
  useLang();
28760
- const { data, error, loading } = usePoll("/sessions", 5e3);
28839
+ const { data, error, loading, refresh } = usePoll("/sessions", 5e3);
28761
28840
  const [open, setOpen] = d2(null);
28762
28841
  const [openLoading, setOpenLoading] = d2(false);
28763
28842
  const [filter, setFilter] = d2("");
28843
+ const [busy, setBusy] = d2(null);
28844
+ const [actionError, setActionError] = d2(null);
28764
28845
  const view = q2(async (name) => {
28765
28846
  setOpen({ name, messages: null });
28766
28847
  setOpenLoading(true);
@@ -28773,17 +28854,64 @@ function SessionsPanel() {
28773
28854
  setOpenLoading(false);
28774
28855
  }
28775
28856
  }, []);
28857
+ const newSession = q2(async () => {
28858
+ setBusy("new");
28859
+ setActionError(null);
28860
+ try {
28861
+ await api("/sessions/new", { method: "POST" });
28862
+ setOpen(null);
28863
+ await refresh();
28864
+ } catch (err) {
28865
+ setActionError(err.message);
28866
+ } finally {
28867
+ setBusy(null);
28868
+ }
28869
+ }, [refresh]);
28870
+ const switchTo = q2(
28871
+ async (name) => {
28872
+ setBusy(`switch:${name}`);
28873
+ setActionError(null);
28874
+ try {
28875
+ await api(`/sessions/${encodeURIComponent(name)}/switch`, { method: "POST" });
28876
+ setOpen(null);
28877
+ await refresh();
28878
+ } catch (err) {
28879
+ setActionError(err.message);
28880
+ } finally {
28881
+ setBusy(null);
28882
+ }
28883
+ },
28884
+ [refresh]
28885
+ );
28886
+ const remove = q2(
28887
+ async (name) => {
28888
+ if (!confirm(t4("sessions.deleteConfirm", { name }))) return;
28889
+ setBusy(`delete:${name}`);
28890
+ setActionError(null);
28891
+ try {
28892
+ await api(`/sessions/${encodeURIComponent(name)}`, { method: "DELETE" });
28893
+ if (open?.name === name) setOpen(null);
28894
+ await refresh();
28895
+ } catch (err) {
28896
+ setActionError(err.message);
28897
+ } finally {
28898
+ setBusy(null);
28899
+ }
28900
+ },
28901
+ [open, refresh]
28902
+ );
28776
28903
  if (loading && !data)
28777
28904
  return html4`<div class="card" style="color:var(--fg-3)">${t4("sessions.loading")}</div>`;
28778
- if (error) return html4`<div class="card accent-err">${t4("common.loadingFailed", { name: "sessions", error: error.message })}</div>`;
28905
+ if (error)
28906
+ return html4`<div class="card accent-err">${t4("common.loadingFailed", { name: "sessions", error: error.message })}</div>`;
28779
28907
  const sessions = data?.sessions ?? [];
28780
- if (sessions.length === 0)
28781
- return html4`<div class="card" style="color:var(--fg-3)">${t4("sessions.noSessions")}</div>`;
28908
+ const currentSession = data?.currentSession ?? null;
28909
+ const canSwitch = data?.canSwitch ?? false;
28782
28910
  const filtered = filter.trim() ? sessions.filter((s3) => s3.name.toLowerCase().includes(filter.toLowerCase())) : sessions;
28783
28911
  return html4`
28784
28912
  <div class="sessions-grid">
28785
28913
  <div class="sessions-list">
28786
- <div class="ssl-h">
28914
+ <div class="ssl-h" style="display:flex;gap:6px">
28787
28915
  <input
28788
28916
  type="text"
28789
28917
  placeholder=${t4("sessions.filterPlaceholder")}
@@ -28791,66 +28919,95 @@ function SessionsPanel() {
28791
28919
  onInput=${(e3) => setFilter(e3.target.value)}
28792
28920
  style="flex:1"
28793
28921
  />
28922
+ <button
28923
+ class="btn primary"
28924
+ disabled=${!canSwitch || busy === "new"}
28925
+ title=${canSwitch ? t4("sessions.newHint") : t4("sessions.attachRequired")}
28926
+ onClick=${newSession}
28927
+ >
28928
+ ${busy === "new" ? t4("common.loading") : `+ ${t4("sessions.newBtn")}`}
28929
+ </button>
28794
28930
  </div>
28931
+ ${!canSwitch ? html4`<div style="padding:0 12px 6px;font-size:11.5px;color:var(--fg-3)">${t4("sessions.attachRequired")}</div>` : null}
28932
+ ${actionError ? html4`<div class="card accent-err" style="margin:0 12px 8px;padding:6px 10px;font-size:12px">${actionError}</div>` : null}
28795
28933
  <div class="chips" style="padding:0 12px 8px">
28796
28934
  <span class="chip-f static active">${t4("common.all")} <span class="ct">${sessions.length}</span></span>
28935
+ ${currentSession ? html4`<span class="chip-f static">${t4("sessions.activeChip")} <span class="ct">${currentSession}</span></span>` : null}
28797
28936
  </div>
28798
- <div class="ssl-rows">
28799
- ${filtered.map(
28800
- (s3) => html4`
28801
- <div
28802
- class=${`ssl-row ${open?.name === s3.name ? "sel" : ""}`}
28803
- onClick=${() => view(s3.name)}
28804
- >
28805
- <span class="name">${s3.name}</span>
28806
- <span class="meta">
28807
- <span><span class="v">${fmtNum(s3.messageCount)}</span> ${t4("sessions.msgs")}</span>
28808
- <span><span class="v">${fmtBytes(s3.size)}</span></span>
28809
- <span>${fmtRelativeTime(s3.mtime)}</span>
28810
- </span>
28811
- </div>
28812
- `
28813
- )}
28814
- </div>
28937
+ ${sessions.length === 0 ? html4`<div class="ctx-empty" style="padding:24px 12px;color:var(--fg-3)">${t4("sessions.noSessions")}</div>` : html4`<div class="ssl-rows">
28938
+ ${filtered.map((s3) => {
28939
+ const isCurrent = currentSession === s3.name;
28940
+ return html4`
28941
+ <div
28942
+ class=${`ssl-row ${open?.name === s3.name ? "sel" : ""}`}
28943
+ onClick=${() => view(s3.name)}
28944
+ >
28945
+ <span class="name">
28946
+ ${isCurrent ? html4`<span class="pill ok" style="margin-right:6px">${t4("sessions.activePill")}</span>` : null}
28947
+ ${s3.name}
28948
+ </span>
28949
+ <span class="meta">
28950
+ <span><span class="v">${fmtNum(s3.messageCount)}</span> ${t4("sessions.msgs")}</span>
28951
+ <span><span class="v">${fmtBytes(s3.size)}</span></span>
28952
+ <span>${fmtRelativeTime(s3.mtime)}</span>
28953
+ </span>
28954
+ </div>
28955
+ `;
28956
+ })}
28957
+ </div>`}
28815
28958
  </div>
28816
28959
 
28817
28960
  <div class="sessions-detail">
28818
28961
  ${open == null ? html4`<div style="color:var(--fg-3);font-size:13px;text-align:center;padding:60px 20px">
28819
28962
  ${t4("sessions.pickHint")}
28820
- </div>` : html4`
28963
+ </div>` : (() => {
28964
+ const isCurrent = currentSession === open.name;
28965
+ return html4`
28821
28966
  <div class="sessions-detail-h">
28822
- <span class="name">${open.name}</span>
28967
+ <span class="name">
28968
+ ${isCurrent ? html4`<span class="pill ok" style="margin-right:6px">${t4("sessions.activePill")}</span>` : null}
28969
+ ${open.name}
28970
+ </span>
28823
28971
  <span class="ws">
28824
28972
  ${open.messages ? t4("sessions.messages", { count: open.messages.length, s: open.messages.length === 1 ? "" : "s" }) : t4("common.loading")}
28825
28973
  </span>
28826
28974
  <span class="actions">
28975
+ ${canSwitch && !isCurrent ? html4`<button class="btn primary" disabled=${busy === `switch:${open.name}`} onClick=${() => switchTo(open.name)}>${busy === `switch:${open.name}` ? t4("common.loading") : t4("sessions.switchBtn")}</button>` : null}
28976
+ <button
28977
+ class="btn"
28978
+ disabled=${isCurrent || busy === `delete:${open.name}`}
28979
+ title=${isCurrent ? t4("sessions.cantDeleteActive") : t4("sessions.deleteBtn")}
28980
+ style="border-color:var(--c-err);color:var(--c-err)"
28981
+ onClick=${() => remove(open.name)}
28982
+ >${busy === `delete:${open.name}` ? t4("common.loading") : t4("sessions.deleteBtn")}</button>
28827
28983
  <button class="btn ghost" onClick=${() => setOpen(null)}>${t4("common.back")}</button>
28828
28984
  </span>
28829
28985
  </div>
28830
- <div class="card accent-brand" style="margin-bottom:10px">
28831
- <div class="card-h"><span class="title">${t4("sessions.resumeTitle")}</span></div>
28832
- <div class="card-b" style="font-size:12.5px;color:var(--fg-2)">
28833
- ${t4("sessions.resumeDesc")}
28834
- <code class="mono" style="display:block;margin-top:8px;padding:8px 10px;background:var(--bg-input);border-radius:var(--r);color:var(--fg-0);font-size:12px;user-select:all">reasonix chat --session ${open.name}</code>
28835
- </div>
28836
- </div>
28986
+ ${!canSwitch ? html4`<div class="card accent-brand" style="margin-bottom:10px">
28987
+ <div class="card-h"><span class="title">${t4("sessions.resumeTitle")}</span></div>
28988
+ <div class="card-b" style="font-size:12.5px;color:var(--fg-2)">
28989
+ ${t4("sessions.resumeDesc")}
28990
+ <code class="mono" style="display:block;margin-top:8px;padding:8px 10px;background:var(--bg-input);border-radius:var(--r);color:var(--fg-0);font-size:12px;user-select:all">reasonix chat --session ${open.name}</code>
28991
+ </div>
28992
+ </div>` : null}
28837
28993
  ${openLoading ? html4`<div style="color:var(--fg-3)">${t4("sessions.loadingTranscript")}</div>` : open.error ? html4`<div class="card accent-err">${open.error}</div>` : open.messages && open.messages.length > 0 ? html4`<div class="chat-feed" style="max-height:calc(100vh - 220px);overflow-y:auto">
28838
28994
  ${open.messages.map(
28839
- (m3, i3) => html4`
28995
+ (m3, i3) => html4`
28840
28996
  <${ChatMessage}
28841
28997
  key=${i3}
28842
28998
  msg=${{
28843
- id: `r-${i3}`,
28844
- role: m3.role === "tool" ? "tool" : m3.role === "assistant" ? "assistant" : m3.role === "user" ? "user" : "info",
28845
- text: m3.content ?? "",
28846
- toolName: m3.toolName
28847
- }}
28999
+ id: `r-${i3}`,
29000
+ role: m3.role === "tool" ? "tool" : m3.role === "assistant" ? "assistant" : m3.role === "user" ? "user" : "info",
29001
+ text: m3.content ?? "",
29002
+ toolName: m3.toolName
29003
+ }}
28848
29004
  streaming=${false}
28849
29005
  />
28850
29006
  `
28851
- )}
29007
+ )}
28852
29008
  </div>` : html4`<div style="color:var(--fg-3)">${t4("sessions.emptyTranscript")}</div>`}
28853
- `}
29009
+ `;
29010
+ })()}
28854
29011
  </div>
28855
29012
  </div>
28856
29013
  `;