From 67f6b293f3ad8a83194b302ec9a8848e9080d48d Mon Sep 17 00:00:00 2001 From: Case Date: Fri, 30 Jan 2026 23:26:00 -0600 Subject: [PATCH] Add unified 'ws' CLI - Single entry point for all tools and projects - Quick status overview - Shortcuts for common tasks - Symlinked to ~/.local/bin --- ws | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100755 ws diff --git a/ws b/ws new file mode 100755 index 0000000..ff6e138 --- /dev/null +++ b/ws @@ -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 [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()