abyss-cli 0.1.0__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.
- abyss/__init__.py +3 -0
- abyss/ansi_menu.py +559 -0
- abyss/api_client.py +123 -0
- abyss/commands/__init__.py +12 -0
- abyss/commands/slash.py +72 -0
- abyss/config.py +121 -0
- abyss/custom_input.py +382 -0
- abyss/extensions/__init__.py +21 -0
- abyss/extensions/cli.py +160 -0
- abyss/extensions/installer.py +452 -0
- abyss/extensions/registry.py +119 -0
- abyss/extensions/url_parser.py +86 -0
- abyss/hooks/__init__.py +12 -0
- abyss/hooks/runner.py +144 -0
- abyss/logger.py +218 -0
- abyss/main.py +763 -0
- abyss/mcp/__init__.py +13 -0
- abyss/mcp/manager.py +189 -0
- abyss/prompts/__init__.py +26 -0
- abyss/session.py +79 -0
- abyss/skills/__init__.py +12 -0
- abyss/skills/loader.py +150 -0
- abyss/tools/__init__.py +20 -0
- abyss/tools/base.py +45 -0
- abyss/tools/file_edit.py +48 -0
- abyss/tools/file_read.py +54 -0
- abyss/tools/file_write.py +44 -0
- abyss/tools/registry.py +107 -0
- abyss/tools/shell_exec.py +181 -0
- abyss/tools/web_search.py +63 -0
- abyss_cli-0.1.0.dist-info/METADATA +11 -0
- abyss_cli-0.1.0.dist-info/RECORD +35 -0
- abyss_cli-0.1.0.dist-info/WHEEL +5 -0
- abyss_cli-0.1.0.dist-info/entry_points.txt +2 -0
- abyss_cli-0.1.0.dist-info/top_level.txt +1 -0
abyss/tools/registry.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
工具注册中心
|
|
4
|
+
替代硬编码 TOOLS dict,支持动态注册/注销,为 MCP 工具接入预留扩展点。
|
|
5
|
+
"""
|
|
6
|
+
import json
|
|
7
|
+
import time
|
|
8
|
+
from typing import Any, Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
from .base import Tool
|
|
11
|
+
from .file_read import FileReadTool
|
|
12
|
+
from .file_write import FileWriteTool
|
|
13
|
+
from .file_edit import FileEditTool
|
|
14
|
+
from .shell_exec import ShellExecTool
|
|
15
|
+
from .web_search import WebSearchTool
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _get_tc_field(tc, name: str, default=None):
|
|
19
|
+
"""兼容 dict 和 SDK 对象两种 tool_call 格式"""
|
|
20
|
+
if isinstance(tc, dict):
|
|
21
|
+
return tc.get(name, default)
|
|
22
|
+
return getattr(tc, name, default)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ToolRegistry:
|
|
26
|
+
"""工具注册中心:统一管理内置工具与外部扩展工具(MCP)。"""
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
self._tools: Dict[str, Tool] = {}
|
|
30
|
+
|
|
31
|
+
def register(self, tool: Tool) -> None:
|
|
32
|
+
"""注册单个工具,按 tool.name 索引"""
|
|
33
|
+
self._tools[tool.name] = tool
|
|
34
|
+
|
|
35
|
+
def unregister(self, name: str) -> None:
|
|
36
|
+
"""按名注销工具"""
|
|
37
|
+
self._tools.pop(name, None)
|
|
38
|
+
|
|
39
|
+
def get(self, name: str) -> Optional[Tool]:
|
|
40
|
+
"""按名获取工具,未注册返回 None"""
|
|
41
|
+
return self._tools.get(name)
|
|
42
|
+
|
|
43
|
+
def list_names(self) -> List[str]:
|
|
44
|
+
"""返回所有已注册工具名"""
|
|
45
|
+
return list(self._tools.keys())
|
|
46
|
+
|
|
47
|
+
def to_openai_schemas(self) -> List[Dict[str, Any]]:
|
|
48
|
+
"""生成所有工具的 OpenAI function calling 定义"""
|
|
49
|
+
return [t.to_openai_schema() for t in self._tools.values()]
|
|
50
|
+
|
|
51
|
+
def register_builtins(self) -> None:
|
|
52
|
+
"""注册 5 个内置工具"""
|
|
53
|
+
for tool in (
|
|
54
|
+
FileReadTool(), FileWriteTool(), FileEditTool(),
|
|
55
|
+
ShellExecTool(), WebSearchTool()
|
|
56
|
+
):
|
|
57
|
+
self.register(tool)
|
|
58
|
+
|
|
59
|
+
def __contains__(self, name: str) -> bool:
|
|
60
|
+
return name in self._tools
|
|
61
|
+
|
|
62
|
+
def execute_tool_call(self, tool_call) -> str:
|
|
63
|
+
"""执行单个 tool_call,返回给 AI 的结果 JSON 字符串。
|
|
64
|
+
|
|
65
|
+
参数解析失败或工具未注册时返回 {"success": False, "error": ...}。
|
|
66
|
+
对 shell_exec 输出做长度截断以保护上下文窗口。
|
|
67
|
+
"""
|
|
68
|
+
func = _get_tc_field(tool_call, "function", {})
|
|
69
|
+
name = _get_tc_field(func, "name", "")
|
|
70
|
+
args_str = _get_tc_field(func, "arguments", "")
|
|
71
|
+
try:
|
|
72
|
+
arguments = json.loads(args_str) if args_str else {}
|
|
73
|
+
except json.JSONDecodeError:
|
|
74
|
+
return json.dumps({"success": False, "error": f"参数解析失败: {args_str}"})
|
|
75
|
+
|
|
76
|
+
tool = self.get(name)
|
|
77
|
+
if tool is None:
|
|
78
|
+
return json.dumps({"success": False, "error": f"未知工具: {name}"})
|
|
79
|
+
|
|
80
|
+
result = tool.execute(**arguments)
|
|
81
|
+
return self._format_result_for_llm(name, result)
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def _format_result_for_llm(name: str, result: Dict[str, Any]) -> str:
|
|
85
|
+
"""格式化工具结果给 LLM,对 shell_exec 输出做截断"""
|
|
86
|
+
if name == "shell_exec":
|
|
87
|
+
max_len = 4000
|
|
88
|
+
stdout = (result.get("stdout", "") or "")
|
|
89
|
+
stderr = (result.get("stderr", "") or "")
|
|
90
|
+
if len(stdout) > max_len:
|
|
91
|
+
stdout = stdout[:max_len] + f"\n...[截断, 共 {result.get('stdout','').count(chr(10))+1} 行]"
|
|
92
|
+
if len(stderr) > max_len:
|
|
93
|
+
stderr = stderr[:max_len] + f"\n...[截断]"
|
|
94
|
+
return json.dumps({
|
|
95
|
+
"success": result.get("success", False),
|
|
96
|
+
"stdout": stdout,
|
|
97
|
+
"stderr": stderr,
|
|
98
|
+
"returncode": result.get("returncode", None),
|
|
99
|
+
}, ensure_ascii=False)
|
|
100
|
+
return json.dumps(result, ensure_ascii=False)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def create_default_registry() -> ToolRegistry:
|
|
104
|
+
"""创建并返回已注册全部内置工具的 ToolRegistry 实例"""
|
|
105
|
+
reg = ToolRegistry()
|
|
106
|
+
reg.register_builtins()
|
|
107
|
+
return reg
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
终端命令执行工具
|
|
4
|
+
执行终端命令,带安全限制和失败重试
|
|
5
|
+
"""
|
|
6
|
+
import re
|
|
7
|
+
import sys
|
|
8
|
+
import time
|
|
9
|
+
import subprocess
|
|
10
|
+
from .base import Tool
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ShellExecTool(Tool):
|
|
14
|
+
"""执行终端命令的工具,带安全限制。失败时自动重试,避免临时网络/IO 抖动。"""
|
|
15
|
+
|
|
16
|
+
# 最大重试次数(不含首次执行)。例如 max_retries=2 表示最多执行 3 次
|
|
17
|
+
MAX_RETRIES = 2
|
|
18
|
+
|
|
19
|
+
# 重试退避基数(秒),实际等待 = BASE_BACKOFF * 2^attempt
|
|
20
|
+
BASE_BACKOFF = 0.5
|
|
21
|
+
|
|
22
|
+
DANGEROUS_PATTERNS = [
|
|
23
|
+
"rm -rf /", "rm -rf /*", "> /dev/sda", "dd if=/dev/zero",
|
|
24
|
+
"mkfs.", "chmod -R 777 /", ":(){ :|:& };:", "> /etc/",
|
|
25
|
+
"del /f /q", "fdisk"
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
# 正则匹配的危险模式:format 是 Windows 格式化磁盘命令(format C: /Q),
|
|
29
|
+
# 但要避免误伤 PowerShell 的 "Get-Date -Format" 这类合法用法。
|
|
30
|
+
DANGEROUS_REGEX = [
|
|
31
|
+
re.compile(r'(^|[\s;&|])format\s+[a-zA-Z]:', re.IGNORECASE),
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def name(self) -> str:
|
|
36
|
+
return "shell_exec"
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def description(self) -> str:
|
|
40
|
+
return "执行终端命令,支持设置工作目录和超时。失败时自动重试。"
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def parameters(self) -> dict:
|
|
44
|
+
return {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"properties": {
|
|
47
|
+
"command": {"type": "string", "description": "要执行的命令"},
|
|
48
|
+
"cwd": {"type": "string", "description": "工作目录"},
|
|
49
|
+
"timeout": {"type": "integer", "description": "超时秒数,默认60"}
|
|
50
|
+
},
|
|
51
|
+
"required": ["command"]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
def _is_safe(self, command: str) -> bool:
|
|
55
|
+
"""检查命令是否安全"""
|
|
56
|
+
lowered = command.lower()
|
|
57
|
+
for pattern in self.DANGEROUS_PATTERNS:
|
|
58
|
+
if pattern in lowered:
|
|
59
|
+
return False
|
|
60
|
+
for pattern in self.DANGEROUS_REGEX:
|
|
61
|
+
if pattern.search(command):
|
|
62
|
+
return False
|
|
63
|
+
return True
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def _enrich_timeout_error(command: str, timeout: int, result: dict) -> dict:
|
|
67
|
+
"""为超时错误附加针对性建议。目标:让 AI 看到错误后能立刻换策略。"""
|
|
68
|
+
cmd_lower = command.lower()
|
|
69
|
+
suggestions = []
|
|
70
|
+
if re.search(r"\b(pip|pip3|python\s+-m\s+pip)\b", cmd_lower) and "install" in cmd_lower:
|
|
71
|
+
suggestions.extend([
|
|
72
|
+
"pip install 在国内常因 pypi 源慢而超时。",
|
|
73
|
+
"建议加 -i https://pypi.tuna.tsinghua.edu.cn/simple(清华源)",
|
|
74
|
+
"或阿里源 https://mirrors.aliyun.com/pypi/simple/",
|
|
75
|
+
"并把 timeout 加大到 300+ 秒。",
|
|
76
|
+
])
|
|
77
|
+
elif re.search(r"\bgit\s+clone\b", cmd_lower):
|
|
78
|
+
suggestions.extend([
|
|
79
|
+
"git clone 慢可换镜像:git clone https://mirror.ghproxy.com/<原github url>",
|
|
80
|
+
"或 https://gitclone.com/<原 url>",
|
|
81
|
+
])
|
|
82
|
+
elif re.search(r"\b(curl|wget|invoke-webrequest)\b", cmd_lower):
|
|
83
|
+
suggestions.extend([
|
|
84
|
+
"下载慢可换国内镜像或在浏览器中下载。",
|
|
85
|
+
])
|
|
86
|
+
else:
|
|
87
|
+
suggestions.append(
|
|
88
|
+
f"已强制终止。建议把 timeout 调大(当前 {timeout}s),或拆成更小的步骤。"
|
|
89
|
+
)
|
|
90
|
+
if suggestions:
|
|
91
|
+
new_err = result.get("error", "") + "\n[建议] " + " ".join(suggestions)
|
|
92
|
+
result = dict(result)
|
|
93
|
+
result["error"] = new_err
|
|
94
|
+
return result
|
|
95
|
+
|
|
96
|
+
def _wrap_powershell(self, command: str) -> str:
|
|
97
|
+
"""包装用户命令,强制 PowerShell 用 UTF-8 输出(避免中文乱码)。
|
|
98
|
+
同时把 PYTHONIOENCODING=utf-8 写到子进程环境,让子 Python 进程也用 UTF-8 输出,
|
|
99
|
+
避免 print('✓') 这类 Unicode 字符在 Windows GBK 终端上崩溃。
|
|
100
|
+
"""
|
|
101
|
+
prefix = (
|
|
102
|
+
"$OutputEncoding = [System.Text.Encoding]::UTF8; "
|
|
103
|
+
"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; "
|
|
104
|
+
"chcp 65001 | Out-Null; "
|
|
105
|
+
)
|
|
106
|
+
return prefix + command
|
|
107
|
+
|
|
108
|
+
def _build_env(self) -> dict:
|
|
109
|
+
"""构造子进程环境:保留系统环境,并注入 PYTHONIOENCODING=utf-8"""
|
|
110
|
+
import os
|
|
111
|
+
env = os.environ.copy()
|
|
112
|
+
env["PYTHONIOENCODING"] = "utf-8"
|
|
113
|
+
env["PYTHONUTF8"] = "1"
|
|
114
|
+
return env
|
|
115
|
+
|
|
116
|
+
def _run_once(self, command: str, cwd, timeout) -> dict:
|
|
117
|
+
"""单次执行命令(不重试)"""
|
|
118
|
+
env = self._build_env()
|
|
119
|
+
if sys.platform == "win32":
|
|
120
|
+
result = subprocess.run(
|
|
121
|
+
["powershell.exe", "-NoProfile", "-Command", self._wrap_powershell(command)],
|
|
122
|
+
cwd=cwd,
|
|
123
|
+
capture_output=True,
|
|
124
|
+
encoding="utf-8",
|
|
125
|
+
errors="replace",
|
|
126
|
+
timeout=timeout,
|
|
127
|
+
env=env
|
|
128
|
+
)
|
|
129
|
+
else:
|
|
130
|
+
result = subprocess.run(
|
|
131
|
+
command,
|
|
132
|
+
shell=True,
|
|
133
|
+
cwd=cwd,
|
|
134
|
+
capture_output=True,
|
|
135
|
+
encoding="utf-8",
|
|
136
|
+
errors="replace",
|
|
137
|
+
timeout=timeout,
|
|
138
|
+
env=env
|
|
139
|
+
)
|
|
140
|
+
return {
|
|
141
|
+
"command": command,
|
|
142
|
+
"success": result.returncode == 0,
|
|
143
|
+
"returncode": result.returncode,
|
|
144
|
+
"stdout": result.stdout,
|
|
145
|
+
"stderr": result.stderr
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
def execute(self, command: str, cwd: str = None, timeout: int = 60) -> dict:
|
|
149
|
+
"""执行命令,失败时按指数退避自动重试。超时场景不重试(重试也没用)"""
|
|
150
|
+
if not self._is_safe(command):
|
|
151
|
+
return {"success": False, "error": "命令被安全策略拦截"}
|
|
152
|
+
|
|
153
|
+
last_result = None
|
|
154
|
+
for attempt in range(self.MAX_RETRIES + 1):
|
|
155
|
+
try:
|
|
156
|
+
last_result = self._run_once(command, cwd, timeout)
|
|
157
|
+
except subprocess.TimeoutExpired:
|
|
158
|
+
# 超时不重试:第一次就附加建议,避免无意义的重试浪费时间
|
|
159
|
+
last_result = {
|
|
160
|
+
"command": command,
|
|
161
|
+
"success": False,
|
|
162
|
+
"error": f"命令执行超时({timeout}秒),已强制终止",
|
|
163
|
+
}
|
|
164
|
+
return self._enrich_timeout_error(command, timeout, last_result)
|
|
165
|
+
except Exception as e:
|
|
166
|
+
last_result = {"command": command, "success": False, "error": str(e)}
|
|
167
|
+
|
|
168
|
+
# 如果是超时(不抛异常时由 _run_once 返回 success=False 且 error 含"超时"),
|
|
169
|
+
# 不再重试,附加建议后直接返回。
|
|
170
|
+
err_msg = (last_result or {}).get("error", "") or ""
|
|
171
|
+
if not last_result.get("success") and "超时" in err_msg:
|
|
172
|
+
return self._enrich_timeout_error(command, timeout, last_result)
|
|
173
|
+
|
|
174
|
+
if last_result.get("success"):
|
|
175
|
+
return last_result
|
|
176
|
+
|
|
177
|
+
# 失败:除最后一次外都退避
|
|
178
|
+
if attempt < self.MAX_RETRIES:
|
|
179
|
+
time.sleep(self.BASE_BACKOFF * (2 ** attempt))
|
|
180
|
+
|
|
181
|
+
return last_result
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
联网搜索工具
|
|
4
|
+
使用 Bing 后端搜索信息(国内可用),避免尝试被墙的其他搜索引擎
|
|
5
|
+
"""
|
|
6
|
+
from .base import Tool
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class WebSearchTool(Tool):
|
|
10
|
+
"""联网搜索工具(需要安装 ddgs)。"""
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def name(self) -> str:
|
|
14
|
+
return "web_search"
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def description(self) -> str:
|
|
18
|
+
return "联网搜索信息,返回搜索结果列表。检索数量由 AI 自行决定,无需询问用户。"
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def parameters(self) -> dict:
|
|
22
|
+
return {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"properties": {
|
|
25
|
+
"query": {"type": "string", "description": "搜索关键词"},
|
|
26
|
+
"num": {
|
|
27
|
+
"type": "integer",
|
|
28
|
+
"description": "返回结果数量,由 AI 根据查询复杂度自行决定(一般 3-10 条)"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"required": ["query", "num"]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def execute(self, query: str, num: int = 5) -> dict:
|
|
35
|
+
"""执行搜索"""
|
|
36
|
+
try:
|
|
37
|
+
try:
|
|
38
|
+
from ddgs import DDGS
|
|
39
|
+
except ImportError:
|
|
40
|
+
from duckduckgo_search import DDGS
|
|
41
|
+
|
|
42
|
+
# 限制 num 在合理范围,避免 AI 误传过大值
|
|
43
|
+
num = max(1, min(int(num), 20))
|
|
44
|
+
|
|
45
|
+
with DDGS(timeout=10) as ddgs:
|
|
46
|
+
results = list(ddgs.text(
|
|
47
|
+
query,
|
|
48
|
+
max_results=num,
|
|
49
|
+
backend="bing"
|
|
50
|
+
))
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
"success": True,
|
|
54
|
+
"query": query,
|
|
55
|
+
"results": [
|
|
56
|
+
{"title": r["title"], "url": r["href"], "snippet": r["body"]}
|
|
57
|
+
for r in results
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
except ImportError:
|
|
61
|
+
return {"success": False, "error": "请安装 ddgs: pip install ddgs"}
|
|
62
|
+
except Exception as e:
|
|
63
|
+
return {"success": False, "error": str(e)}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: abyss-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: 终端AI开发助手
|
|
5
|
+
Author: Abyss Team
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Requires-Dist: openai>=1.0.0
|
|
8
|
+
Requires-Dist: click>=8.0.0
|
|
9
|
+
Requires-Dist: prompt-toolkit>=3.0.0
|
|
10
|
+
Requires-Dist: ddgs>=9.0.0
|
|
11
|
+
Dynamic: requires-python
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
abyss/__init__.py,sha256=0Fud8wvwYRa0b0oXRR9WG3IK_UaXGG4nEYn4yattnCM,82
|
|
2
|
+
abyss/ansi_menu.py,sha256=fB2bBYo5UomBsv-Apm_mQccEWQKCW1ilVtW3hZOCcdo,20475
|
|
3
|
+
abyss/api_client.py,sha256=0ajbtOOQ2NAsIDjdZhWWYEsqxjIDR2qo3uzuvzaOxY8,4664
|
|
4
|
+
abyss/config.py,sha256=j_cMCA-t2myZ-vVCRv66XvaUqEgBhZKEqEJ5-fPp-oo,3967
|
|
5
|
+
abyss/custom_input.py,sha256=UazB6SUkQGQClXmYxq4T732chOVkUKQxrFpKqnZZuTU,12002
|
|
6
|
+
abyss/logger.py,sha256=dlX8UGJ7lkruyHDpi-lrF1ykCMf5TROvYyeaqOOS5-k,6320
|
|
7
|
+
abyss/main.py,sha256=tzV9p-uG9bJLqQ69kF5aZO7d5WuroGMC2a62OnD5NNw,31027
|
|
8
|
+
abyss/session.py,sha256=wQIlIG_VtCd40-eenIQNl8SBGNEWHaPgM4W8fo-hYwc,2772
|
|
9
|
+
abyss/commands/__init__.py,sha256=OOLYmwmOx2qszvZuwmKqP-gBiU0w0xWdJ9p3xRGToRo,268
|
|
10
|
+
abyss/commands/slash.py,sha256=DeClT6lM3B9ccY0mqdRI0WpsPI7tZOFDHWfUqc4svWU,2661
|
|
11
|
+
abyss/extensions/__init__.py,sha256=BbbKwSx-OMsGcgIS5Y2u4ZWAjdg-KPcIq8k2Maz-AQ0,516
|
|
12
|
+
abyss/extensions/cli.py,sha256=Xy-TXjmZ3bsdvfYRMPPVqMDn--gs9plF38oc9krjPV0,5400
|
|
13
|
+
abyss/extensions/installer.py,sha256=xfg3QETsBoVtyijm5bPjnHX1nq9om02A_HsJGfOmESA,16620
|
|
14
|
+
abyss/extensions/registry.py,sha256=B9ap3PbkTAeYbXePD7bziA5IbBJFz0sPoUBY8lSIZAI,3850
|
|
15
|
+
abyss/extensions/url_parser.py,sha256=E5l5-eGLhrcZGokyfazfbzX-uz9KYqasg-XRUPVNoX4,2689
|
|
16
|
+
abyss/hooks/__init__.py,sha256=tT1gucCipUuRg8MdLuQ0VBKjB-0iXQJzLbzu-LCvEnQ,274
|
|
17
|
+
abyss/hooks/runner.py,sha256=i0D36SMg29bKC-TJNMpBRPXThtUcZzBKL6xZvEofBhI,4899
|
|
18
|
+
abyss/mcp/__init__.py,sha256=kiNGPmrzGoQvO0jyi_lffDFY4zlVLko8592R9YsiGG8,316
|
|
19
|
+
abyss/mcp/manager.py,sha256=IzjKnQ-_VBU0NUc3sORXwdYityQIuJ2XTIp8CZbYDkg,6977
|
|
20
|
+
abyss/prompts/__init__.py,sha256=nNd2zNTncRphmM0RFsAa4L8i4-2sryvEQ_n9lh1buFA,862
|
|
21
|
+
abyss/skills/__init__.py,sha256=ab1XjEz295VM0r8Le_7NN00WX3ei5V9Yte7rZHyP5PQ,247
|
|
22
|
+
abyss/skills/loader.py,sha256=NSZ678hCDzqRWNMRgznhrtF-kfiPZPE5B-JFVkh2xkc,5651
|
|
23
|
+
abyss/tools/__init__.py,sha256=GwoWzJAn1VMhjsBaRfNQfVwT10_jPW0kiTtoN4sj1ok,442
|
|
24
|
+
abyss/tools/base.py,sha256=gsZPD0MO9_eMUz9mKPHpTpUzt3gn_VWAQDrSBqgyAsw,1089
|
|
25
|
+
abyss/tools/file_edit.py,sha256=Lobs2uz2EPslG2wuah5lBacl1wAJaAV3i2jsoQg1g4Q,1552
|
|
26
|
+
abyss/tools/file_read.py,sha256=--9v-su3cOwpW5xryB-4KF_5_QE-fkzmiq3TT_FDLyk,1677
|
|
27
|
+
abyss/tools/file_write.py,sha256=5eD1cIT4wGSbdwA4Lsio3d02Fzt1clvu-SlGjxC9l9U,1386
|
|
28
|
+
abyss/tools/registry.py,sha256=4q8TeA7B90LIPO6W63gF06Or-NKwAx8GtgvtB_4Ili4,3868
|
|
29
|
+
abyss/tools/shell_exec.py,sha256=XTWHNEEzOzatPj4qv_o0Su6RAzx-YdPQ-Yq8TCT7Zrs,7149
|
|
30
|
+
abyss/tools/web_search.py,sha256=cYp9p9YAdY48pPM7lgoK3AgorNSmWM3DW4Q-M4512Vs,1978
|
|
31
|
+
abyss_cli-0.1.0.dist-info/METADATA,sha256=S8j3aq_l2ejW1hpzZNLj1hGumnNPswLm-Zv4AdOpIoY,282
|
|
32
|
+
abyss_cli-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
33
|
+
abyss_cli-0.1.0.dist-info/entry_points.txt,sha256=j_8IOp0dIAhyarOiN0v0G0wznEJV7F1Iy3GldgxN4FY,41
|
|
34
|
+
abyss_cli-0.1.0.dist-info/top_level.txt,sha256=66PtKGxE4PwMGB48A5isqqRFciZhenwLMiZugJCC8SE,6
|
|
35
|
+
abyss_cli-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
abyss
|