pocket-coding 0.3.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pocket_coding-0.5.0/LICENSE +4 -0
- pocket_coding-0.5.0/PKG-INFO +263 -0
- pocket_coding-0.5.0/README.md +238 -0
- pocket_coding-0.5.0/pocket_coding.egg-info/PKG-INFO +263 -0
- pocket_coding-0.5.0/pocket_coding.egg-info/SOURCES.txt +100 -0
- pocket_coding-0.5.0/pocket_coding.egg-info/dependency_links.txt +1 -0
- pocket_coding-0.5.0/pocket_coding.egg-info/entry_points.txt +2 -0
- pocket_coding-0.5.0/pocket_coding.egg-info/requires.txt +7 -0
- pocket_coding-0.5.0/pocket_coding.egg-info/top_level.txt +1 -0
- pocket_coding-0.5.0/poco/__init__.py +1 -0
- pocket_coding-0.5.0/poco/agent/__init__.py +1 -0
- pocket_coding-0.5.0/poco/agent/catalog.py +365 -0
- pocket_coding-0.5.0/poco/agent/claude_code.py +570 -0
- pocket_coding-0.5.0/poco/agent/coco.py +727 -0
- pocket_coding-0.5.0/poco/agent/codex_app_server.py +860 -0
- pocket_coding-0.5.0/poco/agent/codex_cli.py +274 -0
- pocket_coding-0.5.0/poco/agent/common.py +153 -0
- pocket_coding-0.5.0/poco/agent/completion_gate.py +63 -0
- pocket_coding-0.5.0/poco/agent/cursor_agent.py +488 -0
- pocket_coding-0.5.0/poco/agent/factory.py +86 -0
- pocket_coding-0.5.0/poco/agent/runner.py +88 -0
- pocket_coding-0.5.0/poco/agent/stub.py +160 -0
- pocket_coding-0.5.0/poco/agent/tokens.py +63 -0
- pocket_coding-0.5.0/poco/cli.py +314 -0
- pocket_coding-0.5.0/poco/config.py +181 -0
- pocket_coding-0.5.0/poco/demo.py +9 -0
- pocket_coding-0.5.0/poco/env_inventory.py +98 -0
- pocket_coding-0.5.0/poco/interaction/__init__.py +1 -0
- pocket_coding-0.5.0/poco/interaction/card_dispatcher.py +101 -0
- pocket_coding-0.5.0/poco/interaction/card_handlers.py +1656 -0
- pocket_coding-0.5.0/poco/interaction/card_models.py +106 -0
- pocket_coding-0.5.0/poco/interaction/service.py +228 -0
- pocket_coding-0.5.0/poco/main.py +652 -0
- pocket_coding-0.5.0/poco/platform/__init__.py +1 -0
- pocket_coding-0.5.0/poco/platform/common/__init__.py +1 -0
- pocket_coding-0.5.0/poco/platform/common/card_renderer.py +17 -0
- pocket_coding-0.5.0/poco/platform/common/message_client.py +50 -0
- pocket_coding-0.5.0/poco/platform/common/platform.py +8 -0
- pocket_coding-0.5.0/poco/platform/feishu/__init__.py +1 -0
- pocket_coding-0.5.0/poco/platform/feishu/card_gateway.py +207 -0
- pocket_coding-0.5.0/poco/platform/feishu/cards.py +1946 -0
- pocket_coding-0.5.0/poco/platform/feishu/client.py +282 -0
- pocket_coding-0.5.0/poco/platform/feishu/debug.py +90 -0
- pocket_coding-0.5.0/poco/platform/feishu/gateway.py +473 -0
- pocket_coding-0.5.0/poco/platform/feishu/longconn.py +333 -0
- pocket_coding-0.5.0/poco/platform/feishu/project_bootstrap.py +169 -0
- pocket_coding-0.5.0/poco/platform/feishu/verification.py +82 -0
- pocket_coding-0.5.0/poco/platform/slack/__init__.py +1 -0
- pocket_coding-0.5.0/poco/platform/slack/card_gateway.py +241 -0
- pocket_coding-0.5.0/poco/platform/slack/cards.py +600 -0
- pocket_coding-0.5.0/poco/platform/slack/client.py +220 -0
- pocket_coding-0.5.0/poco/platform/slack/debug.py +97 -0
- pocket_coding-0.5.0/poco/platform/slack/gateway.py +413 -0
- pocket_coding-0.5.0/poco/platform/slack/project_bootstrap.py +234 -0
- pocket_coding-0.5.0/poco/platform/slack/socket_mode.py +272 -0
- pocket_coding-0.5.0/poco/platform/slack/verification.py +76 -0
- pocket_coding-0.5.0/poco/project/__init__.py +2 -0
- pocket_coding-0.5.0/poco/project/bootstrap.py +64 -0
- pocket_coding-0.5.0/poco/project/controller.py +178 -0
- pocket_coding-0.5.0/poco/project/models.py +114 -0
- pocket_coding-0.5.0/poco/session/controller.py +88 -0
- pocket_coding-0.5.0/poco/session/models.py +71 -0
- pocket_coding-0.5.0/poco/storage/__init__.py +1 -0
- pocket_coding-0.5.0/poco/storage/memory.py +108 -0
- pocket_coding-0.5.0/poco/storage/protocols.py +61 -0
- pocket_coding-0.5.0/poco/storage/sqlite.py +576 -0
- pocket_coding-0.5.0/poco/task/__init__.py +1 -0
- pocket_coding-0.5.0/poco/task/controller.py +630 -0
- pocket_coding-0.5.0/poco/task/dispatcher.py +193 -0
- pocket_coding-0.5.0/poco/task/models.py +208 -0
- pocket_coding-0.5.0/poco/task/notifier.py +472 -0
- pocket_coding-0.5.0/poco/task/rendering.py +61 -0
- pocket_coding-0.5.0/poco/workspace/controller.py +78 -0
- pocket_coding-0.5.0/poco/workspace/models.py +29 -0
- pocket_coding-0.5.0/pyproject.toml +52 -0
- pocket_coding-0.5.0/setup.cfg +4 -0
- pocket_coding-0.5.0/tests/test_agent_catalog.py +145 -0
- pocket_coding-0.5.0/tests/test_agent_runner.py +3192 -0
- pocket_coding-0.5.0/tests/test_card_dispatcher.py +162 -0
- pocket_coding-0.5.0/tests/test_card_gateway.py +2110 -0
- pocket_coding-0.5.0/tests/test_cli.py +200 -0
- pocket_coding-0.5.0/tests/test_completion_gate.py +94 -0
- pocket_coding-0.5.0/tests/test_config.py +148 -0
- pocket_coding-0.5.0/tests/test_debug_api.py +156 -0
- pocket_coding-0.5.0/tests/test_demo_api.py +93 -0
- pocket_coding-0.5.0/tests/test_demo_cards.py +145 -0
- pocket_coding-0.5.0/tests/test_feishu_client.py +1337 -0
- pocket_coding-0.5.0/tests/test_feishu_gateway.py +700 -0
- pocket_coding-0.5.0/tests/test_feishu_longconn.py +194 -0
- pocket_coding-0.5.0/tests/test_health.py +48 -0
- pocket_coding-0.5.0/tests/test_session_controller.py +98 -0
- pocket_coding-0.5.0/tests/test_slack_cards.py +356 -0
- pocket_coding-0.5.0/tests/test_slack_client.py +138 -0
- pocket_coding-0.5.0/tests/test_slack_endpoints.py +209 -0
- pocket_coding-0.5.0/tests/test_slack_gateway.py +316 -0
- pocket_coding-0.5.0/tests/test_slack_project_bootstrap.py +272 -0
- pocket_coding-0.5.0/tests/test_slack_socket_mode.py +208 -0
- pocket_coding-0.5.0/tests/test_slack_verifier.py +85 -0
- pocket_coding-0.5.0/tests/test_state_persistence.py +168 -0
- pocket_coding-0.5.0/tests/test_task_controller.py +753 -0
- pocket_coding-0.5.0/tests/test_task_dispatcher.py +243 -0
- pocket_coding-0.5.0/tests/test_task_notifier.py +468 -0
- pocket_coding-0.3.0/.gitignore +0 -16
- pocket_coding-0.3.0/PKG-INFO +0 -129
- pocket_coding-0.3.0/README.md +0 -108
- pocket_coding-0.3.0/README.zh-CN.md +0 -110
- pocket_coding-0.3.0/poco/__init__.py +0 -4
- pocket_coding-0.3.0/poco/app.py +0 -124
- pocket_coding-0.3.0/poco/config/__init__.py +0 -59
- pocket_coding-0.3.0/poco/config/store.py +0 -507
- pocket_coding-0.3.0/poco/providers/__init__.py +0 -48
- pocket_coding-0.3.0/poco/providers/base.py +0 -54
- pocket_coding-0.3.0/poco/providers/claude.py +0 -400
- pocket_coding-0.3.0/poco/providers/codex.py +0 -367
- pocket_coding-0.3.0/poco/providers/cursor.py +0 -424
- pocket_coding-0.3.0/poco/providers/models.py +0 -73
- pocket_coding-0.3.0/poco/relay/__init__.py +0 -39
- pocket_coding-0.3.0/poco/relay/app.py +0 -1353
- pocket_coding-0.3.0/poco/relay/cards.py +0 -1452
- pocket_coding-0.3.0/poco/relay/messenger.py +0 -450
- pocket_coding-0.3.0/poco/relay/models.py +0 -110
- pocket_coding-0.3.0/poco/relay/runtime.py +0 -433
- pocket_coding-0.3.0/poco/relay/stores.py +0 -310
- pocket_coding-0.3.0/poco/relay/utils.py +0 -116
- pocket_coding-0.3.0/poco/runtime.py +0 -219
- pocket_coding-0.3.0/poco/tui/__init__.py +0 -5
- pocket_coding-0.3.0/poco/tui/app.py +0 -1119
- pocket_coding-0.3.0/poco/tui/resources.py +0 -192
- pocket_coding-0.3.0/poco/tui/sections.py +0 -219
- pocket_coding-0.3.0/poco/tui/state.py +0 -121
- pocket_coding-0.3.0/pyproject.toml +0 -46
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pocket-coding
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: PoCo: pocket coding for server-side AI agents through mobile messaging entrypoints.
|
|
5
|
+
Author: Yihanc
|
|
6
|
+
Keywords: ai-agent,automation,developer-tools,feishu,mobile
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Framework :: FastAPI
|
|
14
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: fastapi<1.0,>=0.115
|
|
19
|
+
Requires-Dist: lark-oapi<2.0,>=1.5
|
|
20
|
+
Requires-Dist: uvicorn<1.0,>=0.32
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: build<2.0,>=1.2; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# PoCo
|
|
27
|
+
|
|
28
|
+
PoCo is a Python-first scaffold for driving server-side coding agents from chat surfaces (Feishu today, Slack since this release). Projects, workspaces, sessions, and tasks all live in PoCo; the chat bot is a thin interactive front-end for them.
|
|
29
|
+
|
|
30
|
+
## Supported Platforms
|
|
31
|
+
|
|
32
|
+
- **Feishu** — DM control plane + per-project group chat, over webhook **or** long connection (`longconn`, default).
|
|
33
|
+
- **Slack** — DM control plane + per-project channel, over Socket Mode (default) **or** HTTP webhooks. Slash command `/poco` opens the same project-list card the DM surface renders.
|
|
34
|
+
|
|
35
|
+
Both platforms run simultaneously when configured. Every `Task` / `Project` remembers which platform it was created from, and replies are routed back to the originating surface by `PlatformRoutingTaskNotifier`.
|
|
36
|
+
|
|
37
|
+
## Supported Agent Backends
|
|
38
|
+
|
|
39
|
+
- `codex` (default) — runs through `codex app-server` over stdio; streams real `agentMessage/delta` events into task cards.
|
|
40
|
+
- `claude_code`
|
|
41
|
+
- `cursor_agent`
|
|
42
|
+
- `coco` (Trae CLI)
|
|
43
|
+
- `stub` — local flow validation only.
|
|
44
|
+
|
|
45
|
+
Backend per project is picked from the DM project-creation card. Environment variables are server-side defaults only.
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python3 -m pip install -e .
|
|
51
|
+
poco config # interactive prompt for Feishu credentials
|
|
52
|
+
poco start
|
|
53
|
+
poco status
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`poco config` writes `~/.poco/poco.config.json`. Environment variables override file values at runtime. To run with no chat platform at all (just the HTTP demo surface and agent runner), skip `poco config` and start directly:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
poco start
|
|
60
|
+
curl http://127.0.0.1:8000/health
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`/health` explicitly lists what is missing for each platform.
|
|
64
|
+
|
|
65
|
+
## Configuration
|
|
66
|
+
|
|
67
|
+
PoCo reads config from three layers, in decreasing precedence:
|
|
68
|
+
|
|
69
|
+
1. `POCO_*` environment variables
|
|
70
|
+
2. Flat keys in `~/.poco/poco.config.json` (same name as the env var)
|
|
71
|
+
3. Sectioned keys in the same file, e.g. `{"feishu": {"app_id": "..."}, "slack": {"bot_token": "..."}}`
|
|
72
|
+
|
|
73
|
+
### Feishu
|
|
74
|
+
|
|
75
|
+
| Key | Purpose |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| `POCO_FEISHU_APP_ID` / `POCO_FEISHU_APP_SECRET` | Required to enable the Feishu integration. |
|
|
78
|
+
| `POCO_FEISHU_DELIVERY_MODE` | `longconn` (default) or `webhook`. |
|
|
79
|
+
| `POCO_FEISHU_VERIFICATION_TOKEN` | Optional webhook token. Lowers friction when unset, lowers security too. |
|
|
80
|
+
| `POCO_FEISHU_ENCRYPT_KEY` | Enables signature validation on webhook callbacks. Encrypted payload bodies are not supported yet. |
|
|
81
|
+
| `POCO_FEISHU_API_BASE_URL` | Defaults to `https://open.feishu.cn`. |
|
|
82
|
+
|
|
83
|
+
Long-connection mode authenticates inbound events via the long-connection session itself and routes both message events and card callbacks over the same listener. Callback token/signature settings only apply to webhook delivery.
|
|
84
|
+
|
|
85
|
+
### Slack
|
|
86
|
+
|
|
87
|
+
| Key | Purpose |
|
|
88
|
+
| --- | --- |
|
|
89
|
+
| `POCO_SLACK_BOT_TOKEN` | `xoxb-…` bot token. Required. |
|
|
90
|
+
| `POCO_SLACK_SIGNING_SECRET` | Required for HTTP webhook signature verification. |
|
|
91
|
+
| `POCO_SLACK_APP_TOKEN` | `xapp-…` app-level token. Required when `POCO_SLACK_DELIVERY_MODE=socket`. |
|
|
92
|
+
| `POCO_SLACK_DELIVERY_MODE` | `socket` (default) or `webhook`. |
|
|
93
|
+
|
|
94
|
+
Slack is considered enabled when bot token + signing secret (+ app token, for socket mode) are all set. `/poco` slash command posts the project-list card as an ephemeral reply.
|
|
95
|
+
|
|
96
|
+
### Agent backend (server-side)
|
|
97
|
+
|
|
98
|
+
Minimum:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
export POCO_AGENT_BACKEND="codex"
|
|
102
|
+
export POCO_CODEX_COMMAND="codex"
|
|
103
|
+
export POCO_CODEX_WORKDIR="/absolute/path/to/your/repo"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Optional per-backend tuning:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Codex
|
|
110
|
+
export POCO_CODEX_MODEL="gpt-5"
|
|
111
|
+
export POCO_CODEX_SANDBOX="workspace-write"
|
|
112
|
+
export POCO_CODEX_APPROVAL_POLICY="never"
|
|
113
|
+
export POCO_CODEX_TIMEOUT_SECONDS="900"
|
|
114
|
+
export POCO_CODEX_TRANSPORT_IDLE_SECONDS="1800"
|
|
115
|
+
|
|
116
|
+
# Claude Code
|
|
117
|
+
export POCO_CLAUDE_COMMAND="claude"
|
|
118
|
+
export POCO_CLAUDE_WORKDIR="/absolute/path/to/your/repo"
|
|
119
|
+
export POCO_CLAUDE_MODEL="sonnet"
|
|
120
|
+
export POCO_CLAUDE_PERMISSION_MODE="default"
|
|
121
|
+
export POCO_CLAUDE_TIMEOUT_SECONDS="900"
|
|
122
|
+
|
|
123
|
+
# Cursor Agent
|
|
124
|
+
export POCO_CURSOR_COMMAND="cursor-agent"
|
|
125
|
+
export POCO_CURSOR_WORKDIR="/absolute/path/to/your/repo"
|
|
126
|
+
export POCO_CURSOR_MODEL="auto"
|
|
127
|
+
export POCO_CURSOR_MODE="default"
|
|
128
|
+
export POCO_CURSOR_SANDBOX="default"
|
|
129
|
+
export POCO_CURSOR_TIMEOUT_SECONDS="900"
|
|
130
|
+
|
|
131
|
+
# Trae CLI (coco)
|
|
132
|
+
export POCO_COCO_COMMAND="traecli"
|
|
133
|
+
export POCO_COCO_WORKDIR="/absolute/path/to/your/repo"
|
|
134
|
+
export POCO_COCO_MODEL="GPT-5"
|
|
135
|
+
export POCO_COCO_APPROVAL_MODE="default"
|
|
136
|
+
export POCO_COCO_TIMEOUT_SECONDS="900"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### State backend
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
export POCO_STATE_BACKEND="sqlite" # default
|
|
143
|
+
export POCO_STATE_DB_PATH="~/.poco/poco.db"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
SQLite is the default runtime path. It persists projects, workspace context, sessions, and tasks so a restart does not lose group/workspace bookkeeping.
|
|
147
|
+
|
|
148
|
+
## Interaction Model
|
|
149
|
+
|
|
150
|
+
- **DM**: control plane. `New` creates a project and its bound group; `Manage` lists projects and exposes delete. DM inbound messages always render the project-list card.
|
|
151
|
+
- **Group**: workspace card with `Stop` / `Working Dir` / `Agent` actions, plus plain-text task submission. `Working Dir` selection (folder browse, manual entry, recent directories, and project-level presets) stays inside cards. `Agent` opens a dedicated selection card.
|
|
152
|
+
|
|
153
|
+
Group behavior:
|
|
154
|
+
|
|
155
|
+
- Plain text in a bound group is a task prompt.
|
|
156
|
+
- Tasks in a project run in a single-project queue — a new message is queued while another task is still active.
|
|
157
|
+
- Codex groups persist the upstream thread id and resume it via `codex app-server`, so follow-up messages continue the same Codex conversation.
|
|
158
|
+
- Task cards show bracketed status in the title (e.g. `[Running] Task: … (codex, /srv/api)`), and live-stream throttled agent output.
|
|
159
|
+
- Waiting task cards expose `Approve` / `Reject`; later state transitions update the same card in place before falling back to a new message.
|
|
160
|
+
- Workspace cards are refreshed when the latest task changes and keep a bound `message_id` across updates.
|
|
161
|
+
|
|
162
|
+
## HTTP Surface
|
|
163
|
+
|
|
164
|
+
Core endpoints:
|
|
165
|
+
|
|
166
|
+
| Path | Purpose |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `GET /health` | Runtime readiness + missing/warn summary for both platforms. |
|
|
169
|
+
| `GET /tasks`, `GET /tasks/{task_id}` | Raw task state. |
|
|
170
|
+
| `GET /debug/feishu`, `GET /debug/slack` | Recent inbound events, outbound attempts, errors, listener snapshot for the respective platform. |
|
|
171
|
+
| `GET /debug/env` | Presence/length of whitelisted env keys (no values are returned). |
|
|
172
|
+
|
|
173
|
+
Feishu endpoints:
|
|
174
|
+
|
|
175
|
+
- `POST /platform/feishu/events`
|
|
176
|
+
- `POST /platform/feishu/card-actions`
|
|
177
|
+
|
|
178
|
+
Slack endpoints:
|
|
179
|
+
|
|
180
|
+
- `POST /platform/slack/events` (JSON body, `X-Slack-Signature` verified)
|
|
181
|
+
- `POST /platform/slack/interactive` (form-encoded `payload=…`)
|
|
182
|
+
- `POST /platform/slack/commands` (form-encoded slash command)
|
|
183
|
+
|
|
184
|
+
Demo endpoints (platform-agnostic):
|
|
185
|
+
|
|
186
|
+
- `POST /demo/command` — `{"text":"/run …"}`
|
|
187
|
+
- `POST /demo/tasks/{task_id}/approve`
|
|
188
|
+
- `POST /demo/tasks/{task_id}/reject`
|
|
189
|
+
- `GET /demo/cards/dm/projects`
|
|
190
|
+
- `POST /demo/card-actions`
|
|
191
|
+
|
|
192
|
+
### Supported text commands
|
|
193
|
+
|
|
194
|
+
In a bound project group, any plain text is treated as a task prompt. The explicit commands are still accepted:
|
|
195
|
+
|
|
196
|
+
- `/run <prompt>` — start a task.
|
|
197
|
+
- `/status <task_id>`
|
|
198
|
+
- `/approve <task_id>` / `/reject <task_id>`
|
|
199
|
+
- `/help`
|
|
200
|
+
|
|
201
|
+
If the prompt starts with `confirm:`, the stub runner and the Codex backend pause at a confirmation checkpoint; `/approve <task_id>` resumes.
|
|
202
|
+
|
|
203
|
+
## Local Demo Example
|
|
204
|
+
|
|
205
|
+
Without any chat platform configured:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
curl -X POST http://127.0.0.1:8000/demo/command \
|
|
209
|
+
-H 'Content-Type: application/json' \
|
|
210
|
+
-d '{"text":"/run Reply with exactly: DEMO_OK"}'
|
|
211
|
+
|
|
212
|
+
curl http://127.0.0.1:8000/tasks/<task_id>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Approval flow:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
curl -X POST http://127.0.0.1:8000/demo/command \
|
|
219
|
+
-H 'Content-Type: application/json' \
|
|
220
|
+
-d '{"text":"/run confirm: Reply with exactly: APPROVED"}'
|
|
221
|
+
|
|
222
|
+
curl -X POST http://127.0.0.1:8000/demo/tasks/<task_id>/approve
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## CLI
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
poco config # interactive Feishu credential prompt
|
|
229
|
+
poco start # starts uvicorn in the background, pid in ~/.poco/poco.pid
|
|
230
|
+
poco status # pid + /health summary
|
|
231
|
+
poco restart
|
|
232
|
+
poco shutdown
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Manual fallback:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
uvicorn poco.main:app --reload
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Packaging
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
python3 -m pip install build
|
|
245
|
+
python3 -m build
|
|
246
|
+
# produces dist/*.whl and dist/*.tar.gz
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
When published, installation will be:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
python3 -m pip install pocket-coding
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Debugging Reply Issues
|
|
256
|
+
|
|
257
|
+
When a chat message does not get a reply, compare `/debug/feishu` or `/debug/slack` against the expected flow:
|
|
258
|
+
|
|
259
|
+
- If there are no recent inbound entries: the platform never reached PoCo (check long-connection/socket-mode listener status under `listener`, or the public webhook route).
|
|
260
|
+
- If inbound entries exist but there are no outbound attempts: PoCo dropped the message (e.g. unbound group, ignored bot message).
|
|
261
|
+
- If outbound attempts exist but errors accumulate: the platform rejected the send (scope/permission issues usually).
|
|
262
|
+
|
|
263
|
+
`/health` also surfaces listener readiness for both platforms plus the current agent backend readiness.
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# PoCo
|
|
2
|
+
|
|
3
|
+
PoCo is a Python-first scaffold for driving server-side coding agents from chat surfaces (Feishu today, Slack since this release). Projects, workspaces, sessions, and tasks all live in PoCo; the chat bot is a thin interactive front-end for them.
|
|
4
|
+
|
|
5
|
+
## Supported Platforms
|
|
6
|
+
|
|
7
|
+
- **Feishu** — DM control plane + per-project group chat, over webhook **or** long connection (`longconn`, default).
|
|
8
|
+
- **Slack** — DM control plane + per-project channel, over Socket Mode (default) **or** HTTP webhooks. Slash command `/poco` opens the same project-list card the DM surface renders.
|
|
9
|
+
|
|
10
|
+
Both platforms run simultaneously when configured. Every `Task` / `Project` remembers which platform it was created from, and replies are routed back to the originating surface by `PlatformRoutingTaskNotifier`.
|
|
11
|
+
|
|
12
|
+
## Supported Agent Backends
|
|
13
|
+
|
|
14
|
+
- `codex` (default) — runs through `codex app-server` over stdio; streams real `agentMessage/delta` events into task cards.
|
|
15
|
+
- `claude_code`
|
|
16
|
+
- `cursor_agent`
|
|
17
|
+
- `coco` (Trae CLI)
|
|
18
|
+
- `stub` — local flow validation only.
|
|
19
|
+
|
|
20
|
+
Backend per project is picked from the DM project-creation card. Environment variables are server-side defaults only.
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
python3 -m pip install -e .
|
|
26
|
+
poco config # interactive prompt for Feishu credentials
|
|
27
|
+
poco start
|
|
28
|
+
poco status
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`poco config` writes `~/.poco/poco.config.json`. Environment variables override file values at runtime. To run with no chat platform at all (just the HTTP demo surface and agent runner), skip `poco config` and start directly:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
poco start
|
|
35
|
+
curl http://127.0.0.1:8000/health
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`/health` explicitly lists what is missing for each platform.
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
PoCo reads config from three layers, in decreasing precedence:
|
|
43
|
+
|
|
44
|
+
1. `POCO_*` environment variables
|
|
45
|
+
2. Flat keys in `~/.poco/poco.config.json` (same name as the env var)
|
|
46
|
+
3. Sectioned keys in the same file, e.g. `{"feishu": {"app_id": "..."}, "slack": {"bot_token": "..."}}`
|
|
47
|
+
|
|
48
|
+
### Feishu
|
|
49
|
+
|
|
50
|
+
| Key | Purpose |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `POCO_FEISHU_APP_ID` / `POCO_FEISHU_APP_SECRET` | Required to enable the Feishu integration. |
|
|
53
|
+
| `POCO_FEISHU_DELIVERY_MODE` | `longconn` (default) or `webhook`. |
|
|
54
|
+
| `POCO_FEISHU_VERIFICATION_TOKEN` | Optional webhook token. Lowers friction when unset, lowers security too. |
|
|
55
|
+
| `POCO_FEISHU_ENCRYPT_KEY` | Enables signature validation on webhook callbacks. Encrypted payload bodies are not supported yet. |
|
|
56
|
+
| `POCO_FEISHU_API_BASE_URL` | Defaults to `https://open.feishu.cn`. |
|
|
57
|
+
|
|
58
|
+
Long-connection mode authenticates inbound events via the long-connection session itself and routes both message events and card callbacks over the same listener. Callback token/signature settings only apply to webhook delivery.
|
|
59
|
+
|
|
60
|
+
### Slack
|
|
61
|
+
|
|
62
|
+
| Key | Purpose |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| `POCO_SLACK_BOT_TOKEN` | `xoxb-…` bot token. Required. |
|
|
65
|
+
| `POCO_SLACK_SIGNING_SECRET` | Required for HTTP webhook signature verification. |
|
|
66
|
+
| `POCO_SLACK_APP_TOKEN` | `xapp-…` app-level token. Required when `POCO_SLACK_DELIVERY_MODE=socket`. |
|
|
67
|
+
| `POCO_SLACK_DELIVERY_MODE` | `socket` (default) or `webhook`. |
|
|
68
|
+
|
|
69
|
+
Slack is considered enabled when bot token + signing secret (+ app token, for socket mode) are all set. `/poco` slash command posts the project-list card as an ephemeral reply.
|
|
70
|
+
|
|
71
|
+
### Agent backend (server-side)
|
|
72
|
+
|
|
73
|
+
Minimum:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
export POCO_AGENT_BACKEND="codex"
|
|
77
|
+
export POCO_CODEX_COMMAND="codex"
|
|
78
|
+
export POCO_CODEX_WORKDIR="/absolute/path/to/your/repo"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Optional per-backend tuning:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Codex
|
|
85
|
+
export POCO_CODEX_MODEL="gpt-5"
|
|
86
|
+
export POCO_CODEX_SANDBOX="workspace-write"
|
|
87
|
+
export POCO_CODEX_APPROVAL_POLICY="never"
|
|
88
|
+
export POCO_CODEX_TIMEOUT_SECONDS="900"
|
|
89
|
+
export POCO_CODEX_TRANSPORT_IDLE_SECONDS="1800"
|
|
90
|
+
|
|
91
|
+
# Claude Code
|
|
92
|
+
export POCO_CLAUDE_COMMAND="claude"
|
|
93
|
+
export POCO_CLAUDE_WORKDIR="/absolute/path/to/your/repo"
|
|
94
|
+
export POCO_CLAUDE_MODEL="sonnet"
|
|
95
|
+
export POCO_CLAUDE_PERMISSION_MODE="default"
|
|
96
|
+
export POCO_CLAUDE_TIMEOUT_SECONDS="900"
|
|
97
|
+
|
|
98
|
+
# Cursor Agent
|
|
99
|
+
export POCO_CURSOR_COMMAND="cursor-agent"
|
|
100
|
+
export POCO_CURSOR_WORKDIR="/absolute/path/to/your/repo"
|
|
101
|
+
export POCO_CURSOR_MODEL="auto"
|
|
102
|
+
export POCO_CURSOR_MODE="default"
|
|
103
|
+
export POCO_CURSOR_SANDBOX="default"
|
|
104
|
+
export POCO_CURSOR_TIMEOUT_SECONDS="900"
|
|
105
|
+
|
|
106
|
+
# Trae CLI (coco)
|
|
107
|
+
export POCO_COCO_COMMAND="traecli"
|
|
108
|
+
export POCO_COCO_WORKDIR="/absolute/path/to/your/repo"
|
|
109
|
+
export POCO_COCO_MODEL="GPT-5"
|
|
110
|
+
export POCO_COCO_APPROVAL_MODE="default"
|
|
111
|
+
export POCO_COCO_TIMEOUT_SECONDS="900"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### State backend
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
export POCO_STATE_BACKEND="sqlite" # default
|
|
118
|
+
export POCO_STATE_DB_PATH="~/.poco/poco.db"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
SQLite is the default runtime path. It persists projects, workspace context, sessions, and tasks so a restart does not lose group/workspace bookkeeping.
|
|
122
|
+
|
|
123
|
+
## Interaction Model
|
|
124
|
+
|
|
125
|
+
- **DM**: control plane. `New` creates a project and its bound group; `Manage` lists projects and exposes delete. DM inbound messages always render the project-list card.
|
|
126
|
+
- **Group**: workspace card with `Stop` / `Working Dir` / `Agent` actions, plus plain-text task submission. `Working Dir` selection (folder browse, manual entry, recent directories, and project-level presets) stays inside cards. `Agent` opens a dedicated selection card.
|
|
127
|
+
|
|
128
|
+
Group behavior:
|
|
129
|
+
|
|
130
|
+
- Plain text in a bound group is a task prompt.
|
|
131
|
+
- Tasks in a project run in a single-project queue — a new message is queued while another task is still active.
|
|
132
|
+
- Codex groups persist the upstream thread id and resume it via `codex app-server`, so follow-up messages continue the same Codex conversation.
|
|
133
|
+
- Task cards show bracketed status in the title (e.g. `[Running] Task: … (codex, /srv/api)`), and live-stream throttled agent output.
|
|
134
|
+
- Waiting task cards expose `Approve` / `Reject`; later state transitions update the same card in place before falling back to a new message.
|
|
135
|
+
- Workspace cards are refreshed when the latest task changes and keep a bound `message_id` across updates.
|
|
136
|
+
|
|
137
|
+
## HTTP Surface
|
|
138
|
+
|
|
139
|
+
Core endpoints:
|
|
140
|
+
|
|
141
|
+
| Path | Purpose |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `GET /health` | Runtime readiness + missing/warn summary for both platforms. |
|
|
144
|
+
| `GET /tasks`, `GET /tasks/{task_id}` | Raw task state. |
|
|
145
|
+
| `GET /debug/feishu`, `GET /debug/slack` | Recent inbound events, outbound attempts, errors, listener snapshot for the respective platform. |
|
|
146
|
+
| `GET /debug/env` | Presence/length of whitelisted env keys (no values are returned). |
|
|
147
|
+
|
|
148
|
+
Feishu endpoints:
|
|
149
|
+
|
|
150
|
+
- `POST /platform/feishu/events`
|
|
151
|
+
- `POST /platform/feishu/card-actions`
|
|
152
|
+
|
|
153
|
+
Slack endpoints:
|
|
154
|
+
|
|
155
|
+
- `POST /platform/slack/events` (JSON body, `X-Slack-Signature` verified)
|
|
156
|
+
- `POST /platform/slack/interactive` (form-encoded `payload=…`)
|
|
157
|
+
- `POST /platform/slack/commands` (form-encoded slash command)
|
|
158
|
+
|
|
159
|
+
Demo endpoints (platform-agnostic):
|
|
160
|
+
|
|
161
|
+
- `POST /demo/command` — `{"text":"/run …"}`
|
|
162
|
+
- `POST /demo/tasks/{task_id}/approve`
|
|
163
|
+
- `POST /demo/tasks/{task_id}/reject`
|
|
164
|
+
- `GET /demo/cards/dm/projects`
|
|
165
|
+
- `POST /demo/card-actions`
|
|
166
|
+
|
|
167
|
+
### Supported text commands
|
|
168
|
+
|
|
169
|
+
In a bound project group, any plain text is treated as a task prompt. The explicit commands are still accepted:
|
|
170
|
+
|
|
171
|
+
- `/run <prompt>` — start a task.
|
|
172
|
+
- `/status <task_id>`
|
|
173
|
+
- `/approve <task_id>` / `/reject <task_id>`
|
|
174
|
+
- `/help`
|
|
175
|
+
|
|
176
|
+
If the prompt starts with `confirm:`, the stub runner and the Codex backend pause at a confirmation checkpoint; `/approve <task_id>` resumes.
|
|
177
|
+
|
|
178
|
+
## Local Demo Example
|
|
179
|
+
|
|
180
|
+
Without any chat platform configured:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
curl -X POST http://127.0.0.1:8000/demo/command \
|
|
184
|
+
-H 'Content-Type: application/json' \
|
|
185
|
+
-d '{"text":"/run Reply with exactly: DEMO_OK"}'
|
|
186
|
+
|
|
187
|
+
curl http://127.0.0.1:8000/tasks/<task_id>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Approval flow:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
curl -X POST http://127.0.0.1:8000/demo/command \
|
|
194
|
+
-H 'Content-Type: application/json' \
|
|
195
|
+
-d '{"text":"/run confirm: Reply with exactly: APPROVED"}'
|
|
196
|
+
|
|
197
|
+
curl -X POST http://127.0.0.1:8000/demo/tasks/<task_id>/approve
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## CLI
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
poco config # interactive Feishu credential prompt
|
|
204
|
+
poco start # starts uvicorn in the background, pid in ~/.poco/poco.pid
|
|
205
|
+
poco status # pid + /health summary
|
|
206
|
+
poco restart
|
|
207
|
+
poco shutdown
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Manual fallback:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
uvicorn poco.main:app --reload
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Packaging
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
python3 -m pip install build
|
|
220
|
+
python3 -m build
|
|
221
|
+
# produces dist/*.whl and dist/*.tar.gz
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
When published, installation will be:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
python3 -m pip install pocket-coding
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Debugging Reply Issues
|
|
231
|
+
|
|
232
|
+
When a chat message does not get a reply, compare `/debug/feishu` or `/debug/slack` against the expected flow:
|
|
233
|
+
|
|
234
|
+
- If there are no recent inbound entries: the platform never reached PoCo (check long-connection/socket-mode listener status under `listener`, or the public webhook route).
|
|
235
|
+
- If inbound entries exist but there are no outbound attempts: PoCo dropped the message (e.g. unbound group, ignored bot message).
|
|
236
|
+
- If outbound attempts exist but errors accumulate: the platform rejected the send (scope/permission issues usually).
|
|
237
|
+
|
|
238
|
+
`/health` also surfaces listener readiness for both platforms plus the current agent backend readiness.
|