auto-coder-web 0.1.61__py3-none-any.whl → 0.1.62__py3-none-any.whl

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 (109) hide show
  1. auto_coder_web/common_router/auto_coder_conf_router.py +3 -3
  2. auto_coder_web/common_router/completions_router.py +15 -8
  3. auto_coder_web/common_router/file_router.py +39 -14
  4. auto_coder_web/expert_routers/history_router.py +1 -1
  5. auto_coder_web/file_manager.py +178 -3
  6. auto_coder_web/proxy.py +2 -1
  7. auto_coder_web/routers/auto_router.py +1 -1
  8. auto_coder_web/routers/chat_router.py +2 -2
  9. auto_coder_web/routers/coding_router.py +3 -3
  10. auto_coder_web/routers/commit_router.py +1 -1
  11. auto_coder_web/routers/config_router.py +9 -4
  12. auto_coder_web/routers/mcp_router.py +287 -62
  13. auto_coder_web/version.py +1 -1
  14. auto_coder_web/web/HistoryPanel-WXEMtQ1V.js +1 -0
  15. auto_coder_web/web/{assets/cssMode-DzQL_FdL.js → cssMode-CQYz0o1d.js} +1 -1
  16. auto_coder_web/web/{assets/freemarker2-B6aemwaC.js → freemarker2-BJU3cSen.js} +1 -1
  17. auto_coder_web/web/{assets/handlebars-C2cM4xS8.js → handlebars-VxUdciXQ.js} +1 -1
  18. auto_coder_web/web/{assets/html-Da2X74rm.js → html-DEgskwXL.js} +1 -1
  19. auto_coder_web/web/{assets/htmlMode-Y3eBAl3y.js → htmlMode-58cXxJlI.js} +1 -1
  20. auto_coder_web/web/index.html +2 -2
  21. auto_coder_web/web/{assets/javascript-zkPPW3gg.js → javascript-DbZlm-ig.js} +1 -1
  22. auto_coder_web/web/{assets/jsonMode-Ce8jLIxT.js → jsonMode-C2HKgmE0.js} +1 -1
  23. auto_coder_web/web/{assets/liquid-CHrk1uPD.js → liquid-BFft-XkQ.js} +1 -1
  24. auto_coder_web/web/main-DxnFm18B.css +32 -0
  25. auto_coder_web/web/{assets/index-kyBHOjJU.js → main.js} +384 -373
  26. auto_coder_web/web/{assets/mdx-B7AzIQ1K.js → mdx-DZdDhrJW.js} +1 -1
  27. auto_coder_web/web/{assets/python-D340AvYz.js → python-DOHUGzLU.js} +1 -1
  28. auto_coder_web/web/{assets/razor-DfFnL0En.js → razor-Dh5mSHi2.js} +1 -1
  29. auto_coder_web/web/{assets/tsMode-CwjVYPI2.js → tsMode-tyI6CeIR.js} +1 -1
  30. auto_coder_web/web/{assets/typescript-JxFW6htN.js → typescript-DZzM_VgT.js} +1 -1
  31. auto_coder_web/web/{assets/xml-CY673mn0.js → xml-Dl6413Na.js} +1 -1
  32. auto_coder_web/web/{assets/yaml-D2wmMay7.js → yaml-DML583wh.js} +1 -1
  33. {auto_coder_web-0.1.61.dist-info → auto_coder_web-0.1.62.dist-info}/METADATA +2 -2
  34. {auto_coder_web-0.1.61.dist-info → auto_coder_web-0.1.62.dist-info}/RECORD +108 -107
  35. auto_coder_web/web/assets/index-CRXh98Y9.css +0 -32
  36. /auto_coder_web/web/{assets/abap-BrgZPUOV.js → abap-BrgZPUOV.js} +0 -0
  37. /auto_coder_web/web/{assets/apex-DyP6w7ZV.js → apex-DyP6w7ZV.js} +0 -0
  38. /auto_coder_web/web/{assets/azcli-BaLxmfj-.js → azcli-BaLxmfj-.js} +0 -0
  39. /auto_coder_web/web/{assets/bat-CFOPXBzS.js → bat-CFOPXBzS.js} +0 -0
  40. /auto_coder_web/web/{assets/bicep-BfEKNvv3.js → bicep-BfEKNvv3.js} +0 -0
  41. /auto_coder_web/web/{assets/cameligo-BFG1Mk7z.js → cameligo-BFG1Mk7z.js} +0 -0
  42. /auto_coder_web/web/{assets/clojure-DTECt2xU.js → clojure-DTECt2xU.js} +0 -0
  43. /auto_coder_web/web/{assets/codicon-DCmgc-ay.ttf → codicon-DCmgc-ay.ttf} +0 -0
  44. /auto_coder_web/web/{assets/coffee-CDGzqUPQ.js → coffee-CDGzqUPQ.js} +0 -0
  45. /auto_coder_web/web/{assets/cpp-CLLBncYj.js → cpp-CLLBncYj.js} +0 -0
  46. /auto_coder_web/web/{assets/csharp-dUCx_-0o.js → csharp-dUCx_-0o.js} +0 -0
  47. /auto_coder_web/web/{assets/csp-5Rap-vPy.js → csp-5Rap-vPy.js} +0 -0
  48. /auto_coder_web/web/{assets/css-D3h14YRZ.js → css-D3h14YRZ.js} +0 -0
  49. /auto_coder_web/web/{assets/cypher-DrQuvNYM.js → cypher-DrQuvNYM.js} +0 -0
  50. /auto_coder_web/web/{assets/dart-CFKIUWau.js → dart-CFKIUWau.js} +0 -0
  51. /auto_coder_web/web/{assets/dockerfile-Zznr-cwX.js → dockerfile-Zznr-cwX.js} +0 -0
  52. /auto_coder_web/web/{assets/ecl-Ce3n6wWz.js → ecl-Ce3n6wWz.js} +0 -0
  53. /auto_coder_web/web/{assets/elixir-deUWdS0T.js → elixir-deUWdS0T.js} +0 -0
  54. /auto_coder_web/web/{assets/flow9-i9-g7ZhI.js → flow9-i9-g7ZhI.js} +0 -0
  55. /auto_coder_web/web/{assets/fsharp-CzKuDChf.js → fsharp-CzKuDChf.js} +0 -0
  56. /auto_coder_web/web/{assets/go-Cphgjts3.js → go-Cphgjts3.js} +0 -0
  57. /auto_coder_web/web/{assets/graphql-Cg7bfA9N.js → graphql-Cg7bfA9N.js} +0 -0
  58. /auto_coder_web/web/{assets/hcl-0cvrggvQ.js → hcl-0cvrggvQ.js} +0 -0
  59. /auto_coder_web/web/{assets/ini-Drc7WvVn.js → ini-Drc7WvVn.js} +0 -0
  60. /auto_coder_web/web/{assets/java-B_fMsGYe.js → java-B_fMsGYe.js} +0 -0
  61. /auto_coder_web/web/{assets/julia-Bqgm2twL.js → julia-Bqgm2twL.js} +0 -0
  62. /auto_coder_web/web/{assets/kotlin-BSkB5QuD.js → kotlin-BSkB5QuD.js} +0 -0
  63. /auto_coder_web/web/{assets/less-BsTHnhdd.js → less-BsTHnhdd.js} +0 -0
  64. /auto_coder_web/web/{assets/lexon-YWi4-JPR.js → lexon-YWi4-JPR.js} +0 -0
  65. /auto_coder_web/web/{assets/lua-nf6ki56Z.js → lua-nf6ki56Z.js} +0 -0
  66. /auto_coder_web/web/{assets/m3-Cpb6xl2v.js → m3-Cpb6xl2v.js} +0 -0
  67. /auto_coder_web/web/{assets/markdown-DSZPf7rp.js → markdown-DSZPf7rp.js} +0 -0
  68. /auto_coder_web/web/{assets/mips-B_c3zf-v.js → mips-B_c3zf-v.js} +0 -0
  69. /auto_coder_web/web/{assets/msdax-rUNN04Wq.js → msdax-rUNN04Wq.js} +0 -0
  70. /auto_coder_web/web/{assets/mysql-DDwshQtU.js → mysql-DDwshQtU.js} +0 -0
  71. /auto_coder_web/web/{assets/objective-c-B5zXfXm9.js → objective-c-B5zXfXm9.js} +0 -0
  72. /auto_coder_web/web/{assets/pascal-CXOwvkN_.js → pascal-CXOwvkN_.js} +0 -0
  73. /auto_coder_web/web/{assets/pascaligo-Bc-ZgV77.js → pascaligo-Bc-ZgV77.js} +0 -0
  74. /auto_coder_web/web/{assets/perl-CwNk8-XU.js → perl-CwNk8-XU.js} +0 -0
  75. /auto_coder_web/web/{assets/pgsql-tGk8EFnU.js → pgsql-tGk8EFnU.js} +0 -0
  76. /auto_coder_web/web/{assets/php-CpIb_Oan.js → php-CpIb_Oan.js} +0 -0
  77. /auto_coder_web/web/{assets/pla-B03wrqEc.js → pla-B03wrqEc.js} +0 -0
  78. /auto_coder_web/web/{assets/postiats-BKlk5iyT.js → postiats-BKlk5iyT.js} +0 -0
  79. /auto_coder_web/web/{assets/powerquery-Bhzvs7bI.js → powerquery-Bhzvs7bI.js} +0 -0
  80. /auto_coder_web/web/{assets/powershell-Dd3NCNK9.js → powershell-Dd3NCNK9.js} +0 -0
  81. /auto_coder_web/web/{assets/protobuf-COyEY5Pt.js → protobuf-COyEY5Pt.js} +0 -0
  82. /auto_coder_web/web/{assets/pug-BaJupSGV.js → pug-BaJupSGV.js} +0 -0
  83. /auto_coder_web/web/{assets/qsharp-DXyYeYxl.js → qsharp-DXyYeYxl.js} +0 -0
  84. /auto_coder_web/web/{assets/r-CdQndTaG.js → r-CdQndTaG.js} +0 -0
  85. /auto_coder_web/web/{assets/redis-CVwtpugi.js → redis-CVwtpugi.js} +0 -0
  86. /auto_coder_web/web/{assets/redshift-25W9uPmb.js → redshift-25W9uPmb.js} +0 -0
  87. /auto_coder_web/web/{assets/restructuredtext-DfzH4Xui.js → restructuredtext-DfzH4Xui.js} +0 -0
  88. /auto_coder_web/web/{assets/ruby-Cp1zYvxS.js → ruby-Cp1zYvxS.js} +0 -0
  89. /auto_coder_web/web/{assets/rust-D5C2fndG.js → rust-D5C2fndG.js} +0 -0
  90. /auto_coder_web/web/{assets/sb-CDntyWJ8.js → sb-CDntyWJ8.js} +0 -0
  91. /auto_coder_web/web/{assets/scala-BoFRg7Ot.js → scala-BoFRg7Ot.js} +0 -0
  92. /auto_coder_web/web/{assets/scheme-Bio4gycK.js → scheme-Bio4gycK.js} +0 -0
  93. /auto_coder_web/web/{assets/scss-4Ik7cdeQ.js → scss-4Ik7cdeQ.js} +0 -0
  94. /auto_coder_web/web/{assets/shell-CX-rkNHf.js → shell-CX-rkNHf.js} +0 -0
  95. /auto_coder_web/web/{assets/solidity-Tw7wswEv.js → solidity-Tw7wswEv.js} +0 -0
  96. /auto_coder_web/web/{assets/sophia-C5WLch3f.js → sophia-C5WLch3f.js} +0 -0
  97. /auto_coder_web/web/{assets/sparql-DHaeiCBh.js → sparql-DHaeiCBh.js} +0 -0
  98. /auto_coder_web/web/{assets/sql-CCSDG5nI.js → sql-CCSDG5nI.js} +0 -0
  99. /auto_coder_web/web/{assets/st-pnP8ivHi.js → st-pnP8ivHi.js} +0 -0
  100. /auto_coder_web/web/{assets/swift-DwJ7jVG9.js → swift-DwJ7jVG9.js} +0 -0
  101. /auto_coder_web/web/{assets/systemverilog-B9Xyijhd.js → systemverilog-B9Xyijhd.js} +0 -0
  102. /auto_coder_web/web/{assets/tcl-DnHyzjbg.js → tcl-DnHyzjbg.js} +0 -0
  103. /auto_coder_web/web/{assets/twig-CPajHgWi.js → twig-CPajHgWi.js} +0 -0
  104. /auto_coder_web/web/{assets/typespec-D-MeaMDU.js → typespec-D-MeaMDU.js} +0 -0
  105. /auto_coder_web/web/{assets/vb-DgyLZaXg.js → vb-DgyLZaXg.js} +0 -0
  106. /auto_coder_web/web/{assets/wgsl-BIv9DU6q.js → wgsl-BIv9DU6q.js} +0 -0
  107. {auto_coder_web-0.1.61.dist-info → auto_coder_web-0.1.62.dist-info}/WHEEL +0 -0
  108. {auto_coder_web-0.1.61.dist-info → auto_coder_web-0.1.62.dist-info}/entry_points.txt +0 -0
  109. {auto_coder_web-0.1.61.dist-info → auto_coder_web-0.1.62.dist-info}/top_level.txt +0 -0
