From a250e458a90aa4e8e2b090a98ebad436fe13feb1 Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sun, 30 Nov 2025 08:49:56 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 12 + README.md | 3 + plugin.lock.json | 93 +++++ skills/document-sync/README.md | 380 ++++++++++++++++++ skills/document-sync/SKILL.md | 143 +++++++ skills/document-sync/commands/doc-delete | 48 +++ skills/document-sync/commands/doc-info | 48 +++ skills/document-sync/commands/doc-pull | 61 +++ skills/document-sync/commands/doc-push | 68 ++++ skills/document-sync/commands/doc-query | 59 +++ skills/document-sync/commands/doc-read | 48 +++ skills/document-sync/references/COMMANDS.md | 223 ++++++++++ .../document-sync/references/CONFIGURATION.md | 14 + .../references/TROUBLESHOOTING.md | 21 + 14 files changed, 1221 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 plugin.lock.json create mode 100644 skills/document-sync/README.md create mode 100644 skills/document-sync/SKILL.md create mode 100755 skills/document-sync/commands/doc-delete create mode 100755 skills/document-sync/commands/doc-info create mode 100755 skills/document-sync/commands/doc-pull create mode 100755 skills/document-sync/commands/doc-push create mode 100755 skills/document-sync/commands/doc-query create mode 100755 skills/document-sync/commands/doc-read create mode 100644 skills/document-sync/references/COMMANDS.md create mode 100644 skills/document-sync/references/CONFIGURATION.md create mode 100644 skills/document-sync/references/TROUBLESHOOTING.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..38e5b40 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,12 @@ +{ + "name": "document-sync", + "description": "Document management system for storing, querying, and retrieving documents across Claude Code sessions. Provides doc-* commands for document operations with a centralized server. Requires Document Sync Server running and Python with uv.", + "version": "0.1.0", + "author": { + "name": "Document Sync Contributors", + "email": "noreply@example.com" + }, + "skills": [ + "./skills" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..46e78ba --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# document-sync + +Document management system for storing, querying, and retrieving documents across Claude Code sessions. Provides doc-* commands for document operations with a centralized server. Requires Document Sync Server running and Python with uv. diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..d2121fa --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,93 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:rawe/claude-agent-orchestrator:plugins/document-sync", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "9c6cbe502108d61cc4a68f5184a1cef6d8eeae82", + "treeHash": "64e8e9f8c150aa4392485b7ceb354f1c899e52f61a1d95eab898c3818e217320", + "generatedAt": "2025-11-28T10:27:48.782471Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "document-sync", + "description": "Document management system for storing, querying, and retrieving documents across Claude Code sessions. Provides doc-* commands for document operations with a centralized server. Requires Document Sync Server running and Python with uv.", + "version": "0.1.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "7388570dbd703e68118cda7e8ce58bb7735347872bcc58e549a2954c2fb55e70" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "cddf7bf6573f6ccd803e2d6183db2411b699e61c5bf262135029036bcf82e5a5" + }, + { + "path": "skills/document-sync/README.md", + "sha256": "c86a3aad151d5e718748ff6377dd377e1ef8df05e8aa04b269cb94f0a3016081" + }, + { + "path": "skills/document-sync/SKILL.md", + "sha256": "e6c1b0ff40de9c9e68f344edc39ed406b64f861455dd62b7ac6233154a0bd156" + }, + { + "path": "skills/document-sync/references/TROUBLESHOOTING.md", + "sha256": "ebb5041bf3f258190ea56198e6db7881476e78db74c05d67239a9506bd1fc03b" + }, + { + "path": "skills/document-sync/references/COMMANDS.md", + "sha256": "996848f8992cfef72d9669243ca9034a090034139cdfc25f6457d2b0afbf7939" + }, + { + "path": "skills/document-sync/references/CONFIGURATION.md", + "sha256": "eeedff39a8ec827c028d1e43098130423f2c00e180dee01d4ae7d9ba05c8528c" + }, + { + "path": "skills/document-sync/commands/doc-pull", + "sha256": "50bc92ef9320c123f4cb1d6e180a9196f44c358e54e69de74271f6f42b82fe1f" + }, + { + "path": "skills/document-sync/commands/doc-read", + "sha256": "2e7988053be05b5b4405a6366a60db73875b91fecb430a53d5c5955d8d569935" + }, + { + "path": "skills/document-sync/commands/doc-delete", + "sha256": "7732e42e16009db0fe955b50a046a42595c8e48b598ab1d75aa4dc62b07936a9" + }, + { + "path": "skills/document-sync/commands/doc-query", + "sha256": "2f17ab1873f83be7912d57f6226d49ee8d290f98a0f15cafacaf667253f05b3d" + }, + { + "path": "skills/document-sync/commands/doc-info", + "sha256": "75d9ef1fd9fc4d14ea75be1169d2f9a070e244bcb912822064d96449abcd9688" + }, + { + "path": "skills/document-sync/commands/doc-push", + "sha256": "b4de511cad5721d53c84b12bf7fd9a639ed7e7ccebf66fa111c53127cb59e459" + }, + { + "path": "skills/document-sync/commands/lib/config.py", + "sha256": "83618f1270511b234c2fc917a2d6ffc0ac6b04b319908106b29e752c3d70b38e" + }, + { + "path": "skills/document-sync/commands/lib/client.py", + "sha256": "d5d696efe19c1b9a433e552a4de93dd5c798784e35400b482cdc6fe19a6a4eb0" + } + ], + "dirSha256": "64e8e9f8c150aa4392485b7ceb354f1c899e52f61a1d95eab898c3818e217320" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/document-sync/README.md b/skills/document-sync/README.md new file mode 100644 index 0000000..6aba52a --- /dev/null +++ b/skills/document-sync/README.md @@ -0,0 +1,380 @@ +# Document Sync CLI Commands + +Command-line tools for interacting with the Document Sync Server. These UV-based scripts enable Claude Code sessions to store, retrieve, query, inspect, read, and delete documents with metadata and tags. + +## Prerequisites + +- **Python 3.11+** - Required for script dependencies +- **UV package manager** - For running scripts with automatic dependency management +- **Document Server** - Must be running (see `../../document-server/README.md`) + +## Available Commands + +All commands output JSON for easy parsing and integration with Claude Code (except `doc-read`, which outputs raw text). + +### doc-push - Upload Documents + +Upload a document to the server with optional tags and description. + +```bash +uv run /path/to/doc-push [OPTIONS] +``` + +**Arguments:** +- `file` - Path to the file to upload (required) + +**Options:** +- `--name TEXT` - Custom name for the document (defaults to filename) +- `--tags TEXT` - Comma-separated tags (e.g., "python,api,docs") +- `--description TEXT` - Document description + +**Example:** +```bash +uv run doc-push architecture.md --tags "design,architecture" --description "System architecture document" +``` + +**Output:** +```json +{ + "id": "doc_abc123...", + "filename": "architecture.md", + "content_type": "text/markdown", + "size_bytes": 2048, + "created_at": "2025-11-23T00:00:00", + "updated_at": "2025-11-23T00:00:00", + "tags": ["design", "architecture"], + "metadata": {"description": "System architecture document"}, + "url": "http://localhost:8766/documents/doc_abc123..." +} +``` + +### doc-query - Search Documents + +Query documents by name pattern and/or tags. + +```bash +uv run /path/to/doc-query [OPTIONS] +``` + +**Options:** +- `--name TEXT` - Filter by filename pattern (partial match) +- `--tags TEXT` - Comma-separated tags with AND logic (document must have ALL tags) +- `--limit INTEGER` - Maximum number of results + +**Examples:** +```bash +# List all documents +uv run doc-query + +# Find documents with specific tags (AND logic) +uv run doc-query --tags "python,tutorial" + +# Filter by name pattern +uv run doc-query --name "architecture" + +# Combine filters +uv run doc-query --name "guide" --tags "python" --limit 5 +``` + +**Tag AND Logic:** When querying with multiple tags (e.g., `--tags "python,api"`), only documents that have **both** tags will be returned. + +**Output:** +```json +[ + { + "id": "doc_abc123...", + "filename": "python-guide.md", + "content_type": "text/markdown", + "size_bytes": 1024, + "created_at": "2025-11-23T00:00:00", + "updated_at": "2025-11-23T00:00:00", + "tags": ["python", "tutorial"], + "metadata": {}, + "url": "http://localhost:8766/documents/doc_abc123..." + } +] +``` + +### doc-info - Get Document Metadata + +Retrieve metadata for a specific document without downloading the file. + +```bash +uv run /path/to/doc-info +``` + +**Arguments:** +- `document_id` - The document's unique identifier (required) + +**Example:** +```bash +uv run doc-info doc_abc123... +``` + +**Output:** +```json +{ + "id": "doc_abc123...", + "filename": "architecture.md", + "content_type": "text/markdown", + "size_bytes": 2048, + "created_at": "2025-11-23T00:00:00", + "updated_at": "2025-11-23T00:00:00", + "tags": ["design", "architecture"], + "metadata": {"description": "System architecture document"}, + "url": "http://localhost:8766/documents/doc_abc123..." +} +``` + +**Use Case:** Check document metadata (file size, MIME type, tags) before downloading. The `url` field provides a direct link to retrieve the document, mostly interesting for the user or system having no access to the skill itself. + +### doc-read - Read Text Documents + +Read text document content directly to stdout without downloading to file. + +```bash +uv run /path/to/doc-read +``` + +**Arguments:** +- `document_id` - The document's unique identifier (required) + +**Supported File Types:** +- Text files (`text/*`) +- JSON files (`application/json`) +- XML files (`application/xml`) + +**Examples:** +```bash +# Output content to terminal +uv run doc-read doc_abc123... + +# Pipe to grep +uv run doc-read doc_abc123... | grep "search term" + +# Pipe to jq (for JSON documents) +uv run doc-read doc_abc123... | jq '.field' + +# Save to file +uv run doc-read doc_abc123... > output.txt +``` + +**Output:** Raw text content (no JSON wrapper) + +**Error (for non-text files):** +```json +{"error": "Cannot read non-text file (MIME type: image/png). Use doc-pull to download binary files."} +``` + +**Use Case:** Quick inspection of text files, piping content to other tools, processing documents in scripts without creating temporary files. + +### doc-pull - Download Documents + +Download a document by its ID. + +```bash +uv run /path/to/doc-pull [OPTIONS] +``` + +**Arguments:** +- `document_id` - The document's unique identifier (required) + +**Options:** +- `--output PATH` or `-o PATH` - Output file path (defaults to original filename) + +**Examples:** +```bash +# Download with original filename +uv run doc-pull doc_abc123... + +# Download to specific path +uv run doc-pull doc_abc123... --output ~/downloads/my-document.md +``` + +**Output:** +```json +{ + "success": true, + "document_id": "doc_abc123...", + "filename": "/path/to/output.md", + "size_bytes": 2048 +} +``` + +### doc-delete - Remove Documents + +Delete a document from the server. + +```bash +uv run /path/to/doc-delete +``` + +**Arguments:** +- `document_id` - The document's unique identifier (required) + +**Example:** +```bash +uv run doc-delete doc_abc123... +``` + +**Output:** +```json +{ + "success": true, + "message": "Document doc_abc123... deleted successfully", + "document_id": "doc_abc123..." +} +``` + +## Configuration + +Commands connect to the document server using environment variables: + +### DOC_SYNC_HOST +- **Description:** Server hostname or IP address +- **Default:** `localhost` +- **Example:** + ```bash + DOC_SYNC_HOST=192.168.1.100 uv run doc-push file.txt + ``` + +### DOC_SYNC_PORT +- **Description:** Server port number +- **Default:** `8766` +- **Example:** + ```bash + DOC_SYNC_PORT=9000 uv run doc-query + ``` + +### DOC_SYNC_SCHEME +- **Description:** HTTP scheme (http or https) +- **Default:** `http` +- **Example:** + ```bash + DOC_SYNC_SCHEME=https uv run doc-pull doc_abc123... + ``` + +**Combined Example:** +```bash +DOC_SYNC_HOST=example.com DOC_SYNC_PORT=443 DOC_SYNC_SCHEME=https \ + uv run doc-push document.pdf --tags "report" +``` + +## Common Workflows + +### Store and Retrieve a Document +```bash +# 1. Upload a document +uv run doc-push specs.md --tags "api,specification" + +# Output includes the document ID: "doc_abc123..." + +# 2. Later, query for it +uv run doc-query --tags "api,specification" + +# 3. Check metadata before downloading +uv run doc-info doc_abc123... + +# 4. Read content (for text files) +uv run doc-read doc_abc123... | less + +# 5. Download it +uv run doc-pull doc_abc123... --output specs-copy.md +``` + +### Share Documents Across Sessions +```bash +# Session 1: Store architecture document +uv run doc-push architecture.md --tags "design,mvp" \ + --description "MVP architecture decisions" + +# Session 2: Query and retrieve +uv run doc-query --tags "design,mvp" +uv run doc-info doc_abc123... # Check metadata +uv run doc-read doc_abc123... | head -20 # Preview first 20 lines +uv run doc-pull doc_abc123... --output architecture.md +``` + +### Manage Document Repository +```bash +# List all documents +uv run doc-query + +# Find specific category +uv run doc-query --tags "deprecated" + +# Remove old documents +uv run doc-delete doc_old123... +``` + +## Error Handling + +All commands output errors to stderr in JSON format and exit with code 1 on failure. + +**Common Errors:** + +**File not found:** +```json +{"error": "File not found: /path/to/file.txt"} +``` + +**Document not found:** +```json +{"error": "Document not found: doc_invalid123"} +``` + +**Non-text file (doc-read only):** +```json +{"error": "Cannot read non-text file (MIME type: image/png). Use doc-pull to download binary files."} +``` + +**Network error:** +```json +{"error": "Network error: Connection refused"} +``` + +**Server not running:** +```json +{"error": "Network error: [Errno 61] Connection refused"} +``` + +## Technical Details + +### Script Architecture +- **UV Scripts:** Use PEP 723 inline dependency metadata +- **Shebang:** `#!/usr/bin/env -S uv run --script` +- **Dependencies:** Automatically installed by UV (httpx, typer) +- **Shared Library:** `lib/config.py` and `lib/client.py` provide reusable components + +### Why UV? +- **Zero installation:** Scripts run with dependencies automatically installed +- **Reproducible:** PEP 723 metadata ensures consistent dependency versions +- **Fast:** UV's Rust-based resolver is extremely fast +- **Portable:** Scripts work across different environments + +## Troubleshooting + +### "Connection refused" error +The document server isn't running. Start it first: +```bash +cd ../../document-server +uv run python -m src.main +``` + +### "No such file or directory" when running commands +Use full paths or navigate to the commands directory: +```bash +# Use full path +uv run /full/path/to/doc-push file.txt + +# Or navigate to commands directory +cd /path/to/commands +uv run doc-push file.txt +``` + +### Commands run slowly the first time +UV is installing dependencies. Subsequent runs will be fast as dependencies are cached. + +## Development + +See `../../docs/implementation/03-IMPLEMENTATION-CHECKLIST.md` for implementation details and design decisions. diff --git a/skills/document-sync/SKILL.md b/skills/document-sync/SKILL.md new file mode 100644 index 0000000..8a8b011 --- /dev/null +++ b/skills/document-sync/SKILL.md @@ -0,0 +1,143 @@ +--- +name: document-sync +description: Document management system for storing, querying, and retrieving documents across Claude Code sessions. Use this to maintain knowledge bases, share documents between agent. Whenever you encounter a in a session, use this skill to retrieve its content. +--- + +# Document Sync Skill + +## What & When + +**What**: Commands for uploading, downloading, querying, and deleting documents with metadata and tags through a centralized document server. + +**When to use**: +- Store important documents for retrieval in future sessions +- Build a knowledge base of project documentation +- Share architecture, API specs, or design documents across different work sessions +- Query documents by tags to find relevant information + +**Key Benefits**: +- Cross-session persistence +- Tag-based organization with AND logic +- Simple JSON output + +--- + +## Quick Reference + +**CRITICAL**: Always use absolute paths - NEVER use `cd`: + +### `doc-push` - Upload Documents +```bash +uv run /commands/doc-push [--tags TEXT] [--description TEXT] +# Example: uv run /commands/doc-push specs.md --tags "api,v2" +``` +**Use when**: Store a document for future reference. + +### `doc-query` - Search Documents +```bash +uv run /commands/doc-query [--tags TEXT] [--name TEXT] +# Example: uv run /commands/doc-query --tags "api,v2" +``` +**Use when**: Find documents by tags (AND logic) or name patterns. + +### `doc-info` - Get Document Metadata +```bash +uv run /commands/doc-info +# Example: uv run /commands/doc-info doc_abc123 +``` +**Use when**: View metadata for a specific document without downloading it. + +### `doc-read` - Read Text Documents +```bash +uv run /commands/doc-read +# Example: uv run /commands/doc-read doc_abc123 +``` +**Use when**: Output text document content directly to stdout (text files only). + +### `doc-pull` - Download Documents +```bash +uv run /commands/doc-pull [-o PATH] +# Example: uv run /commands/doc-pull doc_abc123 -o specs.md +``` +**Use when**: Retrieve a document by its ID. + +### `doc-delete` - Remove Documents +```bash +uv run /commands/doc-delete +# Example: uv run /commands/doc-delete doc_abc123 +``` +**Use when**: Permanently remove a document. + +--- + +## Typical Workflows + +### Store and Retrieve +```bash +# Upload with tags +uv run /commands/doc-push specs.md --tags "api,v2" + +# Find it later +uv run /commands/doc-query --tags "api,v2" + +# Download it +uv run /commands/doc-pull doc_abc123 +``` + +### Build Knowledge Base +```bash +# Upload multiple documents with consistent tags +uv run /commands/doc-push architecture.md --tags "design,mvp" +uv run /commands/doc-push api-spec.md --tags "api,mvp" + +# Query by project phase +uv run /commands/doc-query --tags "mvp" +``` + +--- + +## Key Concepts + +### Tag AND Logic +**IMPORTANT**: Multiple tags means ALL must match: +- `--tags "python,api"` → Document must have BOTH tags +- `--tags "v2,design,spec"` → Document must have ALL THREE tags + +### Output Format +All commands output JSON. Save document IDs from upload for later retrieval/deletion. + +--- + +## Notes for AI Assistants + +1. **Tag AND logic** - Multiple tags = ALL must match +2. **Save document IDs** - From upload output for future operations +3. **Check server running** - Handle connection errors gracefully +4. **Parse JSON output** - All commands return JSON +5. **Tags are lowercase** - Use consistent tag naming (`python` not `Python`) + +--- + +## Quick Decision Tree + +**Store document?** → `doc-push --tags "tag1,tag2"` + +**Find documents?** → `doc-query --tags "tag1,tag2"` (AND logic) + +**Check metadata?** → `doc-info ` (metadata only) + +**Read text file?** → `doc-read ` (text files to stdout) + +**Download document?** → `doc-pull ` (ID from query) + +**Remove document?** → `doc-delete ` (permanent) + +**List all?** → `doc-query` (no args) + +--- + +## Additional Resources + +- **Detailed Command Reference**: See `references/COMMANDS.md` +- **Configuration Options**: See `references/CONFIGURATION.md` +- **Error Handling**: See `references/TROUBLESHOOTING.md` diff --git a/skills/document-sync/commands/doc-delete b/skills/document-sync/commands/doc-delete new file mode 100755 index 0000000..5537365 --- /dev/null +++ b/skills/document-sync/commands/doc-delete @@ -0,0 +1,48 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "httpx", +# "typer", +# ] +# /// + +"""Delete a document from the document sync server.""" + +import typer +from pathlib import Path +import json +import sys + +# Add lib directory to path for imports +sys.path.insert(0, str(Path(__file__).parent / "lib")) +from config import Config +from client import DocumentClient + +app = typer.Typer(add_completion=False) + + +@app.command() +def main( + document_id: str = typer.Argument(..., help="ID of the document to delete"), +): + """Delete a document from the document sync server.""" + try: + # Create client and delete document + config = Config() + client = DocumentClient(config) + + result = client.delete_document(document_id) + + # Output success result as JSON + print(json.dumps(result, indent=2)) + + except Exception as e: + # Output error as JSON to stderr + error = {"error": str(e)} + print(json.dumps(error), file=sys.stderr) + raise typer.Exit(1) + + +if __name__ == "__main__": + app() diff --git a/skills/document-sync/commands/doc-info b/skills/document-sync/commands/doc-info new file mode 100755 index 0000000..b4d8b80 --- /dev/null +++ b/skills/document-sync/commands/doc-info @@ -0,0 +1,48 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "httpx", +# "typer", +# ] +# /// + +"""Retrieve metadata for a document from the document sync server.""" + +import typer +from pathlib import Path +import json +import sys + +# Add lib directory to path for imports +sys.path.insert(0, str(Path(__file__).parent / "lib")) +from config import Config +from client import DocumentClient + +app = typer.Typer(add_completion=False) + + +@app.command() +def main( + document_id: str = typer.Argument(..., help="Document ID to retrieve metadata for"), +): + """Retrieve metadata for a document without downloading the file.""" + try: + # Create client and get document info + config = Config() + client = DocumentClient(config) + + result = client.get_document_info(document_id) + + # Output metadata as JSON + print(json.dumps(result, indent=2)) + + except Exception as e: + # Output error as JSON to stderr + error = {"error": str(e)} + print(json.dumps(error), file=sys.stderr) + raise typer.Exit(1) + + +if __name__ == "__main__": + app() diff --git a/skills/document-sync/commands/doc-pull b/skills/document-sync/commands/doc-pull new file mode 100755 index 0000000..a0daff5 --- /dev/null +++ b/skills/document-sync/commands/doc-pull @@ -0,0 +1,61 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "httpx", +# "typer", +# ] +# /// + +"""Download a document from the document sync server.""" + +import typer +from pathlib import Path +import json +import sys + +# Add lib directory to path for imports +sys.path.insert(0, str(Path(__file__).parent / "lib")) +from config import Config +from client import DocumentClient + +app = typer.Typer(add_completion=False) + + +@app.command() +def main( + document_id: str = typer.Argument(..., help="ID of the document to download"), + output: str = typer.Option(None, "--output", "-o", help="Output file path (defaults to original filename)"), +): + """Download a document from the document sync server.""" + try: + # Create client and pull document + config = Config() + client = DocumentClient(config) + + content, filename = client.pull_document(document_id) + + # Determine output path + output_path = Path(output) if output else Path(filename) + + # Write content to file + output_path.write_bytes(content) + + # Output success message as JSON + result = { + "success": True, + "document_id": document_id, + "filename": str(output_path), + "size_bytes": len(content) + } + print(json.dumps(result, indent=2)) + + except Exception as e: + # Output error as JSON to stderr + error = {"error": str(e)} + print(json.dumps(error), file=sys.stderr) + raise typer.Exit(1) + + +if __name__ == "__main__": + app() diff --git a/skills/document-sync/commands/doc-push b/skills/document-sync/commands/doc-push new file mode 100755 index 0000000..8bd414b --- /dev/null +++ b/skills/document-sync/commands/doc-push @@ -0,0 +1,68 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "httpx", +# "typer", +# ] +# /// + +"""Upload a document to the document sync server.""" + +import typer +from pathlib import Path +import json +import sys + +# Add lib directory to path for imports +sys.path.insert(0, str(Path(__file__).parent / "lib")) +from config import Config +from client import DocumentClient + +app = typer.Typer(add_completion=False) + + +@app.command() +def main( + file_path: str = typer.Argument(..., help="Path to the file to upload"), + name: str = typer.Option(None, "--name", help="Custom name for the document (defaults to filename)"), + tags: str = typer.Option(None, "--tags", help="Comma-separated list of tags"), + description: str = typer.Option(None, "--description", help="Description of the document"), +): + """Upload a document to the document sync server.""" + try: + # Validate file exists + path = Path(file_path) + if not path.exists(): + error = {"error": f"File not found: {file_path}"} + print(json.dumps(error), file=sys.stderr) + raise typer.Exit(1) + + # Parse tags from comma-separated string + parsed_tags = None + if tags: + parsed_tags = [tag.strip() for tag in tags.split(",") if tag.strip()] + + # Create client and push document + config = Config() + client = DocumentClient(config) + + result = client.push_document( + file_path=path, + name=name, + tags=parsed_tags, + description=description + ) + + # Output success result as JSON + print(json.dumps(result, indent=2)) + + except Exception as e: + # Output error as JSON to stderr + error = {"error": str(e)} + print(json.dumps(error), file=sys.stderr) + raise typer.Exit(1) + + +if __name__ == "__main__": + app() diff --git a/skills/document-sync/commands/doc-query b/skills/document-sync/commands/doc-query new file mode 100755 index 0000000..ff3fb01 --- /dev/null +++ b/skills/document-sync/commands/doc-query @@ -0,0 +1,59 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "httpx", +# "typer", +# ] +# /// + +"""Query documents from the document sync server.""" + +import typer +from pathlib import Path +import json +import sys + +# Add lib directory to path for imports +sys.path.insert(0, str(Path(__file__).parent / "lib")) +from config import Config +from client import DocumentClient + +app = typer.Typer(add_completion=False) + + +@app.command() +def main( + name: str = typer.Option(None, "--name", help="Filter by filename pattern"), + tags: str = typer.Option(None, "--tags", help="Comma-separated list of tags (AND logic)"), + limit: int = typer.Option(None, "--limit", help="Maximum number of results"), +): + """Query documents from the document sync server.""" + try: + # Parse tags from comma-separated string + parsed_tags = None + if tags: + parsed_tags = [tag.strip() for tag in tags.split(",") if tag.strip()] + + # Create client and query documents + config = Config() + client = DocumentClient(config) + + results = client.query_documents( + name=name, + tags=parsed_tags, + limit=limit + ) + + # Output results as JSON array + print(json.dumps(results, indent=2)) + + except Exception as e: + # Output error as JSON to stderr + error = {"error": str(e)} + print(json.dumps(error), file=sys.stderr) + raise typer.Exit(1) + + +if __name__ == "__main__": + app() diff --git a/skills/document-sync/commands/doc-read b/skills/document-sync/commands/doc-read new file mode 100755 index 0000000..2895b61 --- /dev/null +++ b/skills/document-sync/commands/doc-read @@ -0,0 +1,48 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "httpx", +# "typer", +# ] +# /// + +"""Read text document content from the document sync server.""" + +import typer +from pathlib import Path +import json +import sys + +# Add lib directory to path for imports +sys.path.insert(0, str(Path(__file__).parent / "lib")) +from config import Config +from client import DocumentClient + +app = typer.Typer(add_completion=False) + + +@app.command() +def main( + document_id: str = typer.Argument(..., help="Document ID to read content from"), +): + """Read text document content directly to stdout (text files only).""" + try: + # Create client and read document + config = Config() + client = DocumentClient(config) + + content = client.read_document(document_id) + + # Output raw content to stdout (no JSON wrapper) + print(content, end="") + + except Exception as e: + # Output error as JSON to stderr + error = {"error": str(e)} + print(json.dumps(error), file=sys.stderr) + raise typer.Exit(1) + + +if __name__ == "__main__": + app() diff --git a/skills/document-sync/references/COMMANDS.md b/skills/document-sync/references/COMMANDS.md new file mode 100644 index 0000000..9799685 --- /dev/null +++ b/skills/document-sync/references/COMMANDS.md @@ -0,0 +1,223 @@ +# Command Reference + +## doc-push + +```bash +uv run commands/doc-push [--name TEXT] [--tags TEXT] [--description TEXT] +``` + +**Arguments**: `` - File path to upload + +**Options**: +- `--name TEXT` - Custom name (default: filename) +- `--tags TEXT` - Comma-separated tags +- `--description TEXT` - Description + +**Examples**: +```bash +uv run commands/doc-push specs.md --tags "api,v2" +uv run commands/doc-push arch.md --tags "design,mvp" --description "MVP architecture" +``` + +**Output**: +```json +{ + "id": "doc_abc123def456...", + "filename": "specs.md", + "content_type": "text/markdown", + "size_bytes": 2048, + "created_at": "2025-11-23T00:00:00", + "updated_at": "2025-11-23T00:00:00", + "tags": ["api", "v2"], + "metadata": {"description": "Specification document for API v2"}, + "url": "http://localhost:8766/documents/doc_abc123def456..." +} +``` + +**Note**: Save the `id` field for pull/delete operations. + +--- + +## doc-query + +```bash +uv run commands/doc-query [--name TEXT] [--tags TEXT] [--limit INTEGER] +``` + +**Options**: +- `--name TEXT` - Filter by filename pattern +- `--tags TEXT` - Filter by tags (AND logic - ALL tags must match) +- `--limit INTEGER` - Max results + +**Examples**: +```bash +uv run commands/doc-query # List all +uv run commands/doc-query --tags "api,v2" # Both tags required (AND) +uv run commands/doc-query --name "spec" # Name contains "spec" +``` + +**Output**: +```json +[ + { + "id": "doc_abc123...", + "filename": "api-spec.md", + "content_type": "text/markdown", + "size_bytes": 1024, + "created_at": "2025-11-23T00:00:00", + "updated_at": "2025-11-23T00:00:00", + "tags": ["api", "v2"], + "metadata": {}, + "url": "http://localhost:8766/documents/doc_abc123..." + } +] +``` + +**Important**: Multiple tags = ALL must match (AND logic, not OR) + +--- + +## doc-info + +```bash +uv run commands/doc-info +``` + +**Arguments**: `` - Document ID to retrieve metadata for + +**Examples**: +```bash +uv run commands/doc-info doc_abc123... +``` + +**Output**: +```json +{ + "id": "doc_abc123...", + "filename": "api-spec.md", + "content_type": "text/markdown", + "size_bytes": 1024, + "created_at": "2025-11-23T00:00:00", + "updated_at": "2025-11-23T00:00:00", + "tags": ["api", "v2"], + "metadata": {"description": "API specification"}, + "url": "http://localhost:8766/documents/doc_abc123..." +} +``` + +**Use Case**: View document metadata without downloading the file. The `url` field provides a direct link to retrieve the document. Useful to provide this url to a user if you don't want to download the file yourself. + +**Error Output** (stderr): +```json +{"error": "Document not found: doc_abc123..."} +``` + +--- + +## doc-read + +```bash +uv run commands/doc-read +``` + +**Arguments**: `` - Document ID to read content from + +**Examples**: +```bash +# Direct output +uv run commands/doc-read doc_abc123... + +# Pipe to grep +uv run commands/doc-read doc_abc123... | grep "pattern" + +# Pipe to wc +uv run commands/doc-read doc_abc123... | wc -l + +# Save to file +uv run commands/doc-read doc_abc123... > output.txt +``` + +**Output**: Raw text content to stdout (no JSON wrapper) + +**Supported MIME Types**: +- `text/*` (text/plain, text/markdown, text/html, etc.) +- `application/json` +- `application/xml` + +**Error Output** (stderr): +```json +{"error": "Cannot read non-text file (MIME type: image/png). Use doc-pull to download binary files."} +{"error": "File is not valid UTF-8 text. Use doc-pull to download."} +{"error": "Document not found: doc_abc123..."} +``` + +**Use Case**: Read text document content directly without downloading to file system. Ideal for: +- Piping content to other tools (grep, awk, jq, etc.) +- Quick inspection of text files +- Processing document content in scripts + +**Limitations**: +- Text files only (binary files will error) +- UTF-8 encoding only +- For binary files or non-UTF-8 content, use `doc-pull` instead + +--- + +## doc-pull + +```bash +uv run commands/doc-pull [--output PATH | -o PATH] +``` + +**Arguments**: `` - Document ID from query results + +**Options**: `--output PATH` or `-o PATH` - Output path (default: original filename) + +**Examples**: +```bash +uv run commands/doc-pull doc_abc123... +uv run commands/doc-pull doc_abc123... -o custom-name.md +``` + +**Output**: +```json +{ + "success": true, + "document_id": "doc_abc123...", + "filename": "/absolute/path/to/output.md", + "size_bytes": 2048 +} +``` + +--- + +## doc-delete + +```bash +uv run commands/doc-delete +``` + +**Arguments**: `` - Document ID from query results + +**Example**: +```bash +uv run commands/doc-delete doc_abc123... +``` + +**Output**: +```json +{ + "success": true, + "message": "Document doc_abc123... deleted successfully", + "document_id": "doc_abc123..." +} +``` + +**Warning**: Permanent deletion - cannot be undone. + +--- + +## Exit Codes + +- `0` - Success +- `1` - Error (JSON error in stderr) \ No newline at end of file diff --git a/skills/document-sync/references/CONFIGURATION.md b/skills/document-sync/references/CONFIGURATION.md new file mode 100644 index 0000000..09db5ff --- /dev/null +++ b/skills/document-sync/references/CONFIGURATION.md @@ -0,0 +1,14 @@ +# Configuration + +## Environment Variables + +- `DOC_SYNC_HOST` - Server hostname (default: `localhost`) +- `DOC_SYNC_PORT` - Server port (default: `8766`) +- `DOC_SYNC_SCHEME` - http or https (default: `http`) + +## Example (only when overriding defaults is needed!!!) + +```bash +DOC_SYNC_HOST=example.com DOC_SYNC_PORT=443 DOC_SYNC_SCHEME=https \ + uv run commands/doc-push file.txt +``` diff --git a/skills/document-sync/references/TROUBLESHOOTING.md b/skills/document-sync/references/TROUBLESHOOTING.md new file mode 100644 index 0000000..f80642a --- /dev/null +++ b/skills/document-sync/references/TROUBLESHOOTING.md @@ -0,0 +1,21 @@ +# Troubleshooting + +## Common Errors + +### Connection Refused +```json +{"error": "Network error: Connection refused"} +``` +**Fix**: Start document server in the correct folder document-server with: (`docker-compose up -d`) + +### File Not Found +```json +{"error": "File not found: /path/to/file"} +``` +**Fix**: Check file path is correct + +### Document Not Found +```json +{"error": "Document not found: doc_xxx"} +``` +**Fix**: Run `doc-query` to find correct document ID \ No newline at end of file