pythonclaw 0.6.4__tar.gz → 0.6.5__tar.gz
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.
- {pythonclaw-0.6.4/pythonclaw.egg-info → pythonclaw-0.6.5}/PKG-INFO +1 -1
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pyproject.toml +1 -1
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/skillhub.py +61 -81
- {pythonclaw-0.6.4 → pythonclaw-0.6.5/pythonclaw.egg-info}/PKG-INFO +1 -1
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/LICENSE +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/MANIFEST.in +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/README.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/__init__.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/__main__.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/channels/discord_bot.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/channels/telegram_bot.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/channels/whatsapp_bot.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/config.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/__init__.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/agent.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/compaction.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/knowledge/rag.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/llm/anthropic_client.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/llm/base.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/llm/gemini_client.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/llm/openai_compatible.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/llm/response.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/memory/manager.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/memory/storage.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/persistent_agent.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/retrieval/__init__.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/retrieval/chunker.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/retrieval/dense.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/retrieval/fusion.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/retrieval/reranker.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/retrieval/retriever.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/retrieval/sparse.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/session_store.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/skill_loader.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/tools.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/core/utils.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/daemon.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/init.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/main.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/onboard.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/scheduler/cron.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/scheduler/heartbeat.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/server.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/session_manager.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/persona/demo_persona.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/communication/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/communication/email/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/communication/email/send_email.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/communication/slack/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/communication/slack/slack_api.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/csv_analyzer/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/csv_analyzer/analyze.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/finance/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/finance/fetch_quote.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/news/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/news/search_news.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/pdf_reader/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/pdf_reader/read_pdf.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/scraper/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/scraper/scrape.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/weather/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/weather/weather.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/youtube/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/youtube/youtube_info.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/dev/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/dev/code_runner/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/dev/code_runner/run_code.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/dev/github/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/dev/github/gh.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/dev/http_request/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/dev/http_request/request.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/google/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/google/workspace/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/google/workspace/check_setup.sh +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/media/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/media/image_gen/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/media/image_gen/generate.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/media/spotify/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/media/spotify/spotify_ctl.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/media/tts/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/media/tts/speak.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/meta/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/meta/skill_creator/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/notion/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/notion/notion_api.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/obsidian/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/obsidian/obsidian_vault.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/trello/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/trello/trello_api.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/change_persona/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/change_setting/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/change_setting/update_config.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/change_soul/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/model_usage/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/model_usage/usage_stats.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/onboarding/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/onboarding/write_identity.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/random/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/random/random_util.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/session_logs/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/session_logs/search_sessions.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/time/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/time/time_util.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/text/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/text/translator/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/text/translator/translate.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/web/CATEGORY.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/web/summarize/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/web/summarize/summarize_url.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/web/tavily/SKILL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/soul/SOUL.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/tools/TOOLS.md +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/web/__init__.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/web/app.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/web/static/favicon.png +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/web/static/index.html +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/web/static/logo.png +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw.egg-info/SOURCES.txt +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw.egg-info/dependency_links.txt +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw.egg-info/entry_points.txt +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw.egg-info/requires.txt +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw.egg-info/top_level.txt +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/setup.cfg +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/tests/test_compaction.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/tests/test_persistence.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/tests/test_rag_hybrid.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/tests/test_skills.py +0 -0
- {pythonclaw-0.6.4 → pythonclaw-0.6.5}/tests/test_soul.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonclaw
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.5
|
|
4
4
|
Summary: OpenClaw reimagined in pure Python — autonomous AI agent with memory, RAG, skills, web dashboard, and multi-channel support.
|
|
5
5
|
Author-email: Eric Wang <wangchen2007915@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pythonclaw"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.5"
|
|
8
8
|
description = "OpenClaw reimagined in pure Python — autonomous AI agent with memory, RAG, skills, web dashboard, and multi-channel support."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -15,10 +15,14 @@ Available ClawHub endpoints
|
|
|
15
15
|
GET /api/certified — security-verified skills
|
|
16
16
|
GET /api/stats — platform statistics
|
|
17
17
|
GET /api/health — API status
|
|
18
|
+
|
|
19
|
+
Skill download (full ZIP with SKILL.md + assets):
|
|
20
|
+
GET https://wry-manatee-359.convex.site/api/v1/download?slug=SLUG
|
|
18
21
|
"""
|
|
19
22
|
|
|
20
23
|
from __future__ import annotations
|
|
21
24
|
|
|
25
|
+
import io
|
|
22
26
|
import json
|
|
23
27
|
import logging
|
|
24
28
|
import os
|
|
@@ -26,12 +30,14 @@ import re
|
|
|
26
30
|
import ssl
|
|
27
31
|
import urllib.error
|
|
28
32
|
import urllib.request
|
|
33
|
+
import zipfile
|
|
29
34
|
from typing import Any
|
|
30
35
|
|
|
31
36
|
logger = logging.getLogger(__name__)
|
|
32
37
|
|
|
33
38
|
CLAWHUB_API = "https://topclawhubskills.com/api"
|
|
34
39
|
CLAWHUB_WEB = "https://clawhub.com"
|
|
40
|
+
CLAWHUB_DOWNLOAD = "https://wry-manatee-359.convex.site/api/v1/download"
|
|
35
41
|
|
|
36
42
|
|
|
37
43
|
def _get_ssl_ctx() -> ssl.SSLContext:
|
|
@@ -128,26 +134,16 @@ def browse(
|
|
|
128
134
|
|
|
129
135
|
|
|
130
136
|
def get_skill_detail(skill_id: str) -> dict | None:
|
|
131
|
-
"""Fetch
|
|
132
|
-
|
|
133
|
-
ClawHub search results already contain summary info. For full
|
|
134
|
-
instructions, the skill must be installed (``clawhub install``).
|
|
135
|
-
We return whatever metadata we have from the listing.
|
|
136
|
-
"""
|
|
137
|
+
"""Fetch metadata for a skill from ClawHub search API."""
|
|
137
138
|
try:
|
|
138
139
|
result = _api_get("/search", params={"q": skill_id})
|
|
139
140
|
data = result.get("data", [])
|
|
140
141
|
for s in data:
|
|
141
142
|
if s.get("slug") == skill_id:
|
|
142
|
-
|
|
143
|
-
normalized["skill_md"] = _build_skill_md(s)
|
|
144
|
-
return normalized
|
|
143
|
+
return _normalize([s])[0]
|
|
145
144
|
|
|
146
145
|
if data:
|
|
147
|
-
|
|
148
|
-
normalized = _normalize([s])[0]
|
|
149
|
-
normalized["skill_md"] = _build_skill_md(s)
|
|
150
|
-
return normalized
|
|
146
|
+
return _normalize([data[0]])[0]
|
|
151
147
|
except Exception as exc:
|
|
152
148
|
logger.warning("ClawHub detail fetch failed for '%s': %s", skill_id, exc)
|
|
153
149
|
|
|
@@ -180,41 +176,19 @@ def verify_api() -> dict:
|
|
|
180
176
|
|
|
181
177
|
# ── Install ───────────────────────────────────────────────────────────────────
|
|
182
178
|
|
|
183
|
-
def
|
|
184
|
-
"""
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
"---",
|
|
197
|
-
"",
|
|
198
|
-
f"# {name}",
|
|
199
|
-
"",
|
|
200
|
-
]
|
|
201
|
-
if author:
|
|
202
|
-
lines.append(f"*By @{author} on ClawHub*")
|
|
203
|
-
lines.append("")
|
|
204
|
-
lines.append(f"Source: {CLAWHUB_WEB}/skills/{slug}")
|
|
205
|
-
lines.append("")
|
|
206
|
-
lines.append("## Instructions")
|
|
207
|
-
lines.append("")
|
|
208
|
-
lines.append(f"This skill was imported from ClawHub (`{slug}`).")
|
|
209
|
-
lines.append("Refer to the source page for full documentation and usage instructions.")
|
|
210
|
-
lines.append("")
|
|
211
|
-
if summary:
|
|
212
|
-
lines.append("## Description")
|
|
213
|
-
lines.append("")
|
|
214
|
-
lines.append(summary)
|
|
215
|
-
lines.append("")
|
|
216
|
-
|
|
217
|
-
return "\n".join(lines)
|
|
179
|
+
def _download_skill_zip(slug: str) -> bytes:
|
|
180
|
+
"""Download the full skill ZIP from ClawHub's Convex CDN."""
|
|
181
|
+
url = f"{CLAWHUB_DOWNLOAD}?slug={urllib.request.quote(slug)}"
|
|
182
|
+
req = urllib.request.Request(
|
|
183
|
+
url, headers={"User-Agent": "PythonClaw/1.0"},
|
|
184
|
+
)
|
|
185
|
+
try:
|
|
186
|
+
with urllib.request.urlopen(req, timeout=30, context=_get_ssl_ctx()) as resp:
|
|
187
|
+
return resp.read()
|
|
188
|
+
except Exception as exc:
|
|
189
|
+
raise RuntimeError(
|
|
190
|
+
f"Failed to download skill '{slug}' from ClawHub: {exc}"
|
|
191
|
+
) from exc
|
|
218
192
|
|
|
219
193
|
|
|
220
194
|
def install_skill(
|
|
@@ -225,24 +199,16 @@ def install_skill(
|
|
|
225
199
|
) -> str:
|
|
226
200
|
"""Download and install a skill from ClawHub into the local skills directory.
|
|
227
201
|
|
|
202
|
+
Downloads the full ZIP archive from ClawHub (contains SKILL.md plus
|
|
203
|
+
any assets, scripts, references, etc.) and extracts it.
|
|
204
|
+
|
|
228
205
|
Returns the path to the installed skill directory.
|
|
229
206
|
"""
|
|
230
207
|
if target_dir is None:
|
|
231
208
|
from .. import config as _cfg
|
|
232
209
|
target_dir = os.path.join(str(_cfg.PYTHONCLAW_HOME), "context", "skills")
|
|
233
210
|
|
|
234
|
-
|
|
235
|
-
if not skill_md_override:
|
|
236
|
-
detail = get_skill_detail(skill_id)
|
|
237
|
-
if not detail:
|
|
238
|
-
raise RuntimeError(f"Could not fetch skill '{skill_id}' from ClawHub.")
|
|
239
|
-
|
|
240
|
-
skill_md = skill_md_override or detail.get("skill_md", "")
|
|
241
|
-
if not skill_md:
|
|
242
|
-
raise RuntimeError(f"No SKILL.md content found for '{skill_id}'.")
|
|
243
|
-
|
|
244
|
-
skill_name = _derive_skill_name(skill_id, skill_md, detail)
|
|
245
|
-
safe_name = re.sub(r"[^a-zA-Z0-9_-]", "_", skill_name).strip("_")
|
|
211
|
+
safe_name = re.sub(r"[^a-zA-Z0-9_-]", "_", skill_id).strip("_")
|
|
246
212
|
if not safe_name:
|
|
247
213
|
safe_name = "imported_skill"
|
|
248
214
|
|
|
@@ -250,33 +216,47 @@ def install_skill(
|
|
|
250
216
|
skill_dir = os.path.join(target_dir, category, safe_name)
|
|
251
217
|
os.makedirs(skill_dir, exist_ok=True)
|
|
252
218
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
219
|
+
if skill_md_override:
|
|
220
|
+
md_path = os.path.join(skill_dir, "SKILL.md")
|
|
221
|
+
md = skill_md_override
|
|
222
|
+
if not md.startswith("---"):
|
|
223
|
+
md = f"---\nname: {safe_name}\ndescription: Imported from ClawHub ({skill_id})\n---\n\n{md}"
|
|
224
|
+
with open(md_path, "w", encoding="utf-8") as f:
|
|
225
|
+
f.write(md + "\n")
|
|
226
|
+
else:
|
|
227
|
+
raw_zip = _download_skill_zip(skill_id)
|
|
228
|
+
try:
|
|
229
|
+
zf = zipfile.ZipFile(io.BytesIO(raw_zip))
|
|
230
|
+
except zipfile.BadZipFile as exc:
|
|
231
|
+
raise RuntimeError(
|
|
232
|
+
f"ClawHub returned invalid ZIP for '{skill_id}'."
|
|
233
|
+
) from exc
|
|
234
|
+
|
|
235
|
+
for member in zf.namelist():
|
|
236
|
+
if member.startswith("__MACOSX") or member.startswith("."):
|
|
237
|
+
continue
|
|
238
|
+
dest = os.path.join(skill_dir, member)
|
|
239
|
+
if member.endswith("/"):
|
|
240
|
+
os.makedirs(dest, exist_ok=True)
|
|
241
|
+
else:
|
|
242
|
+
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
|
243
|
+
with open(dest, "wb") as f:
|
|
244
|
+
f.write(zf.read(member))
|
|
245
|
+
|
|
246
|
+
if not os.path.exists(os.path.join(skill_dir, "SKILL.md")):
|
|
247
|
+
logger.warning("No SKILL.md found in ZIP for '%s'", skill_id)
|
|
248
|
+
|
|
249
|
+
source_url = f"{CLAWHUB_WEB}/skills/{skill_id}"
|
|
262
250
|
meta_path = os.path.join(skill_dir, ".clawhub.json")
|
|
263
251
|
with open(meta_path, "w", encoding="utf-8") as f:
|
|
264
|
-
json.dump(
|
|
252
|
+
json.dump(
|
|
253
|
+
{"id": skill_id, "source": source_url, "installed_by": "pythonclaw"},
|
|
254
|
+
f, indent=2,
|
|
255
|
+
)
|
|
265
256
|
|
|
266
257
|
return skill_dir
|
|
267
258
|
|
|
268
259
|
|
|
269
|
-
def _derive_skill_name(skill_id: str, skill_md: str, detail: dict | None) -> str:
|
|
270
|
-
"""Extract a reasonable skill name from available data."""
|
|
271
|
-
name_match = re.search(r"^name:\s*(.+)$", skill_md, re.MULTILINE)
|
|
272
|
-
if name_match:
|
|
273
|
-
return name_match.group(1).strip()
|
|
274
|
-
if detail and detail.get("name"):
|
|
275
|
-
return detail["name"]
|
|
276
|
-
parts = skill_id.rsplit("-", 1)
|
|
277
|
-
return parts[-1] if parts else skill_id
|
|
278
|
-
|
|
279
|
-
|
|
280
260
|
def format_search_results(results: list[dict]) -> str:
|
|
281
261
|
"""Format search results for CLI display."""
|
|
282
262
|
if not results:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonclaw
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.5
|
|
4
4
|
Summary: OpenClaw reimagined in pure Python — autonomous AI agent with memory, RAG, skills, web dashboard, and multi-channel support.
|
|
5
5
|
Author-email: Eric Wang <wangchen2007915@gmail.com>
|
|
6
6
|
License: MIT
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/communication/email/SKILL.md
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/communication/email/send_email.py
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/communication/slack/SKILL.md
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/communication/slack/slack_api.py
RENAMED
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/csv_analyzer/SKILL.md
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/csv_analyzer/analyze.py
RENAMED
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/finance/fetch_quote.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/pdf_reader/read_pdf.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/data/youtube/youtube_info.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/dev/code_runner/run_code.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/dev/http_request/request.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/google/workspace/check_setup.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/media/image_gen/generate.py
RENAMED
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/media/spotify/spotify_ctl.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/meta/skill_creator/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/notion/SKILL.md
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/notion/notion_api.py
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/obsidian/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/trello/SKILL.md
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/productivity/trello/trello_api.py
RENAMED
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/change_persona/SKILL.md
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/change_setting/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/change_soul/SKILL.md
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/model_usage/SKILL.md
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/model_usage/usage_stats.py
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/onboarding/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/random/random_util.py
RENAMED
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/system/session_logs/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/text/translator/translate.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pythonclaw-0.6.4 → pythonclaw-0.6.5}/pythonclaw/templates/skills/web/summarize/summarize_url.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|