@@ -4,94 +4,277 @@ import os
4
4
  from fastapi import APIRouter, HTTPException, Request, Depends
5
5
  from pydantic import BaseModel, Field
6
6
  from typing import Dict, Any, Optional, List
7
- from autocoder.common.mcp_server import (
8
- get_mcp_server,
9
- McpInstallRequest,
10
- McpRemoveRequest,
11
- McpListRequest,
12
- McpListRunningRequest,
13
- McpRefreshRequest,
7
+ from autocoder.common.mcp_server_types import (
8
+ McpInstallRequest,
9
+ McpRemoveRequest,
10
+ McpListRequest,
11
+ McpListRunningRequest,
12
+ McpRefreshRequest,
14
13
  McpServerInfoRequest,
15
- McpResponse
14
+ McpResponse,
15
+ InstallResult,
16
+ RemoveResult,
17
+ ListResult,
18
+ ListRunningResult,
19
+ RefreshResult,
20
+ QueryResult,
21
+ ErrorResult,
22
+ ServerInfo,
23
+ ExternalServerInfo,
24
+ ServerConfig, # Added for InstallResult
25
+ MarketplaceAddRequest,
26
+ MarketplaceAddResult,
27
+ MarketplaceUpdateRequest, # Added for update endpoint
28
+ MarketplaceUpdateResult, # Added for update endpoint
16
29
  )
17
- from autocoder.common.printer import Printer # For messages
18
- from autocoder.chat_auto_coder_lang import get_message_with_format # For formatted messages
30
+ from autocoder.common.mcp_server import get_mcp_server
31
+ from autocoder.common.printer import Printer # For messages
32
+ from autocoder.chat_auto_coder_lang import (
33
+ get_message_with_format,
34
+ get_message,
35
+ ) # For formatted messages
19
36
  from loguru import logger
20
- from byzerllm.utils.langutil import asyncfy_with_semaphore
21
-
22
- # Use asyncfy_with_semaphore to wrap the synchronous send_request method
23
- async_send_request = asyncfy_with_semaphore(get_mcp_server().send_request, max_workers=5)
24
37
 
25
38
  router = APIRouter()
26
- printer = Printer() # Initialize printer for messages
39
+ printer = Printer() # Initialize printer for messages
40
+
41
+
42
+ # Helper function to run the synchronous send_request in a thread
43
+ async def send_mcp_request_async(*args, **kwargs) -> McpResponse:
44
+ """Runs the synchronous MCP send_request in a separate thread."""
45
+ return await asyncio.to_thread(get_mcp_server().send_request, *args, **kwargs)
46
+
27
47
 
28
48
  # --- Pydantic Models for Requests ---
29
49
 
30
- class McpAddRequest(BaseModel):
31
- server_config: str = Field(..., description="Server configuration string (command-line style or JSON)")
50
+
51
+ class McpInstallRequestModel(BaseModel):
52
+ server_config: str = Field(
53
+ ..., description="Server configuration string (command-line style or JSON)"
54
+ )
55
+
56
+
57
+ # Model for the new /api/mcp/add endpoint
58
+ class MarketplaceAddRequestModel(BaseModel):
59
+ name: str = Field(
60
+ ..., description="Name of the MCP server to add to the marketplace"
61
+ )
62
+ description: Optional[str] = Field("", description="Description of the MCP server")
63
+ mcp_type: str = Field(
64
+ "command", description="Type of MCP server (e.g., 'command', 'sse')"
65
+ )
66
+ command: Optional[str] = Field(
67
+ None, description="Command to run the server (if type is 'command')"
68
+ ) # Allow None
69
+ args: Optional[List[str]] = Field(None, description="Arguments for the command")
70
+ env: Optional[Dict[str, str]] = Field(
71
+ None, description="Environment variables for the command"
72
+ )
73
+ url: Optional[str] = Field(
74
+ None, description="URL endpoint for the server (if type is 'sse')"
75
+ ) # Allow None
76
+
77
+
78
+ # Model for the /api/mcp/update endpoint
79
+ class MarketplaceUpdateRequestModel(BaseModel):
80
+ name: str = Field(
81
+ ..., description="Name of the MCP server to update (used as identifier)"
82
+ )
83
+ description: Optional[str] = Field(
84
+ None, description="Updated description of the MCP server"
85
+ )
86
+ mcp_type: Optional[str] = Field(
87
+ None, description="Updated type of MCP server"
88
+ ) # Allow None if not changing
89
+ command: Optional[str] = Field(None, description="Updated command")
90
+ args: Optional[List[str]] = Field(None, description="Updated arguments")
91
+ env: Optional[Dict[str, str]] = Field(
92
+ None, description="Updated environment variables (replaces existing)"
93
+ )
94
+ url: Optional[str] = Field(None, description="Updated URL endpoint")
95
+
32
96
 
33
97
  class McpRemoveRequestModel(BaseModel):
34
98
  server_name: str = Field(..., description="Name of the MCP server to remove")
35
99
 
100
+
36
101
  class McpRefreshRequestModel(BaseModel):
37
- server_name: Optional[str] = Field(None, description="Name of the MCP server to refresh (optional, refreshes all if None)")
102
+ server_name: Optional[str] = Field(
103
+ None,
104
+ description="Name of the MCP server to refresh (optional, refreshes all if None)",
105
+ )
106
+
38
107
 
39
108
  class McpInfoRequestModel(BaseModel):
40
109
  # Assuming model and product_mode might come from global config or request context later
41
110
  # For now, let's make them optional or derive them if possible
42
111
  model: Optional[str] = None
43
- product_mode: Optional[str] = None # Example: "lite", "pro"
112
+ product_mode: Optional[str] = None # Example: "lite", "pro"
113
+
44
114
 
45
115
  # --- Helper Function to Handle MCP Responses ---
46
116
 
47
- async def handle_mcp_response(request: Any, success_key: str, error_key: str, **kwargs) -> Dict[str, Any]:
117
+
118
+ async def handle_mcp_response(
119
+ request: Any, success_key: str, error_key: str, **kwargs
120
+ ) -> Dict[str, Any]:
48
121
  """Handles sending request to MCP server and formatting the response."""
49
122
  try:
50
- response: McpResponse = await async_send_request(request)
123
+ response: McpResponse = await send_mcp_request_async(request)
51
124
  if response.error:
52
125
  logger.error(f"MCP Error ({error_key}): {response.error}")
53
126
  # Use get_message_with_format if available, otherwise use the raw error
54
127
  error_message = response.error
55
128
  try:
56
129
  # Attempt to format the error message if a key is provided
57
- formatted_error = get_message_with_format(error_key, error=response.error)
58
- if formatted_error: # Check if formatting was successful
130
+ formatted_error = get_message_with_format(
131
+ error_key, error=response.error
132
+ )
133
+ if formatted_error: # Check if formatting was successful
59
134
  error_message = formatted_error
60
- except Exception: # Catch potential errors during formatting
61
- pass # Stick with the original error message
135
+ except Exception: # Catch potential errors during formatting
136
+ pass # Stick with the original error message
62
137
  raise HTTPException(status_code=400, detail=error_message)
63
138
  else:
64
139
  # Use get_message_with_format for success message if available
65
140
  success_message = response.result
66
141
  try:
67
- formatted_success = get_message_with_format(success_key, result=response.result, **kwargs)
68
- if formatted_success: # Check if formatting was successful
142
+ formatted_success = get_message_with_format(
143
+ success_key, result=response.result, **kwargs
144
+ )
145
+ if formatted_success: # Check if formatting was successful
69
146
  success_message = formatted_success
70
147
  except Exception:
71
- pass # Stick with the original result message
72
- return {"status": "success", "message": success_message, "data": response.result} # Include raw data too
148
+ pass # Stick with the original result message
149
+ # Return the formatted message and the raw Pydantic model result
150
+ return {
151
+ "status": "success",
152
+ "message": success_message,
153
+ "raw_result": response.raw_result,
154
+ }
73
155
  except HTTPException as http_exc:
74
- raise http_exc # Re-raise HTTPException
156
+ raise http_exc # Re-raise HTTPException
75
157
  except Exception as e:
76
158
  logger.error(f"Unexpected error during MCP request ({error_key}): {str(e)}")
77
159
  raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
78
160
 
161
+
79
162
  # --- API Endpoints ---
80
163
 
164
+
165
+ @router.post("/api/mcp/install")
166
+ async def install_mcp_server(request: McpInstallRequestModel):
167
+ """
168
+ Installs or updates an MCP server configuration based on name, JSON, or command-line args.
169
+ Handles built-in, external, and custom server installations.
170
+ """
171
+ # First, try to find the server in the marketplace list via McpListRequest
172
+ try:
173
+ list_request = McpListRequest()
174
+ list_response: McpResponse = await send_mcp_request_async(list_request)
175
+
176
+ marketplace_item = None
177
+ if list_response.raw_result and isinstance(
178
+ list_response.raw_result, ListResult
179
+ ):
180
+ # Combine all server lists for searching
181
+ all_servers = list_response.raw_result.marketplace_items
182
+ for item in all_servers:
183
+ if item.name == request.server_config:
184
+ marketplace_item = item
185
+ break
186
+
187
+ if marketplace_item:
188
+ # If found in any list, create install request with the item
189
+ mcp_request = McpInstallRequest(market_install_item=marketplace_item)
190
+ logger.info(
191
+ f"Found '{request.server_config}' in available server lists. Installing using item. {marketplace_item}"
192
+ )
193
+ else:
194
+ # If not found in any list, assume it's a direct config string or an unknown name
195
+ mcp_request = McpInstallRequest(server_name_or_config=request.server_config)
196
+ logger.info(
197
+ f"'{request.server_config}' not found in available server lists. Installing using name/config string."
198
+ )
199
+
200
+ # Proceed with installation using the determined request type
201
+ return await handle_mcp_response(
202
+ mcp_request,
203
+ success_key="mcp_install_success",
204
+ error_key="mcp_install_error",
205
+ result=request.server_config, # Pass original config for success message formatting
206
+ )
207
+
208
+ except HTTPException as http_exc:
209
+ # Re-raise HTTP exceptions from handle_mcp_response or list request
210
+ raise http_exc
211
+ except Exception as e:
212
+ logger.error(
213
+ f"Error during MCP install process for '{request.server_config}': {e}"
214
+ )
215
+ # Fallback to original behavior if list fails or other errors occur
216
+ logger.warning("Falling back to direct install request due to previous error.")
217
+ mcp_request = McpInstallRequest(server_name_or_config=request.server_config)
218
+ return await handle_mcp_response(
219
+ mcp_request,
220
+ success_key="mcp_install_success",
221
+ error_key="mcp_install_error",
222
+ result=request.server_config,
223
+ )
224
+
225
+
81
226
  @router.post("/api/mcp/add")
82
- async def add_mcp_server(request: McpAddRequest):
227
+ async def add_marketplace_server(request: MarketplaceAddRequestModel):
83
228
  """
84
- Adds or updates an MCP server configuration.
85
- Accepts command-line style args or a JSON string.
229
+ Adds a new MCP server configuration to the marketplace file.
86
230
  """
87
- mcp_request = McpInstallRequest(server_name_or_config=request.server_config)
231
+ # Convert API model to the internal McpHub model
232
+ mcp_request = MarketplaceAddRequest(
233
+ name=request.name,
234
+ description=request.description,
235
+ mcp_type=request.mcp_type,
236
+ command=request.command,
237
+ args=request.args,
238
+ env=request.env,
239
+ url=request.url,
240
+ )
88
241
  return await handle_mcp_response(
89
242
  mcp_request,
90
- success_key="mcp_install_success",
91
- error_key="mcp_install_error",
92
- result=request.server_config # Pass original config for success message formatting
243
+ success_key="marketplace_add_success",
244
+ error_key="marketplace_add_error",
245
+ name=request.name, # Pass name for message formatting
93
246
  )
94
247
 
248
+
249
+ @router.post("/api/mcp/update")
250
+ async def update_marketplace_server(request: MarketplaceUpdateRequestModel):
251
+ """
252
+ Updates an existing MCP server configuration in the marketplace file.
253
+ Uses the 'name' field to identify the server to update.
254
+ """
255
+ # Convert API model to the internal McpHub model for update
256
+ # Note: We assume MarketplaceUpdateRequest exists in mcp_server
257
+ # and handles partial updates based on provided fields.
258
+ # If a field is None in the request, it might mean "don't update this field"
259
+ # or "set this field to None/empty", depending on McpHub's implementation.
260
+ # Here, we pass all fields from the request model.
261
+ mcp_request = MarketplaceUpdateRequest(
262
+ name=request.name, # Identifier
263
+ description=request.description,
264
+ mcp_type=request.mcp_type,
265
+ command=request.command,
266
+ args=request.args,
267
+ env=request.env,
268
+ url=request.url,
269
+ )
270
+ return await handle_mcp_response(
271
+ mcp_request,
272
+ success_key="marketplace_update_success", # Define this message key
273
+ error_key="marketplace_update_error", # Define this message key
274
+ name=request.name, # Pass name for message formatting
275
+ )
276
+
277
+
95
278
  @router.post("/api/mcp/remove")
96
279
  async def remove_mcp_server(request: McpRemoveRequestModel):
97
280
  """Removes an MCP server configuration by name."""
@@ -100,24 +283,36 @@ async def remove_mcp_server(request: McpRemoveRequestModel):
100
283
  mcp_request,
101
284
  success_key="mcp_remove_success",
102
285
  error_key="mcp_remove_error",
103
- result=request.server_name # Pass server name for success message formatting
286
+ result=request.server_name, # Pass server name for success message formatting
104
287
  )
