mirror of
https://github.com/pocketpaw/pocketpaw.git
synced 2026-05-13 21:21:53 +00:00
fix: rename Python package from pocketclaw to pocketpaw
Complete the package rename: src/pocketclaw/ → src/pocketpaw/, all imports, pyproject.toml entry point, docs code examples, installer references, and test patch targets updated. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Project Overview
|
||||
|
||||
PocketPaw is a self-hosted AI agent that runs locally and is controlled via Telegram, Discord, Slack, WhatsApp, or a web dashboard. The Python package is named `pocketclaw` (the internal/legacy name), while the public-facing name is `pocketpaw`. Python 3.11+ required.
|
||||
PocketPaw is a self-hosted AI agent that runs locally and is controlled via Telegram, Discord, Slack, WhatsApp, or a web dashboard. The Python package is named `pocketpaw` (the internal/legacy name), while the public-facing name is `pocketpaw`. Python 3.11+ required.
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -56,7 +56,7 @@ python -m build
|
||||
|
||||
### Message Bus Pattern
|
||||
|
||||
The core architecture is an event-driven message bus (`src/pocketclaw/bus/`). All communication flows through three event types defined in `bus/events.py`:
|
||||
The core architecture is an event-driven message bus (`src/pocketpaw/bus/`). All communication flows through three event types defined in `bus/events.py`:
|
||||
|
||||
- **InboundMessage** — user input from any channel (Telegram, WebSocket, CLI)
|
||||
- **OutboundMessage** — agent responses back to channels (supports streaming via `is_stream_chunk`/`is_stream_end`)
|
||||
@@ -104,5 +104,5 @@ The web dashboard (`frontend/`) is vanilla JS/CSS/HTML served via FastAPI+Jinja2
|
||||
- **Protocol-oriented**: Core interfaces (`AgentProtocol`, `ToolProtocol`, `MemoryStoreProtocol`, `BaseChannelAdapter`) are Python `Protocol` classes for swappable implementations
|
||||
- **Env vars**: All settings use `POCKETPAW_` prefix (e.g., `POCKETPAW_ANTHROPIC_API_KEY`)
|
||||
- **Ruff config**: line-length 100, target Python 3.11, lint rules E/F/I/UP
|
||||
- **Entry point**: `pocketclaw.__main__:main`
|
||||
- **Entry point**: `pocketpaw.__main__:main`
|
||||
- **Lazy imports**: Agent backends are imported inside `AgentRouter._initialize_agent()` to avoid loading unused dependencies
|
||||
|
||||
@@ -79,7 +79,7 @@ test: add coverage for injection scanner
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
src/pocketclaw/ # Core package (internal name: pocketclaw)
|
||||
src/pocketpaw/ # Core package (internal name: pocketpaw)
|
||||
agents/ # Agent backends + routing
|
||||
bus/adapters/ # Channel adapters (Discord, Slack, etc.)
|
||||
tools/builtin/ # Built-in tools
|
||||
|
||||
@@ -68,33 +68,37 @@ title: Get Channel Status
|
||||
description: ...
|
||||
api: GET /api/channels/status
|
||||
baseUrl: http://localhost:8000
|
||||
layout: '@/layouts/APIEndpointLayout.astro'
|
||||
layout: "@/layouts/APIEndpointLayout.astro"
|
||||
auth: bearer
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
...
|
||||
|
||||
## Response
|
||||
<ResponseField name="..." type="...">...</ResponseField>
|
||||
|
||||
<ResponseField name="..." type="...">
|
||||
...
|
||||
</ResponseField>
|
||||
|
||||
<RequestExample>
|
||||
<Tabs items={["cURL", "JavaScript", "Python"]}>
|
||||
<Tab title="cURL">...</Tab>
|
||||
...
|
||||
</Tabs>
|
||||
<Tabs items={["cURL", "JavaScript", "Python"]}>
|
||||
<Tab title="cURL">...</Tab>
|
||||
...
|
||||
</Tabs>
|
||||
</RequestExample>
|
||||
|
||||
<ResponseExample>
|
||||
<Tabs items={["200"]}>
|
||||
<Tab title="200">...</Tab>
|
||||
</Tabs>
|
||||
<Tabs items={["200"]}>
|
||||
<Tab title="200">...</Tab>
|
||||
</Tabs>
|
||||
</ResponseExample>
|
||||
```
|
||||
|
||||
## Key Conventions
|
||||
|
||||
- **Package name duality**: Internal Python package is `pocketclaw`, public-facing name in docs is `PocketPaw`. Import paths use `pocketclaw` (e.g., `from pocketclaw.tools.registry import ...`).
|
||||
- **Package name duality**: Internal Python package is `pocketpaw`, public-facing name in docs is `PocketPaw`. Import paths use `pocketpaw` (e.g., `from pocketpaw.tools.registry import ...`).
|
||||
- **Channel count**: "9+" channels (Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Teams, Google Chat, Web Dashboard).
|
||||
- **Tool count**: "50+" built-in tools across search, media, integrations, sessions, desktop, and coding categories.
|
||||
- **Backend count**: 3 backends (Claude Agent SDK, PocketPaw Native, Open Interpreter).
|
||||
|
||||
@@ -3,7 +3,14 @@ title: Cron Scheduler
|
||||
description: "PocketPaw's built-in cron scheduler handles recurring tasks and one-time reminders with APScheduler. Tasks persist across restarts, support natural language time parsing, and auto-reschedule after execution."
|
||||
section: Advanced
|
||||
ogType: article
|
||||
keywords: ["cron scheduler", "recurring tasks", "reminders", "apscheduler", "task scheduling"]
|
||||
keywords:
|
||||
[
|
||||
"cron scheduler",
|
||||
"recurring tasks",
|
||||
"reminders",
|
||||
"apscheduler",
|
||||
"task scheduling",
|
||||
]
|
||||
tags: ["advanced", "automation"]
|
||||
---
|
||||
|
||||
@@ -43,7 +50,7 @@ The scheduler provides two main functions:
|
||||
### add_recurring
|
||||
|
||||
```python
|
||||
from pocketclaw.scheduler import scheduler
|
||||
from pocketpaw.scheduler import scheduler
|
||||
|
||||
scheduler.add_recurring(
|
||||
task_id="weekly-summary",
|
||||
@@ -67,9 +74,9 @@ Recurring tasks are persisted to the config and re-loaded on startup. One-time r
|
||||
|
||||
Standard cron format: `minute hour day_of_month month day_of_week`
|
||||
|
||||
| Expression | Description |
|
||||
|------------|-------------|
|
||||
| `0 9 * * 1` | Every Monday at 9:00 AM |
|
||||
| `*/30 * * * *` | Every 30 minutes |
|
||||
| `0 8,17 * * 1-5` | 8 AM and 5 PM on weekdays |
|
||||
| `0 0 1 * *` | First day of every month at midnight |
|
||||
| Expression | Description |
|
||||
| ---------------- | ------------------------------------ |
|
||||
| `0 9 * * 1` | Every Monday at 9:00 AM |
|
||||
| `*/30 * * * *` | Every 30 minutes |
|
||||
| `0 8,17 * * 1-5` | 8 AM and 5 PM on weekdays |
|
||||
| `0 0 1 * *` | First day of every month at midnight |
|
||||
|
||||
@@ -3,7 +3,14 @@ title: Message Bus
|
||||
description: "The message bus is PocketPaw's communication backbone: async pub/sub for InboundMessage, OutboundMessage, and SystemEvent types flowing between channels and the agent loop."
|
||||
section: Core Concepts
|
||||
ogType: article
|
||||
keywords: ["pub/sub", "async messaging", "event types", "inbound message", "outbound message"]
|
||||
keywords:
|
||||
[
|
||||
"pub/sub",
|
||||
"async messaging",
|
||||
"event types",
|
||||
"inbound message",
|
||||
"outbound message",
|
||||
]
|
||||
tags: ["architecture", "messaging"]
|
||||
---
|
||||
|
||||
@@ -16,8 +23,8 @@ The message bus is the backbone of PocketPaw's architecture. All communication b
|
||||
The message bus implements a simple **publish/subscribe** pattern. Publishers emit events, and subscribers receive them asynchronously. This decouples components so they don't need to know about each other.
|
||||
|
||||
```python
|
||||
from pocketclaw.bus.message_bus import MessageBus
|
||||
from pocketclaw.bus.events import InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus.message_bus import MessageBus
|
||||
from pocketpaw.bus.events import InboundMessage, OutboundMessage
|
||||
|
||||
bus = MessageBus()
|
||||
|
||||
@@ -39,35 +46,35 @@ await bus.publish(InboundMessage(
|
||||
|
||||
Represents user input from any channel:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `content` | `str` | The message text |
|
||||
| `channel` | `str` | Source channel (telegram, discord, slack, etc.) |
|
||||
| `session_id` | `str` | Unique session identifier |
|
||||
| `metadata` | `dict` | Channel-specific metadata (chat_id, thread_ts, etc.) |
|
||||
| Field | Type | Description |
|
||||
| ------------ | ------ | ---------------------------------------------------- |
|
||||
| `content` | `str` | The message text |
|
||||
| `channel` | `str` | Source channel (telegram, discord, slack, etc.) |
|
||||
| `session_id` | `str` | Unique session identifier |
|
||||
| `metadata` | `dict` | Channel-specific metadata (chat_id, thread_ts, etc.) |
|
||||
|
||||
### OutboundMessage
|
||||
|
||||
Agent responses sent back to channels:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `content` | `str` | Response text |
|
||||
| `channel` | `str` | Target channel |
|
||||
| `session_id` | `str` | Session identifier |
|
||||
| Field | Type | Description |
|
||||
| ----------------- | ------ | --------------------------------- |
|
||||
| `content` | `str` | Response text |
|
||||
| `channel` | `str` | Target channel |
|
||||
| `session_id` | `str` | Session identifier |
|
||||
| `is_stream_chunk` | `bool` | Whether this is a streaming chunk |
|
||||
| `is_stream_end` | `bool` | Whether this is the final chunk |
|
||||
| `metadata` | `dict` | Channel-specific metadata |
|
||||
| `is_stream_end` | `bool` | Whether this is the final chunk |
|
||||
| `metadata` | `dict` | Channel-specific metadata |
|
||||
|
||||
### SystemEvent
|
||||
|
||||
Internal events consumed by the web dashboard:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `event_type` | `str` | Event type (tool_start, tool_result, thinking, error, inbox_update) |
|
||||
| `data` | `dict` | Event-specific data |
|
||||
| `session_id` | `str` | Session identifier |
|
||||
| Field | Type | Description |
|
||||
| ------------ | ------ | ------------------------------------------------------------------- |
|
||||
| `event_type` | `str` | Event type (tool_start, tool_result, thinking, error, inbox_update) |
|
||||
| `data` | `dict` | Event-specific data |
|
||||
| `session_id` | `str` | Session identifier |
|
||||
|
||||
## Streaming Protocol
|
||||
|
||||
|
||||
@@ -3,7 +3,14 @@ title: Tool System
|
||||
description: "PocketPaw's extensible tool system uses ToolProtocol interfaces with dual-schema export (Anthropic and OpenAI), a policy engine with deny-wins precedence, and 50+ built-in tools."
|
||||
section: Core Concepts
|
||||
ogType: article
|
||||
keywords: ["tool protocol", "tool registry", "policy engine", "anthropic schema", "openai schema"]
|
||||
keywords:
|
||||
[
|
||||
"tool protocol",
|
||||
"tool registry",
|
||||
"policy engine",
|
||||
"anthropic schema",
|
||||
"openai schema",
|
||||
]
|
||||
tags: ["tools", "architecture"]
|
||||
---
|
||||
|
||||
@@ -11,7 +18,10 @@ tags: ["tools", "architecture"]
|
||||
|
||||
PocketPaw's tool system provides 30+ built-in tools and supports custom tool creation. Tools are governed by a policy system that controls which tools are available.
|
||||
|
||||
<img src="/Tool-system-architecture-and-policy-system.webp" alt="Tool system architecture: 21 built-in tools across eight categories, ToolProtocol interface with dual-schema export, and three-tier policy engine (profiles, groups, allow/deny lists) with strict deny-wins precedence." />
|
||||
<img
|
||||
src="/Tool-system-architecture-and-policy-system.webp"
|
||||
alt="Tool system architecture: 21 built-in tools across eight categories, ToolProtocol interface with dual-schema export, and three-tier policy engine (profiles, groups, allow/deny lists) with strict deny-wins precedence."
|
||||
/>
|
||||
|
||||
## Tool Protocol
|
||||
|
||||
@@ -38,7 +48,7 @@ The `ToolDefinition` provides schema export for both Anthropic and OpenAI format
|
||||
The `ToolRegistry` is the central registry for all tools:
|
||||
|
||||
```python
|
||||
from pocketclaw.tools.registry import ToolRegistry
|
||||
from pocketpaw.tools.registry import ToolRegistry
|
||||
|
||||
registry = ToolRegistry()
|
||||
registry.register(MyCustomTool())
|
||||
@@ -57,60 +67,67 @@ The registry automatically filters tools based on the active [tool policy](/tool
|
||||
PocketPaw ships with these built-in tools:
|
||||
|
||||
### Core Tools (Claude Agent SDK)
|
||||
|
||||
- **Bash** — Execute shell commands
|
||||
- **Read** — Read files from the filesystem
|
||||
- **Write** — Write files to the filesystem
|
||||
- **Edit** — Edit existing files
|
||||
|
||||
### Search & Research
|
||||
|
||||
- **web_search** — Search the web via Tavily or Brave
|
||||
- **research** — Multi-step web research chains
|
||||
|
||||
### Media
|
||||
|
||||
- **image_gen** — Generate images with Google Gemini
|
||||
- **voice** — Text-to-speech (OpenAI, ElevenLabs)
|
||||
- **stt** — Speech-to-text (OpenAI Whisper)
|
||||
- **ocr** — Extract text from images (GPT-4o Vision + pytesseract)
|
||||
|
||||
### Productivity
|
||||
|
||||
- **gmail** — Search, read, and send emails
|
||||
- **calendar** — List, create, and search calendar events
|
||||
- **gdrive** — List, download, upload, and share files
|
||||
- **gdocs** — Read, create, and search documents
|
||||
|
||||
### Entertainment
|
||||
|
||||
- **spotify** — Search, playback, playlists, now playing
|
||||
- **reddit** — Search, read threads, trending content
|
||||
|
||||
### Agent Tools
|
||||
|
||||
- **delegate** — Spawn sub-agents for parallel work
|
||||
- **skill_gen** — Generate custom skill definitions
|
||||
|
||||
### Browser
|
||||
|
||||
- **browser** — Playwright-based web automation using accessibility tree snapshots
|
||||
|
||||
## Tool Groups
|
||||
|
||||
Tools are organized into groups for policy management:
|
||||
|
||||
| Group | Tools |
|
||||
|-------|-------|
|
||||
| `group:filesystem` | read_file, write_file, list_dir |
|
||||
| `group:shell` | shell |
|
||||
| `group:memory` | save_memory, recall_memory |
|
||||
| `group:search` | web_search |
|
||||
| `group:media` | image_gen, voice, stt, ocr |
|
||||
| `group:gmail` | gmail_search, gmail_read, gmail_send |
|
||||
| `group:calendar` | calendar_list, calendar_create, calendar_search |
|
||||
| `group:drive` | gdrive_list, gdrive_download, gdrive_upload, gdrive_share |
|
||||
| `group:docs` | gdocs_read, gdocs_create, gdocs_search |
|
||||
| `group:spotify` | spotify_search, spotify_now_playing, spotify_playback, spotify_playlist |
|
||||
| `group:reddit` | reddit_search, reddit_read, reddit_trending |
|
||||
| `group:voice` | voice, stt |
|
||||
| `group:research` | research |
|
||||
| `group:delegation` | delegate |
|
||||
| `group:skills` | skill_gen |
|
||||
| `group:mcp` | All MCP server tools |
|
||||
| Group | Tools |
|
||||
| ------------------ | ----------------------------------------------------------------------- |
|
||||
| `group:filesystem` | read_file, write_file, list_dir |
|
||||
| `group:shell` | shell |
|
||||
| `group:memory` | save_memory, recall_memory |
|
||||
| `group:search` | web_search |
|
||||
| `group:media` | image_gen, voice, stt, ocr |
|
||||
| `group:gmail` | gmail_search, gmail_read, gmail_send |
|
||||
| `group:calendar` | calendar_list, calendar_create, calendar_search |
|
||||
| `group:drive` | gdrive_list, gdrive_download, gdrive_upload, gdrive_share |
|
||||
| `group:docs` | gdocs_read, gdocs_create, gdocs_search |
|
||||
| `group:spotify` | spotify_search, spotify_now_playing, spotify_playback, spotify_playlist |
|
||||
| `group:reddit` | reddit_search, reddit_read, reddit_trending |
|
||||
| `group:voice` | voice, stt |
|
||||
| `group:research` | research |
|
||||
| `group:delegation` | delegate |
|
||||
| `group:skills` | skill_gen |
|
||||
| `group:mcp` | All MCP server tools |
|
||||
|
||||
## Schema Export
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Project Structure
|
||||
description: "Explore the PocketPaw codebase layout — src/pocketclaw package structure, bus adapters, agent backends, tool registry, memory stores, and frontend dashboard files."
|
||||
description: "Explore the PocketPaw codebase layout — src/pocketpaw package structure, bus adapters, agent backends, tool registry, memory stores, and frontend dashboard files."
|
||||
section: Getting Started
|
||||
ogType: article
|
||||
keywords: ["codebase", "directory layout", "source code", "package structure"]
|
||||
@@ -15,7 +15,7 @@ PocketPaw's codebase follows a modular architecture. Here's how it's organized.
|
||||
|
||||
```text
|
||||
pocketpaw/
|
||||
├── src/pocketclaw/ # Main Python package
|
||||
├── src/pocketpaw/ # Main Python package
|
||||
│ ├── __main__.py # CLI entry point
|
||||
│ ├── config.py # Pydantic Settings configuration
|
||||
│ ├── scheduler.py # Cron/recurring task scheduler
|
||||
|
||||
@@ -3,7 +3,8 @@ title: Custom Tools
|
||||
description: "Build custom tools for PocketPaw using the ToolProtocol interface. Define tool schemas compatible with both Anthropic and OpenAI APIs, register them in the ToolRegistry, and use them immediately."
|
||||
section: Tools
|
||||
ogType: article
|
||||
keywords: ["custom tools", "tool protocol", "tool development", "plugin", "extensible"]
|
||||
keywords:
|
||||
["custom tools", "tool protocol", "tool development", "plugin", "extensible"]
|
||||
tags: ["tools", "development"]
|
||||
---
|
||||
|
||||
@@ -14,7 +15,7 @@ PocketPaw's tool system is extensible. You can create custom tools by implementi
|
||||
## ToolProtocol Interface
|
||||
|
||||
```python
|
||||
from pocketclaw.tools.registry import ToolProtocol, ToolDefinition
|
||||
from pocketpaw.tools.registry import ToolProtocol, ToolDefinition
|
||||
|
||||
class MyCustomTool:
|
||||
@property
|
||||
@@ -53,7 +54,7 @@ class MyCustomTool:
|
||||
Register your tool with the `ToolRegistry`:
|
||||
|
||||
```python
|
||||
from pocketclaw.tools.registry import ToolRegistry
|
||||
from pocketpaw.tools.registry import ToolRegistry
|
||||
|
||||
registry = ToolRegistry()
|
||||
registry.register(MyCustomTool())
|
||||
|
||||
@@ -1122,7 +1122,7 @@ class PocketPawInstaller:
|
||||
except FileNotFoundError:
|
||||
# Might not be on PATH yet, try python -m
|
||||
try:
|
||||
os.execvp(sys.executable, [sys.executable, "-m", "pocketclaw"])
|
||||
os.execvp(sys.executable, [sys.executable, "-m", "pocketpaw"])
|
||||
except Exception as exc:
|
||||
print(f" Could not launch: {exc}")
|
||||
print(" Try running 'pocketpaw' manually.\n")
|
||||
|
||||
@@ -26,16 +26,16 @@ A lightweight desktop app (~15MB) that lets non-developers run PocketPaw with ze
|
||||
|
||||
## Modules
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `__main__.py` | Entry point — orchestrates bootstrap, server, tray |
|
||||
| `bootstrap.py` | Python detection, venv creation, pip install |
|
||||
| `server.py` | Server process lifecycle, PID management, health checks |
|
||||
| `tray.py` | System tray icon with dynamic menu (via pystray) |
|
||||
| `splash.py` | First-run tkinter progress window |
|
||||
| `updater.py` | PyPI version check and one-click upgrade |
|
||||
| `build/build.py` | PyInstaller build script |
|
||||
| `build/launcher.spec` | PyInstaller spec file (folder mode, platform-specific) |
|
||||
| File | Purpose |
|
||||
| --------------------- | ------------------------------------------------------- |
|
||||
| `__main__.py` | Entry point — orchestrates bootstrap, server, tray |
|
||||
| `bootstrap.py` | Python detection, venv creation, pip install |
|
||||
| `server.py` | Server process lifecycle, PID management, health checks |
|
||||
| `tray.py` | System tray icon with dynamic menu (via pystray) |
|
||||
| `splash.py` | First-run tkinter progress window |
|
||||
| `updater.py` | PyPI version check and one-click upgrade |
|
||||
| `build/build.py` | PyInstaller build script |
|
||||
| `build/launcher.spec` | PyInstaller spec file (folder mode, platform-specific) |
|
||||
|
||||
## Running from source
|
||||
|
||||
@@ -54,16 +54,16 @@ PYTHONPATH=. python -m installer.launcher --no-browser --no-tray --port 9999
|
||||
|
||||
### CLI Options
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--no-browser` | Don't auto-open the browser |
|
||||
| `--no-tray` | Run headless (no system tray icon, Ctrl+C to stop) |
|
||||
| `--port PORT` | Override the dashboard port (default: 8888) |
|
||||
| Flag | Description |
|
||||
| --------------- | ---------------------------------------------------------------------------- |
|
||||
| `--no-browser` | Don't auto-open the browser |
|
||||
| `--no-tray` | Run headless (no system tray icon, Ctrl+C to stop) |
|
||||
| `--port PORT` | Override the dashboard port (default: 8888) |
|
||||
| `--extras LIST` | Comma-separated pip extras, e.g. `telegram,discord` (default: `recommended`) |
|
||||
| `--reset` | Delete the venv and reinstall from scratch |
|
||||
| `--dev` | Install from the `dev` branch instead of PyPI (shortcut for `--branch dev`) |
|
||||
| `--branch NAME` | Install from a specific git branch (e.g. `--branch feat/new-thing`) |
|
||||
| `--local PATH` | Install from a local directory in editable mode |
|
||||
| `--reset` | Delete the venv and reinstall from scratch |
|
||||
| `--dev` | Install from the `dev` branch instead of PyPI (shortcut for `--branch dev`) |
|
||||
| `--branch NAME` | Install from a specific git branch (e.g. `--branch feat/new-thing`) |
|
||||
| `--local PATH` | Install from a local directory in editable mode |
|
||||
|
||||
## Dev / Branch Testing
|
||||
|
||||
@@ -143,6 +143,7 @@ hdiutil create -volname PocketPaw \
|
||||
Option A: Use [Inno Setup](https://jrsoftware.org/isinfo.php) (free) — point it at `dist\launcher\PocketPaw\`.
|
||||
|
||||
Option B: Zip the folder for a portable build:
|
||||
|
||||
```powershell
|
||||
Compress-Archive -Path dist\launcher\PocketPaw -DestinationPath dist\launcher\PocketPaw-portable.zip
|
||||
```
|
||||
@@ -150,11 +151,13 @@ Compress-Archive -Path dist\launcher\PocketPaw -DestinationPath dist\launcher\Po
|
||||
### Automated builds (CI)
|
||||
|
||||
The GitHub Actions workflow `.github/workflows/build-launcher.yml` builds for:
|
||||
|
||||
- **macOS (Apple Silicon)** — `.dmg`
|
||||
- **macOS (Intel)** — `.dmg`
|
||||
- **Windows** — `.exe` installer (via Inno Setup)
|
||||
|
||||
Triggered on:
|
||||
|
||||
- **Release published** — artifacts are attached to the GitHub release
|
||||
- **Manual dispatch** — artifacts are uploaded as workflow artifacts
|
||||
|
||||
@@ -169,7 +172,7 @@ Triggered on:
|
||||
|
||||
### Server management (`server.py`)
|
||||
|
||||
- Starts PocketPaw as a subprocess: `{venv}/bin/python -m pocketclaw --port {port}`
|
||||
- Starts PocketPaw as a subprocess: `{venv}/bin/python -m pocketpaw --port {port}`
|
||||
- Writes PID to `~/.pocketpaw/launcher.pid`
|
||||
- Health check via HTTP GET to `http://127.0.0.1:{port}/`
|
||||
- Graceful shutdown: SIGTERM → wait → SIGKILL
|
||||
@@ -189,14 +192,14 @@ Triggered on:
|
||||
|
||||
## File locations
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `~/.pocketpaw/venv/` | Virtual environment with pocketpaw installed |
|
||||
| `~/.pocketpaw/config.json` | PocketPaw configuration |
|
||||
| `~/.pocketpaw/launcher.pid` | Server process PID |
|
||||
| `~/.pocketpaw/logs/launcher.log` | Launcher log file |
|
||||
| `~/.pocketpaw/.dev-mode` | Dev mode marker (present when `--dev`/`--branch`/`--local` was used) |
|
||||
| `~/.pocketpaw/python/` | Embedded Python (Windows only) |
|
||||
| Path | Purpose |
|
||||
| -------------------------------- | -------------------------------------------------------------------- |
|
||||
| `~/.pocketpaw/venv/` | Virtual environment with pocketpaw installed |
|
||||
| `~/.pocketpaw/config.json` | PocketPaw configuration |
|
||||
| `~/.pocketpaw/launcher.pid` | Server process PID |
|
||||
| `~/.pocketpaw/logs/launcher.log` | Launcher log file |
|
||||
| `~/.pocketpaw/.dev-mode` | Dev mode marker (present when `--dev`/`--branch`/`--local` was used) |
|
||||
| `~/.pocketpaw/python/` | Embedded Python (Windows only) |
|
||||
|
||||
## Tests
|
||||
|
||||
|
||||
@@ -313,7 +313,7 @@ cat ~/.pocketpaw/.dev-mode
|
||||
# Should show: branch=dev
|
||||
|
||||
# Verify pocketpaw is installed
|
||||
~/.pocketpaw/venv/bin/python -c "import pocketclaw; print(pocketclaw.__version__)"
|
||||
~/.pocketpaw/venv/bin/python -c "import pocketpaw; print(pocketpaw.__version__)"
|
||||
```
|
||||
|
||||
### Windows (PowerShell)
|
||||
@@ -329,7 +329,7 @@ Get-Content $env:USERPROFILE\.pocketpaw\.dev-mode
|
||||
# Should show: branch=dev
|
||||
|
||||
# Verify pocketpaw is installed
|
||||
& "$env:USERPROFILE\.pocketpaw\venv\Scripts\python.exe" -c "import pocketclaw; print(pocketclaw.__version__)"
|
||||
& "$env:USERPROFILE\.pocketpaw\venv\Scripts\python.exe" -c "import pocketpaw; print(pocketpaw.__version__)"
|
||||
```
|
||||
|
||||
### Test local editable install
|
||||
@@ -355,6 +355,7 @@ ls ~/.pocketpaw/.dev-mode 2>&1
|
||||
```
|
||||
|
||||
**What to verify:**
|
||||
|
||||
- [ ] `--dev` installs from git, not PyPI
|
||||
- [ ] `~/.pocketpaw/.dev-mode` marker file is created
|
||||
- [ ] `--reset` without `--dev` removes the marker and installs from PyPI
|
||||
@@ -437,28 +438,28 @@ gh workflow run "Build Desktop Launcher" -f version=test-0.0.1
|
||||
|
||||
## Quick Checklist
|
||||
|
||||
| # | Test | macOS | Windows | Linux |
|
||||
|---|------|:-----:|:-------:|:-----:|
|
||||
| 1 | `make_icons.py` produces `.ico` + `.icns` | [ ] | [ ] | [ ] |
|
||||
| 2 | `build.py --version X` succeeds | [ ] | [ ] | N/A |
|
||||
| 3 | DMG mounts, shows app + Applications alias | [ ] | N/A | N/A |
|
||||
| 4 | Installer wizard works, shortcuts created | N/A | [ ] | N/A |
|
||||
| 5 | Launcher starts from source (`--no-browser`) | [ ] | [ ] | [ ] |
|
||||
| 6 | Tray menu shows all items with version | [ ] | [ ] | [ ] |
|
||||
| 7 | Tooltip updates dynamically | [ ] | [ ] | [ ] |
|
||||
| 8 | `--autostart` creates platform entry | [ ] | [ ] | [ ] |
|
||||
| 9 | `--no-autostart` removes it | [ ] | [ ] | [ ] |
|
||||
| 10 | Tray "Start on Login" toggles correctly | [ ] | [ ] | [ ] |
|
||||
| 11 | `--uninstall` interactive mode works | [ ] | [ ] | [ ] |
|
||||
| 12 | Tray "Uninstall..." removes safe components | [ ] | [ ] | [ ] |
|
||||
| 13 | "View Logs..." opens log file | [ ] | [ ] | [ ] |
|
||||
| 14 | `--dev` installs from git branch | [ ] | [ ] | [ ] |
|
||||
| 15 | `--branch X` installs from custom branch | [ ] | [ ] | [ ] |
|
||||
| 16 | `--local /path` does editable install | [ ] | [ ] | [ ] |
|
||||
| 17 | `--reset` without `--dev` switches back to PyPI | [ ] | [ ] | [ ] |
|
||||
| 18 | Dev mode updater re-pulls from branch | [ ] | [ ] | [ ] |
|
||||
| 19 | `install.ps1` bootstraps correctly | N/A | [ ] | N/A |
|
||||
| 20 | `install.sh` redirects Windows users to PS1 | N/A | [ ] | N/A |
|
||||
| 21 | CI workflow produces all 3 artifacts | [ ] | [ ] | N/A |
|
||||
| 22 | Checksums are generated alongside artifacts | [ ] | [ ] | N/A |
|
||||
| 23 | Automated tests pass (62 tests) | [ ] | [ ] | [ ] |
|
||||
| # | Test | macOS | Windows | Linux |
|
||||
| --- | ----------------------------------------------- | :---: | :-----: | :---: |
|
||||
| 1 | `make_icons.py` produces `.ico` + `.icns` | [ ] | [ ] | [ ] |
|
||||
| 2 | `build.py --version X` succeeds | [ ] | [ ] | N/A |
|
||||
| 3 | DMG mounts, shows app + Applications alias | [ ] | N/A | N/A |
|
||||
| 4 | Installer wizard works, shortcuts created | N/A | [ ] | N/A |
|
||||
| 5 | Launcher starts from source (`--no-browser`) | [ ] | [ ] | [ ] |
|
||||
| 6 | Tray menu shows all items with version | [ ] | [ ] | [ ] |
|
||||
| 7 | Tooltip updates dynamically | [ ] | [ ] | [ ] |
|
||||
| 8 | `--autostart` creates platform entry | [ ] | [ ] | [ ] |
|
||||
| 9 | `--no-autostart` removes it | [ ] | [ ] | [ ] |
|
||||
| 10 | Tray "Start on Login" toggles correctly | [ ] | [ ] | [ ] |
|
||||
| 11 | `--uninstall` interactive mode works | [ ] | [ ] | [ ] |
|
||||
| 12 | Tray "Uninstall..." removes safe components | [ ] | [ ] | [ ] |
|
||||
| 13 | "View Logs..." opens log file | [ ] | [ ] | [ ] |
|
||||
| 14 | `--dev` installs from git branch | [ ] | [ ] | [ ] |
|
||||
| 15 | `--branch X` installs from custom branch | [ ] | [ ] | [ ] |
|
||||
| 16 | `--local /path` does editable install | [ ] | [ ] | [ ] |
|
||||
| 17 | `--reset` without `--dev` switches back to PyPI | [ ] | [ ] | [ ] |
|
||||
| 18 | Dev mode updater re-pulls from branch | [ ] | [ ] | [ ] |
|
||||
| 19 | `install.ps1` bootstraps correctly | N/A | [ ] | N/A |
|
||||
| 20 | `install.sh` redirects Windows users to PS1 | N/A | [ ] | N/A |
|
||||
| 21 | CI workflow produces all 3 artifacts | [ ] | [ ] | N/A |
|
||||
| 22 | Checksums are generated alongside artifacts | [ ] | [ ] | N/A |
|
||||
| 23 | Automated tests pass (62 tests) | [ ] | [ ] | [ ] |
|
||||
|
||||
@@ -63,7 +63,7 @@ class ServerManager:
|
||||
logger.info("Default port busy, using port %d", self.port)
|
||||
|
||||
self.on_status(f"Starting PocketPaw on port {self.port}...")
|
||||
logger.info("Starting server: %s -m pocketclaw --port %d", python, self.port)
|
||||
logger.info("Starting server: %s -m pocketpaw --port %d", python, self.port)
|
||||
|
||||
try:
|
||||
# Start the server process — redirect output to a log file
|
||||
@@ -72,7 +72,7 @@ class ServerManager:
|
||||
self._log_fh = open(log_file, "a", encoding="utf-8") # noqa: SIM115
|
||||
env = self._build_env()
|
||||
self._process = subprocess.Popen(
|
||||
[str(python), "-m", "pocketclaw", "--port", str(self.port)],
|
||||
[str(python), "-m", "pocketpaw", "--port", str(self.port)],
|
||||
env=env,
|
||||
stdout=self._log_fh,
|
||||
stderr=self._log_fh,
|
||||
@@ -84,7 +84,7 @@ class ServerManager:
|
||||
PID_FILE.write_text(str(self._process.pid))
|
||||
|
||||
# Wait for the server to become healthy
|
||||
# pocketclaw needs ~25s for startup + internal setup
|
||||
# pocketpaw needs ~25s for startup + internal setup
|
||||
if self._wait_for_healthy(timeout=60):
|
||||
self.on_status(f"PocketPaw running on port {self.port}")
|
||||
return True
|
||||
@@ -180,17 +180,17 @@ class ServerManager:
|
||||
else:
|
||||
venv_bin = str(VENV_DIR / "bin")
|
||||
|
||||
# Also add the uv directory so pocketclaw's auto_install can find uv
|
||||
# Also add the uv directory so pocketpaw's auto_install can find uv
|
||||
uv_dir = str(POCKETPAW_HOME / "uv")
|
||||
env["PATH"] = venv_bin + os.pathsep + uv_dir + os.pathsep + env.get("PATH", "")
|
||||
|
||||
env["VIRTUAL_ENV"] = str(VENV_DIR)
|
||||
# Force UTF-8 so emoji/unicode in pocketclaw output doesn't crash
|
||||
# Force UTF-8 so emoji/unicode in pocketpaw output doesn't crash
|
||||
# on Windows (default cp1252 can't encode them)
|
||||
env["PYTHONIOENCODING"] = "utf-8"
|
||||
env["PYTHONUTF8"] = "1"
|
||||
|
||||
# Set UV_OVERRIDE so any uv invocation (including pocketclaw's
|
||||
# Set UV_OVERRIDE so any uv invocation (including pocketpaw's
|
||||
# internal auto_install) uses our tiktoken override
|
||||
overrides_file = POCKETPAW_HOME / "uv-overrides.txt"
|
||||
if not overrides_file.exists():
|
||||
|
||||
@@ -153,7 +153,7 @@ dev = [
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
pocketpaw = "pocketclaw.__main__:main"
|
||||
pocketpaw = "pocketpaw.__main__:main"
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/pocketpaw/pocketpaw"
|
||||
@@ -167,7 +167,7 @@ requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/pocketclaw"]
|
||||
packages = ["src/pocketpaw"]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Bootstrap package.
|
||||
# Created: 2026-02-02
|
||||
|
||||
from pocketclaw.bootstrap.protocol import BootstrapProviderProtocol, BootstrapContext
|
||||
from pocketclaw.bootstrap.default_provider import DefaultBootstrapProvider
|
||||
from pocketclaw.bootstrap.context_builder import AgentContextBuilder
|
||||
|
||||
__all__ = [
|
||||
"BootstrapProviderProtocol",
|
||||
"BootstrapContext",
|
||||
"DefaultBootstrapProvider",
|
||||
"AgentContextBuilder",
|
||||
]
|
||||
@@ -1,6 +0,0 @@
|
||||
"""LLM package for PocketPaw."""
|
||||
|
||||
from pocketclaw.llm.client import LLMClient, resolve_llm_client
|
||||
from pocketclaw.llm.router import LLMRouter
|
||||
|
||||
__all__ = ["LLMClient", "LLMRouter", "resolve_llm_client"]
|
||||
@@ -1,11 +0,0 @@
|
||||
from pocketclaw.security.audit import AuditLogger, AuditEvent, AuditSeverity, get_audit_logger
|
||||
from pocketclaw.security.guardian import GuardianAgent, get_guardian
|
||||
|
||||
__all__ = [
|
||||
"AuditLogger",
|
||||
"AuditEvent",
|
||||
"AuditSeverity",
|
||||
"get_audit_logger",
|
||||
"GuardianAgent",
|
||||
"get_guardian",
|
||||
]
|
||||
@@ -1,15 +0,0 @@
|
||||
# Tools package.
|
||||
|
||||
from pocketclaw.tools.policy import TOOL_GROUPS, TOOL_PROFILES, ToolPolicy
|
||||
from pocketclaw.tools.protocol import BaseTool, ToolDefinition, ToolProtocol
|
||||
from pocketclaw.tools.registry import ToolRegistry
|
||||
|
||||
__all__ = [
|
||||
"ToolProtocol",
|
||||
"BaseTool",
|
||||
"ToolDefinition",
|
||||
"ToolRegistry",
|
||||
"ToolPolicy",
|
||||
"TOOL_GROUPS",
|
||||
"TOOL_PROFILES",
|
||||
]
|
||||
@@ -18,8 +18,8 @@ import sys
|
||||
import webbrowser
|
||||
from importlib.metadata import version as get_version
|
||||
|
||||
from pocketclaw.config import Settings, get_settings
|
||||
from pocketclaw.logging_setup import setup_logging
|
||||
from pocketpaw.config import Settings, get_settings
|
||||
from pocketpaw.logging_setup import setup_logging
|
||||
|
||||
# Setup beautiful logging with Rich
|
||||
setup_logging(level="INFO")
|
||||
@@ -28,8 +28,8 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
async def run_telegram_mode(settings: Settings) -> None:
|
||||
"""Run in Telegram bot mode."""
|
||||
from pocketclaw.bot_gateway import run_bot
|
||||
from pocketclaw.web_server import find_available_port, run_pairing_server
|
||||
from pocketpaw.bot_gateway import run_bot
|
||||
from pocketpaw.web_server import find_available_port, run_pairing_server
|
||||
|
||||
# Check if we need to run pairing flow
|
||||
if not settings.telegram_bot_token or not settings.allowed_user_id:
|
||||
@@ -68,8 +68,8 @@ async def run_telegram_mode(settings: Settings) -> None:
|
||||
|
||||
async def run_multi_channel_mode(settings: Settings, args: argparse.Namespace) -> None:
|
||||
"""Run one or more channel adapters sharing a single bus and AgentLoop."""
|
||||
from pocketclaw.agents.loop import AgentLoop
|
||||
from pocketclaw.bus import get_message_bus
|
||||
from pocketpaw.agents.loop import AgentLoop
|
||||
from pocketpaw.bus import get_message_bus
|
||||
|
||||
bus = get_message_bus()
|
||||
adapters = []
|
||||
@@ -78,7 +78,7 @@ async def run_multi_channel_mode(settings: Settings, args: argparse.Namespace) -
|
||||
if not settings.discord_bot_token:
|
||||
logger.error("Discord bot token not configured. Set POCKETPAW_DISCORD_BOT_TOKEN.")
|
||||
else:
|
||||
from pocketclaw.bus.adapters.discord_adapter import DiscordAdapter
|
||||
from pocketpaw.bus.adapters.discord_adapter import DiscordAdapter
|
||||
|
||||
adapters.append(
|
||||
DiscordAdapter(
|
||||
@@ -95,7 +95,7 @@ async def run_multi_channel_mode(settings: Settings, args: argparse.Namespace) -
|
||||
"and POCKETPAW_SLACK_APP_TOKEN."
|
||||
)
|
||||
else:
|
||||
from pocketclaw.bus.adapters.slack_adapter import SlackAdapter
|
||||
from pocketpaw.bus.adapters.slack_adapter import SlackAdapter
|
||||
|
||||
adapters.append(
|
||||
SlackAdapter(
|
||||
@@ -112,7 +112,7 @@ async def run_multi_channel_mode(settings: Settings, args: argparse.Namespace) -
|
||||
"and POCKETPAW_WHATSAPP_PHONE_NUMBER_ID."
|
||||
)
|
||||
else:
|
||||
from pocketclaw.bus.adapters.whatsapp_adapter import WhatsAppAdapter
|
||||
from pocketpaw.bus.adapters.whatsapp_adapter import WhatsAppAdapter
|
||||
|
||||
adapters.append(
|
||||
WhatsAppAdapter(
|
||||
@@ -127,7 +127,7 @@ async def run_multi_channel_mode(settings: Settings, args: argparse.Namespace) -
|
||||
if not settings.signal_phone_number:
|
||||
logger.error("Signal not configured. Set POCKETPAW_SIGNAL_PHONE_NUMBER.")
|
||||
else:
|
||||
from pocketclaw.bus.adapters.signal_adapter import SignalAdapter
|
||||
from pocketpaw.bus.adapters.signal_adapter import SignalAdapter
|
||||
|
||||
adapters.append(
|
||||
SignalAdapter(
|
||||
@@ -144,7 +144,7 @@ async def run_multi_channel_mode(settings: Settings, args: argparse.Namespace) -
|
||||
"and POCKETPAW_MATRIX_USER_ID."
|
||||
)
|
||||
else:
|
||||
from pocketclaw.bus.adapters.matrix_adapter import MatrixAdapter
|
||||
from pocketpaw.bus.adapters.matrix_adapter import MatrixAdapter
|
||||
|
||||
adapters.append(
|
||||
MatrixAdapter(
|
||||
@@ -164,7 +164,7 @@ async def run_multi_channel_mode(settings: Settings, args: argparse.Namespace) -
|
||||
"and POCKETPAW_TEAMS_APP_PASSWORD."
|
||||
)
|
||||
else:
|
||||
from pocketclaw.bus.adapters.teams_adapter import TeamsAdapter
|
||||
from pocketpaw.bus.adapters.teams_adapter import TeamsAdapter
|
||||
|
||||
adapters.append(
|
||||
TeamsAdapter(
|
||||
@@ -179,7 +179,7 @@ async def run_multi_channel_mode(settings: Settings, args: argparse.Namespace) -
|
||||
if not settings.gchat_service_account_key:
|
||||
logger.error("Google Chat not configured. Set POCKETPAW_GCHAT_SERVICE_ACCOUNT_KEY.")
|
||||
else:
|
||||
from pocketclaw.bus.adapters.gchat_adapter import GoogleChatAdapter
|
||||
from pocketpaw.bus.adapters.gchat_adapter import GoogleChatAdapter
|
||||
|
||||
adapters.append(
|
||||
GoogleChatAdapter(
|
||||
@@ -208,8 +208,8 @@ async def run_multi_channel_mode(settings: Settings, args: argparse.Namespace) -
|
||||
if args.whatsapp:
|
||||
import uvicorn
|
||||
|
||||
import pocketclaw.whatsapp_gateway as wa_gw
|
||||
from pocketclaw.whatsapp_gateway import create_whatsapp_app
|
||||
import pocketpaw.whatsapp_gateway as wa_gw
|
||||
from pocketpaw.whatsapp_gateway import create_whatsapp_app
|
||||
|
||||
# Point the gateway module at our adapter
|
||||
for a in adapters:
|
||||
@@ -245,7 +245,7 @@ def _is_headless() -> bool:
|
||||
|
||||
def run_dashboard_mode(settings: Settings, host: str, port: int) -> None:
|
||||
"""Run in web dashboard mode."""
|
||||
from pocketclaw.dashboard import run_dashboard
|
||||
from pocketpaw.dashboard import run_dashboard
|
||||
|
||||
run_dashboard(host=host, port=port, open_browser=not _is_headless())
|
||||
|
||||
@@ -258,7 +258,7 @@ async def check_ollama(settings: Settings) -> int:
|
||||
import httpx
|
||||
from rich.console import Console
|
||||
|
||||
from pocketclaw.llm.client import resolve_llm_client
|
||||
from pocketpaw.llm.client import resolve_llm_client
|
||||
|
||||
console = Console()
|
||||
llm = resolve_llm_client(settings, force_provider="ollama")
|
||||
@@ -489,7 +489,7 @@ Examples:
|
||||
exit_code = asyncio.run(check_ollama(settings))
|
||||
raise SystemExit(exit_code)
|
||||
elif args.security_audit:
|
||||
from pocketclaw.security.audit_cli import run_security_audit
|
||||
from pocketpaw.security.audit_cli import run_security_audit
|
||||
|
||||
exit_code = asyncio.run(run_security_audit(fix=args.fix))
|
||||
raise SystemExit(exit_code)
|
||||
@@ -504,7 +504,7 @@ Examples:
|
||||
logger.info("👋 PocketPaw stopped.")
|
||||
finally:
|
||||
# Coordinated singleton shutdown
|
||||
from pocketclaw.lifecycle import shutdown_all
|
||||
from pocketpaw.lifecycle import shutdown_all
|
||||
|
||||
try:
|
||||
asyncio.run(shutdown_all())
|
||||
@@ -1,5 +1,5 @@
|
||||
"""Agents package for PocketPaw."""
|
||||
|
||||
from pocketclaw.agents.router import AgentRouter
|
||||
from pocketpaw.agents.router import AgentRouter
|
||||
|
||||
__all__ = ["AgentRouter"]
|
||||
@@ -4,8 +4,8 @@ import asyncio
|
||||
import logging
|
||||
from typing import AsyncIterator, Optional
|
||||
|
||||
from pocketclaw.config import Settings
|
||||
from pocketclaw.tools.screenshot import take_screenshot
|
||||
from pocketpaw.config import Settings
|
||||
from pocketpaw.tools.screenshot import take_screenshot
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -21,7 +21,7 @@ class ClaudeCodeAgent:
|
||||
|
||||
def _initialize(self) -> None:
|
||||
"""Initialize the Anthropic client."""
|
||||
from pocketclaw.llm.client import resolve_llm_client
|
||||
from pocketpaw.llm.client import resolve_llm_client
|
||||
|
||||
try:
|
||||
llm = resolve_llm_client(self.settings, force_provider="anthropic")
|
||||
@@ -25,9 +25,9 @@ from collections.abc import AsyncIterator
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from pocketclaw.agents.protocol import AgentEvent, ExecutorProtocol
|
||||
from pocketclaw.config import Settings
|
||||
from pocketclaw.tools.policy import ToolPolicy
|
||||
from pocketpaw.agents.protocol import AgentEvent, ExecutorProtocol
|
||||
from pocketpaw.config import Settings
|
||||
from pocketpaw.tools.policy import ToolPolicy
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -69,7 +69,7 @@ _TOOL_INSTRUCTIONS = """
|
||||
|
||||
You have extra tools installed. Call them with:
|
||||
```bash
|
||||
python -m pocketclaw.tools.cli <tool_name> '<json_args>'
|
||||
python -m pocketpaw.tools.cli <tool_name> '<json_args>'
|
||||
```
|
||||
|
||||
### Memory
|
||||
@@ -155,7 +155,7 @@ directly — never use a tool to look up what you already know.
|
||||
## Guidelines
|
||||
|
||||
1. **Be AGENTIC** — execute tasks using tools, don't just describe how.
|
||||
2. **Use PocketPaw tools** — always prefer `python -m pocketclaw.tools.cli` over platform-specific commands (AppleScript, PowerShell, etc.). These tools work on all operating systems.
|
||||
2. **Use PocketPaw tools** — always prefer `python -m pocketpaw.tools.cli` over platform-specific commands (AppleScript, PowerShell, etc.). These tools work on all operating systems.
|
||||
3. **Be concise** — give clear, helpful responses.
|
||||
4. **Be safe** — don't run destructive commands. Ask for confirmation if unsure.
|
||||
5. If Gmail/Calendar/Drive/Docs returns "not authenticated", tell the user to visit:
|
||||
@@ -429,7 +429,7 @@ class ClaudeAgentSDK:
|
||||
McpHttpServerConfig).
|
||||
"""
|
||||
try:
|
||||
from pocketclaw.mcp.config import load_mcp_config
|
||||
from pocketpaw.mcp.config import load_mcp_config
|
||||
except ImportError:
|
||||
return {}
|
||||
|
||||
@@ -570,7 +570,7 @@ class ClaudeAgentSDK:
|
||||
}
|
||||
|
||||
# Configure LLM provider for the Claude CLI subprocess.
|
||||
from pocketclaw.llm.client import resolve_llm_client
|
||||
from pocketpaw.llm.client import resolve_llm_client
|
||||
|
||||
llm = resolve_llm_client(self.settings)
|
||||
sdk_env = llm.to_sdk_env()
|
||||
@@ -603,7 +603,7 @@ class ClaudeAgentSDK:
|
||||
|
||||
# Smart model routing (opt-in, skip for Ollama — model already set)
|
||||
if self.settings.smart_routing_enabled and not llm.is_ollama:
|
||||
from pocketclaw.agents.model_router import ModelRouter
|
||||
from pocketpaw.agents.model_router import ModelRouter
|
||||
|
||||
model_router = ModelRouter(self.settings)
|
||||
selection = model_router.classify(message)
|
||||
@@ -12,7 +12,7 @@ import asyncio
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from pocketclaw.config import Settings
|
||||
from pocketpaw.config import Settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -38,7 +38,7 @@ class OpenInterpreterExecutor:
|
||||
try:
|
||||
from interpreter import interpreter
|
||||
|
||||
from pocketclaw.llm.client import resolve_llm_client
|
||||
from pocketpaw.llm.client import resolve_llm_client
|
||||
|
||||
# Configure for execution mode (minimal LLM usage)
|
||||
interpreter.auto_run = True
|
||||
@@ -17,14 +17,14 @@ It replaces the old highly-coupled bot loops.
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from pocketclaw.agents.router import AgentRouter
|
||||
from pocketclaw.bootstrap import AgentContextBuilder
|
||||
from pocketclaw.bus import InboundMessage, OutboundMessage, SystemEvent, get_message_bus
|
||||
from pocketclaw.bus.commands import get_command_handler
|
||||
from pocketclaw.bus.events import Channel
|
||||
from pocketclaw.config import Settings, get_settings
|
||||
from pocketclaw.memory import get_memory_manager
|
||||
from pocketclaw.security.injection_scanner import ThreatLevel, get_injection_scanner
|
||||
from pocketpaw.agents.router import AgentRouter
|
||||
from pocketpaw.bootstrap import AgentContextBuilder
|
||||
from pocketpaw.bus import InboundMessage, OutboundMessage, SystemEvent, get_message_bus
|
||||
from pocketpaw.bus.commands import get_command_handler
|
||||
from pocketpaw.bus.events import Channel
|
||||
from pocketpaw.config import Settings, get_settings
|
||||
from pocketpaw.memory import get_memory_manager
|
||||
from pocketpaw.security.injection_scanner import ThreatLevel, get_injection_scanner
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -9,7 +9,7 @@ import re
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
|
||||
from pocketclaw.config import Settings
|
||||
from pocketpaw.config import Settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -10,7 +10,7 @@ import asyncio
|
||||
import logging
|
||||
from collections.abc import AsyncIterator
|
||||
|
||||
from pocketclaw.config import Settings
|
||||
from pocketpaw.config import Settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -36,7 +36,7 @@ class OpenInterpreterAgent:
|
||||
try:
|
||||
from interpreter import interpreter
|
||||
|
||||
from pocketclaw.llm.client import resolve_llm_client
|
||||
from pocketpaw.llm.client import resolve_llm_client
|
||||
|
||||
# Configure interpreter
|
||||
interpreter.auto_run = True # Don't ask for confirmation
|
||||
@@ -24,10 +24,10 @@ import re
|
||||
from pathlib import Path
|
||||
from typing import AsyncIterator, Optional
|
||||
|
||||
from pocketclaw.agents.protocol import AgentEvent
|
||||
from pocketclaw.config import Settings
|
||||
from pocketclaw.llm.client import LLMClient, resolve_llm_client
|
||||
from pocketclaw.tools.policy import ToolPolicy
|
||||
from pocketpaw.agents.protocol import AgentEvent
|
||||
from pocketpaw.config import Settings
|
||||
from pocketpaw.llm.client import LLMClient, resolve_llm_client
|
||||
from pocketpaw.tools.policy import ToolPolicy
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -359,7 +359,7 @@ class PocketPawOrchestrator:
|
||||
|
||||
# Initialize executor (Open Interpreter)
|
||||
try:
|
||||
from pocketclaw.agents.executor import OpenInterpreterExecutor
|
||||
from pocketpaw.agents.executor import OpenInterpreterExecutor
|
||||
|
||||
self._executor = OpenInterpreterExecutor(self.settings)
|
||||
except Exception as e:
|
||||
@@ -391,7 +391,7 @@ class PocketPawOrchestrator:
|
||||
def _get_mcp_tools(self) -> list[dict]:
|
||||
"""Convert MCP tools to Anthropic tool format, filtered by policy."""
|
||||
try:
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
except ImportError:
|
||||
return []
|
||||
|
||||
@@ -622,7 +622,7 @@ class PocketPawOrchestrator:
|
||||
return "\n".join(os.listdir(Path(path).expanduser()))
|
||||
|
||||
elif tool_name == "remember":
|
||||
from pocketclaw.memory.manager import get_memory_manager
|
||||
from pocketpaw.memory.manager import get_memory_manager
|
||||
|
||||
content = tool_input.get("content", "")
|
||||
tags = tool_input.get("tags", [])
|
||||
@@ -639,7 +639,7 @@ class PocketPawOrchestrator:
|
||||
)
|
||||
|
||||
elif tool_name == "recall":
|
||||
from pocketclaw.memory.manager import get_memory_manager
|
||||
from pocketpaw.memory.manager import get_memory_manager
|
||||
|
||||
query = tool_input.get("query", "")
|
||||
limit = tool_input.get("limit", 5)
|
||||
@@ -661,7 +661,7 @@ class PocketPawOrchestrator:
|
||||
return "\n".join(lines)
|
||||
|
||||
elif tool_name == "forget":
|
||||
from pocketclaw.memory.manager import get_memory_manager
|
||||
from pocketpaw.memory.manager import get_memory_manager
|
||||
|
||||
query = tool_input.get("query", "")
|
||||
if not query:
|
||||
@@ -684,7 +684,7 @@ class PocketPawOrchestrator:
|
||||
mcp_parsed = self._parse_mcp_tool_name(tool_name)
|
||||
if mcp_parsed:
|
||||
server_name, original_tool = mcp_parsed
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
|
||||
mgr = get_mcp_manager()
|
||||
result = await mgr.call_tool(server_name, original_tool, tool_input)
|
||||
@@ -752,7 +752,7 @@ class PocketPawOrchestrator:
|
||||
|
||||
# Smart model routing (opt-in, skip for Ollama — single model)
|
||||
if self.settings.smart_routing_enabled and not self._llm.is_ollama:
|
||||
from pocketclaw.agents.model_router import ModelRouter
|
||||
from pocketpaw.agents.model_router import ModelRouter
|
||||
|
||||
model_router = ModelRouter(self.settings)
|
||||
selection = model_router.classify(message)
|
||||
@@ -12,7 +12,7 @@ Changes:
|
||||
import logging
|
||||
from collections.abc import AsyncIterator
|
||||
|
||||
from pocketclaw.config import Settings
|
||||
from pocketpaw.config import Settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -39,7 +39,7 @@ class AgentRouter:
|
||||
|
||||
def _initialize_agent(self) -> None:
|
||||
"""Initialize the selected agent backend."""
|
||||
from pocketclaw.llm.client import resolve_llm_client
|
||||
from pocketpaw.llm.client import resolve_llm_client
|
||||
|
||||
backend = self.settings.agent_backend
|
||||
|
||||
@@ -59,7 +59,7 @@ class AgentRouter:
|
||||
|
||||
try:
|
||||
if backend == "claude_agent_sdk":
|
||||
from pocketclaw.agents.claude_sdk import ClaudeAgentSDKWrapper
|
||||
from pocketpaw.agents.claude_sdk import ClaudeAgentSDKWrapper
|
||||
|
||||
self._agent = ClaudeAgentSDKWrapper(self.settings)
|
||||
logger.info(
|
||||
@@ -67,13 +67,13 @@ class AgentRouter:
|
||||
)
|
||||
|
||||
elif backend == "pocketpaw_native":
|
||||
from pocketclaw.agents.pocketpaw_native import PocketPawOrchestrator
|
||||
from pocketpaw.agents.pocketpaw_native import PocketPawOrchestrator
|
||||
|
||||
self._agent = PocketPawOrchestrator(self.settings)
|
||||
logger.info("🧠 [bold blue]PocketPaw Native[/] ─ Anthropic + Open Interpreter")
|
||||
|
||||
elif backend == "open_interpreter":
|
||||
from pocketclaw.agents.open_interpreter import OpenInterpreterAgent
|
||||
from pocketpaw.agents.open_interpreter import OpenInterpreterAgent
|
||||
|
||||
self._agent = OpenInterpreterAgent(self.settings)
|
||||
logger.info(
|
||||
@@ -82,7 +82,7 @@ class AgentRouter:
|
||||
|
||||
else:
|
||||
logger.warning(f"Unknown backend: {backend} → using claude_agent_sdk")
|
||||
from pocketclaw.agents.claude_sdk import ClaudeAgentSDKWrapper
|
||||
from pocketpaw.agents.claude_sdk import ClaudeAgentSDKWrapper
|
||||
|
||||
self._agent = ClaudeAgentSDKWrapper(self.settings)
|
||||
except ImportError as exc:
|
||||
13
src/pocketpaw/bootstrap/__init__.py
Normal file
13
src/pocketpaw/bootstrap/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# Bootstrap package.
|
||||
# Created: 2026-02-02
|
||||
|
||||
from pocketpaw.bootstrap.protocol import BootstrapProviderProtocol, BootstrapContext
|
||||
from pocketpaw.bootstrap.default_provider import DefaultBootstrapProvider
|
||||
from pocketpaw.bootstrap.context_builder import AgentContextBuilder
|
||||
|
||||
__all__ = [
|
||||
"BootstrapProviderProtocol",
|
||||
"BootstrapContext",
|
||||
"DefaultBootstrapProvider",
|
||||
"AgentContextBuilder",
|
||||
]
|
||||
@@ -7,11 +7,11 @@ Updated: 2026-02-10 - Channel-aware format hints
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pocketclaw.bootstrap.default_provider import DefaultBootstrapProvider
|
||||
from pocketclaw.bootstrap.protocol import BootstrapProviderProtocol
|
||||
from pocketclaw.bus.events import Channel
|
||||
from pocketclaw.bus.format import CHANNEL_FORMAT_HINTS
|
||||
from pocketclaw.memory.manager import MemoryManager, get_memory_manager
|
||||
from pocketpaw.bootstrap.default_provider import DefaultBootstrapProvider
|
||||
from pocketpaw.bootstrap.protocol import BootstrapProviderProtocol
|
||||
from pocketpaw.bus.events import Channel
|
||||
from pocketpaw.bus.format import CHANNEL_FORMAT_HINTS
|
||||
from pocketpaw.memory.manager import MemoryManager, get_memory_manager
|
||||
|
||||
|
||||
class AgentContextBuilder:
|
||||
@@ -70,7 +70,7 @@ class AgentContextBuilder:
|
||||
|
||||
# 3. Inject sender identity block
|
||||
if sender_id:
|
||||
from pocketclaw.config import get_settings
|
||||
from pocketpaw.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
if settings.owner_id:
|
||||
@@ -5,8 +5,8 @@ Created: 2026-02-02
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from pocketclaw.bootstrap.protocol import BootstrapContext, BootstrapProviderProtocol
|
||||
from pocketclaw.config import get_config_dir
|
||||
from pocketpaw.bootstrap.protocol import BootstrapContext, BootstrapProviderProtocol
|
||||
from pocketpaw.config import get_config_dir
|
||||
|
||||
|
||||
class DefaultBootstrapProvider(BootstrapProviderProtocol):
|
||||
@@ -3,10 +3,10 @@
|
||||
import logging
|
||||
import asyncio
|
||||
|
||||
from pocketclaw.config import Settings
|
||||
from pocketclaw.bus import get_message_bus
|
||||
from pocketclaw.bus.adapters.telegram_adapter import TelegramAdapter
|
||||
from pocketclaw.agents.loop import AgentLoop
|
||||
from pocketpaw.config import Settings
|
||||
from pocketpaw.bus import get_message_bus
|
||||
from pocketpaw.bus.adapters.telegram_adapter import TelegramAdapter
|
||||
from pocketpaw.agents.loop import AgentLoop
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -68,7 +68,7 @@ class BrowserDriver:
|
||||
try:
|
||||
import playwright # noqa: F401
|
||||
except ImportError:
|
||||
from pocketclaw._compat import require_extra
|
||||
from pocketpaw._compat import require_extra
|
||||
|
||||
require_extra("playwright", "browser")
|
||||
|
||||
@@ -171,7 +171,7 @@ def get_browser_session_manager() -> BrowserSessionManager:
|
||||
if _manager_instance is None:
|
||||
_manager_instance = BrowserSessionManager()
|
||||
|
||||
from pocketclaw.lifecycle import register
|
||||
from pocketpaw.lifecycle import register
|
||||
|
||||
def _reset():
|
||||
global _manager_instance
|
||||
@@ -1,9 +1,9 @@
|
||||
# Message bus package.
|
||||
# Created: 2026-02-02
|
||||
|
||||
from pocketclaw.bus.events import InboundMessage, OutboundMessage, SystemEvent, Channel
|
||||
from pocketclaw.bus.queue import MessageBus, get_message_bus
|
||||
from pocketclaw.bus.adapters import ChannelAdapter, BaseChannelAdapter
|
||||
from pocketpaw.bus.events import InboundMessage, OutboundMessage, SystemEvent, Channel
|
||||
from pocketpaw.bus.queue import MessageBus, get_message_bus
|
||||
from pocketpaw.bus.adapters import ChannelAdapter, BaseChannelAdapter
|
||||
|
||||
__all__ = [
|
||||
"InboundMessage",
|
||||
@@ -10,8 +10,8 @@ import subprocess
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Protocol
|
||||
|
||||
from pocketclaw.bus.events import Channel, InboundMessage, OutboundMessage
|
||||
from pocketclaw.bus.queue import MessageBus
|
||||
from pocketpaw.bus.events import Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus.queue import MessageBus
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
@@ -7,7 +7,7 @@ import asyncio
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pocketclaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -45,7 +45,7 @@ class DiscordAdapter(BaseChannelAdapter):
|
||||
try:
|
||||
import discord
|
||||
except ImportError:
|
||||
from pocketclaw.bus.adapters import auto_install
|
||||
from pocketpaw.bus.adapters import auto_install
|
||||
|
||||
auto_install("discord", "discord")
|
||||
import discord
|
||||
@@ -172,7 +172,7 @@ class DiscordAdapter(BaseChannelAdapter):
|
||||
media_paths: list[str] = []
|
||||
if message.attachments:
|
||||
try:
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
downloader = get_media_downloader()
|
||||
names = []
|
||||
@@ -12,8 +12,8 @@ Created: 2026-02-07
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from pocketclaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketclaw.bus.format import convert_markdown
|
||||
from pocketpaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus.format import convert_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -72,7 +72,7 @@ class GoogleChatAdapter(BaseChannelAdapter):
|
||||
from google.oauth2 import service_account
|
||||
from googleapiclient.discovery import build
|
||||
except ImportError:
|
||||
from pocketclaw.bus.adapters import auto_install
|
||||
from pocketpaw.bus.adapters import auto_install
|
||||
|
||||
auto_install("gchat", "googleapiclient")
|
||||
from google.oauth2 import service_account
|
||||
@@ -111,7 +111,7 @@ class GoogleChatAdapter(BaseChannelAdapter):
|
||||
if attachment:
|
||||
attachments = attachment if isinstance(attachment, list) else [attachment]
|
||||
try:
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
downloader = get_media_downloader()
|
||||
names = []
|
||||
@@ -12,7 +12,7 @@ import asyncio
|
||||
import logging
|
||||
import time
|
||||
|
||||
from pocketclaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -57,7 +57,7 @@ class MatrixAdapter(BaseChannelAdapter):
|
||||
try:
|
||||
from nio import AsyncClient, RoomMessageText
|
||||
except ImportError:
|
||||
from pocketclaw.bus.adapters import auto_install
|
||||
from pocketpaw.bus.adapters import auto_install
|
||||
|
||||
auto_install("matrix", "nio")
|
||||
from nio import AsyncClient, RoomMessageText
|
||||
@@ -159,7 +159,7 @@ class MatrixAdapter(BaseChannelAdapter):
|
||||
mxc_url = getattr(event, "url", None)
|
||||
if mxc_url and mxc_url.startswith("mxc://"):
|
||||
try:
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
# Convert mxc://server/media_id to HTTPS download URL
|
||||
parts = mxc_url[len("mxc://") :]
|
||||
@@ -13,8 +13,8 @@ import threading
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from pocketclaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketclaw.bus.format import convert_markdown
|
||||
from pocketpaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus.format import convert_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -74,7 +74,7 @@ class NeonizeAdapter(BaseChannelAdapter):
|
||||
from neonize.aioze.events import ConnectedEv, MessageEv
|
||||
from neonize.utils.jid import Jid2String
|
||||
except ImportError:
|
||||
from pocketclaw.bus.adapters import auto_install
|
||||
from pocketpaw.bus.adapters import auto_install
|
||||
|
||||
auto_install("whatsapp-personal", "neonize")
|
||||
from neonize.aioze.client import NewAClient
|
||||
@@ -141,7 +141,7 @@ class NeonizeAdapter(BaseChannelAdapter):
|
||||
)
|
||||
if media_msg:
|
||||
try:
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
data = await client.download_any(message)
|
||||
mime = getattr(media_msg, "mimetype", None)
|
||||
@@ -14,8 +14,8 @@ import logging
|
||||
|
||||
import httpx
|
||||
|
||||
from pocketclaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketclaw.bus.format import convert_markdown
|
||||
from pocketpaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus.format import convert_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -96,7 +96,7 @@ class SignalAdapter(BaseChannelAdapter):
|
||||
attachments = data_msg.get("attachments", [])
|
||||
if attachments and self._http:
|
||||
try:
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
downloader = get_media_downloader()
|
||||
names = []
|
||||
@@ -7,8 +7,8 @@ import asyncio
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pocketclaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketclaw.bus.format import convert_markdown
|
||||
from pocketpaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus.format import convert_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -44,7 +44,7 @@ class SlackAdapter(BaseChannelAdapter):
|
||||
from slack_bolt.adapter.socket_mode.async_handler import AsyncSocketModeHandler
|
||||
from slack_bolt.async_app import AsyncApp
|
||||
except ImportError:
|
||||
from pocketclaw.bus.adapters import auto_install
|
||||
from pocketpaw.bus.adapters import auto_install
|
||||
|
||||
auto_install("slack", "slack_bolt")
|
||||
from slack_bolt.adapter.socket_mode.async_handler import AsyncSocketModeHandler
|
||||
@@ -146,7 +146,7 @@ class SlackAdapter(BaseChannelAdapter):
|
||||
files = event.get("files", [])
|
||||
if files:
|
||||
try:
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
downloader = get_media_downloader()
|
||||
names = []
|
||||
@@ -12,8 +12,8 @@ import asyncio
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pocketclaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketclaw.bus.format import convert_markdown
|
||||
from pocketpaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus.format import convert_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -57,7 +57,7 @@ class TeamsAdapter(BaseChannelAdapter):
|
||||
BotFrameworkAdapterSettings,
|
||||
)
|
||||
except ImportError:
|
||||
from pocketclaw.bus.adapters import auto_install
|
||||
from pocketpaw.bus.adapters import auto_install
|
||||
|
||||
auto_install("teams", "botbuilder")
|
||||
from botbuilder.core import (
|
||||
@@ -160,7 +160,7 @@ class TeamsAdapter(BaseChannelAdapter):
|
||||
attachments = getattr(activity, "attachments", None) or []
|
||||
if attachments:
|
||||
try:
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
downloader = get_media_downloader()
|
||||
names = []
|
||||
@@ -22,13 +22,13 @@ except ImportError as _exc:
|
||||
"Install it with: pip install 'pocketpaw[telegram]'"
|
||||
) from _exc
|
||||
|
||||
from pocketclaw.bus import (
|
||||
from pocketpaw.bus import (
|
||||
BaseChannelAdapter,
|
||||
Channel,
|
||||
InboundMessage,
|
||||
OutboundMessage,
|
||||
)
|
||||
from pocketclaw.bus.format import convert_markdown
|
||||
from pocketpaw.bus.format import convert_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -348,7 +348,7 @@ class TelegramAdapter(BaseChannelAdapter):
|
||||
|
||||
if file_obj:
|
||||
try:
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
data = await file_obj.download_as_bytearray()
|
||||
downloader = get_media_downloader()
|
||||
@@ -14,8 +14,8 @@ import json
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
|
||||
from pocketclaw.bus.adapters import BaseChannelAdapter
|
||||
from pocketclaw.bus.events import Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus.adapters import BaseChannelAdapter
|
||||
from pocketpaw.bus.events import Channel, InboundMessage, OutboundMessage
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
@@ -115,7 +115,7 @@ class WebhookAdapter(BaseChannelAdapter):
|
||||
media_urls = body.get("media_urls", [])
|
||||
if media_urls and isinstance(media_urls, list):
|
||||
try:
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
downloader = get_media_downloader()
|
||||
names = []
|
||||
@@ -10,9 +10,9 @@ from typing import Any
|
||||
|
||||
from fastapi import WebSocket
|
||||
|
||||
from pocketclaw.bus.adapters import BaseChannelAdapter
|
||||
from pocketclaw.bus.events import Channel, InboundMessage, OutboundMessage, SystemEvent
|
||||
from pocketclaw.bus.queue import MessageBus
|
||||
from pocketpaw.bus.adapters import BaseChannelAdapter
|
||||
from pocketpaw.bus.events import Channel, InboundMessage, OutboundMessage, SystemEvent
|
||||
from pocketpaw.bus.queue import MessageBus
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -77,7 +77,7 @@ class WebSocketAdapter(BaseChannelAdapter):
|
||||
try:
|
||||
import base64
|
||||
|
||||
from pocketclaw.bus.media import build_media_hint, get_media_downloader
|
||||
from pocketpaw.bus.media import build_media_hint, get_media_downloader
|
||||
|
||||
downloader = get_media_downloader()
|
||||
names = []
|
||||
@@ -7,8 +7,8 @@ import logging
|
||||
|
||||
import httpx
|
||||
|
||||
from pocketclaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketclaw.bus.format import convert_markdown
|
||||
from pocketpaw.bus import BaseChannelAdapter, Channel, InboundMessage, OutboundMessage
|
||||
from pocketpaw.bus.format import convert_markdown
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -143,7 +143,7 @@ class WhatsAppAdapter(BaseChannelAdapter):
|
||||
path = await self._download_whatsapp_media(media_id, filename, mime)
|
||||
if path:
|
||||
media_paths.append(path)
|
||||
from pocketclaw.bus.media import build_media_hint
|
||||
from pocketpaw.bus.media import build_media_hint
|
||||
|
||||
caption += build_media_hint([filename])
|
||||
except Exception as e:
|
||||
@@ -171,7 +171,7 @@ class WhatsAppAdapter(BaseChannelAdapter):
|
||||
return None
|
||||
|
||||
# Step 2: Download the actual file (reuse existing auth headers)
|
||||
from pocketclaw.bus.media import get_media_downloader
|
||||
from pocketpaw.bus.media import get_media_downloader
|
||||
|
||||
downloader = get_media_downloader()
|
||||
return await downloader.download_url_with_auth(
|
||||
@@ -10,8 +10,8 @@ import logging
|
||||
import re
|
||||
import uuid
|
||||
|
||||
from pocketclaw.bus.events import InboundMessage, OutboundMessage
|
||||
from pocketclaw.memory import get_memory_manager
|
||||
from pocketpaw.bus.events import InboundMessage, OutboundMessage
|
||||
from pocketpaw.memory import get_memory_manager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -274,7 +274,7 @@ class CommandHandler:
|
||||
|
||||
async def _cmd_status(self, message: InboundMessage, session_key: str) -> OutboundMessage:
|
||||
"""Show current session info."""
|
||||
from pocketclaw.config import get_settings
|
||||
from pocketpaw.config import get_settings
|
||||
|
||||
memory = get_memory_manager()
|
||||
settings = get_settings()
|
||||
@@ -10,7 +10,7 @@ from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
from pocketclaw.bus.events import Channel
|
||||
from pocketpaw.bus.events import Channel
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# LLM system-prompt hints (one sentence each)
|
||||
@@ -13,7 +13,7 @@ from pathlib import Path
|
||||
|
||||
import httpx
|
||||
|
||||
from pocketclaw.config import get_config_dir, get_settings
|
||||
from pocketpaw.config import get_config_dir, get_settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -6,7 +6,7 @@ and publishes OutboundMessage events to the message bus.
|
||||
|
||||
import logging
|
||||
|
||||
from pocketclaw.bus.events import Channel, OutboundMessage
|
||||
from pocketpaw.bus.events import Channel, OutboundMessage
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -26,14 +26,14 @@ async def notify(content: str, targets: list[str] | None = None) -> int:
|
||||
Number of messages successfully published.
|
||||
"""
|
||||
if targets is None:
|
||||
from pocketclaw.config import get_settings
|
||||
from pocketpaw.config import get_settings
|
||||
|
||||
targets = get_settings().notification_channels
|
||||
|
||||
if not targets:
|
||||
return 0
|
||||
|
||||
from pocketclaw.bus import get_message_bus
|
||||
from pocketpaw.bus import get_message_bus
|
||||
|
||||
bus = get_message_bus()
|
||||
count = 0
|
||||
@@ -7,7 +7,7 @@ import asyncio
|
||||
import logging
|
||||
from collections.abc import Awaitable, Callable
|
||||
|
||||
from pocketclaw.bus.events import Channel, InboundMessage, OutboundMessage, SystemEvent
|
||||
from pocketpaw.bus.events import Channel, InboundMessage, OutboundMessage, SystemEvent
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -166,7 +166,7 @@ def get_message_bus() -> MessageBus:
|
||||
if _bus is None:
|
||||
_bus = MessageBus()
|
||||
|
||||
from pocketclaw.lifecycle import register
|
||||
from pocketpaw.lifecycle import register
|
||||
|
||||
def _reset():
|
||||
global _bus
|
||||
@@ -379,7 +379,7 @@ class Settings(BaseSettings):
|
||||
Non-secret fields go to config.json. Secret fields (API keys, tokens)
|
||||
go to the encrypted credential store.
|
||||
"""
|
||||
from pocketclaw.credentials import SECRET_FIELDS, get_credential_store
|
||||
from pocketpaw.credentials import SECRET_FIELDS, get_credential_store
|
||||
|
||||
config_path = get_config_path()
|
||||
|
||||
@@ -543,7 +543,7 @@ class Settings(BaseSettings):
|
||||
@classmethod
|
||||
def load(cls) -> "Settings":
|
||||
"""Load settings from config file + encrypted credential store."""
|
||||
from pocketclaw.credentials import SECRET_FIELDS, get_credential_store
|
||||
from pocketpaw.credentials import SECRET_FIELDS, get_credential_store
|
||||
|
||||
# Run one-time migration from plaintext config
|
||||
_migrate_plaintext_keys()
|
||||
@@ -614,7 +614,7 @@ _MIGRATION_DONE_PATH: Path | None = None
|
||||
|
||||
def _migrate_plaintext_keys() -> None:
|
||||
"""One-time migration: move plaintext API keys from config.json to encrypted store."""
|
||||
from pocketclaw.credentials import SECRET_FIELDS, get_credential_store
|
||||
from pocketpaw.credentials import SECRET_FIELDS, get_credential_store
|
||||
|
||||
global _MIGRATION_DONE_PATH # noqa: PLW0603
|
||||
if _MIGRATION_DONE_PATH is None:
|
||||
@@ -9,7 +9,7 @@ import logging
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
from pocketclaw.config import get_config_dir, get_settings
|
||||
from pocketpaw.config import get_config_dir, get_settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -127,7 +127,7 @@ async def run_self_audit() -> dict:
|
||||
|
||||
# Run audit_cli checks (the 7 original ones)
|
||||
try:
|
||||
from pocketclaw.security.audit_cli import (
|
||||
from pocketpaw.security.audit_cli import (
|
||||
_check_audit_log,
|
||||
_check_bypass_permissions,
|
||||
_check_config_permissions,
|
||||
@@ -41,21 +41,21 @@ except ImportError as _exc:
|
||||
"but not installed. Reinstall with: pip install --upgrade pocketpaw"
|
||||
) from _exc
|
||||
|
||||
from pocketclaw.agents.loop import AgentLoop
|
||||
from pocketclaw.bootstrap import DefaultBootstrapProvider
|
||||
from pocketclaw.bus import get_message_bus
|
||||
from pocketclaw.bus.adapters.websocket_adapter import WebSocketAdapter
|
||||
from pocketclaw.config import Settings, get_access_token, get_config_path, regenerate_token
|
||||
from pocketclaw.daemon import get_daemon
|
||||
from pocketclaw.deep_work.api import router as deep_work_router
|
||||
from pocketclaw.memory import MemoryType, get_memory_manager
|
||||
from pocketclaw.mission_control.api import router as mission_control_router
|
||||
from pocketclaw.scheduler import get_scheduler
|
||||
from pocketclaw.security import get_audit_logger
|
||||
from pocketclaw.security.rate_limiter import api_limiter, auth_limiter, cleanup_all, ws_limiter
|
||||
from pocketclaw.security.session_tokens import create_session_token, verify_session_token
|
||||
from pocketclaw.skills import SkillExecutor, get_skill_loader
|
||||
from pocketclaw.tunnel import get_tunnel_manager
|
||||
from pocketpaw.agents.loop import AgentLoop
|
||||
from pocketpaw.bootstrap import DefaultBootstrapProvider
|
||||
from pocketpaw.bus import get_message_bus
|
||||
from pocketpaw.bus.adapters.websocket_adapter import WebSocketAdapter
|
||||
from pocketpaw.config import Settings, get_access_token, get_config_path, regenerate_token
|
||||
from pocketpaw.daemon import get_daemon
|
||||
from pocketpaw.deep_work.api import router as deep_work_router
|
||||
from pocketpaw.memory import MemoryType, get_memory_manager
|
||||
from pocketpaw.mission_control.api import router as mission_control_router
|
||||
from pocketpaw.scheduler import get_scheduler
|
||||
from pocketpaw.security import get_audit_logger
|
||||
from pocketpaw.security.rate_limiter import api_limiter, auth_limiter, cleanup_all, ws_limiter
|
||||
from pocketpaw.security.session_tokens import create_session_token, verify_session_token
|
||||
from pocketpaw.skills import SkillExecutor, get_skill_loader
|
||||
from pocketpaw.tunnel import get_tunnel_manager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -148,7 +148,7 @@ async def broadcast_reminder(reminder: dict):
|
||||
|
||||
# Push to notification channels
|
||||
try:
|
||||
from pocketclaw.bus.notifier import notify
|
||||
from pocketpaw.bus.notifier import notify
|
||||
|
||||
await notify(f"Reminder: {reminder.get('text', '')}")
|
||||
except Exception:
|
||||
@@ -168,7 +168,7 @@ async def broadcast_intention(intention_id: str, chunk: dict):
|
||||
# Push message-type intention chunks to notification channels
|
||||
if chunk.get("type") == "message":
|
||||
try:
|
||||
from pocketclaw.bus.notifier import notify
|
||||
from pocketpaw.bus.notifier import notify
|
||||
|
||||
await notify(chunk.get("content", ""))
|
||||
except Exception:
|
||||
@@ -195,7 +195,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
if channel == "discord":
|
||||
if not settings.discord_bot_token:
|
||||
return False
|
||||
from pocketclaw.bus.adapters.discord_adapter import DiscordAdapter
|
||||
from pocketpaw.bus.adapters.discord_adapter import DiscordAdapter
|
||||
|
||||
adapter = DiscordAdapter(
|
||||
token=settings.discord_bot_token,
|
||||
@@ -209,7 +209,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
if channel == "slack":
|
||||
if not settings.slack_bot_token or not settings.slack_app_token:
|
||||
return False
|
||||
from pocketclaw.bus.adapters.slack_adapter import SlackAdapter
|
||||
from pocketpaw.bus.adapters.slack_adapter import SlackAdapter
|
||||
|
||||
adapter = SlackAdapter(
|
||||
bot_token=settings.slack_bot_token,
|
||||
@@ -224,7 +224,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
mode = settings.whatsapp_mode
|
||||
|
||||
if mode == "personal":
|
||||
from pocketclaw.bus.adapters.neonize_adapter import NeonizeAdapter
|
||||
from pocketpaw.bus.adapters.neonize_adapter import NeonizeAdapter
|
||||
|
||||
db_path = settings.whatsapp_neonize_db or None
|
||||
adapter = NeonizeAdapter(db_path=db_path)
|
||||
@@ -235,7 +235,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
# Business mode (Cloud API)
|
||||
if not settings.whatsapp_access_token or not settings.whatsapp_phone_number_id:
|
||||
return False
|
||||
from pocketclaw.bus.adapters.whatsapp_adapter import WhatsAppAdapter
|
||||
from pocketpaw.bus.adapters.whatsapp_adapter import WhatsAppAdapter
|
||||
|
||||
adapter = WhatsAppAdapter(
|
||||
access_token=settings.whatsapp_access_token,
|
||||
@@ -250,7 +250,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
if channel == "telegram":
|
||||
if not settings.telegram_bot_token:
|
||||
return False
|
||||
from pocketclaw.bus.adapters.telegram_adapter import TelegramAdapter
|
||||
from pocketpaw.bus.adapters.telegram_adapter import TelegramAdapter
|
||||
|
||||
adapter = TelegramAdapter(
|
||||
token=settings.telegram_bot_token,
|
||||
@@ -263,7 +263,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
if channel == "signal":
|
||||
if not settings.signal_phone_number:
|
||||
return False
|
||||
from pocketclaw.bus.adapters.signal_adapter import SignalAdapter
|
||||
from pocketpaw.bus.adapters.signal_adapter import SignalAdapter
|
||||
|
||||
adapter = SignalAdapter(
|
||||
api_url=settings.signal_api_url,
|
||||
@@ -277,7 +277,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
if channel == "matrix":
|
||||
if not settings.matrix_homeserver or not settings.matrix_user_id:
|
||||
return False
|
||||
from pocketclaw.bus.adapters.matrix_adapter import MatrixAdapter
|
||||
from pocketpaw.bus.adapters.matrix_adapter import MatrixAdapter
|
||||
|
||||
adapter = MatrixAdapter(
|
||||
homeserver=settings.matrix_homeserver,
|
||||
@@ -294,7 +294,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
if channel == "teams":
|
||||
if not settings.teams_app_id or not settings.teams_app_password:
|
||||
return False
|
||||
from pocketclaw.bus.adapters.teams_adapter import TeamsAdapter
|
||||
from pocketpaw.bus.adapters.teams_adapter import TeamsAdapter
|
||||
|
||||
adapter = TeamsAdapter(
|
||||
app_id=settings.teams_app_id,
|
||||
@@ -309,7 +309,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
if channel == "google_chat":
|
||||
if not settings.gchat_service_account_key:
|
||||
return False
|
||||
from pocketclaw.bus.adapters.gchat_adapter import GoogleChatAdapter
|
||||
from pocketpaw.bus.adapters.gchat_adapter import GoogleChatAdapter
|
||||
|
||||
adapter = GoogleChatAdapter(
|
||||
mode=settings.gchat_mode,
|
||||
@@ -323,7 +323,7 @@ async def _start_channel_adapter(channel: str, settings: Settings | None = None)
|
||||
return True
|
||||
|
||||
if channel == "webhook":
|
||||
from pocketclaw.bus.adapters.webhook_adapter import WebhookAdapter
|
||||
from pocketpaw.bus.adapters.webhook_adapter import WebhookAdapter
|
||||
|
||||
adapter = WebhookAdapter()
|
||||
await adapter.start(bus)
|
||||
@@ -382,7 +382,7 @@ async def startup_event():
|
||||
|
||||
# Ensure project directories exist for all Deep Work projects
|
||||
try:
|
||||
from pocketclaw.mission_control.manager import get_mission_control_manager
|
||||
from pocketpaw.mission_control.manager import get_mission_control_manager
|
||||
|
||||
mc_manager = get_mission_control_manager()
|
||||
await mc_manager.ensure_project_directories()
|
||||
@@ -391,7 +391,7 @@ async def startup_event():
|
||||
|
||||
# Recover Deep Work projects interrupted by previous shutdown
|
||||
try:
|
||||
from pocketclaw.deep_work import recover_interrupted_projects
|
||||
from pocketpaw.deep_work import recover_interrupted_projects
|
||||
|
||||
recovered = await recover_interrupted_projects()
|
||||
if recovered:
|
||||
@@ -401,7 +401,7 @@ async def startup_event():
|
||||
|
||||
# Auto-start enabled MCP servers
|
||||
try:
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
|
||||
mcp = get_mcp_manager()
|
||||
await mcp.start_enabled_servers()
|
||||
@@ -461,7 +461,7 @@ async def shutdown_event():
|
||||
|
||||
# Stop MCP servers
|
||||
try:
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
|
||||
mcp = get_mcp_manager()
|
||||
await mcp.stop_all()
|
||||
@@ -475,7 +475,7 @@ async def shutdown_event():
|
||||
@app.get("/api/mcp/status")
|
||||
async def get_mcp_status():
|
||||
"""Get status of all configured MCP servers."""
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
|
||||
mgr = get_mcp_manager()
|
||||
return mgr.get_server_status()
|
||||
@@ -484,8 +484,8 @@ async def get_mcp_status():
|
||||
@app.post("/api/mcp/add")
|
||||
async def add_mcp_server(request: Request):
|
||||
"""Add a new MCP server configuration and optionally start it."""
|
||||
from pocketclaw.mcp.config import MCPServerConfig
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.config import MCPServerConfig
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
|
||||
data = await request.json()
|
||||
config = MCPServerConfig(
|
||||
@@ -516,7 +516,7 @@ async def add_mcp_server(request: Request):
|
||||
@app.post("/api/mcp/remove")
|
||||
async def remove_mcp_server(request: Request):
|
||||
"""Remove an MCP server config and stop it if running."""
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
|
||||
data = await request.json()
|
||||
name = data.get("name", "")
|
||||
@@ -532,8 +532,8 @@ async def remove_mcp_server(request: Request):
|
||||
@app.post("/api/mcp/toggle")
|
||||
async def toggle_mcp_server(request: Request):
|
||||
"""Toggle an MCP server: start if stopped/disconnected, stop if running."""
|
||||
from pocketclaw.mcp.config import load_mcp_config
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.config import load_mcp_config
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
|
||||
data = await request.json()
|
||||
name = data.get("name", "")
|
||||
@@ -565,8 +565,8 @@ async def toggle_mcp_server(request: Request):
|
||||
@app.post("/api/mcp/test")
|
||||
async def test_mcp_server(request: Request):
|
||||
"""Test an MCP server connection and return discovered tools."""
|
||||
from pocketclaw.mcp.config import MCPServerConfig
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.config import MCPServerConfig
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
|
||||
data = await request.json()
|
||||
config = MCPServerConfig(
|
||||
@@ -599,8 +599,8 @@ async def test_mcp_server(request: Request):
|
||||
@app.get("/api/mcp/presets")
|
||||
async def list_mcp_presets():
|
||||
"""Return all MCP presets with installed flag."""
|
||||
from pocketclaw.mcp.config import load_mcp_config
|
||||
from pocketclaw.mcp.presets import get_all_presets
|
||||
from pocketpaw.mcp.config import load_mcp_config
|
||||
from pocketpaw.mcp.presets import get_all_presets
|
||||
|
||||
installed_names = {c.name for c in load_mcp_config()}
|
||||
presets = get_all_presets()
|
||||
@@ -637,8 +637,8 @@ async def install_mcp_preset(request: Request):
|
||||
"""Install an MCP preset by ID with user-supplied env vars."""
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketclaw.mcp.presets import get_preset, preset_to_config
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.presets import get_preset, preset_to_config
|
||||
|
||||
data = await request.json()
|
||||
preset_id = data.get("preset_id", "")
|
||||
@@ -775,8 +775,8 @@ async def install_from_registry(request: Request):
|
||||
"""
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from pocketclaw.mcp.config import MCPServerConfig
|
||||
from pocketclaw.mcp.manager import get_mcp_manager
|
||||
from pocketpaw.mcp.config import MCPServerConfig
|
||||
from pocketpaw.mcp.manager import get_mcp_manager
|
||||
|
||||
data = await request.json()
|
||||
server = data.get("server", {})
|
||||
@@ -1120,7 +1120,7 @@ async def webhook_inbound(
|
||||
if slot_dict is None:
|
||||
raise HTTPException(status_code=404, detail=f"Webhook '{webhook_name}' not found")
|
||||
|
||||
from pocketclaw.bus.adapters.webhook_adapter import WebhookSlotConfig
|
||||
from pocketpaw.bus.adapters.webhook_adapter import WebhookSlotConfig
|
||||
|
||||
slot = WebhookSlotConfig(
|
||||
name=slot_dict["name"],
|
||||
@@ -1501,7 +1501,7 @@ async def oauth_authorize(service: str = Query("google_gmail")):
|
||||
detail="Google OAuth Client ID not configured. Set it in Settings first.",
|
||||
)
|
||||
|
||||
from pocketclaw.integrations.oauth import OAuthManager
|
||||
from pocketpaw.integrations.oauth import OAuthManager
|
||||
|
||||
manager = OAuthManager()
|
||||
redirect_uri = f"http://localhost:{settings.web_port}/oauth/callback"
|
||||
@@ -1533,8 +1533,8 @@ async def oauth_callback(
|
||||
return HTMLResponse("<h2>Missing authorization code</h2>")
|
||||
|
||||
try:
|
||||
from pocketclaw.integrations.oauth import OAuthManager
|
||||
from pocketclaw.integrations.token_store import TokenStore
|
||||
from pocketpaw.integrations.oauth import OAuthManager
|
||||
from pocketpaw.integrations.token_store import TokenStore
|
||||
|
||||
settings = Settings.load()
|
||||
manager = OAuthManager(TokenStore())
|
||||
@@ -2299,7 +2299,7 @@ async def websocket_endpoint(
|
||||
agent_loop.reset_router()
|
||||
|
||||
# Clear settings cache so memory manager picks up new values
|
||||
from pocketclaw.config import get_settings as _get_settings
|
||||
from pocketpaw.config import get_settings as _get_settings
|
||||
|
||||
_get_settings.cache_clear()
|
||||
|
||||
@@ -2565,7 +2565,7 @@ async def websocket_endpoint(
|
||||
# ==================== Plan Mode API ====================
|
||||
|
||||
elif action == "approve_plan":
|
||||
from pocketclaw.agents.plan_mode import get_plan_manager
|
||||
from pocketpaw.agents.plan_mode import get_plan_manager
|
||||
|
||||
pm = get_plan_manager()
|
||||
session_key = data.get("session_key", "")
|
||||
@@ -2578,7 +2578,7 @@ async def websocket_endpoint(
|
||||
)
|
||||
|
||||
elif action == "reject_plan":
|
||||
from pocketclaw.agents.plan_mode import get_plan_manager
|
||||
from pocketpaw.agents.plan_mode import get_plan_manager
|
||||
|
||||
pm = get_plan_manager()
|
||||
session_key = data.get("session_key", "")
|
||||
@@ -2969,7 +2969,7 @@ async def clear_audit_log():
|
||||
@app.post("/api/security-audit")
|
||||
async def run_security_audit_endpoint():
|
||||
"""Run security audit checks and return results."""
|
||||
from pocketclaw.security.audit_cli import (
|
||||
from pocketpaw.security.audit_cli import (
|
||||
_check_audit_log,
|
||||
_check_bypass_permissions,
|
||||
_check_config_permissions,
|
||||
@@ -3022,7 +3022,7 @@ async def run_security_audit_endpoint():
|
||||
@app.get("/api/self-audit/reports")
|
||||
async def get_self_audit_reports():
|
||||
"""List recent self-audit reports."""
|
||||
from pocketclaw.config import get_config_dir
|
||||
from pocketpaw.config import get_config_dir
|
||||
|
||||
reports_dir = get_config_dir() / "audit_reports"
|
||||
if not reports_dir.exists():
|
||||
@@ -3052,7 +3052,7 @@ async def get_self_audit_report(date: str):
|
||||
"""Get a specific self-audit report by date."""
|
||||
import json
|
||||
|
||||
from pocketclaw.config import get_config_dir
|
||||
from pocketpaw.config import get_config_dir
|
||||
|
||||
report_path = get_config_dir() / "audit_reports" / f"{date}.json"
|
||||
if not report_path.exists():
|
||||
@@ -3063,7 +3063,7 @@ async def get_self_audit_report(date: str):
|
||||
@app.post("/api/self-audit/run")
|
||||
async def run_self_audit_endpoint():
|
||||
"""Trigger a self-audit run and return the report."""
|
||||
from pocketclaw.daemon.self_audit import run_self_audit
|
||||
from pocketpaw.daemon.self_audit import run_self_audit
|
||||
|
||||
report = await run_self_audit()
|
||||
return report
|
||||
@@ -3077,7 +3077,7 @@ async def handle_tool(websocket: WebSocket, tool: str, settings: Settings, data:
|
||||
import asyncio
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from pocketclaw.tools.status import get_system_status
|
||||
from pocketpaw.tools.status import get_system_status
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
with ThreadPoolExecutor() as pool:
|
||||
@@ -3085,7 +3085,7 @@ async def handle_tool(websocket: WebSocket, tool: str, settings: Settings, data:
|
||||
await websocket.send_json({"type": "status", "content": status})
|
||||
|
||||
elif tool == "screenshot":
|
||||
from pocketclaw.tools.screenshot import take_screenshot
|
||||
from pocketpaw.tools.screenshot import take_screenshot
|
||||
|
||||
result = take_screenshot() # sync function
|
||||
|
||||
@@ -3097,7 +3097,7 @@ async def handle_tool(websocket: WebSocket, tool: str, settings: Settings, data:
|
||||
await websocket.send_json({"type": "error", "content": result})
|
||||
|
||||
elif tool == "fetch":
|
||||
from pocketclaw.tools.fetch import list_directory
|
||||
from pocketpaw.tools.fetch import list_directory
|
||||
|
||||
path = data.get("path") or str(Path.home())
|
||||
result = list_directory(path, settings.file_jail_path) # sync function
|
||||
@@ -3115,7 +3115,7 @@ async def handle_tool(websocket: WebSocket, tool: str, settings: Settings, data:
|
||||
|
||||
async def handle_file_navigation(websocket: WebSocket, path: str, settings: Settings):
|
||||
"""Handle file browser navigation."""
|
||||
from pocketclaw.tools.fetch import list_directory
|
||||
from pocketpaw.tools.fetch import list_directory
|
||||
|
||||
result = list_directory(path, settings.file_jail_path) # sync function
|
||||
await websocket.send_json({"type": "message", "content": result})
|
||||
@@ -3129,7 +3129,7 @@ async def handle_file_browse(
|
||||
If an optional ``context`` string is provided it is echoed back in the
|
||||
response so the frontend can route sidebar vs modal file responses.
|
||||
"""
|
||||
from pocketclaw.tools.fetch import is_safe_path
|
||||
from pocketpaw.tools.fetch import is_safe_path
|
||||
|
||||
def _resp(payload: dict) -> dict:
|
||||
"""Attach context to every response so frontend can route sidebar vs modal."""
|
||||
@@ -3251,12 +3251,12 @@ async def save_memory_settings(request: Request):
|
||||
settings.save()
|
||||
|
||||
# Clear settings cache so memory manager picks up new values
|
||||
from pocketclaw.config import get_settings as _get_settings
|
||||
from pocketpaw.config import get_settings as _get_settings
|
||||
|
||||
_get_settings.cache_clear()
|
||||
|
||||
# Force reload the memory manager with fresh settings
|
||||
from pocketclaw.memory import get_memory_manager
|
||||
from pocketpaw.memory import get_memory_manager
|
||||
|
||||
manager = get_memory_manager(force_reload=True)
|
||||
agent_loop.memory = manager
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import logging
|
||||
|
||||
from pocketclaw.deep_work.models import (
|
||||
from pocketpaw.deep_work.models import (
|
||||
AgentSpec,
|
||||
PlannerResult,
|
||||
Project,
|
||||
@@ -55,9 +55,9 @@ def get_deep_work_session():
|
||||
if _session_instance is not None:
|
||||
return _session_instance
|
||||
|
||||
from pocketclaw.deep_work.session import DeepWorkSession
|
||||
from pocketclaw.mission_control.executor import get_mc_task_executor
|
||||
from pocketclaw.mission_control.manager import get_mission_control_manager
|
||||
from pocketpaw.deep_work.session import DeepWorkSession
|
||||
from pocketpaw.mission_control.executor import get_mc_task_executor
|
||||
from pocketpaw.mission_control.manager import get_mission_control_manager
|
||||
|
||||
manager = get_mission_control_manager()
|
||||
executor = get_mc_task_executor()
|
||||
@@ -47,9 +47,9 @@ async def start_deep_work(request: StartDeepWorkRequest) -> dict[str, Any]:
|
||||
planner in the background. Frontend tracks progress via WebSocket
|
||||
events (dw_planning_phase, dw_planning_complete).
|
||||
"""
|
||||
from pocketclaw.deep_work import get_deep_work_session
|
||||
from pocketclaw.deep_work.models import ProjectStatus
|
||||
from pocketclaw.mission_control.manager import get_mission_control_manager
|
||||
from pocketpaw.deep_work import get_deep_work_session
|
||||
from pocketpaw.deep_work.models import ProjectStatus
|
||||
from pocketpaw.mission_control.manager import get_mission_control_manager
|
||||
|
||||
manager = get_mission_control_manager()
|
||||
|
||||
@@ -86,8 +86,8 @@ async def get_plan(project_id: str) -> dict[str, Any]:
|
||||
Returns project details, tasks, progress, PRD document, and execution_levels
|
||||
(task IDs grouped by dependency level for parallel execution).
|
||||
"""
|
||||
from pocketclaw.deep_work.scheduler import DependencyScheduler
|
||||
from pocketclaw.mission_control.manager import get_mission_control_manager
|
||||
from pocketpaw.deep_work.scheduler import DependencyScheduler
|
||||
from pocketpaw.mission_control.manager import get_mission_control_manager
|
||||
|
||||
manager = get_mission_control_manager()
|
||||
project = await manager.get_project(project_id)
|
||||
@@ -124,7 +124,7 @@ async def get_plan(project_id: str) -> dict[str, Any]:
|
||||
@router.post("/projects/{project_id}/approve")
|
||||
async def approve_project(project_id: str) -> dict[str, Any]:
|
||||
"""Approve a project plan and start execution."""
|
||||
from pocketclaw.deep_work import approve_project as _approve
|
||||
from pocketpaw.deep_work import approve_project as _approve
|
||||
|
||||
try:
|
||||
project = await _approve(project_id)
|
||||
@@ -139,7 +139,7 @@ async def approve_project(project_id: str) -> dict[str, Any]:
|
||||
@router.post("/projects/{project_id}/pause")
|
||||
async def pause_project(project_id: str) -> dict[str, Any]:
|
||||
"""Pause project execution."""
|
||||
from pocketclaw.deep_work import pause_project as _pause
|
||||
from pocketpaw.deep_work import pause_project as _pause
|
||||
|
||||
try:
|
||||
project = await _pause(project_id)
|
||||
@@ -154,7 +154,7 @@ async def pause_project(project_id: str) -> dict[str, Any]:
|
||||
@router.post("/projects/{project_id}/resume")
|
||||
async def resume_project(project_id: str) -> dict[str, Any]:
|
||||
"""Resume a paused project."""
|
||||
from pocketclaw.deep_work import resume_project as _resume
|
||||
from pocketpaw.deep_work import resume_project as _resume
|
||||
|
||||
try:
|
||||
project = await _resume(project_id)
|
||||
@@ -173,9 +173,9 @@ async def skip_task(project_id: str, task_id: str) -> dict[str, Any]:
|
||||
Sets task status to SKIPPED with completed_at timestamp, then
|
||||
cascades unblocking via the scheduler.
|
||||
"""
|
||||
from pocketclaw.deep_work import get_deep_work_session
|
||||
from pocketclaw.mission_control.manager import get_mission_control_manager
|
||||
from pocketclaw.mission_control.models import TaskStatus, now_iso
|
||||
from pocketpaw.deep_work import get_deep_work_session
|
||||
from pocketpaw.mission_control.manager import get_mission_control_manager
|
||||
from pocketpaw.mission_control.models import TaskStatus, now_iso
|
||||
|
||||
manager = get_mission_control_manager()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import logging
|
||||
|
||||
from pocketclaw.mission_control.models import Task
|
||||
from pocketpaw.mission_control.models import Task
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -115,8 +115,8 @@ class HumanTaskRouter:
|
||||
async def _publish_outbound(self, content: str, metadata: dict) -> None:
|
||||
"""Broadcast OutboundMessage to all active channel adapters."""
|
||||
try:
|
||||
from pocketclaw.bus import get_message_bus
|
||||
from pocketclaw.bus.events import Channel, OutboundMessage
|
||||
from pocketpaw.bus import get_message_bus
|
||||
from pocketpaw.bus.events import Channel, OutboundMessage
|
||||
|
||||
bus = get_message_bus()
|
||||
msg = OutboundMessage(
|
||||
@@ -11,7 +11,7 @@ from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
from pocketclaw.mission_control.models import generate_id, now_iso
|
||||
from pocketpaw.mission_control.models import generate_id, now_iso
|
||||
|
||||
# ============================================================================
|
||||
# Enums
|
||||
@@ -11,8 +11,8 @@ import json
|
||||
import logging
|
||||
import re
|
||||
|
||||
from pocketclaw.deep_work.models import AgentSpec, PlannerResult, TaskSpec
|
||||
from pocketclaw.deep_work.prompts import (
|
||||
from pocketpaw.deep_work.models import AgentSpec, PlannerResult, TaskSpec
|
||||
from pocketpaw.deep_work.prompts import (
|
||||
PRD_PROMPT,
|
||||
RESEARCH_PROMPT,
|
||||
RESEARCH_PROMPT_DEEP,
|
||||
@@ -20,8 +20,8 @@ from pocketclaw.deep_work.prompts import (
|
||||
TASK_BREAKDOWN_PROMPT,
|
||||
TEAM_ASSEMBLY_PROMPT,
|
||||
)
|
||||
from pocketclaw.mission_control.manager import MissionControlManager
|
||||
from pocketclaw.mission_control.models import AgentProfile
|
||||
from pocketpaw.mission_control.manager import MissionControlManager
|
||||
from pocketpaw.mission_control.models import AgentProfile
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -80,8 +80,8 @@ class PlannerAgent:
|
||||
progress (e.g. spinner text).
|
||||
"""
|
||||
# Create a single AgentRouter for all phases (avoids 4x SDK init)
|
||||
from pocketclaw.agents.router import AgentRouter
|
||||
from pocketclaw.config import get_settings
|
||||
from pocketpaw.agents.router import AgentRouter
|
||||
from pocketpaw.config import get_settings
|
||||
|
||||
router = AgentRouter(get_settings())
|
||||
|
||||
@@ -180,8 +180,8 @@ class PlannerAgent:
|
||||
router: Optional pre-created AgentRouter (avoids re-initialization).
|
||||
"""
|
||||
if router is None:
|
||||
from pocketclaw.agents.router import AgentRouter
|
||||
from pocketclaw.config import get_settings
|
||||
from pocketpaw.agents.router import AgentRouter
|
||||
from pocketpaw.config import get_settings
|
||||
|
||||
router = AgentRouter(get_settings())
|
||||
|
||||
@@ -259,8 +259,8 @@ class PlannerAgent:
|
||||
message = phase_messages.get(phase, f"Planning phase: {phase}")
|
||||
|
||||
try:
|
||||
from pocketclaw.bus import get_message_bus
|
||||
from pocketclaw.bus.events import SystemEvent
|
||||
from pocketpaw.bus import get_message_bus
|
||||
from pocketpaw.bus.events import SystemEvent
|
||||
|
||||
bus = get_message_bus()
|
||||
import asyncio
|
||||
@@ -14,7 +14,7 @@ import asyncio
|
||||
import logging
|
||||
from collections import deque
|
||||
|
||||
from pocketclaw.mission_control.models import Task, TaskStatus, now_iso
|
||||
from pocketpaw.mission_control.models import Task, TaskStatus, now_iso
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -156,7 +156,7 @@ class DependencyScheduler:
|
||||
if all_done:
|
||||
project = await self.manager.get_project(project_id)
|
||||
if project:
|
||||
from pocketclaw.deep_work.models import ProjectStatus
|
||||
from pocketpaw.deep_work.models import ProjectStatus
|
||||
|
||||
project.status = ProjectStatus.COMPLETED
|
||||
project.completed_at = now_iso()
|
||||
@@ -18,12 +18,12 @@
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pocketclaw.deep_work.human_tasks import HumanTaskRouter
|
||||
from pocketclaw.deep_work.models import Project, ProjectStatus
|
||||
from pocketclaw.deep_work.planner import PlannerAgent
|
||||
from pocketclaw.deep_work.scheduler import DependencyScheduler
|
||||
from pocketclaw.mission_control.manager import MissionControlManager
|
||||
from pocketclaw.mission_control.models import (
|
||||
from pocketpaw.deep_work.human_tasks import HumanTaskRouter
|
||||
from pocketpaw.deep_work.models import Project, ProjectStatus
|
||||
from pocketpaw.deep_work.planner import PlannerAgent
|
||||
from pocketpaw.deep_work.scheduler import DependencyScheduler
|
||||
from pocketpaw.mission_control.manager import MissionControlManager
|
||||
from pocketpaw.mission_control.models import (
|
||||
DocumentType,
|
||||
TaskPriority,
|
||||
TaskStatus,
|
||||
@@ -77,7 +77,7 @@ class DeepWorkSession:
|
||||
if self._subscribed:
|
||||
return
|
||||
try:
|
||||
from pocketclaw.bus import get_message_bus
|
||||
from pocketpaw.bus import get_message_bus
|
||||
|
||||
bus = get_message_bus()
|
||||
bus.subscribe_system(self._on_system_event)
|
||||
@@ -404,8 +404,8 @@ class DeepWorkSession:
|
||||
try:
|
||||
import asyncio
|
||||
|
||||
from pocketclaw.bus import get_message_bus
|
||||
from pocketclaw.bus.events import SystemEvent
|
||||
from pocketpaw.bus import get_message_bus
|
||||
from pocketpaw.bus.events import SystemEvent
|
||||
|
||||
bus = get_message_bus()
|
||||
loop = asyncio.get_running_loop()
|
||||
@@ -3,10 +3,10 @@
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from pocketclaw.agents.loop import AgentLoop
|
||||
from pocketclaw.bus import get_message_bus
|
||||
from pocketclaw.bus.adapters.discord_adapter import DiscordAdapter
|
||||
from pocketclaw.config import Settings
|
||||
from pocketpaw.agents.loop import AgentLoop
|
||||
from pocketpaw.bus import get_message_bus
|
||||
from pocketpaw.bus.adapters.discord_adapter import DiscordAdapter
|
||||
from pocketpaw.config import Settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user