super-code-assistant 3.3.6__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 (61) hide show
  1. commands/__init__.py +859 -0
  2. core/__init__.py +0 -0
  3. core/config.py +263 -0
  4. core/config_template.json +7 -0
  5. core/context.py +271 -0
  6. core/engine.py +635 -0
  7. core/file_state.py +279 -0
  8. core/llm.py +309 -0
  9. core/model_capabilities.py +45 -0
  10. core/permissions.py +204 -0
  11. core/sandbox/__init__.py +15 -0
  12. core/sandbox/blacklist.py +176 -0
  13. core/sandbox/config.py +38 -0
  14. core/sandbox/network.py +136 -0
  15. core/sandbox/path_protection.py +126 -0
  16. core/session.py +295 -0
  17. core/tool.py +45 -0
  18. features/__init__.py +0 -0
  19. features/compact.py +945 -0
  20. features/coordinator.py +105 -0
  21. features/cost_tracker.py +184 -0
  22. features/extract_memories.py +326 -0
  23. features/find_relevant_memories.py +376 -0
  24. features/git_ai.py +256 -0
  25. features/memory.py +531 -0
  26. features/memory_age.py +66 -0
  27. features/memory_scan.py +153 -0
  28. features/memory_types.py +34 -0
  29. features/plan.py +327 -0
  30. features/skills.py +300 -0
  31. features/worker_manager.py +232 -0
  32. mcp/__init__.py +0 -0
  33. mcp/client.py +112 -0
  34. mcp/loader.py +80 -0
  35. mcp/tool_proxy.py +59 -0
  36. super_code_assistant-3.3.6.dist-info/METADATA +45 -0
  37. super_code_assistant-3.3.6.dist-info/RECORD +61 -0
  38. super_code_assistant-3.3.6.dist-info/WHEEL +5 -0
  39. super_code_assistant-3.3.6.dist-info/entry_points.txt +2 -0
  40. super_code_assistant-3.3.6.dist-info/top_level.txt +7 -0
  41. tools/__init__.py +21 -0
  42. tools/agent.py +132 -0
  43. tools/ask_user.py +111 -0
  44. tools/bash.py +77 -0
  45. tools/file_edit.py +269 -0
  46. tools/file_read.py +206 -0
  47. tools/file_write.py +78 -0
  48. tools/glob_tool.py +81 -0
  49. tools/grep_tool.py +134 -0
  50. tools/plan_tools.py +75 -0
  51. tools/skill.py +108 -0
  52. tools/tool.py +44 -0
  53. tools/web_fetch.py +129 -0
  54. tools/web_search.py +220 -0
  55. tui/__init__.py +0 -0
  56. tui/app.py +726 -0
  57. tui/clipboard_image.py +42 -0
  58. tui/keylistener.py +140 -0
  59. tui/prompt.py +752 -0
  60. tui/query.py +200 -0
  61. tui/rendering.py +135 -0