105
288
 
289
+
106
290
  @router.get("/api/mcp/list")
107
291
  async def list_mcp_servers():
108
292
  """Lists all available built-in and external MCP servers."""
109
293
  mcp_request = McpListRequest()
110
294
  # Specific handling for list as the result is the data itself
111
295
  try:
112
- response: McpResponse = await async_send_request(mcp_request)
296
+ response: McpResponse = await send_mcp_request_async(mcp_request)
113
297
  if response.error:
114
298
  logger.error(f"MCP Error (mcp_list_builtin_error): {response.error}")
115
- error_message = get_message_with_format("mcp_list_builtin_error", error=response.error) or response.error
116
- raise HTTPException(status_code=400, detail=error_message)
299
+ error_message = (
300
+ get_message_with_format("mcp_list_builtin_error", error=response.error)
301
+ or response.error
302
+ )
303
+ # Ensure raw_result is included in the error detail if it's an ErrorResult
304
+ detail = error_message
305
+ if isinstance(response.raw_result, ErrorResult):
306
+ detail = f"{error_message} (Details: {response.raw_result.error})"
307
+ raise HTTPException(status_code=400, detail=detail)
117
308
  else:
118
- # Split the result string into a list for better JSON representation
119
- server_list = response.result.strip().split('\n') if response.result else []
120
- return {"status": "success", "servers": server_list}
309
+ # Return the raw_result which should be of type ListResult
310
+ # Ensure the response is structured consistently
311
+ return {
312
+ "status": "success",
313
+ "message": "MCP servers listed successfully.",
314
+ "raw_result": response.raw_result,
315
+ }
121
316
  except HTTPException as http_exc:
