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:
5
TASKS.md
5
TASKS.md
@ -7,7 +7,7 @@
|
|||||||
## In Progress
|
## In Progress
|
||||||
*Currently working on*
|
*Currently working on*
|
||||||
|
|
||||||
- [ ] Sandbox buildout - setting up environment
|
- [ ] Sandbox buildout - continue expanding capabilities
|
||||||
|
|
||||||
## Waiting
|
## Waiting
|
||||||
*Blocked or waiting on something*
|
*Blocked or waiting on something*
|
||||||
@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
- [x] 2026-01-30: Initial setup - folder structure, templates, scripts
|
- [x] 2026-01-30: Initial setup - folder structure, templates, scripts
|
||||||
- [x] 2026-01-30: System packages installed - ffmpeg, imagemagick, neovim, tmux, pip, pnpm, build-essential
|
- [x] 2026-01-30: System packages installed - ffmpeg, imagemagick, neovim, tmux, pip, pnpm, build-essential
|
||||||
|
- [x] 2026-01-30: Shell aliases, tmux config, bashrc integration
|
||||||
|
- [x] 2026-01-30: Tools: search, inbox-processor, daily-digest, web-clipper
|
||||||
|
- [x] 2026-01-30: Created workspace-tools skill
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
67
skills/workspace-tools/SKILL.md
Normal file
67
skills/workspace-tools/SKILL.md
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
---
|
||||||
|
name: workspace-tools
|
||||||
|
description: Tools for managing the OpenClaw workspace. Use for searching files, checking inbox, generating daily digests, creating projects, and workspace organization tasks.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Workspace Tools
|
||||||
|
|
||||||
|
Tools for managing this workspace.
|
||||||
|
|
||||||
|
## Available Tools
|
||||||
|
|
||||||
|
### Search (`tools/search.py`)
|
||||||
|
Search workspace files for keywords.
|
||||||
|
```bash
|
||||||
|
python3 $WORKSPACE/tools/search.py "query" [max_results]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inbox (`tools/inbox-processor.py`)
|
||||||
|
Show inbox contents and pending items.
|
||||||
|
```bash
|
||||||
|
python3 $WORKSPACE/tools/inbox-processor.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Daily Digest (`tools/daily-digest.py`)
|
||||||
|
Generate activity summary.
|
||||||
|
```bash
|
||||||
|
python3 $WORKSPACE/tools/daily-digest.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### New Project (`scripts/new-project.sh`)
|
||||||
|
Create a new project from template.
|
||||||
|
```bash
|
||||||
|
$WORKSPACE/scripts/new-project.sh project-name
|
||||||
|
```
|
||||||
|
|
||||||
|
## Shell Aliases
|
||||||
|
|
||||||
|
If sourced from bashrc, these aliases are available:
|
||||||
|
- `ws` - cd to workspace
|
||||||
|
- `proj` - cd to projects
|
||||||
|
- `tasks` - show TASKS.md
|
||||||
|
- `today` - show today's notes
|
||||||
|
- `note "text"` - add timestamped note to today's log
|
||||||
|
- `search "query"` - search workspace
|
||||||
|
- `digest` - run daily digest
|
||||||
|
|
||||||
|
## Workspace Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
workspace/
|
||||||
|
├── projects/ - Active work
|
||||||
|
├── docs/ - Reference materials
|
||||||
|
├── inbox/ - Items to process
|
||||||
|
├── archive/ - Completed work
|
||||||
|
├── memory/ - Daily notes (YYYY-MM-DD.md)
|
||||||
|
├── templates/ - Project/note templates
|
||||||
|
├── scripts/ - Shell scripts
|
||||||
|
├── tools/ - Python utilities
|
||||||
|
└── skills/ - Custom skills
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- File names: lowercase, hyphens, no spaces
|
||||||
|
- Dates: YYYY-MM-DD format
|
||||||
|
- Projects: one folder per project in projects/
|
||||||
|
- Archive completed work, don't delete
|
||||||
@ -22,8 +22,15 @@ Generate daily activity summary.
|
|||||||
python3 tools/daily-digest.py
|
python3 tools/daily-digest.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### web-clipper.py
|
||||||
|
Save URLs with titles, notes, and tags.
|
||||||
|
```bash
|
||||||
|
python3 tools/web-clipper.py add "url" "title" "notes"
|
||||||
|
python3 tools/web-clipper.py list [limit]
|
||||||
|
python3 tools/web-clipper.py search "query"
|
||||||
|
```
|
||||||
|
|
||||||
## Planned
|
## Planned
|
||||||
|
|
||||||
- [ ] Web clipper (save URLs with notes)
|
|
||||||
- [ ] File indexer with tags
|
- [ ] File indexer with tags
|
||||||
- [ ] Reminder system
|
- [ ] Reminder system
|
||||||
|
|||||||
112
tools/web-clipper.py
Executable file
112
tools/web-clipper.py
Executable 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()
|
||||||
Reference in New Issue
Block a user