commit 235ca68ee55a1b099eb2763db19c0eda8f1716ca Author: anthonyrawlins Date: Sat Aug 9 13:17:33 2025 +1000 Initial RUSTLE implementation with UCXL Browser and standardized codes - Complete UCXL protocol implementation with DHT storage layer - BZZZ Gateway for peer-to-peer networking and content distribution - Temporal navigation engine with version control and timeline browsing - Standardized UCXL error/response codes for Rust, Go, and Python - React-based UI with multi-tab interface and professional styling - libp2p integration for distributed hash table operations - Self-healing network mechanisms and peer management - Comprehensive IPC commands for Tauri desktop integration Major Components: - ucxl-core: Core UCXL protocol and DHT implementation - BZZZ Gateway: Local subnet peer discovery and content replication - Temporal Engine: Version control and state reconstruction - Cross-language standards: Unified error handling across implementations - Modern UI: Professional React interface with DHT and network monitoring Standards Compliance: - UCXL-ERROR-CODES.md and UCXL-RESPONSE-CODES.md v1.0 - Machine-readable error codes with structured payloads - Client guidance for retry logic and error handling - Cross-language compatibility with identical APIs πŸ€– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3291d37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +# Rust +/target/ +**/*.rs.bk +Cargo.lock + +# Node.js +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# Tauri +src-tauri/target/ +src-tauri/gen/ + +# Logs +*.log + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Build outputs +dist/ +build/ + +# Environment files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# OS generated files +Thumbs.db +ehthumbs.db + +# Temporary files +*.tmp +*.temp \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..991ec1f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] +resolver = "2" +members = [ + "ucxl-core", + "ucxl-tauri-app/src-tauri", +] diff --git a/Context Browser.md b/Context Browser.md new file mode 100644 index 0000000..22ebd35 --- /dev/null +++ b/Context Browser.md @@ -0,0 +1 @@ +# Briefing Document: UCXL Browser with Temporal Navigation and Markdown Context Storage\n\nPhase 2B has completed. This briefing outlines a design for a browser that:\n- implements temporal navigation techniques native to the UCXL protocol\n- supports submitting Markdown content as context and storing it in the DHT\n- boots first in a local subnet with BZZZ software\n- considers a self-healing mechanism (whether implemented today or how to add it)\n\nThe document is written for the development team and product stakeholders. It emphasizes architecture, data models, workflows, security, testing, and deployment.\n\n---\n\n## 1. Executive Summary\n\n- Objective: Build a browser client that can:\n - navigate document state over time using UCXL temporal capabilities\n - publish Markdown context to the DHT with versioned metadata\n - store and retrieve content efficiently and deterministically (content-addressable storage)\n - run first on a local subnet using the BZZZ software gateway and self-healing concepts\n- Success metrics:\n - Latency to fetch a historical state under 2 seconds on a typical local subnet\n - 99.9% successful storage and retrieval of Markdown contexts in a pilot\n - Intuitive temporal navigation UX (timeline/versions) with accurate state reconstruction\n - Clear API surface for frontend and extensible backend modules\n\n---\n\n## 2. Scope\n\n- In Scope:\n - Frontend browser UI for temporal navigation (timeline scrubber, version compare, diff view)\n - UCXL temporal engine integration (state at a given time/version)\n - Markdown submission pipeline (markdown -> context blob -> DHT storage)\n - DHT integration (put/get, content addressing, version metadata)\n - Local subnet bootstrap with BZZZ software (gateway/bridge to UCXL and DHT)\n - Self-healing design concepts (anti-entropy, replication, repair hooks)\n - Developer-facing API and data models\n- Out of Scope:\n - Production-grade global routing beyond the local subnet\n - Non-UCXL protocol features not required for debugging\n - Advanced UI themes/branding beyond core usability\n\n---\n\n## 3. Reference Architecture\n\n- UI/Frontend\n - Lightweight browser app (Electron/Chromium extension or web app) with:\n - Timeline/Version Navigator\n - Markdown editor + preview\n - Context submission flow\n - Version diff and compare UI\n- UCXL Temporal Engine\n - Core logic to query, assemble, and render document state at a given time/version\n - Traverses UCXL-backed DAGs of state changes\n- DHT Layer\n - Content-addressable storage layer\n - Put/get operations with metadata\n - Versioned pointers (handles to previous versions)\n- BZZZ Gateway/Node\n - Local gateway operating on the subnet\n - Interfaces with UCXL and DHT\n - Provides predictable, low-latency access for development\n- Context Store\n - Markdown content stored as context blobs\n - Metadata: title, author, timestamp, version, content hash, parent hash\n - Optional front matter for additional metadata\n- Self-Healing Module (design/optional)\n - Checksums, anti-entropy, background repair, replication policy\n - Health dashboard and repair triggers\n\n---\n\n## 4. Temporal Navigation for UCXL\n\n### 4.1 Concept\nTemporal navigation enables debugging by allowing users to:\n- view document state as it existed at a given time\n- traverse a version DAG (branching/merging)\n- replay sequences of edits to reconstruct the state\n\n### 4.2 Data Model (Temporal)\n- DocumentRoot\n - doc_id: string\n - version: string (semantic version or UUID)\n - timestamp: ISO8601 string\n - parent_version: string|null\n - state_pointer: multihash or DHT key for the serialized state\n - metadata: { author, source, tags, ... }\n- StateDelta / Block\n - Each change to the document is a delta/rooted change\n - state_pointer may reference a blob or linked list of blocks\n- Timeline\n - A directed acyclic graph (DAG) of versions\n - Each node stores: version_id, timestamp, parent_ids, metadata\n - UI renders as a chronological timeline with branches\n\n### 4.3 Workflow\n- To view state at time T:\n - Query UCXL for the latest state up to T\n - Traverse the version DAG to reconstruct the state\n- To compare two versions:\n - Retrieve both state pointers\n - Compute diff at the Markdown/text level (or at AST level)\n- To navigate branches:\n - Expose branch/merge UI; allow selecting a branch head\n - Resolve merges using a defined policy (e.g., last-writer-wins, CRDT-based merge hints)\n\n### 4.4 API Sketch\n- UCXL Temporal API (high level)\n - GET /ucxl/state?doc_id=&at_time=\n - GET /ucxl/state?doc_id=&version_id=\n - GET /ucxl/diff?doc_id=&from_version=&to_version=\n- Internal data format accepted by the UI\n - A normalized JSON state: { doc_id, version, timestamp, content: \"\", metadata }\n\n---\n\n## 5. Markdown Context Submission to the DHT\n\n### 5.1 Ingestion Pipeline\n1. Editor collects Markdown content from the user.\n2. Optional front matter is parsed/validated (title, author, date, tags).\n3. Markdown content is sanitized (to remove script tags and unsafe constructs if user-provided).\n4. The content is converted into a stable blob or a set of chunks (chunking strategy optional but recommended for large docs).\n5. Compute a content hash (e.g., SHA-256) for the blob(s).\n6. Create a Context Blob that stores:\n - content_hash, size, chunk metadata (if chunked)\n - metadata: doc_id, version, author, timestamp, parent_version, source_uri\n - optional signature for authenticity\n7. Publish to DHT:\n - Put the Context Blob with a key derived from its content_hash\n - Store pointers to parent version(s) and to the document root/version\n8. Return to UI:\n - New version_id, content_hash, and DHT keys\n\n### 5.2 Data Model\n- MarkdownContextBlob\n - blob_id: string (content_hash)\n - doc_id: string\n - version: string\n - timestamp: ISO8601\n - parent_version: string|null\n - content_hashes: [string] // if chunked\n - content_size: int\n - mime_type: \"text/markdown\"\n - metadata: { author, source, title, tags }\n - signature: string|null\n\n- DocumentRootVersion\n - doc_id\n - version\n - state_pointer: string (reference to ContextBlob or a root pointer)\n - timestamp\n - parent_versions: [string]\n\n### 5.3 Security Considerations\n- Signatures: optional digital signatures on content blobs for authenticity\n- Integrity: content-addressable storage ensures content cannot be altered after publish\n- Access control: DHT read access can be public; consider encrypted blobs if sensitive\n- Sanitization: ensure Markdown rendering in UI cannot execute scripts\n\n---\n\n## 6. DHT and Content Addressing\n\n### 6.1 Storage Model\n- Content-addressable: each blob is stored under a key derived from its hash\n- Metadata pointers: doc_id, version, parent_version, and state_pointer\n- Version DAG: each version node contains pointers to parent versions\n\n### 6.2 Write Path\n- User submits Markdown context\n- System computes hash, stores blob, writes metadata and version pointers\n- Returns version_id and blob_id to the UI\n\n### 6.3 Read Path\n- User requests a specific document version\n- System follows pointers to fetch the ContextBlob\n- Reconstruct state: combine content blob(s) with metadata to render\n\n### 6.4 Indexing and Discovery\n- Optional: lightweight local index to map doc_id -> latest_version\n- For cross-node discovery in the local subnet, maintain a small, sparse index replicated by BZZZ\n\n---\n\n## 7. BZZZ Software Plan (Local Subnet Bootstrapping)\n\n### 7.1 What BZZZ Does\n- Acts as a gateway/node on the local subnet for:\n - UCXL protocol interactions\n - DHT put/get operations\n - Local content caching and retrieval\n - Bridging the frontend to the UCXL network with predictable latency\n\n### 7.2 Deployment Model\n- Run BZZZ as a daemon on a dev machine or a small server within the subnet\n- Expose a local API (REST/gRPC) consumed by the browser app\n- Use mDNS or static DNS within the subnet for discovery\n\n### 7.3 Local Subnet Rollout\n- Phase 1: Stand up a single BZZZ node, ensure basic put/get works\n- Phase 2: Add a second BZZZ node for redundancy; test replication\n- Phase 3: Test network partition scenarios and latency budgets\n\n### 7.4 Interfaces\n- API surface for the browser:\n - POST /store/context\n - GET /fetch/context?blob_id=\n - POST /store/document_version\n - GET /state?doc_id=&at_time=\n- Security: mutual TLS or token-based auth for internal use only\n\n---\n\n## 8. Self-Healing Mechanism\n\n### 8.1 Concept\n- Self-healing refers to autonomously detecting and repairing data loss or corruption, and maintaining consistent state across nodes.\n\n### 8.2 Implementation Options\n- Anti-Entropy Protocol\n - Periodically compare checksums of replicas and repair mismatches\n- Background Repair\n - Auto-replicate popular/important blobs to additional nodes\n- Versioned Integrity\n - Use content hashes and version DAG to detect orphaned or missing blocks\n- On-Demand Repair\n - Trigger repair when a read detects a missing piece\n\n### 8.3 Has It Been Implemented?\n- Current UCXL baseline: often not automatically self-healing in all stacks\n- Recommendation: implement a SelfHealingModule as an optional pluggable component\n - Provides API hooks:\n - startRepair(doc_id, version)\n - reportMissingBlob(blob_id)\n - healthStatus()\n - With a pilot on local subnet for a subset of critical docs\n- Deliverables if implemented:\n - Repair scheduler\n - Integrity verifier (checksum validation)\n - Redundancy policy (lower latency, higher replication factor for frequently accessed docs)\n\n### 8.4 Migration Path\n- If not implemented in phase 2B, plan a dedicated sprint to add SelfHealingModule with test coverage and telemetry\n\n---\n\n## 9. Security and Compliance\n\n- Data in DHT: consider encryption for sensitive content or use public, read-only public blobs with signed metadata\n- Integrity: all content blobs are content-addressed; verify hash on retrieval\n- Authentication: internal APIs (BZZZ) should require strong authentication and encryption\n- Code signing: sign the browser extension/desktop app to ensure integrity\n- Logging: avoid leaking sensitive content in logs; redact metadata where appropriate\n\n---\n\n## 10. UX and UI Considerations\n\n- Temporal Navigator\n - Timeline with zoom levels (hour/day/week/month)\n - Version markers and branch indicators\n - β€œJump to state” action with a single click\n - Diff view between two selected versions\n- Markdown Editor\n - Live preview\n - Front matter editor (optional)\n - Validation messages for content readiness (e.g., title presence)\n- Context Submission\n - Clear success/failure feedback\n - Display of new version_id and blob_id\n- Status Dashboard\n - Local subnet health, BZZZ connectivity, replication status\n - Self-healing activity log (if enabled)\n\n---\n\n## 11. API Design (High Level)\n\n- UCXL Temporal Engine\n - GET /ucxl/state?doc_id=&at_time=\n - GET /ucxl/state?doc_id=&version_id=\n - GET /ucxl/diff?doc_id=&from_version=&to_version=\n- Markdown Context Submission\n - POST /store/context\n - Body: { doc_id, markdown, author, title, timestamp, parent_version, [front_matter] }\n - Response: { version_id, blob_id, state_pointer }\n - POST /store/document_version\n - Body: { doc_id, version, parent_versions, state_pointer, metadata }\n - Response: { success: true, version_id }\n- DHT Fetch\n - GET /fetch/context?blob_id=\n - GET /fetch/document?doc_id=&version_id=\n- BZZZ Gateway\n - Internal API endpoints are used by the frontend; documented in internal API spec\n\n---\n\n## 12. Testing and Quality Assurance\n\n- Unit tests for:\n - Markdown ingestion and sanitization\n - DHT blob serialization/deserialization\n - Version/DAG logic\n- Integration tests:\n - End-to-end: submit MD, publish version, retrieve state at time t\n - Temporal navigation: navigate across versions and branches\n - Local subnet routing with BZZZ\n- Performance tests:\n - Latency budgets for fetch/store under varying network conditions\n - Stress test with large markdown documents\n- Chaos testing:\n - Simulate node outages and network partitions to validate self-healing behavior (if enabled)\n\n---\n\n## 13. Deployment Roadmap\n\n- Phase 0 (Immediate)\n - Define data models and API surface\n - Set up local BZZZ skeleton on the subnet\n - Establish a minimal UI with temporal navigation scaffolding\n- Phase 1\n - Implement Markdown ingestion and DHT storage (single node)\n - Implement basic temporal engine to reconstruct state at given time\n - Basic self-healing hooks (watch for missing blocks)\n- Phase 2\n - Multi-node BZZZ with replication tests\n - Full self-healing module in place (anti-entropy, repair)\n - Timeline UI polish, diff view\n- Phase 3\n - Pilot with a broader set of docs, performance tuning\n - Security hardening and access control\n - Documentation for developers and operators\n\n---\n\n## 14. Deliverables to Create\n\n- Architecture and API design documents (this briefing can be a living doc)\n- Data models (JSON schemas or TypeScript interfaces)\n- UI wireframes or a minimal prototype\n- A runnable local subnet setup guide (with BZZZ, UCXL, and DHT)\n- Self-healing module design/spec (and a plan for MVP)\n- Test plans and CI benchmarks\n\n---\n\n## 15. Risks and Mitigations\n\n- Risk: Temporal state reconstruction latency\n - Mitigation: caching of frequently accessed states; prefetch of probable next states; efficient delta application\n- Risk: DHT data loss on subnet partition\n - Mitigation: replicate critical blobs; implement self-healing repair\n- Risk: Complex version DAG leading to user confusion\n - Mitigation: intuitive UI; guided tours; simplified diff/merge presets\n- Risk: Security exposure of Markdown payloads\n - Mitigation: sanitization, signing, optional encryption, access control\n\n---\n\n## 16. Next Steps\n\n- Schedule a design review with frontend, backend, and DevOps to validate data models and API contracts\n- Create a minimal viable product (MVP) plan with milestones for:\n - Markdown ingestion to DHT\n - Temporal state retrieval\n - Local BZZZ deployment\n - Basic self-healing hooks\n- Prepare test datasets (sample Markdown docs with versions)\n\n---\n\nIf you’d like, I can tailor this briefing into a concrete project plan with:\n- a detailed data dictionary (JSON schemas)\n- a starter API spec with concrete endpoint definitions\n- sample UI wireframes or user stories for the temporal navigator\n\nWould you prefer a lighter or more detailed version for your dev kickoff? diff --git a/Development Plan ucxl Browser using Rust and Tauri.md b/Development Plan ucxl Browser using Rust and Tauri.md new file mode 100644 index 0000000..9eea280 --- /dev/null +++ b/Development Plan ucxl Browser using Rust and Tauri.md @@ -0,0 +1,191 @@ +Here’s a detailed development plan for a Rust + Tauri-based UXCL Browser (uxcl-browser), focused on delivering a solid MVP and a clean long-term path. It covers architecture, scope, milestones, and concrete tasks you can hand to a small team. + +Goals, scope, and success criteria +MVP scope (first 12 weeks, adjustable): +A Rust core that implements UCXL protocol interactions (parsing UCXL URIs, envelope operations like GET/PUT/POST/ANNOUNCE/DELETE, basic envelope history/store). +A Tauri-based UI shell with a web frontend (React or Svelte) that talks to the Rust core via a secure IPC bridge. +Core UI screens: Dashboard (overview), Envelope Viewer (JSON/details), Action Toolbar (GET/PUT/POST/ANNOUNCE/DELETE), and Logs/Console. +Local storage for envelopes/history (in-memory with optional on-disk persistence for MVP). +Linux-native look-and-feel with decent cross-distro packaging support (AppImage and Flatpak). +Basic security posture: sandboxed UI, strict IPC surface, input validation, CSP. +Non-goals for MVP: +Cross-platform parity in visuals beyond Linux initially (Windows/macOS can come later). +Advanced encryption or hardware security modules in MVP (focus on solid core and secure IPC first). +Success metrics: +Buildable AppImage/Flatpak artefacts for Pop!_OS within 12 weeks. +Sub-1-second IPC latency for typical UCXL commands in a dev machine. +Positive developer feedback on code structure and testability. +Passes a basic security hygiene review (no untrusted code paths, input validation, minimal privileges). +Reference architecture +Core rust crate (uxcl-core) +Responsibilities: UCXL URI parsing, envelope data models, envelope operations (GET/PUT/POST/ANNOUNCE/DELETE), in-memory envelope store, simple transport layer (mock or real UCXI interactions), async runtime. +Public API example (high level): +UCxlEnvelope, UCxlCommand (enum of GET/PUT/POST/ANNOUNCE/DELETE), UCxlResult +Async functions: execute_command(cmd, params) -> Result +EnvelopeStore trait with CRUD methods +UI layer (Tauri app) +Frontend: Single-page app (SPA) built with React or Svelte, TypeScript. +IPC: Define a small, versioned set of commands sent from UI to Rust core, with strict input/output schemas (e.g., UiToCoreCommand and CoreToUiResponse). +UI panels: +Address bar for UCXL URIs +Envelope list/history panel +Envelope detail viewer (formatted JSON and raw) +Action bar for GET/PUT/POST/ANNOUNCE/DELETE +Logs panel +Security: Tauri sandbox, content security policy, only permit necessary APIs; frontend code isolated from direct filesystem/network access. +Data flow +UI issues commands via IPC to uxcl-core +Core performs the operation and responds with structured data +UI renders results and appends to logs +Packaging and deployment +Linux-first packaging: AppImage and Flatpak (target Pop!_OS), with optional Debian packaging later +CI builds for Linux, with artifact publishing +Tech stack decisions +Core: Rust (stable, safe, fast) +Async runtime: Tokio (or async-std if you prefer; Tokio is more common and robust) +Data formats: serde with serde_json for envelope payloads +Networking/IO: reqwest or hyper for any local/remote UCXI endpoints +Persistence: in-memory store initially; optional on-disk store via sled or a simple JSON store +UI: Tauri with a React or Svelte frontend +Web framework: React (with Vite) or SvelteKit +Styling: CSS variables, lib/adwaita color tokens if you want a GNOME-like look +Build and packaging +Rust toolchain (rustup), cargo workspaces +Tauri CLI for building the native app +AppImage and Flatpak for Linux packaging +Testing +Unit tests in Rust for core logic +Integration tests for IPC surface +UI end-to-end tests (optional; can start with Playwright or Cypress in a later phase) +Repository layout (starter) +UXCL workspace +uxcl-core/ (Rust library) +Cargo.toml +src/lib.rs (core API) +src/envelope.rs (data models) +src/store.rs (in-memory store) +uxcl-tauri-app/ (Tauri project) +src-tauri/Cargo.toml (backend integration) +src-tauri/tauri.conf.json +src/ (frontend assets built by Vite) +uxcl-workspace Cargo.toml (workspace members) +Simple example: +uxcl-core = lib +uxcl-tauri-app = bin (tauri app) that depends on uxcl-core +MVP features by milestone (12–16 weeks plan) Milestone 1 β€” Foundation (weeks 1–2) +Setup repository, CI pipeline, and coding standards +Implement uxcl-core skeleton +UCXL URI parsing scaffold +Basic Envelope data model and in-memory store +Async command handling scaffold +Initialize uxcl-tauri-app with a minimal Tauri scaffold +Establish IPC contract (UiToCoreCommand, CoreToUiResponse) Deliverables: +Working monorepo skeleton +Basic unit tests for core parsing and envelope data model +Milestone 2 β€” Core functionality (weeks 3–5) + +Implement core operations: GET, PUT, POST, ANNOUNCE, DELETE +Wire up in-memory envelope store with simple persistence mock +IPC: implement a sample command round-trip (UI sends GET, core returns envelope) +Basic error handling and validation Deliverables: +Core library with full command surface +Basic IPC integration test +README with API surface +Milestone 3 β€” UI scaffolding and MVP UI (weeks 4–7) + +Build out MVP UI screens +Address bar, envelope list/history, envelope viewer, action toolbar, logs +Integrate frontend with IPC +Implement minimal UX flows for common tasks +Add CSP and sandbox configuration Deliverables: +Functional UI shell with IPC to core +Wireframes and a simple UI kit +Initial accessibility considerations (keyboard navigation, contrast) +Milestone 4 β€” UX polish and security hardening (weeks 6–9) + +Improve UI/UX: responsive layout, polishing, error messages +Harden security: input validation, restricted IPC surface, secure defaults +Add basic unit/integration tests for IPC layer +Implement simple local persistence strategy (optional on-disk store) Deliverables: +Hardened UI and IPC +Documentation on security model and data flow +Milestone 5 β€” Packaging, CI, and testing (weeks 9–12) + +Set up Linux packaging: AppImage and Flatpak pipelines +Implement end-to-end tests (UI or IPC-level tests) +Add cargo-audit/clippy/rustfmt checks in CI +Prepare release notes and developer onboarding docs Deliverables: +Automated packaging artifacts for Linux +CI that builds, tests, and packages on push +Milestone 6 β€” MVP release candidate and feedback loop (weeks 12–16) + +Polish features based on internal feedback +Add simple user settings (storage location, log level) +Prepare for beta testing, gather feedback, plan iterations Deliverables: +Release candidate build for Linux +Feedback channel and roadmap for next iteration +UI/UX design approach +Focus on clarity and minimalism: +Consistent typography and spacing +Clear status indicators for envelope operations +Console/logs pane with filtering and search +Screens concept +Dashboard: quick overview of recent envelopes and status +Envelopes: list with sortable columns (id, status, timestamp) +Envelope detail: JSON viewer with pretty-print toggle; raw view +Actions: clearly labeled GET/PUT/POST/ANNOUNCE/DELETE buttons with confirmations +Logs: filterable and copyable logs +Accessibility basics: keyboard navigation, ARIA roles, sufficient color contrast +Testing strategy +Unit tests (Rust core) +Tests for URI parsing, envelope data validation, command execution +Integration tests (IPC) +End-to-end test that issues a command from UI to core and validates response +UI tests (optional in early phase) +Playwright or Cypress tests for core flows (optional for MVP) +Security/testing hygiene +Dependency audits (cargo audit) +Validate inputs across UI and core +Code signing plan in later stage +Security and compliance +Isolation: Tauri sandbox, minimal privileges for the frontend +Data validation: strict validation on all UCXL inputs +CSP: implement content security policy for the webview +Dependency management: pin versions, CI scans for vulnerabilities +Data at rest: plan for protecting stored envelopes (encryption later if needed) +CI/CD and quality gates +Linux-focused CI for MVP: +Build and test Rust core +Build Tauri app for Linux (AppImage/Flatpak) +Run basic UI IPC tests +Run cargo fmt, cargo clippy, cargo audit +Automatic artifact creation: +Generate AppImage and Flatpak manifests +Publish artifacts to a suitable artifact store or GitHub Releases +Packaging and release plan +Target Pop!_OS (and Ubuntu derivatives) for MVP +Primary packaging formats: AppImage, Flatpak +Deb packaging can follow if needed; ensure runtime dependencies are available +Release notes focusing on MVP capabilities and how to test locally +Risks and mitigations +Risk: UCXL core complexity grows beyond simple in-memory store +Mitigation: design core with clean interfaces and allow swapping in a database or mock UCXI transport later +Risk: UI/IPC surface grows too large +Mitigation: lock scope to essential MVP commands; add additional commands only when needed +Risk: Linux packaging headaches +Mitigation: rely on established tooling (Tauri bundling, Flatpak) and keep packaging logic modular +Risk: Security validation gaps +Mitigation: implement strict input validation, CSP, sandboxed UI, code reviews focused on IPC +Roles and responsibilities (small team) +Product/UX Lead: define UX flow, wireframes, and acceptance criteria +Rust Core Developer: implement ucxl-core, data models, IPC surface, tests +Frontend Developer: build SPA, integrate with IPC, ensure good UX +DevOps/CI Engineer: set up CI, packaging pipelines, automated tests +QA/Security Reviewer: review security posture, run basic tests, ensure compliance +Next steps (immediate actions) +Create the monorepo structure with uxcl-core and uxcl-tauri-app +Set up initial CI workflow (Linux build and tests) +Create a minimal UCXL core with URI parsing and a simple envelope struct +Generate the Tauri app scaffold and wire it to call a sample core function +Define the IPC contract: UiToCoreCommand, CoreToUiResponse, with a couple of initial commands (e.g., GET envelope) +Prepare wireframes and design tokens for the UI diff --git a/README.md b/README.md new file mode 100644 index 0000000..14625db --- /dev/null +++ b/README.md @@ -0,0 +1,158 @@ +# RUSTLE - UCXL Browser + +**RUSTLE** (Rust + Tauri UCXL Engine) is a desktop application for browsing and interacting with UCXL (Unified Context Exchange Language) content through a distributed hash table (DHT) network. + +## Features + +- **UCXL Protocol Support**: Full implementation of UCXL URI parsing and content handling +- **DHT Storage**: Distributed content storage using libp2p and BZZZ gateway +- **Temporal Navigation**: Version control and timeline browsing for UCXL content +- **BZZZ Gateway Integration**: Local subnet peer discovery and content replication +- **Cross-Language Standards**: Standardized error/response codes for Rust, Go, and Python +- **Modern UI**: React-based interface with professional styling + +## Architecture + +### Core Components + +- **ucxl-core**: Rust library containing UCXL protocol implementation +- **BZZZ Gateway**: Peer-to-peer networking layer for content distribution +- **DHT Storage**: Distributed hash table for decentralized content storage +- **Temporal Engine**: Version control and timeline management +- **React UI**: Modern web-based user interface + +### Technology Stack + +- **Backend**: Rust with Tauri for native desktop integration +- **Frontend**: React with TypeScript for the user interface +- **Networking**: libp2p for peer-to-peer communication +- **Storage**: DHT-based distributed storage +- **Standards**: UCXL standardized error/response codes + +## Getting Started + +### Prerequisites + +- Rust 1.70+ with Cargo +- Node.js 18+ with npm +- Git + +### Development Setup + +1. **Clone the repository:** + ```bash + git clone + cd rustle + ``` + +2. **Install dependencies:** + ```bash + # Install Rust dependencies + cargo build + + # Install Node.js dependencies + npm install + ``` + +3. **Run in development mode:** + ```bash + cargo tauri dev + ``` + +### Building for Production + +```bash +cargo tauri build +``` + +## Project Structure + +``` +rustle/ +β”œβ”€β”€ ucxl-core/ # Core UCXL implementation +β”‚ β”œβ”€β”€ src/ +β”‚ β”‚ β”œβ”€β”€ lib.rs # Main library exports +β”‚ β”‚ β”œβ”€β”€ envelope.rs # UCXL envelope handling +β”‚ β”‚ β”œβ”€β”€ commands.rs # UCXL command processing +β”‚ β”‚ β”œβ”€β”€ dht.rs # DHT storage implementation +β”‚ β”‚ β”œβ”€β”€ bzzz.rs # BZZZ gateway networking +β”‚ β”‚ β”œβ”€β”€ temporal.rs # Temporal navigation engine +β”‚ β”‚ └── ucxl_codes.rs # Standardized error/response codes +β”‚ └── Cargo.toml +β”œβ”€β”€ src-tauri/ # Tauri desktop app +β”‚ β”œβ”€β”€ src/ +β”‚ β”‚ β”œβ”€β”€ main.rs # Application entry point +β”‚ β”‚ β”œβ”€β”€ lib.rs # Tauri configuration +β”‚ β”‚ └── commands.rs # IPC commands +β”‚ └── Cargo.toml +β”œβ”€β”€ src/ # React frontend +β”‚ β”œβ”€β”€ App.tsx # Main application component +β”‚ β”œβ”€β”€ App.css # Application styles +β”‚ └── main.tsx # React entry point +β”œβ”€β”€ ucxl_codes.go # Go standard library +β”œβ”€β”€ ucxl_codes.py # Python standard library +└── UCXL_CODES_README.md # Standards documentation +``` + +## UCXL Standards Compliance + +RUSTLE implements the full UCXL specification including: + +- **Standardized Error Codes**: `UCXL-400-INVALID_ADDRESS`, `UCXL-404-NOT_FOUND`, etc. +- **Standardized Response Codes**: `UCXL-200-OK`, `UCXL-201-CREATED`, etc. +- **Cross-Language Libraries**: Identical APIs for Rust, Go, and Python +- **Structured Payloads**: Machine-readable error and response formats + +See [UCXL_CODES_README.md](./UCXL_CODES_README.md) for complete documentation. + +## Development Commands + +### Core Library +```bash +cd ucxl-core +cargo test # Run tests +cargo build --release # Build optimized library +``` + +### Desktop Application +```bash +cargo tauri dev # Development mode with hot reload +cargo tauri build # Production build +cargo tauri info # System information +``` + +### Frontend +```bash +npm run dev # Development server +npm run build # Production build +npm run lint # Code linting +``` + +## DHT Network + +RUSTLE uses a distributed hash table (DHT) for decentralized content storage: + +- **BZZZ Gateway**: Local subnet peer discovery and bootstrap +- **Content Replication**: Automatic content replication across peers +- **Self-Healing**: Network partition detection and recovery +- **Temporal Navigation**: Version-aware content retrieval + +## Contributing + +1. Fork the repository +2. Create a feature branch: `git checkout -b feature-name` +3. Make changes and test thoroughly +4. Follow Rust and React best practices +5. Update documentation as needed +6. Submit a pull request + +## License + +This project follows the same license as the UCXL specification. + +## Architecture Documentation + +For detailed technical documentation, see: +- `Development Plan ucxl Browser using Rust and Tauri.md` - Complete development plan +- `Context Browser.md` - Context and requirements +- `UCXL_CODES_README.md` - Standards compliance documentation \ No newline at end of file diff --git a/UCXL_CODES_README.md b/UCXL_CODES_README.md new file mode 100644 index 0000000..ce66cc1 --- /dev/null +++ b/UCXL_CODES_README.md @@ -0,0 +1,296 @@ +# UCXL Standard Response and Error Codes Library + +This repository contains standardized UCXL error and response codes libraries for **Rust**, **Go**, and **Python** to ensure consistent cross-service communication and client handling across all UCXL implementations. + +## Overview + +The UCXL codes standard provides: +- **Unified error signaling** across UCXL services (UCXI, Browser, BZZZ, etc.) +- **Machine-readable error codes** with structured payloads +- **Client guidance** for retry logic and error handling +- **Cross-language compatibility** with identical APIs + +## Standard Format + +### Error Codes +Format: `UCXL--` + +Examples: +- `UCXL-400-INVALID_ADDRESS` - Malformed UCXL URI +- `UCXL-404-NOT_FOUND` - Resource not found +- `UCXL-503-SERVICE_UNAVAILABLE` - Service temporarily unavailable + +### Response Codes +Format: `UCXL--` + +Examples: +- `UCXL-200-OK` - Successful request +- `UCXL-201-CREATED` - Resource created +- `UCXL-202-ACCEPTED` - Async operation accepted + +## Error Payload Schema + +```json +{ + "error": { + "code": "UCXL-400-INVALID_ADDRESS", + "message": "Invalid UCXL address format", + "details": { + "field": "address", + "provided": "ucxl://invalid/address", + "expected_format": "ucxl://:@:[//]" + }, + "source": "ucxl-browser/v1", + "path": "/resolve", + "request_id": "req-12345", + "timestamp": "2025-08-09T16:22:20Z", + "cause": "parse_error" + } +} +``` + +## Success Payload Schema + +```json +{ + "response": { + "code": "UCXL-200-OK", + "message": "Request completed successfully", + "data": { + "items": [{"id": "item-1", "name": "Alpha"}] + }, + "details": { + "count": 1 + }, + "request_id": "req-12345", + "timestamp": "2025-08-09T16:22:20Z" + } +} +``` + +## Language Implementations + +### Rust (`ucxl_codes.rs`) + +```rust +use ucxl_core::*; + +// Create error response +let error = UCXLErrorBuilder::new(UCXLErrorCode::InvalidAddress) + .field("address", "ucxl://invalid".into()) + .expected_format("ucxl://:@:") + .source("my-service") + .path("/resolve") + .build(); + +// Create success response +let success = UCXLResponseBuilder::new(UCXLResponseCode::Ok) + .data(serde_json::json!({"result": "success"})) + .build(); + +// Check error properties +if error.error.code.should_retry() { + // Implement retry logic +} +``` + +### Go (`ucxl_codes.go`) + +```go +package main + +import ( + "fmt" + "your-module/ucxl_codes" +) + +func main() { + // Create error response + error := ucxl_codes.NewErrorBuilder(ucxl_codes.ErrorInvalidAddress). + Field("address", "ucxl://invalid"). + ExpectedFormat("ucxl://:@:"). + Source("my-service"). + Path("/resolve"). + Build() + + // Create success response + success := ucxl_codes.NewResponseBuilder(ucxl_codes.ResponseOK). + Data(map[string]interface{}{"result": "success"}). + Build() + + // Check error properties + if error.Error.Code.ShouldRetry() { + // Implement retry logic + } +} +``` + +### Python (`ucxl_codes.py`) + +```python +from ucxl_codes import UCXLErrorBuilder, UCXLErrorCode, UCXLResponseBuilder, UCXLResponseCode + +# Create error response +error = UCXLErrorBuilder(UCXLErrorCode.INVALID_ADDRESS) \ + .field("address", "ucxl://invalid") \ + .expected_format("ucxl://:@:") \ + .source("my-service") \ + .path("/resolve") \ + .build() + +# Create success response +success = UCXLResponseBuilder(UCXLResponseCode.OK) \ + .data({"result": "success"}) \ + .build() + +# Check error properties +if error.error.code.should_retry(): + # Implement retry logic + pass +``` + +## Complete Error Code Reference + +| Code | HTTP | Description | Retry? | +|------|------|-------------|--------| +| `UCXL-400-INVALID_ADDRESS` | 400 | Malformed UCXL URI | No | +| `UCXL-400-MISSING_FIELD` | 400 | Required field missing | No | +| `UCXL-400-INVALID_FORMAT` | 400 | Input format invalid | No | +| `UCXL-401-UNAUTHORIZED` | 401 | Authentication required | No | +| `UCXL-403-FORBIDDEN` | 403 | Insufficient permissions | No | +| `UCXL-404-NOT_FOUND` | 404 | Resource not found | No | +| `UCXL-409-CONFLICT` | 409 | State conflict | No | +| `UCXL-422-UNPROCESSABLE_ENTITY` | 422 | Business rule violation | No | +| `UCXL-429-RATE_LIMIT` | 429 | Rate limiting active | **Yes** | +| `UCXL-500-INTERNAL_ERROR` | 500 | Unhandled server error | **Yes** | +| `UCXL-503-SERVICE_UNAVAILABLE` | 503 | Service down/maintenance | **Yes** | +| `UCXL-504-GATEWAY_TIMEOUT` | 504 | Downstream timeout | **Yes** | + +## Complete Response Code Reference + +| Code | HTTP | Description | Use Case | +|------|------|-------------|----------| +| `UCXL-200-OK` | 200 | Successful request | Standard operations | +| `UCXL-201-CREATED` | 201 | Resource created | POST/PUT create | +| `UCXL-202-ACCEPTED` | 202 | Async operation accepted | Long-running tasks | +| `UCXL-204-NO_CONTENT` | 204 | Success, no content | DELETE operations | +| `UCXL-206-PARTIAL_CONTENT` | 206 | Partial results | Paginated responses | +| `UCXL-304-NOT_MODIFIED` | 304 | Not changed since last fetch | Caching | + +## Client Implementation Guidance + +### Retry Logic +```rust +fn should_retry_request(error_code: UCXLErrorCode, attempt: u32) -> bool { + error_code.should_retry() && attempt < MAX_RETRIES +} + +async fn execute_with_retry(operation: impl Fn() -> Result) -> Result { + let mut attempt = 0; + loop { + match operation() { + Ok(result) => return Ok(result), + Err(error) if should_retry_request(error, attempt) => { + let backoff = Duration::from_millis(100 * 2_u64.pow(attempt)); + tokio::time::sleep(backoff).await; + attempt += 1; + }, + Err(error) => return Err(error), + } + } +} +``` + +### Error Classification +```rust +fn classify_error(error: &UCXLErrorCode) -> ErrorCategory { + if error.is_client_error() { + ErrorCategory::ClientError // Fix input, don't retry + } else if error.should_retry() { + ErrorCategory::RetryableServerError // Retry with backoff + } else { + ErrorCategory::PermanentServerError // Don't retry + } +} +``` + +### Response Handling +```rust +fn handle_response(response: UCXLResponseCode) -> ActionRequired { + if response.is_async() { + ActionRequired::Poll // Poll for completion + } else if response.is_partial() { + ActionRequired::Paginate // Fetch remaining data + } else { + ActionRequired::None // Complete response + } +} +``` + +## Integration with BZZZ + +The BZZZ Gateway has been updated to use standardized UCXL codes: + +```rust +// BZZZ now returns standardized errors +let error_response = create_error_response( + UCXLErrorCode::ServiceUnavailable, + "/bzzz/store", + Some(&request_id) +); + +// DHT operations use standard codes +let not_found = create_envelope_error( + UCXLErrorCode::NotFound, + &envelope_id, + "/dht/retrieve" +); +``` + +## Testing + +Each implementation includes comprehensive tests: + +**Rust:** +```bash +cargo test --lib ucxl_codes +``` + +**Go:** +```bash +go test ./ucxl_codes +``` + +**Python:** +```bash +python -m pytest ucxl_codes.py -v +# Or run inline tests: +python ucxl_codes.py +``` + +## Governance and Versioning + +- **Version:** 1.0 (following UCXL-ERROR-CODES.md specification) +- **Registry:** Machine-readable definitions in `error-codes.yaml` (future) +- **Deprecation Policy:** New codes added in minor versions, deprecated codes marked but maintained for compatibility +- **Updates:** Changes published with changelog and migration guidance + +## Future Enhancements + +1. **Machine-readable registry** (`error-codes.yaml`) for code generation +2. **OpenAPI integration** for automatic client generation +3. **Observability integration** with tracing and metrics +4. **Additional language support** (JavaScript/TypeScript, C#, etc.) + +## Contributing + +When adding new error codes: +1. Follow the `UCXL--` format +2. Add to all three language implementations +3. Update this documentation +4. Include appropriate tests +5. Ensure retry logic is correctly classified + +## License + +This UCXL codes library follows the same license as the UCXL project. \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..e4b78ea --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..9c8ffea --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "ucxl-browser", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "tauri dev", + "build": "tauri build", + "preview": "tauri build --debug", + "tauri": "tauri" + }, + "dependencies": { + "@tauri-apps/api": ">=2.0.0", + "@tauri-apps/plugin-shell": ">=2.0.0", + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@tauri-apps/cli": ">=2.0.0", + "@eslint/js": "^9.32.0", + "@types/react": "^19.1.9", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^4.7.0", + "eslint": "^9.32.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.39.0", + "vite": "^7.1.0" + } +} \ No newline at end of file diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore new file mode 100644 index 0000000..502406b --- /dev/null +++ b/src-tauri/.gitignore @@ -0,0 +1,4 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +/gen/schemas diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml new file mode 100644 index 0000000..6c5bbf4 --- /dev/null +++ b/src-tauri/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "app" +version = "0.1.0" +description = "A Tauri App" +authors = ["you"] +license = "" +repository = "" +edition = "2021" +rust-version = "1.77.2" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +name = "app_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2.3.1", features = [] } + +[dependencies] +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +log = "0.4" +tauri = { version = "2.7.0", features = [] } +tauri-plugin-log = "2" diff --git a/src-tauri/build.rs b/src-tauri/build.rs new file mode 100644 index 0000000..795b9b7 --- /dev/null +++ b/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json new file mode 100644 index 0000000..c135d7f --- /dev/null +++ b/src-tauri/capabilities/default.json @@ -0,0 +1,11 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "enables the default permissions", + "windows": [ + "main" + ], + "permissions": [ + "core:default" + ] +} diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png new file mode 100644 index 0000000..77e7d23 Binary files /dev/null and b/src-tauri/icons/128x128.png differ diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000..0f7976f Binary files /dev/null and b/src-tauri/icons/128x128@2x.png differ diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png new file mode 100644 index 0000000..98fda06 Binary files /dev/null and b/src-tauri/icons/32x32.png differ diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000..f35d84f Binary files /dev/null and b/src-tauri/icons/Square107x107Logo.png differ diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000..1823bb2 Binary files /dev/null and b/src-tauri/icons/Square142x142Logo.png differ diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 0000000..dc2b22c Binary files /dev/null and b/src-tauri/icons/Square150x150Logo.png differ diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000..0ed3984 Binary files /dev/null and b/src-tauri/icons/Square284x284Logo.png differ diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000..60bf0ea Binary files /dev/null and b/src-tauri/icons/Square30x30Logo.png differ diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000..c8ca0ad Binary files /dev/null and b/src-tauri/icons/Square310x310Logo.png differ diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000..8756459 Binary files /dev/null and b/src-tauri/icons/Square44x44Logo.png differ diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000..2c8023c Binary files /dev/null and b/src-tauri/icons/Square71x71Logo.png differ diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000..2c5e603 Binary files /dev/null and b/src-tauri/icons/Square89x89Logo.png differ diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000..17d142c Binary files /dev/null and b/src-tauri/icons/StoreLogo.png differ diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns new file mode 100644 index 0000000..a2993ad Binary files /dev/null and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico new file mode 100644 index 0000000..06c23c8 Binary files /dev/null and b/src-tauri/icons/icon.ico differ diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png new file mode 100644 index 0000000..d1756ce Binary files /dev/null and b/src-tauri/icons/icon.png differ diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs new file mode 100644 index 0000000..9c3118c --- /dev/null +++ b/src-tauri/src/lib.rs @@ -0,0 +1,16 @@ +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .setup(|app| { + if cfg!(debug_assertions) { + app.handle().plugin( + tauri_plugin_log::Builder::default() + .level(log::LevelFilter::Info) + .build(), + )?; + } + Ok(()) + }) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs new file mode 100644 index 0000000..ad5fe83 --- /dev/null +++ b/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + app_lib::run(); +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json new file mode 100644 index 0000000..1cc4f8c --- /dev/null +++ b/src-tauri/tauri.conf.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "ucxl-browser", + "version": "0.1.0", + "identifier": "com.tauri.dev", + "build": { + "frontendDist": "../ui/dist", + "devUrl": "http://localhost:1420", + "beforeDevCommand": "npm run dev", + "beforeBuildCommand": "npm run build" + }, + "app": { + "windows": [ + { + "title": "UCXL Browser", + "width": 800, + "height": 600, + "resizable": true, + "fullscreen": false + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..d559815 --- /dev/null +++ b/src/App.css @@ -0,0 +1,239 @@ +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +h1 { + color: #2c3e50; + text-align: center; + margin-bottom: 30px; +} + +/* Tab Styles */ +.tabs { + display: flex; + border-bottom: 2px solid #e1e8ed; + margin-bottom: 20px; +} + +.tab { + padding: 12px 24px; + background: none; + border: none; + cursor: pointer; + font-size: 14px; + color: #657786; + transition: all 0.2s ease; + border-bottom: 2px solid transparent; +} + +.tab:hover { + color: #1da1f2; + background-color: #f7f9fa; +} + +.tab-active { + padding: 12px 24px; + background: none; + border: none; + cursor: pointer; + font-size: 14px; + color: #1da1f2; + border-bottom: 2px solid #1da1f2; + font-weight: 600; +} + +/* Tab Content */ +.tab-content { + min-height: 400px; +} + +.section { + background: #ffffff; + border: 1px solid #e1e8ed; + border-radius: 8px; + padding: 20px; + margin-bottom: 20px; +} + +.section h3 { + margin-top: 0; + margin-bottom: 20px; + color: #14171a; +} + +/* Form Styles */ +.form-row { + display: flex; + gap: 12px; + margin-bottom: 16px; + align-items: flex-start; +} + +.form-row:last-child { + margin-bottom: 0; +} + +input[type="text"], .uri-input, .search-input { + flex: 1; + padding: 12px 16px; + border: 1px solid #ccd6dd; + border-radius: 6px; + font-size: 14px; + transition: border-color 0.2s ease; +} + +input[type="text"]:focus, .uri-input:focus, .search-input:focus { + outline: none; + border-color: #1da1f2; + box-shadow: 0 0 0 2px rgba(29, 161, 242, 0.1); +} + +.markdown-editor { + width: 100%; + padding: 12px 16px; + border: 1px solid #ccd6dd; + border-radius: 6px; + font-size: 14px; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + resize: vertical; + transition: border-color 0.2s ease; +} + +.markdown-editor:focus { + outline: none; + border-color: #1da1f2; + box-shadow: 0 0 0 2px rgba(29, 161, 242, 0.1); +} + +button { + padding: 12px 24px; + background-color: #1da1f2; + color: white; + border: none; + border-radius: 6px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: background-color 0.2s ease; + white-space: nowrap; +} + +button:hover:not(:disabled) { + background-color: #1991da; +} + +button:disabled { + background-color: #aab8c2; + cursor: not-allowed; +} + +/* Response Section */ +.response-section { + margin-top: 30px; +} + +.response-section h3 { + margin-bottom: 10px; + color: #14171a; +} + +.response { + background-color: #f8f9fa; + border: 1px solid #e1e8ed; + border-radius: 6px; + padding: 16px; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 12px; + line-height: 1.4; + max-height: 400px; + overflow-y: auto; + white-space: pre-wrap; + word-wrap: break-word; +} + +.response:empty { + color: #657786; + font-style: italic; +} + +.response:empty::before { + content: "Response will appear here..."; +} + +/* DHT and Network specific styles */ +.dht-status { + color: #657786; + font-size: 12px; + margin: 0; + font-style: italic; +} + +.network-info { + background: #f7f9fa; + border-radius: 6px; + padding: 16px; + margin-top: 16px; +} + +.network-info p { + margin: 0 0 12px 0; + color: #14171a; +} + +.network-info ul { + margin: 0; + padding-left: 20px; +} + +.network-info li { + margin: 6px 0; + color: #657786; + font-size: 14px; +} + +.network-info strong { + color: #14171a; +} + +hr { + border: none; + border-top: 1px solid #e1e8ed; + margin: 24px 0; +} + +/* Status indicators */ +.status-connected { + color: #17bf63; + font-weight: 600; +} + +.status-disconnected { + color: #e0245e; + font-weight: 600; +} + +.status-warning { + color: #ffad1f; + font-weight: 600; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .tabs { + flex-wrap: wrap; + } + + .form-row { + flex-direction: column; + align-items: stretch; + } + + .form-row input[type="text"], + .form-row .uri-input, + .form-row .search-input { + margin-bottom: 8px; + } +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..3a58ef2 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,382 @@ +import { useState } from 'react'; +import { invoke } from '@tauri-apps/api/tauri'; +import './App.css'; + +// Types matching the Rust backend +interface EnvelopeData { + ucxl_uri: string; + content: string; + content_type: string; + author?: string; + title?: string; + tags: string[]; +} + +interface SearchQueryData { + text?: string; + tags: string[]; + author?: string; + content_type?: string; + limit?: number; + offset?: number; +} + +type UiToCoreCommand = + | { GetEnvelope: { envelope_id: string } } + | { GetEnvelopeByUri: { uri: string } } + | { StoreEnvelope: { envelope: EnvelopeData } } + | { ExecuteUCXLGet: { uri: string; version?: string; at_time?: string } } + | { ExecuteUCXLPost: { uri: string; markdown_content: string; author?: string; title?: string } } + | { SearchEnvelopes: { query: SearchQueryData } } + | 'GetStoreStats' + | 'InitializeDHT' + | 'GetNetworkStatus' + | 'GetBZZZStats' + | { StoreToDHT: { envelope: EnvelopeData } } + | { RetrieveFromDHT: { envelope_id: string } } + | 'GetPeerList'; + +function App() { + const [activeTab, setActiveTab] = useState<'get' | 'post' | 'search' | 'store' | 'dht' | 'network'>('get'); + const [uri, setUri] = useState('ucxl://example.com/test'); + const [response, setResponse] = useState(''); + const [loading, setLoading] = useState(false); + const [dhtInitialized, setDhtInitialized] = useState(false); + + // Form states + const [markdownContent, setMarkdownContent] = useState('# Example Document\n\nThis is example markdown content.'); + const [author, setAuthor] = useState('User'); + const [title, setTitle] = useState('Test Document'); + const [searchText, setSearchText] = useState(''); + const [searchTags, setSearchTags] = useState(''); + + const executeCommand = async (command: UiToCoreCommand) => { + setLoading(true); + try { + const result = await invoke('handle_command', { command }); + setResponse(JSON.stringify(result, null, 2)); + } catch (err) { + setResponse(`Error: ${err}`); + } finally { + setLoading(false); + } + }; + + const handleGetEnvelope = () => { + executeCommand({ GetEnvelopeByUri: { uri } }); + }; + + const handlePostMarkdown = () => { + executeCommand({ + ExecuteUCXLPost: { + uri, + markdown_content: markdownContent, + author: author || undefined, + title: title || undefined + } + }); + }; + + const handleSearch = () => { + const query: SearchQueryData = { + text: searchText || undefined, + tags: searchTags ? searchTags.split(',').map(t => t.trim()) : [], + limit: 10 + }; + executeCommand({ SearchEnvelopes: { query } }); + }; + + const handleGetStats = () => { + executeCommand('GetStoreStats'); + }; + + const handleInitializeDHT = () => { + executeCommand('InitializeDHT').then(() => { + setDhtInitialized(true); + }); + }; + + const handleGetNetworkStatus = () => { + executeCommand('GetNetworkStatus'); + }; + + const handleGetBZZZStats = () => { + executeCommand('GetBZZZStats'); + }; + + const handleStoreToDHT = () => { + const envelope: EnvelopeData = { + ucxl_uri: uri, + content: markdownContent, + content_type: 'text/markdown', + author: author || undefined, + title: title || undefined, + tags: ['dht', 'test'] + }; + executeCommand({ StoreToDHT: { envelope } }); + }; + + const handleRetrieveFromDHT = () => { + const envelopeId = searchText; // Use search input as envelope ID + executeCommand({ RetrieveFromDHT: { envelope_id: envelopeId } }); + }; + + const handleGetPeerList = () => { + executeCommand('GetPeerList'); + }; + + return ( +
+

UCXL Browser

+ + {/* Tab Navigation */} +
+ + + + + + +
+ + {/* Tab Content */} +
+ {activeTab === 'get' && ( +
+

Retrieve Content

+
+ setUri(e.target.value)} + placeholder="Enter UCXL URI" + className="uri-input" + /> + +
+
+ )} + + {activeTab === 'post' && ( +
+

Submit Markdown Context

+
+ setUri(e.target.value)} + placeholder="UCXL URI" + className="uri-input" + /> +
+
+ setTitle(e.target.value)} + placeholder="Document Title" + /> + setAuthor(e.target.value)} + placeholder="Author" + /> +
+
+