122
317
  raise http_exc
123
318
  except Exception as e:
@@ -131,58 +326,88 @@ async def list_running_mcp_servers():
131
326
  mcp_request = McpListRunningRequest()
132
327
  # Specific handling for list_running
133
328
  try:
134
- response: McpResponse = await async_send_request(mcp_request)
329
+ response: McpResponse = await send_mcp_request_async(mcp_request)
135
330
  if response.error:
136
331
  logger.error(f"MCP Error (mcp_list_running_error): {response.error}")
137
- error_message = get_message_with_format("mcp_list_running_error", error=response.error) or response.error
138
- raise HTTPException(status_code=400, detail=error_message)
332
+ error_message = (
333
+ get_message_with_format("mcp_list_running_error", error=response.error)
334
+ or response.error
335
+ )
336
+ # Ensure raw_result is included in the error detail if it's an ErrorResult
337
+ detail = error_message
338
+ if isinstance(response.raw_result, ErrorResult):
339
+ detail = f"{error_message} (Details: {response.raw_result.error})"
340
+ raise HTTPException(status_code=400, detail=detail)
139
341
  else:
140
- # Split the result string into a list
141
- running_server_list = response.result.strip().split('\n') if response.result else []
142
- # Clean up list (remove potential leading hyphens/spaces)
143
- cleaned_list = [s.strip().lstrip('-').strip() for s in running_server_list if s.strip()]
144
- return {"status": "success", "running_servers": cleaned_list}
342
+ # Return the raw_result which should be of type ListRunningResult
343
+ # Ensure the response is structured consistently
344
+ return {
345
+ "status": "success",
346
+ "message": "Running MCP servers listed successfully.",
347
+ "raw_result": response.raw_result,
348
+ }
145
349
  except HTTPException as http_exc:
