Add tools and workspace skill - web-clipper.py for saving URLs with notes - workspace-tools skill documenting the setup - Shell aliases and tmux config - Updated task tracking

This commit is contained in:
2026-01-30 23:15:47 -06:00
parent f18a1944d6
commit 41dc7ca06b
4 changed files with 191 additions and 2 deletions

112
tools/web-clipper.py Executable file
View File

@ -0,0 +1,112 @@
#!/usr/bin/env python3
"""
Web clipper - save URLs with notes to a clips file.
"""
import sys
import json
from datetime import datetime
from pathlib import Path
from urllib.parse import urlparse
WORKSPACE = Path("/home/wdjones/.openclaw/workspace")
CLIPS_FILE = WORKSPACE / "docs" / "clips.json"
def load_clips() -> list:
"""Load existing clips."""
if CLIPS_FILE.exists():
with open(CLIPS_FILE) as f:
return json.load(f)
return []
def save_clips(clips: list):
"""Save clips to file."""
CLIPS_FILE.parent.mkdir(parents=True, exist_ok=True)
with open(CLIPS_FILE, 'w') as f:
json.dump(clips, f, indent=2)
def add_clip(url: str, title: str = None, notes: str = None, tags: list = None):
"""Add a new clip."""
clips = load_clips()
clip = {
'url': url,
'title': title or urlparse(url).netloc,
'notes': notes,
'tags': tags or [],
'saved': datetime.now().isoformat(),
}
clips.insert(0, clip)
save_clips(clips)
print(f"Saved: {clip['title']}")
return clip
def list_clips(limit: int = 10, tag: str = None):
"""List saved clips."""
clips = load_clips()
if tag:
clips = [c for c in clips if tag in c.get('tags', [])]
if not clips:
print("No clips found")
return
print(f"📎 Saved Clips ({len(clips)} total)\n")
for clip in clips[:limit]:
saved = clip['saved'][:10]
tags = ' '.join(f"#{t}" for t in clip.get('tags', []))
print(f"[{saved}] {clip['title']}")
print(f" {clip['url']}")
if clip.get('notes'):
print(f"{clip['notes']}")
if tags:
print(f" {tags}")
print()
def search_clips(query: str):
"""Search clips by title, URL, or notes."""
clips = load_clips()
query_lower = query.lower()
matches = []
for clip in clips:
searchable = f"{clip.get('title', '')} {clip.get('url', '')} {clip.get('notes', '')}".lower()
if query_lower in searchable:
matches.append(clip)
if not matches:
print(f"No clips matching: {query}")
return
print(f"Found {len(matches)} clips:\n")
for clip in matches:
print(f" {clip['title']}: {clip['url']}")
def main():
if len(sys.argv) < 2:
print("Usage:")
print(" web-clipper.py add <url> [title] [notes]")
print(" web-clipper.py list [limit]")
print(" web-clipper.py search <query>")
sys.exit(1)
cmd = sys.argv[1]
if cmd == "add" and len(sys.argv) >= 3:
url = sys.argv[2]
title = sys.argv[3] if len(sys.argv) > 3 else None
notes = sys.argv[4] if len(sys.argv) > 4 else None
add_clip(url, title, notes)
elif cmd == "list":
limit = int(sys.argv[2]) if len(sys.argv) > 2 else 10
list_clips(limit)
elif cmd == "search" and len(sys.argv) >= 3:
search_clips(sys.argv[2])
else:
print("Unknown command")
if __name__ == "__main__":
main()