Add unified 'ws' CLI - Single entry point for all tools and projects - Quick status overview - Shortcuts for common tasks - Symlinked to ~/.local/bin
This commit is contained in:
156
ws
Executable file
156
ws
Executable file
@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
ws - Unified workspace CLI
|
||||
|
||||
A single entry point for all workspace tools and projects.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
WORKSPACE = Path("/home/wdjones/.openclaw/workspace")
|
||||
TOOLS = WORKSPACE / "tools"
|
||||
PROJECTS = WORKSPACE / "projects"
|
||||
|
||||
COMMANDS = {
|
||||
# Tools
|
||||
'search': ('tools/search.py', 'Search workspace files'),
|
||||
'inbox': ('tools/inbox-processor.py', 'Show inbox status'),
|
||||
'digest': ('tools/daily-digest.py', 'Generate daily digest'),
|
||||
'clip': ('tools/web-clipper.py', 'Web clipper (add, list, search)'),
|
||||
'note': ('tools/quicknote.py', 'Quick timestamped notes'),
|
||||
'dash': ('tools/dashboard.py', 'Start web dashboard'),
|
||||
'brief': ('tools/briefing.py', 'Morning briefing'),
|
||||
'scaffold': ('tools/scaffold.py', 'Create new project'),
|
||||
'watch': ('tools/watcher.py', 'Watch for file changes'),
|
||||
'focus': ('tools/focus.py', 'Pomodoro focus timer'),
|
||||
|
||||
# Projects
|
||||
'news': ('projects/news-feed/main.py', 'RSS news reader'),
|
||||
'reddit': ('projects/reddit-scanner/main.py', 'Reddit scanner'),
|
||||
}
|
||||
|
||||
def show_help():
|
||||
"""Show help message."""
|
||||
print("""
|
||||
╔═══════════════════════════════════════════════════╗
|
||||
║ 🖤 Case's Workspace CLI ║
|
||||
╚═══════════════════════════════════════════════════╝
|
||||
|
||||
Usage: ws <command> [args...]
|
||||
|
||||
TOOLS:
|
||||
""")
|
||||
for cmd, (path, desc) in sorted(COMMANDS.items()):
|
||||
if path.startswith('tools/'):
|
||||
print(f" {cmd:12} {desc}")
|
||||
|
||||
print("\nPROJECTS:")
|
||||
for cmd, (path, desc) in sorted(COMMANDS.items()):
|
||||
if path.startswith('projects/'):
|
||||
print(f" {cmd:12} {desc}")
|
||||
|
||||
print("""
|
||||
SHORTCUTS:
|
||||
ws Show this help
|
||||
ws status Quick status overview
|
||||
ws today Show today's notes
|
||||
ws tasks Show tasks
|
||||
ws git Git status
|
||||
|
||||
EXAMPLES:
|
||||
ws search "config" Search workspace
|
||||
ws news refresh Fetch new articles
|
||||
ws reddit sub python Show r/python
|
||||
ws focus 25 "coding" 25 min focus session
|
||||
ws scaffold myapp node Create Node.js project
|
||||
""")
|
||||
|
||||
def quick_status():
|
||||
"""Show quick status overview."""
|
||||
print("\n🖤 Workspace Status")
|
||||
print("=" * 40)
|
||||
|
||||
# Git status
|
||||
result = subprocess.run(['git', 'status', '-s'], cwd=WORKSPACE, capture_output=True, text=True)
|
||||
changes = len(result.stdout.strip().split('\n')) if result.stdout.strip() else 0
|
||||
print(f"📂 Git: {changes} uncommitted changes")
|
||||
|
||||
# Tasks
|
||||
tasks_file = WORKSPACE / "TASKS.md"
|
||||
if tasks_file.exists():
|
||||
content = tasks_file.read_text()
|
||||
in_progress = content.count("- [ ]")
|
||||
print(f"✅ Tasks: {in_progress} in progress")
|
||||
|
||||
# Today's notes
|
||||
from datetime import datetime
|
||||
today_file = WORKSPACE / "memory" / f"{datetime.now().strftime('%Y-%m-%d')}.md"
|
||||
if today_file.exists():
|
||||
lines = len(today_file.read_text().split('\n'))
|
||||
print(f"📝 Today: {lines} lines logged")
|
||||
|
||||
# Projects
|
||||
projects = [p for p in PROJECTS.iterdir() if p.is_dir() and not p.name.startswith('.')]
|
||||
print(f"🔨 Projects: {len(projects)}")
|
||||
|
||||
# Tools
|
||||
tools = [t for t in TOOLS.iterdir() if t.suffix == '.py']
|
||||
print(f"🔧 Tools: {len(tools)}")
|
||||
|
||||
print()
|
||||
|
||||
def run_command(cmd: str, args: list):
|
||||
"""Run a workspace command."""
|
||||
if cmd not in COMMANDS:
|
||||
print(f"Unknown command: {cmd}")
|
||||
print("Run 'ws' for help")
|
||||
return 1
|
||||
|
||||
path, _ = COMMANDS[cmd]
|
||||
full_path = WORKSPACE / path
|
||||
|
||||
if not full_path.exists():
|
||||
print(f"Command not found: {full_path}")
|
||||
return 1
|
||||
|
||||
# Run the command
|
||||
result = subprocess.run(
|
||||
['python3', str(full_path)] + args,
|
||||
cwd=WORKSPACE
|
||||
)
|
||||
return result.returncode
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
show_help()
|
||||
return
|
||||
|
||||
cmd = sys.argv[1]
|
||||
args = sys.argv[2:]
|
||||
|
||||
# Special commands
|
||||
if cmd == 'help' or cmd == '-h' or cmd == '--help':
|
||||
show_help()
|
||||
elif cmd == 'status':
|
||||
quick_status()
|
||||
elif cmd == 'today':
|
||||
from datetime import datetime
|
||||
today_file = WORKSPACE / "memory" / f"{datetime.now().strftime('%Y-%m-%d')}.md"
|
||||
if today_file.exists():
|
||||
print(today_file.read_text())
|
||||
else:
|
||||
print("No notes for today")
|
||||
elif cmd == 'tasks':
|
||||
tasks_file = WORKSPACE / "TASKS.md"
|
||||
if tasks_file.exists():
|
||||
print(tasks_file.read_text())
|
||||
elif cmd == 'git':
|
||||
subprocess.run(['git'] + args, cwd=WORKSPACE)
|
||||
else:
|
||||
sys.exit(run_command(cmd, args))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user