146
350
  raise http_exc
147
351
  except Exception as e:
148
352
  logger.error(f"Unexpected error during MCP list_running request: {str(e)}")
149
353
  raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
150
354
 
355
+
151
356
  @router.post("/api/mcp/refresh")
152
357
  async def refresh_mcp_connections(request: McpRefreshRequestModel):
153
358
  """Refreshes connections to MCP servers (all or a specific one)."""
154
359
  mcp_request = McpRefreshRequest(name=request.server_name)
155
360
  return await handle_mcp_response(
156
- mcp_request,
157
- success_key="mcp_refresh_success",
158
- error_key="mcp_refresh_error"
361
+ mcp_request, success_key="mcp_refresh_success", error_key="mcp_refresh_error"
159
362
  )
160
363
 
364
+
161
365
  @router.get("/api/mcp/info")
162
- async def get_mcp_server_info(model: Optional[str] = None, product_mode: Optional[str] = None):
366
+ async def get_mcp_server_info(
367
+ model: Optional[str] = None, product_mode: Optional[str] = "lite"
368
+ ):
163
369
  """Gets detailed information about connected MCP servers."""
164
370
  # TODO: Determine how to get model/product_mode - from app state, global config, or request?
165
371
  # Using optional query params for now.
166
372
  mcp_request = McpServerInfoRequest(model=model, product_mode=product_mode)
167
373
  # Specific handling for info
168
374
  try:
169
- response: McpResponse = await async_send_request(mcp_request)
375
+ response: McpResponse = await send_mcp_request_async(mcp_request)
170
376
  if response.error:
171
377
  logger.error(f"MCP Error (mcp_server_info_error): {response.error}")
172
- error_message = get_message_with_format("mcp_server_info_error", error=response.error) or response.error
173
- raise HTTPException(status_code=400, detail=error_message)
378
+ error_message = (
379
+ get_message_with_format("mcp_server_info_error", error=response.error)
380
+ or response.error
381
+ )
382
+ # Ensure raw_result is included in the error detail if it's an ErrorResult
383
+ detail = error_message
384
+ if isinstance(response.raw_result, ErrorResult):
385
+ detail = f"{error_message} (Details: {response.raw_result.error})"
386
+ raise HTTPException(status_code=400, detail=detail)
174
387
  else:
175
- # The result is likely a markdown string or complex structure. Return as is.
176
- return {"status": "success", "info": response.result}
388
+ # Return the raw_result. It might be a string or a specific Pydantic model later.
389
+ # For now, we assume it's included in McpResponse.raw_result
390
+ # Ensure the response is structured consistently
391
+ # The success message might vary or be generic
392
+ success_message = (
393
+ get_message_with_format("mcp_server_info_success")
394
+ or "Server info retrieved successfully."
395
+ )
396
+ return {
397
+ "status": "success",
398
+ "message": success_message,
399
+ "raw_result": response.raw_result,
400
+ }
177
401
  except HTTPException as http_exc:
178
402
  raise http_exc
179
403
  except Exception as e:
180
404
  logger.error(f"Unexpected error during MCP info request: {str(e)}")
181
405
  raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
182
406
 
407
+
183
408
  # Potentially add endpoints for direct tool calls or resource access if needed in the future
184
409
  # @router.post("/api/mcp/call_tool")
185
410
  # async def call_mcp_tool(...): ...
186
411
 
187
412
  # @router.get("/api/mcp/read_resource")