tools/web_search.py ADDED
@@ -0,0 +1,220 @@
1
+ """WebSearch tool: search the web using Bing and return structured results.
2
+
3
+ Uses Bing.com search — zero dependencies, pure stdlib. Works in China.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import html
8
+ import os
9
+ import re
10
+ import urllib.request
11
+ import urllib.error
12
+ import urllib.parse
13
+ from html.parser import HTMLParser
14
+
15
+ from core.tool import Tool, ToolResult
16
+
17
+ _MAX_RESULTS = 10
18
+ _DEFAULT_RESULTS = 5
19
+ _MAX_CHARS = 3_000
20
+
21
+
22
+ class _BingParser(HTMLParser):
23
+ """Parse Bing search result page HTML.
24
+
25
+ Bing results are in <li class="b_algo"> blocks:
26
+ <h2><a href="URL">title</a></h2>
27
+ <div class="b_caption"><p>snippet</p></div>
28
+
29
+ Uses depth counters to handle nested elements inside b_caption
30
+ (e.g. <div class="b_caption"><div class="f">...</div></div>).
31
+ """
32
+
33
+ def __init__(self):
34
+ super().__init__()
35
+ self.results: list[dict[str, str]] = []
36
+ self._in_algo = False
37
+ self._in_title = False # inside <h2><a>
38
+ self._in_caption = False # inside <div class="b_caption">
39
+ self._caption_depth = 0 # 嵌套 div 深度计数
40
+ self._text: list[str] = []
41
+ self._current_href = ""
42
+ self._current_title = ""
43
+ self._current_snippet = ""
44
+
45
+ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
46
+ d = dict(attrs)
47
+ cls = d.get("class", "")
48
+
49
+ if tag == "li" and "b_algo" in cls.split():
50
+ self._in_algo = True
51
+ self._in_title = False
52
+ self._in_caption = False
53
+ self._caption_depth = 0
54
+ self._current_href = ""
55
+ self._current_title = ""
56
+ self._current_snippet = ""
57
+
58
+ elif self._in_algo and not self._current_href:
59
+ # 第一个 <h2><a href="..."> 就是结果标题链接
60
+ if tag == "h2":
61
+ self._in_title = True
62
+ elif self._in_title and tag == "a":
63
+ self._current_href = d.get("href", "")
64
+ self._text = []
65
+
66
+ elif self._in_algo:
67
+ if tag == "div" and "b_caption" in cls.split():
68
+ self._in_caption = True
69
+ self._caption_depth = 1
70
+ elif self._in_caption and tag == "div":
71
+ self._caption_depth += 1
72
+
73
+ def handle_endtag(self, tag: str) -> None:
74
+ if self._in_title and tag == "a":
75
+ self._current_title = "".join(self._text).strip()
76
+ elif self._in_title and tag == "h2":
77
+ self._in_title = False
78
+ elif self._in_caption and tag == "div":
79
+ self._caption_depth -= 1
80
+ if self._caption_depth > 0:
81
+ return # 内层 </div>,跳过
82
+ self._in_caption = False
83
+ # 外层 b_caption 的 </div>,收尾
84
+ if self._current_href:
85
+ self.results.append({
86
+ "title": self._current_title,
87
+ "href": self._current_href,
88
+ "snippet": self._current_snippet,
89
+ })
90
+ self._in_algo = False
91
+ elif self._in_algo and tag == "li":
92
+ # 有些结果可能没有 b_caption(如视频/图片结果),在 </li> 时兜底
93
+ if self._current_href and not self._current_snippet:
94
+ self.results.append({
95
+ "title": self._current_title,
96
+ "href": self._current_href,
97
+ "snippet": self._current_snippet,
98
+ })
99
+ self._in_algo = False
100
+
101
+ def handle_data(self, data: str) -> None:
102
+ if self._in_title and self._current_href:
103
+ self._text.append(data)
104
+ elif self._in_caption:
105
+ self._current_snippet += data
106
+
107
+ def finalize(self) -> None:
108
+ if self._in_algo and self._current_href:
109
+ self.results.append({
110
+ "title": self._current_title,
111
+ "href": self._current_href,
112
+ "snippet": self._current_snippet.strip(),
113
+ })
114
+
115
+
116
+ class WebSearchTool(Tool):
117
+ name = "WebSearch"
118
+ description = (
119
+ "Searches the web using Bing and returns results as structured text. "
120
+ "Use this to find documentation, code examples, or any information on the web. "
121
+ "Each result includes a title, URL, and text snippet."
122
+ )
123
+ input_schema = {
124
+ "type": "object",
125
+ "properties": {
126
+ "query": {
127
+ "type": "string",
128
+ "description": "Search query string",
129
+ },
130
+ "max_results": {
131
+ "type": "integer",
132
+ "description": f"Maximum number of results (1-{_MAX_RESULTS}, default {_DEFAULT_RESULTS})",
133
+ "default": _DEFAULT_RESULTS,
134
+ },
135
+ },
136
+ "required": ["query"],
137
+ }
138
+
139
+ def is_read_only(self) -> bool:
140
+ return True
141
+
142
+ def get_activity_description(self, **kwargs) -> str | None:
143
+ query = kwargs.get("query", "")
144
+ return f"Searching: {query}" if query else None
145
+
146
+ def execute(self, query: str, max_results: int = _DEFAULT_RESULTS, **kwargs) -> ToolResult:
147
+ if not query.strip():
148
+ return ToolResult(content="Error: query must not be empty.", is_error=True)
149
+
150
+ max_results = min(max(max_results, 1), _MAX_RESULTS)
151
+
152
+ encoded_query = urllib.parse.quote_plus(query)
153
+ url = f"https://www.bing.com/search?q={encoded_query}"
154
+
155
+ # 代理支持:读取环境变量 HTTPS_PROXY / HTTP_PROXY
156
+ proxy_url = os.environ.get("HTTPS_PROXY") or os.environ.get("HTTP_PROXY")
157
+ opener = (
158
+ urllib.request.build_opener(
159
+ urllib.request.ProxyHandler({"https": proxy_url, "http": proxy_url})
160
+ )
161
+ if proxy_url
162
+ else urllib.request.build_opener()
163
+ )
164
+
165
+ try:
166
+ req = urllib.request.Request(
167
+ url,
168
+ headers={
169
+ "User-Agent": (
170
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
171
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
172
+ "Chrome/120.0.0.0 Safari/537.36"
173
+ ),
174
+ },
175
+ )
176
+ with opener.open(req, timeout=15) as resp:
177
+ raw_bytes = resp.read(200_000)
178
+ except urllib.error.HTTPError as e:
179
+ return ToolResult(content=f"Search error: HTTP {e.code} {e.reason}", is_error=True)
180
+ except urllib.error.URLError as e:
181
+ return ToolResult(content=f"Search error: {e.reason}", is_error=True)
182
+ except TimeoutError:
183
+ return ToolResult(content="Search error: request timed out after 15s", is_error=True)
184
+ except Exception as e:
185
+ return ToolResult(content=f"Search error: {e}", is_error=True)
186
+
187
+ charset = resp.headers.get_content_charset() or "utf-8"
188
+ try:
189
+ raw_html = raw_bytes.decode(charset, errors="replace")
190
+ except LookupError:
191
+ raw_html = raw_bytes.decode("utf-8", errors="replace")
192
+
193
+ parser = _BingParser()
194
+ try:
195
+ parser.feed(raw_html)
196
+ parser.finalize()
197
+ except Exception:
198
+ return ToolResult(content="Search error: failed to parse results.", is_error=True)
199
+
200
+ results = parser.results[:max_results]
201
+
202
+ if not results:
203
+ return ToolResult(content="No results found.")
204
+
205
+ lines = []
206
+ total = 0
207
+ for i, r in enumerate(results, 1):
208
+ title = r["title"] or "(no title)"
209
+ href = r["href"]
210
+ # 清理 HTML 标签和实体
211
+ snippet = html.unescape(re.sub(r"<[^>]+>", "", r["snippet"].strip()))
212
+ line = f"{i}. **{title}**\n {href}\n {snippet}"
213
+ total += len(line)
214
+ if total > _MAX_CHARS:
215
+ if i == 1:
216
+ lines.append(line[:_MAX_CHARS] + "...")
217
+ break
218
+ lines.append(line)
219
+
220
+ return ToolResult(content="\n\n".join(lines))
tui/__init__.py ADDED
File without changes