Metadata-Version: 2.5
Name: teamver-openclaw-adapter
Version: 0.1.5
Summary: OpenClaw tool adapter for teamver-agent-skills
Author-email: NeuralStudio <dev@neuralstudio.kr>
License: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: teamver-agent-sdk<0.8,>=0.6.15
Requires-Dist: teamver-agent-skills<0.2,>=0.1.4
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# teamver-openclaw-adapter

## 변경 이력

| 일시 (KST) | 변경 내용 |
|---|-----|
| 2026-09-21 16:15 | 0.1.5: `tools-rpc` JSONL (게이트웨이가 dispatch 호출) |
| 2026-09-21 15:50 | 0.1.4: echo 미큐잉 · `/sdk/webhook` · inbox 툴 opt-in |
| 2026-09-21 14:40 | 0.1.3: 등록 훅 · CIS HMAC · webhook 공인 listen 금지 · MAIN_FORBIDDEN |

Wraps `teamver-agent-skills` for OpenClaw tool registration and dispatch
(channel · DM · Drive · mail). Tokens come from `openclaw.env`
(`tv_ak_*` / `tv_agent_*`). This package does not read `tv_cp_*`.

**Channel/DM auto-receive is not this adapter.** Product OpenClaw uses the
channel plugin + hostd turn. This package registers Drive/Mail/Jobs tools and
optionally drains a W4 event webhook for an **external worker**.

```python
from teamver_openclaw_adapter import (
    OpenClawToolBridge,
    MappingRegistrar,
    register_openclaw_tools,
    DRIVE_TOOL_NAMES,
)

bridge = OpenClawToolBridge.from_env()
tools = bridge.list_tools()  # OpenAI envelopes: {"type":"function","function":{...}}
await bridge.dispatch("teamver_whoami", {})
await bridge.dispatch("teamver_drive_list_files", {})

# S12 — attach to whatever OpenClaw actually calls (not SKILL.md alone)
registrar = MappingRegistrar()
register_openclaw_tools(bridge, registrar)
print(bridge.drive_tools_listed())  # teamver_drive_list_files must be present

# S12 — gateway/shim process (JSONL). Not W3 inbound.
# python -m teamver_openclaw_adapter tools-rpc
# stdin:  {"id":"1","method":"list_tools"}
#         {"id":"2","method":"dispatch","params":{"name":"teamver_whoami","arguments":{}}}
```

Drive tool names (must match hostd TOOLS.md):

`teamver_drive_list_drives` · `teamver_drive_list_files` · `teamver_drive_download_url` · `teamver_drive_download` · `teamver_drive_upload`

Results are path / URL / `asset_id`. File bytes are never returned.

**Inbound event webhook (N35 / W4) — external worker only.**
제품 게스트에서 공인 listen 금지. N64 FE must not auto-fill this URL.

```bash
# loopback only. Do not bind 0.0.0.0 in a product guest.
TEAMVER_WEBHOOK_SECRET=… TEAMVER_WEBHOOK_QUEUE=./teamver-webhook-queue.jsonl \
  python -m teamver_openclaw_adapter webhook --host 127.0.0.1 --port 8788
```

`TEAMVER_CHANNEL_INGRESS_SECRET` (`tv_cis_`) is accepted as an HMAC alias.
Signature is still `{timestamp}.{raw_body}`. This is **not** W3 plugin loopback.

```python
# export TEAMVER_INBOX_REPLY=1   # required or reply() is a no-op
from teamver_openclaw_adapter import WebhookIngress

ingress = WebhookIngress("./teamver-webhook-queue.jsonl", secret="…")
status, _ = await ingress.accept(headers, raw_body)  # 202 / 204 / 401
for item in ingress.drain():
    await agent.inbox.reply(item, "received")
```

Public docs: [openclaw-adapter.md](https://github.com/NeuralStudioKr/teamver-sdk-docs/blob/main/agent-skills/openclaw-adapter.md)