188
- # async def read_mcp_resource(...): ...
413
+ # async def read_mcp_resource(...): ...
auto_coder_web/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.61"
1
+ __version__ = "0.1.62"
@@ -0,0 +1 @@
1
+ import{r,I as K,_ as P,j as e,S as Q,T as q,R as ee,a as I,h as se,v as te,b as U,s as b,d as O,l as J,c as re,e as ae,E as ne,B as M,L as z,C as le,f as W,g as oe,i as ie,M as ce}from"./main.js";var de={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M839.6 433.8L749 150.5a9.24 9.24 0 00-8.9-6.5h-77.4c-4.1 0-7.6 2.6-8.9 6.5l-91.3 283.3c-.3.9-.5 1.9-.5 2.9 0 5.1 4.2 9.3 9.3 9.3h56.4c4.2 0 7.8-2.8 9-6.8l17.5-61.6h89l17.3 61.5c1.1 4 4.8 6.8 9 6.8h61.2c1 0 1.9-.1 2.8-.4 2.4-.8 4.3-2.4 5.5-4.6 1.1-2.2 1.3-4.7.6-7.1zM663.3 325.5l32.8-116.9h6.3l32.1 116.9h-71.2zm143.5 492.9H677.2v-.4l132.6-188.9c1.1-1.6 1.7-3.4 1.7-5.4v-36.4c0-5.1-4.2-9.3-9.3-9.3h-204c-5.1 0-9.3 4.2-9.3 9.3v43c0 5.1 4.2 9.3 9.3 9.3h122.6v.4L587.7 828.9a9.35 9.35 0 00-1.7 5.4v36.4c0 5.1 4.2 9.3 9.3 9.3h211.4c5.1 0 9.3-4.2 9.3-9.3v-43a9.2 9.2 0 00-9.2-9.3zM416 702h-76V172c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v530h-76c-6.7 0-10.5 7.8-6.3 13l112 141.9a8 8 0 0012.6 0l112-141.9c4.1-5.2.4-13-6.3-13z"}}]},name:"sort-ascending",theme:"outlined"},he=function(i,l){return r.createElement(K,P({},i,{ref:l,icon:de}))},fe=r.forwardRef(he),ue={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M839.6 433.8L749 150.5a9.24 9.24 0 00-8.9-6.5h-77.4c-4.1 0-7.6 2.6-8.9 6.5l-91.3 283.3c-.3.9-.5 1.9-.5 2.9 0 5.1 4.2 9.3 9.3 9.3h56.4c4.2 0 7.8-2.8 9-6.8l17.5-61.6h89l17.3 61.5c1.1 4 4.8 6.8 9 6.8h61.2c1 0 1.9-.1 2.8-.4 2.4-.8 4.3-2.4 5.5-4.6 1.1-2.2 1.3-4.7.6-7.1zM663.3 325.5l32.8-116.9h6.3l32.1 116.9h-71.2zm143.5 492.9H677.2v-.4l132.6-188.9c1.1-1.6 1.7-3.4 1.7-5.4v-36.4c0-5.1-4.2-9.3-9.3-9.3h-204c-5.1 0-9.3 4.2-9.3 9.3v43c0 5.1 4.2 9.3 9.3 9.3h122.6v.4L587.7 828.9a9.35 9.35 0 00-1.7 5.4v36.4c0 5.1 4.2 9.3 9.3 9.3h211.4c5.1 0 9.3-4.2 9.3-9.3v-43a9.2 9.2 0 00-9.2-9.3zM310.3 167.1a8 8 0 00-12.6 0L185.7 309c-4.2 5.3-.4 13 6.3 13h76v530c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V322h76c6.7 0 10.5-7.8 6.3-13l-112-141.9z"}}]},name:"sort-descending",theme:"outlined"},xe=function(i,l){return r.createElement(K,P({},i,{ref:l,icon:ue}))},me=r.forwardRef(xe),ge={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M511.4 124C290.5 124.3 112 303 112 523.9c0 128 60.2 242 153.8 315.2l-37.5 48c-4.1 5.3-.3 13 6.3 12.9l167-.8c5.2 0 9-4.9 7.7-9.9L369.8 727a8 8 0 00-14.1-3L315 776.1c-10.2-8-20-16.7-29.3-26a318.64 318.64 0 01-68.6-101.7C200.4 609 192 567.1 192 523.9s8.4-85.1 25.1-124.5c16.1-38.1 39.2-72.3 68.6-101.7 29.4-29.4 63.6-52.5 101.7-68.6C426.9 212.4 468.8 204 512 204s85.1 8.4 124.5 25.1c38.1 16.1 72.3 39.2 101.7 68.6 29.4 29.4 52.5 63.6 68.6 101.7 16.7 39.4 25.1 81.3 25.1 124.5s-8.4 85.1-25.1 124.5a318.64 318.64 0 01-68.6 101.7c-7.5 7.5-15.3 14.5-23.4 21.2a7.93 7.93 0 00-1.2 11.1l39.4 50.5c2.8 3.5 7.9 4.1 11.4 1.3C854.5 760.8 912 649.1 912 523.9c0-221.1-179.4-400.2-400.6-399.9z"}}]},name:"undo",theme:"outlined"},pe=function(i,l){return r.createElement(K,P({},i,{ref:l,icon:ge}))},be=r.forwardRef(pe);J.config({paths:{vs:"/monaco-editor/min/vs"},"vs/nls":{availableLanguages:{"*":"zh-cn"}}});const{TabPane:G}=q,ve=({commitId:n,onClose:i})=>{const[l,B]=r.useState({diff:""}),[o,k]=r.useState(null),[c,v]=r.useState(null),[S,R]=r.useState(!1),[f,E]=r.useState("split"),[u,L]=r.useState(null),[m,y]=r.useState(!1),[g,$]=r.useState("1"),j=r.useRef(null),p=r.useRef(null),w=r.useRef(null),N=r.useRef(null),D=async()=>{if(n){y(!0);try{const t=encodeURIComponent(n),a=await U.get(`/api/history/commit-diff/${t}`);a.data.success?B({diff:a.data.diff,file_changes:a.data.file_changes}):b.error(a.data.message||"获取diff失败")}catch(t){console.error("Error fetching diff:",t),b.error("获取diff失败")}finally{y(!1)}}},C=async t=>{if(n)try{R(!0),v(null),j.current=null,p.current=null,w.current=null;const a=encodeURIComponent(n),x=await U.get(`/api/history/file-diff/${a}?file_path=${encodeURIComponent(t)}`);x.data.success?v(x.data.file_diff):b.error(x.data.message||"获取文件差异失败")}catch(a){console.error("Error fetching file diff:",a),b.error("获取文件差异失败")}finally{R(!1)}},F=t=>{o===t?(k(null),v(null),j.current=null,p.current=null,w.current=null,L(null)):(k(t),C(t),L(null))},A=r.useCallback(t=>{j.current=t},[]),T=r.useCallback(t=>{p.current=t},[]),s=r.useCallback(t=>{w.current=t},[]),d=t=>{var _;const a=(_=t.split(".").pop())==null?void 0:_.toLowerCase();return{js:"javascript",jsx:"javascript",ts:"typescript",tsx:"typescript",py:"python",java:"java",c:"c",cpp:"cpp",cs:"csharp",go:"go",rs:"rust",rb:"ruby",php:"php",html:"html",css:"css",scss:"scss",json:"json",md:"markdown",yml:"yaml",yaml:"yaml",xml:"xml",sh:"shell",bash:"shell",txt:"plaintext"}[a||""]||"plaintext"},h=({viewType:t})=>{const a=u===t;return e.jsx("button",{className:"ml-2 text-gray-400 hover:text-white transition-colors",onClick:x=>{x.stopPropagation(),L(a?null:t)},title:a?"恢复正常视图":"最大化视图",children:a?e.jsx("svg",{className:"w-3.5 h-3.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5"})}):e.jsx("svg",{className:"w-3.5 h-3.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5"})})})},X=()=>{if(!o||!c)return null;const t=d(o),a=`diff-${n}-${o}-${f}`,x=`before-${n}-${o}`,_=`after-${n}-${o}`,V={readOnly:!0,scrollBeyondLastLine:!1,minimap:{enabled:!1},lineNumbers:"on",wordWrap:"on",automaticLayout:!0,scrollbar:{vertical:"visible",horizontal:"visible",verticalScrollbarSize:14,horizontalScrollbarSize:14}};return f==="unified"?e.jsxs("div",{ref:N,className:"bg-gray-900 rounded-lg border border-gray-700",style:{height:"500px",width:"100%",overflow:"hidden"},children:[e.jsxs("div",{className:"py-1 px-3 bg-gray-800 border-b border-gray-700 text-xs font-medium text-white flex justify-between items-center",children:[e.jsx("span",{children:"差异视图"}),e.jsx(h,{viewType:"diff"})]}),e.jsx(O,{height:"calc(100% - 26px)",width:"100%",defaultLanguage:"diff",value:c.diff_content||"",theme:"vs-dark",onMount:s,options:V,loading:e.jsx("div",{className:"flex items-center justify-center h-full text-white",children:"加载中..."})},a)]}):e.jsxs("div",{ref:N,className:"grid grid-cols-2 gap-2",style:{height:"500px",width:"100%"},children:[(u===null||u==="before")&&e.jsxs("div",{className:`bg-gray-900 rounded-lg border border-gray-700 ${u==="before"?"col-span-2":""}`,style:{overflow:"hidden"},children:[e.jsxs("div",{className:"py-1 px-3 bg-gray-800 border-b border-gray-700 text-xs font-medium text-white flex justify-between items-center",children:[e.jsxs("span",{children:["修改前 (",c.file_status==="added"?"新文件":o,")"]}),e.jsx(h,{viewType:"before"})]}),e.jsx(O,{height:"calc(100% - 26px)",width:"100%",defaultLanguage:t,value:c.before_content||"",theme:"vs-dark",onMount:A,options:V,loading:e.jsx("div",{className:"flex items-center justify-center h-full text-white",children:"加载中..."})},x)]}),(u===null||u==="after")&&e.jsxs("div",{className:`bg-gray-900 rounded-lg border border-gray-700 ${u==="after"?"col-span-2":""}`,style:{overflow:"hidden"},children:[e.jsxs("div",{className:"py-1 px-3 bg-gray-800 border-b border-gray-700 text-xs font-medium text-white flex justify-between items-center",children:[e.jsxs("span",{children:["修改后 (",c.file_status==="deleted"?"文件已删除":o,")"]}),e.jsx(h,{viewType:"after"})]}),e.jsx(O,{height:"calc(100% - 26px)",width:"100%",defaultLanguage:t,value:c.after_content||"",theme:"vs-dark",onMount:T,options:V,loading:e.jsx("div",{className:"flex items-center justify-center h-full text-white",children:"加载中..."})},_)]})]})};r.useEffect(()=>{n&&D()},[n]);const Y={background:"#1F2937",borderBottom:"1px solid #374151",margin:0,padding:"0 16px"},Z=(t,a)=>e.jsx(a,{...t,style:Y,className:"custom-tabs-bar"});return e.jsxs("div",{className:"flex flex-col h-full bg-[#111827] overflow-hidden",children:[e.jsxs("div",{className:"flex justify-between items-center p-4 bg-[#1F2937] border-b border-[#374151]",children:[e.jsx("h2",{className:"text-lg font-semibold text-white",children:"代码变更详情"}),e.jsx(Q,{children:i&&e.jsx("button",{className:"px-3 py-1.5 bg-gray-700 hover:bg-gray-600 text-white rounded text-sm",onClick:i,children:"关闭"})})]}),e.jsx("div",{className:"flex-1 overflow-y-auto",children:e.jsxs(q,{activeKey:g,onChange:$,type:"card",className:"diff-viewer-tabs",renderTabBar:Z,style:{background:"#111827"},children:[e.jsx(G,{tab:e.jsx("div",{className:`py-2 px-4 ${g==="1"?"text-white font-medium":"text-gray-400"}`,children:"文件列表"}),children:e.jsxs("div",{className:"p-4",children:[e.jsx("div",{className:"space-y-2 mb-4",children:m?e.jsx("div",{className:"flex items-center justify-center py-10",children:e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-white"})}):l.file_changes&&l.file_changes.length>0?l.file_changes.map((t,a)=>e.jsx("div",{className:`text-sm py-2 px-3 rounded cursor-pointer ${o===t.path?"bg-gray-700 border-l-2 border-indigo-500":"hover:bg-gray-750 bg-gray-800"}`,onClick:()=>F(t.path),children:e.jsxs("div",{className:"flex items-center",children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full mr-2 ${t.change_type==="added"?"bg-green-500":t.change_type==="modified"?"bg-yellow-500":t.change_type==="deleted"?"bg-red-500":"bg-blue-500"}`}),e.jsx("span",{className:`font-mono ${t.change_type==="deleted"?"line-through text-gray-500":"text-white"}`,children:t.path}),e.jsx(ee,{className:"ml-2 text-gray-400"})]})},a)):e.jsx("div",{className:"text-center text-white py-8",children:e.jsx("p",{children:"没有文件变更信息"})})}),S&&e.jsx("div",{className:"flex items-center justify-center py-10",children:e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-white"})}),o&&c&&!S&&e.jsx("div",{className:"flex justify-end mb-3",children:e.jsxs(I.Group,{value:f,onChange:t=>E(t.target.value),buttonStyle:"solid",children:[e.jsx(I.Button,{value:"split",style:{color:f==="split"?"#fff":"#1f2937"},children:"分割视图"}),e.jsx(I.Button,{value:"unified",style:{color:f==="unified"?"#fff":"#1f2937"},children:"统一视图"})]})}),o&&c&&!S&&X()]})},"1"),e.jsx(G,{tab:e.jsx("div",{className:`py-2 px-4 ${g==="2"?"text-white font-medium":"text-gray-400"}`,children:"原始差异"}),children:e.jsx("div",{className:"p-4",children:m?e.jsx("div",{className:"flex items-center justify-center py-10",children:e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-white"})}):e.jsx(se,{language:"diff",style:te,customStyle:{padding:"12px",borderRadius:"4px",overflow:"auto",maxHeight:"600px"},children:l.diff||""})})},"2")]})})]})};J.config({paths:{vs:"/monaco-editor/min/vs"},"vs/nls":{availableLanguages:{"*":"zh-cn"}}});const{Text:H}=oe,{TabPane:je}=q,we=()=>{const[n,i]=r.useState([]),[l,B]=r.useState(!1),[o,k]=r.useState(!1),[c,v]=r.useState(!1),[S,R]=r.useState([]),[f,E]=r.useState(null),[u,L]=r.useState(!1),[m,y]=r.useState({show:!1,commitHash:"",commitMessage:""}),[g,$]=r.useState(!1),[j,p]=r.useState(null),[w,N]=r.useState(null),D=s=>{if(!s){b.info("该消息没有关联的代码变更");return}E(s)},C=async()=>{k(!0);try{const s=await U.get("/api/history/validate-and-load");s.data.success?i(s.data.queries):b.error(s.data.message||"加载历史记录失败")}catch(s){console.error("Error loading queries:",s),b.error("加载失败")}finally{k(!1)}};re.useEffect(()=>{C();const s=ae.subscribe(ne.CODING.TASK_COMPLETE,d=>{console.log("Coding task completed, reloading queries",d),C()});return()=>{s()}},[]);const F=(s,d,h)=>{s.stopPropagation(),y({show:!0,commitHash:d,commitMessage:h})},A=async()=>{try{$(!0),p(null),N(null);const s=await fetch(`/api/commits/${m.commitHash}/revert`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!s.ok){const h=await s.json();throw new Error(h.detail||"撤销提交失败")}const d=await s.json();N(`成功撤销提交。新的撤销提交: ${d.new_commit_hash.substring(0,7)}`),y(h=>({...h,show:!1})),C(),setTimeout(()=>{N(null)},5e3)}catch(s){p(s instanceof Error?s.message:"撤销提交失败"),console.error("Failed to revert commit:",s)}finally{$(!1)}},T=()=>{y({show:!1,commitHash:"",commitMessage:""}),p(null)};return f?e.jsx(ve,{commitId:f,onClose:()=>E(null)}):e.jsxs("div",{className:"flex flex-col bg-[#111827] overflow-hidden",style:{height:"650px"},children:[e.jsx("div",{className:"flex justify-between items-center p-4 bg-[#1F2937] border-b border-[#374151] sticky top-0 z-10 shadow-md",children:e.jsxs(Q,{children:[e.jsx(M,{icon:l?e.jsx(fe,{}):e.jsx(me,{}),onClick:()=>{B(!l),i([...n].reverse())},children:l?"升序":"降序"}),e.jsx(M,{type:"primary",onClick:C,loading:o,children:"刷新"})]})}),m.show&&e.jsx("div",{className:"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4",children:e.jsxs("div",{className:"bg-gray-800 rounded-lg shadow-xl max-w-md w-full p-6 border border-gray-700",children:[e.jsx("h3",{className:"text-xl font-semibold text-white mb-4",children:"确认撤销提交"}),e.jsx("p",{className:"text-gray-300 mb-6",children:"您确定要撤销此提交吗?这将创建一个新的提交来撤销更改。"}),e.jsxs("div",{className:"bg-gray-900 p-3 rounded mb-6 border border-gray-700",children:[e.jsx("p",{className:"text-sm text-gray-400 mb-1",children:"提交信息:"}),e.jsx("p",{className:"text-white",children:m.commitMessage}),e.jsxs("p",{className:"text-xs text-gray-500 mt-2",children:["Commit: ",m.commitHash.substring(0,7)]})]}),j&&e.jsx("div",{className:"bg-red-900 bg-opacity-25 text-red-400 p-3 rounded mb-4",children:j}),e.jsxs("div",{className:"flex justify-end space-x-3",children:[e.jsx("button",{className:"px-4 py-2 bg-gray-700 hover:bg-gray-600 text-gray-300 rounded transition-colors",onClick:T,disabled:g,children:"取消"}),e.jsx("button",{className:"px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded transition-colors flex items-center",onClick:A,disabled:g,children:g?e.jsxs(e.Fragment,{children:[e.jsxs("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),"处理中..."]}):e.jsx(e.Fragment,{children:"确认撤销"})})]})]})}),w&&e.jsx("div",{className:"fixed top-4 right-4 bg-green-800 text-green-100 p-4 rounded-lg shadow-lg z-50 animate-fade-in-out",children:e.jsxs("div",{className:"flex items-center",children:[e.jsx("svg",{className:"w-5 h-5 mr-2",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"2",d:"M5 13l4 4L19 7"})}),e.jsx("span",{children:w})]})}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-4",children:[e.jsx(z,{dataSource:n,renderItem:s=>e.jsx(z.Item,{className:"border-b border-[#374151] last:border-b-0",children:e.jsx(le,{className:"w-full bg-[#1F2937] border-[#374151] hover:bg-[#2D3748] transition-colors duration-200",title:e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[e.jsxs("div",{children:[e.jsx(W,{style:{marginRight:"8px",color:"#9CA3AF"}}),e.jsx(H,{style:{color:"#E5E7EB"},children:`${s.file_number}_chat_action.yml`}),s.timestamp&&e.jsx(H,{style:{marginLeft:"10px",fontSize:"12px",color:"#9CA3AF"},children:s.timestamp})]}),e.jsxs("div",{className:"flex space-x-2",children:[s.urls&&s.urls.length>0&&e.jsx(M,{icon:e.jsx(W,{}),type:"link",style:{color:"#60A5FA"},onClick:()=>{R(s.urls||[]),v(!0)},children:"查看上下文"}),s.response&&!s.is_reverted&&e.jsx(M,{icon:e.jsx(be,{}),type:"link",style:{color:"#F87171"},onClick:d=>F(d,s.response,s.query),children:"撤销"}),e.jsx(M,{icon:e.jsx(ie,{}),type:"link",style:{color:s.response?"#60A5FA":"#9CA3AF"},onClick:()=>D(s.response),disabled:!s.response,children:"查看变更"})]})]}),children:e.jsxs("div",{className:`${s.is_reverted?"border border-red-500 rounded-lg p-2 relative":""}`,children:[s.is_reverted&&e.jsx("div",{className:"absolute -top-2 -right-2 bg-red-500 text-white text-xs px-2 py-0.5 rounded-full",children:"已撤销"}),e.jsx("div",{style:{backgroundColor:"#111827",padding:"12px",borderRadius:"4px",color:"#E5E7EB",border:"1px solid #374151",maxWidth:"100%",fontSize:"14px",lineHeight:"1.6",whiteSpace:"normal",wordBreak:"break-word"},children:s.query})]})})})}),e.jsx(ce,{title:"上下文文件列表",open:c,onCancel:()=>v(!1),width:600,footer:null,className:"dark-theme-modal",styles:{content:{backgroundColor:"#1f2937",padding:"20px"},header:{backgroundColor:"#1f2937",borderBottom:"1px solid #374151",color:"#ffffff"},body:{backgroundColor:"#1f2937",color:"#ffffff"},mask:{backgroundColor:"rgba(0, 0, 0, 0.6)"}},children:e.jsx(z,{dataSource:S,className:"dark-theme-list max-h-96 overflow-y-auto",renderItem:s=>e.jsx(z.Item,{className:"text-gray-200 border-gray-700",children:e.jsx("div",{className:"flex items-center w-full",children:e.jsx(H,{style:{color:"#E5E7EB"},children:s})})})})})]})]})};export{we as default};
@@ -1,4 +1,4 @@
1
- import{m as et}from"./index-kyBHOjJU.js";/*!-----------------------------------------------------------------------------
1
+ import{m as et}from"./main.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -1,4 +1,4 @@
1
- import{m as f}from"./index-kyBHOjJU.js";/*!-----------------------------------------------------------------------------
1
+ import{m as f}from"./main.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -1,4 +1,4 @@
1
- import{m as l}from"./index-kyBHOjJU.js";/*!-----------------------------------------------------------------------------
1
+ import{m as l}from"./main.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -1,4 +1,4 @@
1
- import{m as s}from"./index-kyBHOjJU.js";/*!-----------------------------------------------------------------------------
1
+ import{m as s}from"./main.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -1,4 +1,4 @@
1
- import{m as lt}from"./index-kyBHOjJU.js";/*!-----------------------------------------------------------------------------
1
+ import{m as lt}from"./main.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" href="/favicon.ico" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Vite React App</title>
8
- <script type="module" crossorigin src="/assets/index-kyBHOjJU.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-CRXh98Y9.css">
8
+ <script type="module" crossorigin src="/main.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/main-DxnFm18B.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -1,4 +1,4 @@
1
- import{conf as t,language as e}from"./typescript-JxFW6htN.js";import"./index-kyBHOjJU.js";/*!-----------------------------------------------------------------------------
1
+ import{conf as t,language as e}from"./typescript-DZzM_VgT.js";import"./main.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -1,4 +1,4 @@
1
- import{m as Et}from"./index-kyBHOjJU.js";/*!-----------------------------------------------------------------------------
1
+ import{m as Et}from"./main.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -1,4 +1,4 @@
1
- import{m as l}from"./index-kyBHOjJU.js";/*!-----------------------------------------------------------------------------
1
+ import{m as l}from"./main.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license