mini-agent-cli 0.2.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.
mini_agent/skills.py ADDED
@@ -0,0 +1,138 @@
1
+ """Agent Skills:一个目录 + SKILL.md,和 Claude Code / Codex / opencode 同一个格式。
2
+
3
+ <name>/SKILL.md frontmatter 写 name + description,正文是给模型的流程
4
+ <name>/其他文件 脚本、模板、参考资料。正文里让模型用 bash / read 去用它们
5
+
6
+ 启动时只把 name + description 放进 system prompt;模型觉得用得上,
7
+ 才调 skill(name) 把正文读进来。装 100 个 skill 的成本是 100 行描述,不是 100 篇正文。
8
+
9
+ 查找目录(同名先到先得,所以项目的覆盖全局的):
10
+ 项目:从当前目录往上到 git 根目录,每层的 .agents/skills、.claude/skills、.opencode/skills
11
+ 全局:~/.config/mini-agent/skills、~/.agents/skills、~/.claude/skills、~/.config/opencode/skills
12
+ 内置:mini_agent/skills(mini-agent 自己的几个,比如改配置)
13
+
14
+ 单独跑可以看装了哪些:uv run python -m mini_agent.skills
15
+ """
16
+
17
+ from dataclasses import dataclass
18
+ from pathlib import Path
19
+
20
+ from .config import project_dirs
21
+
22
+ PROJECT_SUBDIRS = (".agents/skills", ".claude/skills", ".opencode/skills")
23
+ GLOBAL_DIRS = ("~/.config/mini-agent/skills", "~/.agents/skills", "~/.claude/skills", "~/.config/opencode/skills")
24
+ BUILTIN_DIR = Path(__file__).resolve().parent / "skills"
25
+ FALSE = {"false", "no", "0", "off"}
26
+ CATALOG_DESC_LIMIT = 160
27
+
28
+
29
+ def skill_dirs():
30
+ project = [d / sub for d in reversed(project_dirs()) for sub in PROJECT_SUBDIRS]
31
+ return [p for p in [*project, *(Path(g).expanduser() for g in GLOBAL_DIRS), BUILTIN_DIR] if p.is_dir()]
32
+
33
+
34
+ def parse_front_matter(text):
35
+ """--- 包起来的 key: value,外加 YAML 的 > / | 多行块。
36
+
37
+ 嵌套和列表不支持(缩进的子键直接忽略)—— 不值得为它引一个 yaml 依赖。
38
+ """
39
+ if not text.startswith("---"):
40
+ return {}, text
41
+ _, _, rest = text.partition("\n")
42
+ block, separator, body = rest.partition("\n---")
43
+ if not separator:
44
+ return {}, text
45
+
46
+ meta, block_key, joiner = {}, None, " "
47
+ for line in block.splitlines():
48
+ indented = line[:1] in (" ", "\t")
49
+ if block_key and (indented or not line.strip()):
50
+ meta[block_key] = (meta[block_key] + joiner + line.strip()).strip()
51
+ continue
52
+ block_key = None
53
+ key, sep, value = line.partition(":")
54
+ if not sep or indented:
55
+ continue
56
+ value = value.strip()
57
+ if value in (">", "|", ">-", "|-", ">+", "|+"):
58
+ block_key, joiner = key.strip(), "\n" if value[0] == "|" else " "
59
+ meta[block_key] = ""
60
+ else:
61
+ meta[key.strip()] = value.strip("\"'")
62
+ return meta, body.partition("\n")[2].lstrip("\n")
63
+
64
+
65
+ @dataclass
66
+ class Skill:
67
+ name: str
68
+ description: str
69
+ body: str
70
+ directory: Path
71
+
72
+ def render(self):
73
+ # 带上目录绝对路径:正文里写 scripts/x.sh 时,模型得知道相对的是哪儿
74
+ return f"# skill: {self.name}\n(skill 目录:{self.directory},正文里的相对路径都相对它)\n\n{self.body}"
75
+
76
+
77
+ def load_skills(directories=None):
78
+ """返回 ({name: Skill}, 跳过原因)。坏掉的 skill 只是少一个,不影响启动。"""
79
+ skills, notes, seen = {}, [], set()
80
+ for root in directories or skill_dirs():
81
+ for child in sorted(root.iterdir()):
82
+ manifest = child / "SKILL.md"
83
+ if not manifest.is_file() or child.name in seen:
84
+ continue
85
+ seen.add(child.name)
86
+ try:
87
+ meta, body = parse_front_matter(manifest.read_text(encoding="utf-8"))
88
+ except OSError as error:
89
+ notes.append(f"{child.name}:读不了({error})")
90
+ continue
91
+ name = meta.get("name") or child.name
92
+ if any(str(meta.get(k, "")).lower() in FALSE for k in ("enabled", "active", "isActive")):
93
+ notes.append(f"{name}:已关闭")
94
+ elif not meta.get("description"):
95
+ notes.append(f"{name}:没写 description,模型不知道什么时候用它")
96
+ else:
97
+ skills.setdefault(name, Skill(name, meta["description"], body, child.resolve()))
98
+ return skills, notes
99
+
100
+
101
+ def _clip(text, limit=CATALOG_DESC_LIMIT):
102
+ text = " ".join(text.split())
103
+ return text if len(text) <= limit else text[:limit] + "…"
104
+
105
+
106
+ def catalog(skills):
107
+ """注入 system prompt 的清单。正文一个字都不在这儿。"""
108
+ if not skills:
109
+ return ""
110
+ lines = "\n".join(f"- {s.name}:{_clip(s.description)}" for s in skills.values())
111
+ return ("\n\n## Skills\n动手之前先看有没有匹配的 skill,有就先调 skill 工具读出流程再照着做:\n" + lines)
112
+
113
+
114
+ SKILL_SCHEMA = {
115
+ "name": "skill",
116
+ "description": "读取一个 skill 的完整流程。开始任务前,如果 Skills 清单里有匹配的,先调这个。",
117
+ "parameters": {
118
+ "type": "object",
119
+ "properties": {"name": {"type": "string", "description": "skill 名字,必须来自清单"}},
120
+ "required": ["name"],
121
+ },
122
+ }
123
+
124
+
125
+ def main():
126
+ skills, notes = load_skills()
127
+ print("目录:\n" + "\n".join(f" {d}" for d in skill_dirs()) + "\n")
128
+ print(f"skill {len(skills)} 个:")
129
+ for s in skills.values():
130
+ print(f" {s.name:<24} {_clip(s.description, 60)}")
131
+ if notes:
132
+ print(f"\n跳过的({len(notes)} 个):")
133
+ for note in notes:
134
+ print(f" {note}")
135
+
136
+
137
+ if __name__ == "__main__":
138
+ main()
mini_agent/tools.py ADDED
@@ -0,0 +1,137 @@
1
+ """内置工具。只管干活,要不要先问用户由 agent.py 按 permission 决定。
2
+
3
+ awk / sed / jq 这类不单独做工具 —— bash 里直接用,模型比我们更熟它们的参数。
4
+ grep / glob 单独做,是因为它们只读、不用每次问,而 bash 每次都要问。
5
+ """
6
+
7
+ import difflib
8
+ import os
9
+ import shutil
10
+ import subprocess
11
+ from pathlib import Path
12
+
13
+ READ_LINES = 2000
14
+ MAX_LINE = 2000 # 单行超过这么长就截断(压缩过的 js 之类)
15
+ SEARCH_LIMIT = 200 # grep / glob 最多返回这么多条
16
+ SKIP_DIRS = {".git", "node_modules", ".venv", "__pycache__", "dist", "build", ".next", "target"}
17
+
18
+
19
+ def bash(command, timeout=120):
20
+ try:
21
+ result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=timeout)
22
+ except subprocess.TimeoutExpired:
23
+ return f"命令超过 {timeout} 秒未结束,已终止。"
24
+ output = (result.stdout + result.stderr).strip()
25
+ return output or f"(无输出,退出码 {result.returncode})"
26
+
27
+
28
+ def read(path, offset=1, limit=READ_LINES):
29
+ lines = Path(path).expanduser().read_text(encoding="utf-8", errors="replace").splitlines()
30
+ start = max(offset, 1) - 1
31
+ chunk = lines[start:start + limit]
32
+ out = "\n".join(f"{i:>6}\t{line[:MAX_LINE]}" for i, line in enumerate(chunk, start + 1))
33
+ if start + limit < len(lines):
34
+ out += f"\n…(共 {len(lines)} 行,用 offset={start + limit + 1} 继续读)"
35
+ return out or "(空文件)"
36
+
37
+
38
+ def write(path, content):
39
+ target = Path(path).expanduser()
40
+ target.parent.mkdir(parents=True, exist_ok=True)
41
+ target.write_text(content, encoding="utf-8")
42
+ return f"已写入 {path}({len(content.splitlines())} 行)"
43
+
44
+
45
+ def edit(path, old_string, new_string, replace_all=False):
46
+ target = Path(path).expanduser()
47
+ text = target.read_text(encoding="utf-8")
48
+ count = text.count(old_string)
49
+ if count == 0:
50
+ return "错误:old_string 在文件里找不到,先 read 确认原文(注意缩进和空白)"
51
+ if count > 1 and not replace_all:
52
+ return f"错误:old_string 出现了 {count} 次,多带几行上下文让它唯一,或者设 replace_all=true"
53
+ target.write_text(text.replace(old_string, new_string), encoding="utf-8")
54
+ return f"已修改 {path}(替换 {count if replace_all else 1} 处)"
55
+
56
+
57
+ def grep(pattern, path=".", glob=None, ignore_case=False):
58
+ """有 ripgrep 用 ripgrep,没有就退回 grep -rn。"""
59
+ if shutil.which("rg"):
60
+ cmd = ["rg", "-n", "--no-heading", "--max-columns", "300", pattern, path]
61
+ cmd[1:1] = ["-i"] * ignore_case + (["-g", glob] if glob else [])
62
+ else:
63
+ cmd = ["grep", "-rnE", *(["-i"] * ignore_case), *(f"--exclude-dir={d}" for d in SKIP_DIRS),
64
+ *([f"--include={glob}"] if glob else []), pattern, path]
65
+ result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
66
+ if result.returncode > 1:
67
+ return f"错误:{result.stderr.strip()}"
68
+ lines = result.stdout.splitlines()
69
+ more = f"\n…(共 {len(lines)} 条,只显示前 {SEARCH_LIMIT} 条,缩小范围再搜)" if len(lines) > SEARCH_LIMIT else ""
70
+ return "\n".join(lines[:SEARCH_LIMIT]) + more if lines else "(没有匹配)"
71
+
72
+
73
+ def glob(pattern, path="."):
74
+ """按修改时间倒序,最近改过的在前。"""
75
+ root = Path(path).expanduser()
76
+ hits = [p for p in root.glob(pattern) if not SKIP_DIRS & set(p.relative_to(root).parts)]
77
+ hits.sort(key=lambda p: p.stat().st_mtime, reverse=True)
78
+ more = f"\n…(共 {len(hits)} 个,只显示前 {SEARCH_LIMIT} 个)" if len(hits) > SEARCH_LIMIT else ""
79
+ return "\n".join(str(p) for p in hits[:SEARCH_LIMIT]) + more if hits else "(没有匹配)"
80
+
81
+
82
+ def preview(name, args, max_lines=40):
83
+ """write / edit 审批时给人看的 diff。"""
84
+ path = Path(args.get("path", "")).expanduser()
85
+ old = path.read_text(encoding="utf-8", errors="replace") if path.is_file() else ""
86
+ if name == "write":
87
+ new = args.get("content", "")
88
+ else:
89
+ count = -1 if args.get("replace_all") else 1
90
+ new = old.replace(args.get("old_string", ""), args.get("new_string", ""), count)
91
+ diff = list(difflib.unified_diff(old.splitlines(), new.splitlines(), str(path), str(path), lineterm="", n=2))
92
+ if len(diff) > max_lines:
93
+ diff = diff[:max_lines] + [f"…(diff 共 {len(diff)} 行)"]
94
+ return "\n".join(diff) or "(内容没有变化)"
95
+
96
+
97
+ TOOLS = {f.__name__: f for f in (bash, read, write, edit, grep, glob)}
98
+
99
+
100
+ def _schema(name, description, properties, required):
101
+ return {"name": name, "description": description,
102
+ "parameters": {"type": "object", "properties": properties, "required": required}}
103
+
104
+
105
+ _PATH = {"type": "string", "description": "文件路径,相对工作目录或绝对路径"}
106
+
107
+ TOOL_SCHEMAS = [
108
+ _schema("bash", "执行 shell 命令(zsh/bash),返回 stdout+stderr。每次都是新进程,cd 不会保留。"
109
+ "适合 git、构建、测试、awk/sed/jq 等。只读的搜索优先用 grep / glob。", {
110
+ "command": {"type": "string"},
111
+ "timeout": {"type": "integer", "description": "秒,默认 120"},
112
+ }, ["command"]),
113
+ _schema("read", f"读文本文件,带行号。默认从第 1 行读 {READ_LINES} 行,大文件用 offset 分段。", {
114
+ "path": _PATH,
115
+ "offset": {"type": "integer", "description": "起始行号,从 1 开始"},
116
+ "limit": {"type": "integer", "description": "读多少行"},
117
+ }, ["path"]),
118
+ _schema("write", "创建或整体覆盖文件。改已有文件优先用 edit。", {
119
+ "path": _PATH, "content": {"type": "string", "description": "完整内容"},
120
+ }, ["path", "content"]),
121
+ _schema("edit", "精确字符串替换。old_string 必须和原文一字不差(含缩进)且唯一;read 输出里的行号前缀不是原文。", {
122
+ "path": _PATH,
123
+ "old_string": {"type": "string"},
124
+ "new_string": {"type": "string"},
125
+ "replace_all": {"type": "boolean", "description": "替换全部出现,默认 false"},
126
+ }, ["path", "old_string", "new_string"]),
127
+ _schema("grep", "按正则搜文件内容,返回 文件:行号:内容。", {
128
+ "pattern": {"type": "string", "description": "正则"},
129
+ "path": {"type": "string", "description": "目录或文件,默认当前目录"},
130
+ "glob": {"type": "string", "description": "只搜匹配的文件,如 *.py"},
131
+ "ignore_case": {"type": "boolean"},
132
+ }, ["pattern"]),
133
+ _schema("glob", "按通配符找文件,如 **/*.py,最近修改的在前。", {
134
+ "pattern": {"type": "string"},
135
+ "path": {"type": "string", "description": "从哪个目录开始,默认当前目录"},
136
+ }, ["pattern"]),
137
+ ]
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.3
2
+ Name: mini-agent-cli
3
+ Version: 0.2.0
4
+ Summary: 终端里的编码 Agent:配置驱动,支持 OpenAI Chat / Responses 与 Anthropic 协议、MCP、Agent Skills
5
+ Keywords: agent,llm,mcp,cli,coding-agent,skills
6
+ Author: zhaomo08
7
+ Classifier: Environment :: Console
8
+ Classifier: Operating System :: MacOS
9
+ Classifier: Operating System :: POSIX :: Linux
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Topic :: Software Development
12
+ Requires-Dist: mcp>=2.1.1
13
+ Requires-Python: >=3.13
14
+ Project-URL: Repository, https://github.com/zhaomo08/mini-agent
15
+ Description-Content-Type: text/markdown
16
+
17
+ # mini-agent
18
+
19
+ 终端里的编码 Agent,面向会写配置的开发者。模型、MCP、权限都写在一个 `mini-agent.json` 里,
20
+ skill 用和 Claude Code / Codex / opencode 相同的 `SKILL.md` 格式。唯一的依赖是 `mcp`。
21
+
22
+ ```
23
+ Agent = LLM + 工具 + 循环
24
+ ```
25
+
26
+ ## 安装
27
+
28
+ 三种方式任选,装完都是 `mini-agent` 命令。需要先有 [uv](https://docs.astral.sh/uv/)(`curl -LsSf https://astral.sh/uv/install.sh | sh` 或 `brew install uv`),它会自动准备 Python 3.13:
29
+
30
+ ```bash
31
+ uv tool install mini-agent-cli # PyPI(包名带 -cli,命令是 mini-agent)
32
+ npm i -g @zhaomo08/mini-agent # npm(启动器,内部用 uvx 跑同版本的 PyPI 包)
33
+ uvx --from mini-agent-cli mini-agent # 不安装,直接跑
34
+ ```
35
+
36
+ 首次运行会把包里的 `mini-agent.example.json` 复制到 `~/.config/mini-agent/mini-agent.json`,改这份就行。
37
+
38
+ 开发时用 `uv tool install -e .`,改代码即时生效。
39
+
40
+ ## 使用
41
+
42
+ ```bash
43
+ mini-agent # 交互模式,在哪个目录启动就在哪干活
44
+ mini-agent -p "这个仓库是干什么的" > out.md # 问一句就退出;stdout 只有答案,思考和工具进度走 stderr
45
+ mini-agent -m bailian-anthropic/qwen3.8-flash
46
+ mini-agent --yes # ask 类操作全部放行(deny 仍然禁止)
47
+ ```
48
+
49
+ | 命令 | 作用 |
50
+ |---|---|
51
+ | `/model [provider/model]` | 查看或切换模型。对话保留,可以跨厂商、跨协议 |
52
+ | `/reload` | 重新读配置、skills、MCP,对话保留 |
53
+ | `/img [路径]` | 挂一张图,不带路径从剪贴板取;也可以直接把图片文件拖进来 |
54
+ | `/clear` `/tools` `/help` | |
55
+ | Ctrl+C | 回答中:打断这一轮(包括审批提示);输入时:清空当前行 |
56
+ | Ctrl+D / `exit` | 退出 |
57
+
58
+ 输出是流式的,思考过程以灰色显示。
59
+
60
+ ## 配置:mini-agent.json
61
+
62
+ 完整带注释的示例见 [mini_agent/mini-agent.example.json](mini_agent/mini-agent.example.json)。
63
+
64
+ | 位置 | 作用 |
65
+ |---|---|
66
+ | `~/.config/mini-agent/mini-agent.json` | 全局(`$MINI_AGENT_CONFIG` 可改) |
67
+ | 项目里的 `mini-agent.json` | 从 git 根目录到当前目录逐层深度合并,越近优先级越高 |
68
+
69
+ ```jsonc
70
+ {
71
+ "model": "deepseek/deepseek-flash",
72
+ "provider": {
73
+ "deepseek": { "api": "openai-chat", "baseURL": "https://api.deepseek.com", "apiKey": "{env:DEEPSEEK_API_KEY}" }
74
+ },
75
+ "mcp": {
76
+ "memory": { "type": "local", "command": ["npx", "-y", "@modelcontextprotocol/server-memory"] },
77
+ "amap": { "type": "remote", "url": "https://mcp.amap.com/mcp?key={env:AMAP_MAPS_API_KEY}" }
78
+ },
79
+ "permission": { "bash": "ask", "edit": "ask", "external": "ask", "mcp": "ask" }
80
+ }
81
+ ```
82
+
83
+ **协议**(`api` 字段),baseURL 的写法和各家 SDK 一致:
84
+
85
+ | api | 请求 | baseURL 示例 |
86
+ |---|---|---|
87
+ | `openai-chat` | `POST {baseURL}/chat/completions` | `https://api.deepseek.com` |
88
+ | `openai-responses` | `POST {baseURL}/responses` | `https://api.openai.com/v1` |
89
+ | `anthropic` | `POST {baseURL}/v1/messages` | `https://api.anthropic.com` |
90
+
91
+ `options` 原样并进请求体(`enable_thinking`、`max_tokens`、`temperature`…),
92
+ `models.<id>.options` 只对某个模型生效。密钥写 `{env:变量名}`;配置文件支持整行 `//` 注释。
93
+
94
+ **让模型改配置**:直接说「加一个 xxx MCP」。内置的 `mini-agent-config` skill 会引导模型
95
+ 用 edit 改文件、校验 JSON,然后你输入 `/reload` 就生效。
96
+
97
+ ## 工具
98
+
99
+ | 工具 | 说明 | 权限类别 |
100
+ |---|---|---|
101
+ | `bash` | 执行命令;awk / sed / jq 都走它 | `bash` |
102
+ | `read` | 带行号,默认 2000 行,`offset` 分段 | 工作目录外归 `external` |
103
+ | `write` / `edit` | 整体写入 / 精确字符串替换,确认时显示 diff | `edit` |
104
+ | `grep` | 有 ripgrep 就用 ripgrep,没有就用 grep -rn | 工作目录外归 `external` |
105
+ | `glob` | 按通配符找文件,最近修改的在前 | 工作目录外归 `external` |
106
+ | `skill` | 按需读取 skill 正文 | — |
107
+ | MCP 工具 | 名字以 create / delete / send / run … 开头的 | `mcp` |
108
+
109
+ 权限:`ask` 先问,`allow` 直接放行,`deny` 禁止。非交互模式(管道或 `-p`)下没加 `--yes` 时,ask 一律按拒绝处理。
110
+
111
+ ## Skills
112
+
113
+ 一个目录加一个 `SKILL.md`(frontmatter 写 `name`、`description`),脚本和参考资料放在同一目录,
114
+ 正文里让模型用 bash / read 去调用。启动时只把描述放进 system prompt,正文由模型按需读取。
115
+
116
+ 查找顺序,同名的先找到先用:
117
+
118
+ 1. 项目:从当前目录往上到 git 根目录,每层的 `.agents/skills`、`.claude/skills`、`.opencode/skills`
119
+ 2. 全局:`~/.config/mini-agent/skills`、`~/.agents/skills`、`~/.claude/skills`、`~/.config/opencode/skills`
120
+ 3. 内置:`mini_agent/skills/`
121
+
122
+ ## 中途换模型
123
+
124
+ 参考 pi-ai 的 cross-provider handoff 设计。历史用中立格式保存,每条 assistant 消息都记着它是由哪个协议、哪个模型产生的:
125
+
126
+ - **同一个模型产生的**:原样回放协议原文,thinking 签名、加密 reasoning 都不会丢
127
+ - **其他模型产生的**:只用中立字段重建。thinking 转成 `<thinking>` 文本,签名丢弃,
128
+ 工具调用 id 规范成 `[A-Za-z0-9_-]{1,64}`(Anthropic 的要求)
129
+ - **中断后留下的"有调用没结果"的工具调用**:补一条占位结果,保证每家接口都接受这段历史
130
+
131
+ ## 上下文预算
132
+
133
+ - 工具结果超过 3 万字符就截断
134
+ - 只有最新一条消息保留图片
135
+ - 历史超过 40 万字符,就从最旧的一轮开始整轮丢弃
136
+
137
+ ## 代码
138
+
139
+ ```
140
+ mini_agent/
141
+ __main__.py 命令行 / REPL agent.py 装配、权限、循环、上下文预算
142
+ config.py 配置加载与合并 llm.py 三种协议,标准库 urllib
143
+ tools.py 内置工具 mcp.py MCP 连接
144
+ skills.py skill 发现与加载 images.py 剪贴板 / 文件 → 多模态
145
+ test_agent.py 不调模型的自检:uv run python test_agent.py
146
+ ```
147
+
148
+ 排查用:`uv run python -m mini_agent.mcp`、`uv run python -m mini_agent.skills`。
149
+
150
+ 早期的教学版(step1–3、extras/)在 git 历史里:`git show c619ecb`。
151
+
152
+ ## 发布
153
+
154
+ 版本号要在三个地方保持一致:`pyproject.toml`、`npm/package.json` 和 git tag。推送 tag 后,由
155
+ `.github/workflows/release.yml` 依次完成:检查版本号 → 自检 → 验证 wheel 能装 → 发布 PyPI → 发布 npm。
156
+ 两边都用 Trusted Publishing(OIDC),仓库里不存任何 token。
157
+
158
+ ```bash
159
+ # 改好两处 version 之后
160
+ git tag v0.2.1 && git push origin v0.2.1
161
+ ```
@@ -0,0 +1,15 @@
1
+ mini_agent/__init__.py,sha256=elfF6MIaCV0bQsVcJEGpfFL1t6-dy-QxshITqDcrwzE,529
2
+ mini_agent/__main__.py,sha256=YVV3pks_W3IYo8QODLVwtoUjA1hHsWvL1HgozhXW9L0,6368
3
+ mini_agent/agent.py,sha256=eD-GHLCWXIoBdNqPcgc0xcbkqd7ASjp4V52iz7j2flM,12140
4
+ mini_agent/config.py,sha256=W-VsYdwoIShYKCErJHdlqQ3-g2ratatjJG0IxMxbWyc,2709
5
+ mini_agent/images.py,sha256=rz2krDAReKJRLlNrVxvyCtQ7nt7h0_U3v0ii4JxMH1Q,4800
6
+ mini_agent/llm.py,sha256=7zo5OH7WW9kAV0YZycSzPuXvl2sxAzFJGo4Lis4V4Lk,15328
7
+ mini_agent/mcp.py,sha256=wX8tzPj1VmDeJGP9Zcqef0HmTgXyZVLP86sTaXBZzmM,3095
8
+ mini_agent/mini-agent.example.json,sha256=tB_8QOS2y93N1b6dl-vz1ITiUPmO7ctldOw7yeCnxrM,3095
9
+ mini_agent/skills/mini-agent-config/SKILL.md,sha256=M1XocEwS3VRAE_08bsmC0PQwmr-mWcGmCkNgz6QjkPM,2028
10
+ mini_agent/skills.py,sha256=1tyE4WqwT8pLleCxXJYFQmPKLmU3VN3edySKdCvfjQI,5490
11
+ mini_agent/tools.py,sha256=e2rKyWQgX-9iwQABhuOt-9WnzvtimfL2LZFZFqiFiJU,6800
12
+ mini_agent_cli-0.2.0.dist-info/WHEEL,sha256=e4_1dyBeezi8ZjfxrZ3bnVOxFDa3ksqVqH0jTHkUZ3k,81
13
+ mini_agent_cli-0.2.0.dist-info/entry_points.txt,sha256=sEuFhw0cBJk-JDwSo5DQLK6fS_r6t3-cibeXPYg7DP4,57
14
+ mini_agent_cli-0.2.0.dist-info/METADATA,sha256=bFxDySrfsuryaOD-vJP_raeY8L3X2nBbOoiMZgjpqCU,7220
15
+ mini_agent_cli-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.12.19
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ mini-agent = mini_agent.__main__:main
3
+