opencode-talk-bridge 0.2.7__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.
- opencode_talk_bridge-0.2.7/.env.example +79 -0
- opencode_talk_bridge-0.2.7/.github/workflows/ci.yml +37 -0
- opencode_talk_bridge-0.2.7/.github/workflows/publish.yml +61 -0
- opencode_talk_bridge-0.2.7/.gitignore +35 -0
- opencode_talk_bridge-0.2.7/CHANGELOG.md +176 -0
- opencode_talk_bridge-0.2.7/LICENSE +21 -0
- opencode_talk_bridge-0.2.7/PKG-INFO +284 -0
- opencode_talk_bridge-0.2.7/README.md +253 -0
- opencode_talk_bridge-0.2.7/deploy/com.leiverkus.opencode-talk-bridge.plist +56 -0
- opencode_talk_bridge-0.2.7/docs/publishing.md +58 -0
- opencode_talk_bridge-0.2.7/docs/smoke-test.md +172 -0
- opencode_talk_bridge-0.2.7/pyproject.toml +62 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/__init__.py +8 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/__main__.py +116 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/allowlist.py +33 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/bridge.py +1014 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/commands.py +60 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/config.py +169 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/events.py +85 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/init.py +118 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/messages.py +226 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/opencode.py +418 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/pending.py +115 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/permissions.py +79 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/scheduler.py +144 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/sessions.py +141 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/status.py +88 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/streaming.py +78 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/stt.py +48 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/talk.py +171 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/tts.py +43 -0
- opencode_talk_bridge-0.2.7/src/opencode_talk_bridge/webdav.py +93 -0
- opencode_talk_bridge-0.2.7/tests/conftest.py +22 -0
- opencode_talk_bridge-0.2.7/tests/test_allowlist.py +37 -0
- opencode_talk_bridge-0.2.7/tests/test_bridge.py +740 -0
- opencode_talk_bridge-0.2.7/tests/test_commands.py +42 -0
- opencode_talk_bridge-0.2.7/tests/test_config.py +60 -0
- opencode_talk_bridge-0.2.7/tests/test_events.py +64 -0
- opencode_talk_bridge-0.2.7/tests/test_init.py +92 -0
- opencode_talk_bridge-0.2.7/tests/test_main.py +53 -0
- opencode_talk_bridge-0.2.7/tests/test_messages.py +34 -0
- opencode_talk_bridge-0.2.7/tests/test_opencode.py +201 -0
- opencode_talk_bridge-0.2.7/tests/test_pending.py +62 -0
- opencode_talk_bridge-0.2.7/tests/test_permissions.py +68 -0
- opencode_talk_bridge-0.2.7/tests/test_scheduler.py +72 -0
- opencode_talk_bridge-0.2.7/tests/test_sessions.py +58 -0
- opencode_talk_bridge-0.2.7/tests/test_status.py +42 -0
- opencode_talk_bridge-0.2.7/tests/test_streaming.py +69 -0
- opencode_talk_bridge-0.2.7/tests/test_talk.py +168 -0
- opencode_talk_bridge-0.2.7/tests/test_voice.py +63 -0
- opencode_talk_bridge-0.2.7/tests/test_webdav.py +82 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# opencode-talk-bridge configuration.
|
|
2
|
+
# Copy to `.env` and fill in. NEVER commit the real `.env`.
|
|
3
|
+
|
|
4
|
+
# --- Nextcloud Talk (consumed by nextcloud-talk-core) ----------------------
|
|
5
|
+
# Base URL of your Nextcloud instance.
|
|
6
|
+
NC_URL=https://cloud.example.com
|
|
7
|
+
# Your Nextcloud username (the bot/control account).
|
|
8
|
+
NC_USER=your-username
|
|
9
|
+
# An APP PASSWORD (Settings -> Security -> App passwords), NOT your login password.
|
|
10
|
+
NC_APP_PASSWORD=xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
|
|
11
|
+
|
|
12
|
+
# --- Which conversations to watch ------------------------------------------
|
|
13
|
+
# Comma-separated Talk conversation tokens, or "all" to watch every conversation
|
|
14
|
+
# the account participates in. A single dedicated control conversation is the
|
|
15
|
+
# recommended setup.
|
|
16
|
+
TALK_CONVERSATIONS=abcdef12
|
|
17
|
+
|
|
18
|
+
# --- Security: command allowlist (MANDATORY) -------------------------------
|
|
19
|
+
# Comma-separated Talk user IDs (the stable login id, e.g. "jdoe", NOT the
|
|
20
|
+
# display name) allowed to issue commands. Messages from anyone else are
|
|
21
|
+
# ignored. The bridge REFUSES TO START if this is empty.
|
|
22
|
+
ALLOWED_USERS=jdoe
|
|
23
|
+
|
|
24
|
+
# --- OpenCode server -------------------------------------------------------
|
|
25
|
+
# Base URL of a running `opencode serve` (or `opencode web`). Default 4096.
|
|
26
|
+
OPENCODE_URL=http://127.0.0.1:4096
|
|
27
|
+
# Optional HTTP Basic-Auth for the OpenCode server. Leave blank if unsecured.
|
|
28
|
+
# (`opencode serve`/`web` reads OPENCODE_SERVER_USERNAME/PASSWORD on its side.)
|
|
29
|
+
OPENCODE_USERNAME=
|
|
30
|
+
OPENCODE_PASSWORD=
|
|
31
|
+
# Workspace directory OpenCode sessions operate in. Defaults to the bridge CWD.
|
|
32
|
+
OPENCODE_DIRECTORY=
|
|
33
|
+
# Optional default model as "providerID/modelID" (e.g. anthropic/claude-sonnet-4-6).
|
|
34
|
+
# Leave blank to use the OpenCode server's configured default.
|
|
35
|
+
OPENCODE_MODEL=
|
|
36
|
+
|
|
37
|
+
# --- Local storage & interface ---------------------------------------------
|
|
38
|
+
# SQLite file mapping Talk conversations to OpenCode sessions.
|
|
39
|
+
DB_PATH=bridge.sqlite3
|
|
40
|
+
# JSON status file the menubar app polls.
|
|
41
|
+
STATUS_FILE=status.json
|
|
42
|
+
# WebDAV folder (relative to your Nextcloud user root) the bridge uploads code /
|
|
43
|
+
# long-output attachments into before sharing them, e.g. "/opencode-talk-bridge".
|
|
44
|
+
# The folder is created on demand. Leave blank to disable attachments (long
|
|
45
|
+
# output is then posted as text). No desktop sync client required.
|
|
46
|
+
SHARE_WEBDAV_DIR=
|
|
47
|
+
|
|
48
|
+
# --- Interaction / streaming ------------------------------------------------
|
|
49
|
+
# Stream the assistant reply by editing one Talk message as it is generated.
|
|
50
|
+
RESPONSE_STREAMING=true
|
|
51
|
+
# Minimum delay between streamed edits (ms). Each edit is a full REST call.
|
|
52
|
+
STREAM_THROTTLE_MS=1500
|
|
53
|
+
# Post "💻 tool" / "💠thinking" service messages while the agent works.
|
|
54
|
+
HIDE_TOOL_MESSAGES=false
|
|
55
|
+
HIDE_THINKING=true
|
|
56
|
+
# Notify on activity of detached/non-current sessions.
|
|
57
|
+
TRACK_BACKGROUND_SESSIONS=true
|
|
58
|
+
# Max entries shown in pickers (/sessions, /model, …).
|
|
59
|
+
LIST_LIMIT=10
|
|
60
|
+
# UI language for bridge messages: de or en.
|
|
61
|
+
BOT_LOCALE=de
|
|
62
|
+
|
|
63
|
+
# --- Voice (optional, Phase 3) ----------------------------------------------
|
|
64
|
+
# Speech-to-text for incoming voice notes (Whisper-compatible endpoint).
|
|
65
|
+
STT_API_URL=
|
|
66
|
+
STT_API_KEY=
|
|
67
|
+
STT_MODEL=whisper-large-v3-turbo
|
|
68
|
+
STT_LANGUAGE=
|
|
69
|
+
# Text-to-speech for spoken replies (per-conversation /tts toggle).
|
|
70
|
+
# Requires SHARE_WEBDAV_DIR to upload the audio before sharing.
|
|
71
|
+
TTS_API_URL=
|
|
72
|
+
TTS_API_KEY=
|
|
73
|
+
TTS_MODEL=gpt-4o-mini-tts
|
|
74
|
+
TTS_VOICE=alloy
|
|
75
|
+
# Max concurrent scheduled tasks (/task).
|
|
76
|
+
TASK_LIMIT=10
|
|
77
|
+
|
|
78
|
+
# --- Logging ----------------------------------------------------------------
|
|
79
|
+
LOG_LEVEL=INFO
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
pip install -e ".[dev]" # nextcloud-talk-core comes from PyPI
|
|
29
|
+
|
|
30
|
+
- name: Ruff lint
|
|
31
|
+
run: ruff check src tests
|
|
32
|
+
|
|
33
|
+
- name: Ruff format check
|
|
34
|
+
run: ruff format --check src tests
|
|
35
|
+
|
|
36
|
+
- name: Pytest
|
|
37
|
+
run: pytest
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Publishes the package to PyPI on every version tag (vX.Y.Z), using PyPI
|
|
4
|
+
# Trusted Publishing (OIDC) — no API token is stored in the repo.
|
|
5
|
+
#
|
|
6
|
+
# One-time PyPI setup (see docs/publishing.md): add a Trusted Publisher for the
|
|
7
|
+
# project pointing at this repo, workflow `publish.yml`, and environment `pypi`.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
tags: ["v*"]
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
|
|
26
|
+
- name: Guard — tag must match the package version
|
|
27
|
+
run: |
|
|
28
|
+
TAG="${GITHUB_REF_NAME#v}"
|
|
29
|
+
PKG="$(python -c 'import tomllib;print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')"
|
|
30
|
+
echo "tag=$TAG pyproject=$PKG"
|
|
31
|
+
test "$TAG" = "$PKG" || { echo "::error::tag v$TAG != pyproject version $PKG"; exit 1; }
|
|
32
|
+
|
|
33
|
+
- name: Build sdist + wheel
|
|
34
|
+
run: |
|
|
35
|
+
python -m pip install --upgrade build
|
|
36
|
+
python -m build
|
|
37
|
+
|
|
38
|
+
- name: Check metadata
|
|
39
|
+
run: |
|
|
40
|
+
python -m pip install --upgrade twine
|
|
41
|
+
python -m twine check dist/*
|
|
42
|
+
|
|
43
|
+
- uses: actions/upload-artifact@v4
|
|
44
|
+
with:
|
|
45
|
+
name: dist
|
|
46
|
+
path: dist/
|
|
47
|
+
|
|
48
|
+
publish:
|
|
49
|
+
needs: build
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
environment: pypi
|
|
52
|
+
permissions:
|
|
53
|
+
id-token: write # required for Trusted Publishing (OIDC)
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/download-artifact@v4
|
|
56
|
+
with:
|
|
57
|
+
name: dist
|
|
58
|
+
path: dist/
|
|
59
|
+
|
|
60
|
+
- name: Publish to PyPI
|
|
61
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Secrets — never commit a real environment file.
|
|
2
|
+
.env
|
|
3
|
+
|
|
4
|
+
# Runtime artifacts
|
|
5
|
+
*.sqlite
|
|
6
|
+
*.sqlite3
|
|
7
|
+
*.db
|
|
8
|
+
status.json
|
|
9
|
+
*.log
|
|
10
|
+
|
|
11
|
+
# Python
|
|
12
|
+
__pycache__/
|
|
13
|
+
*.py[cod]
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
*.egg-info/
|
|
17
|
+
build/
|
|
18
|
+
dist/
|
|
19
|
+
.eggs/
|
|
20
|
+
|
|
21
|
+
# Tooling caches
|
|
22
|
+
.pytest_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
.coverage
|
|
25
|
+
htmlcov/
|
|
26
|
+
.coverage.*
|
|
27
|
+
|
|
28
|
+
# macOS
|
|
29
|
+
.DS_Store
|
|
30
|
+
|
|
31
|
+
# Local editor / agent settings
|
|
32
|
+
.claude/
|
|
33
|
+
|
|
34
|
+
# Internal design brief — not published
|
|
35
|
+
BRIEFING-bridge.md
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.2.7] - 2026-06-01
|
|
10
|
+
|
|
11
|
+
First release published to **PyPI** — `uv tool install opencode-talk-bridge`
|
|
12
|
+
(or `pipx install …`) now works without a git URL.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- PyPI Trusted-Publishing workflow (`.github/workflows/publish.yml`): on each
|
|
16
|
+
`vX.Y.Z` tag it guards the tag↔version match, builds, `twine check`s, and
|
|
17
|
+
publishes to PyPI via OIDC (no token). Package classifiers + a
|
|
18
|
+
`docs/publishing.md` setup guide.
|
|
19
|
+
|
|
20
|
+
## [0.2.6] - 2026-06-01
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- `nextcloud-talk-core` is now a normal **PyPI dependency** (`>=1.0.2,<2`)
|
|
24
|
+
instead of a pinned git URL — it has been published to PyPI. Simpler installs
|
|
25
|
+
and resolution; dropped `allow-direct-references` and the git-dep notes in the
|
|
26
|
+
README/CI. Verified our used API (TalkClient/OCSClient methods) is unchanged in
|
|
27
|
+
1.0.2 and the full suite passes against it.
|
|
28
|
+
|
|
29
|
+
## [0.2.5] - 2026-06-01
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- **No server text leaks into chat.** The prompt worker caught generic
|
|
33
|
+
exceptions and posted `Fehler: {exc}`; an `OpenCodeError` carries up to ~300
|
|
34
|
+
chars of the OpenCode HTTP response body, which could reach Talk. The worker
|
|
35
|
+
(both session-setup and prompt paths) now catches `OpenCodeError` and posts a
|
|
36
|
+
generic `oc_error` message, logging the details only — matching the command
|
|
37
|
+
handlers. Remaining `error: {exc}` paths only fire for local validation errors
|
|
38
|
+
(e.g. a bad model string), which carry no server body.
|
|
39
|
+
|
|
40
|
+
## [0.2.4] - 2026-05-31
|
|
41
|
+
|
|
42
|
+
Hardening pass from a code review.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
- **Error isolation.** Command handlers run inline on the poll thread and only
|
|
46
|
+
caught `OpenCodeDownError`; an OpenCode HTTP 4xx/5xx (`OpenCodeError`) could
|
|
47
|
+
escape and kill a conversation's poll thread. The poll loop now isolates every
|
|
48
|
+
message (logs + notifies + keeps polling), and command dispatch catches
|
|
49
|
+
`OpenCodeError` with a clean message.
|
|
50
|
+
- **`/task` validation.** Reject `0`-minute schedules and empty prompts
|
|
51
|
+
(`minutes >= 1` and a non-empty prompt are now required).
|
|
52
|
+
|
|
53
|
+
### Internal
|
|
54
|
+
- Added tests for `__main__` (CLI wiring: `--check`/`--init`/run, 0→90%) and the
|
|
55
|
+
Talk gateway / message parsing (57→95%); overall coverage 76→82%.
|
|
56
|
+
|
|
57
|
+
## [0.2.3] - 2026-05-31
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
- `/sessions`, `/commands`, and `/skills` are **project-scoped** in OpenCode, but
|
|
61
|
+
the bridge listed them against the global `OPENCODE_DIRECTORY` and ignored the
|
|
62
|
+
per-conversation project chosen via `/projects`. They now use the
|
|
63
|
+
conversation's directory, so `/sessions` shows the same sessions as the
|
|
64
|
+
OpenCode desktop/TUI for that project (and follows `/projects` switches).
|
|
65
|
+
`/projects` itself is global (all known projects), matching desktop.
|
|
66
|
+
|
|
67
|
+
## [0.2.2] - 2026-05-31
|
|
68
|
+
|
|
69
|
+
### Added
|
|
70
|
+
- `opencode-talk-bridge --init` — interactive `.env` wizard. Prompts for the
|
|
71
|
+
essentials (Talk credentials, allowlist, OpenCode URL), hides the app password,
|
|
72
|
+
refuses to overwrite without confirmation, and writes the file `chmod 600`.
|
|
73
|
+
|
|
74
|
+
## [0.2.1] - 2026-05-31
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
- `/skills` — browse & run OpenCode skills (via `GET /skill`).
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
- `run_command` now always sends the required `arguments` field — without it the
|
|
81
|
+
command endpoint returned HTTP 400, so `/commands` (and any command run) was
|
|
82
|
+
broken.
|
|
83
|
+
- `/commands` no longer lists skills (entries with `source == "skill"`); those
|
|
84
|
+
live under `/skills`.
|
|
85
|
+
|
|
86
|
+
## [0.2.0] - 2026-05-31
|
|
87
|
+
|
|
88
|
+
Feature-parity push toward `grinev/opencode-telegram-bot`, adapted to Talk.
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
- **Live response streaming**: the assistant reply is streamed into a single
|
|
92
|
+
Talk message via editing (`PUT`, throttled by `STREAM_THROTTLE_MS`), instead
|
|
93
|
+
of one post at the end. Toggle with `RESPONSE_STREAMING`.
|
|
94
|
+
- **Tool & thinking notices** from the SSE stream (`💻 bash`, `💠…`), each tool
|
|
95
|
+
announced once per turn; toggle with `HIDE_TOOL_MESSAGES` / `HIDE_THINKING`.
|
|
96
|
+
- **Agent questions** (`question.asked`) are surfaced into Talk and answered by
|
|
97
|
+
a numbered option or free text.
|
|
98
|
+
- **Numbered-text pickers** (Talk has no buttons): `/sessions` (switch),
|
|
99
|
+
`/model` (pick), `/agent` (pick plan/build/…); `/agent <name>` sets directly.
|
|
100
|
+
- OpenCode client wrappers for sessions (rename/revert/unrevert/fork), projects,
|
|
101
|
+
worktrees, models, agents, commands, MCP, and question reply/reject.
|
|
102
|
+
|
|
103
|
+
- **Breadth commands** (Phase 2): `/rename`, `/detach`, `/projects`,
|
|
104
|
+
`/worktree`, `/commands` (run with streaming), `/mcps` (toggle), and
|
|
105
|
+
`/messages` → revert/fork. Projects/worktrees bind a per-conversation
|
|
106
|
+
directory for new sessions.
|
|
107
|
+
- **Background-session notifications** when a non-foreground session goes idle
|
|
108
|
+
(`TRACK_BACKGROUND_SESSIONS`).
|
|
109
|
+
- **i18n**: user-facing strings localised via `messages.py` (German + English),
|
|
110
|
+
selected by `BOT_LOCALE`.
|
|
111
|
+
- **Voice & files** (Phase 3): incoming file/image attachments are inlined into
|
|
112
|
+
the prompt as OpenCode file parts; voice notes are transcribed (STT,
|
|
113
|
+
Whisper-compatible) into the prompt; optional spoken replies (TTS) shared as
|
|
114
|
+
audio, toggled per-conversation with `/tts`. Config: `STT_*`, `TTS_*`.
|
|
115
|
+
- **Scheduled tasks** (Phase 3): `/task <min> <prompt>` (or `/task every <min>
|
|
116
|
+
…`) and `/tasklist`; a daemon scheduler fires due tasks, persisted in SQLite.
|
|
117
|
+
|
|
118
|
+
### Changed
|
|
119
|
+
- Internal refactor: unified pending-interaction registry (`pending.py`),
|
|
120
|
+
streaming substrate (`streaming.py`), and typed SSE dispatch (`events.py`).
|
|
121
|
+
- `TalkGateway.send` now returns the message id; added `edit`/`download`.
|
|
122
|
+
|
|
123
|
+
## [0.1.1] - 2026-05-30
|
|
124
|
+
|
|
125
|
+
### Changed
|
|
126
|
+
- File attachments now upload to Nextcloud directly via **WebDAV** (`PUT`,
|
|
127
|
+
creating the target folder on demand) before sharing into the conversation.
|
|
128
|
+
This removes the previous dependency on a desktop sync client having already
|
|
129
|
+
uploaded the file, which could make `share_file` fail with "not found".
|
|
130
|
+
- Attachment config simplified to a single `SHARE_WEBDAV_DIR` (the server-side
|
|
131
|
+
folder), replacing `SHARE_DIR` + `SHARE_WEBDAV_ROOT`.
|
|
132
|
+
|
|
133
|
+
### Added
|
|
134
|
+
- `webdav.py`: minimal WebDAV client (reuses the app-password credentials).
|
|
135
|
+
|
|
136
|
+
## [0.1.0] - 2026-05-30
|
|
137
|
+
|
|
138
|
+
Initial release.
|
|
139
|
+
|
|
140
|
+
### Added
|
|
141
|
+
- Polling bridge between Nextcloud Talk and a local OpenCode instance — no
|
|
142
|
+
webhooks, works on institutional Talk instances without admin access.
|
|
143
|
+
- OpenCode HTTP + SSE client (`opencode.py`), verified against the
|
|
144
|
+
`opencode serve` 1.15 OpenAPI: health, session create/list, blocking prompt,
|
|
145
|
+
abort, global permission reply, and the `/global/event` stream.
|
|
146
|
+
- Mandatory user allowlist enforced on the stable OCS `actorId` with
|
|
147
|
+
`actorType == "users"`; the bridge refuses to start with an empty allowlist.
|
|
148
|
+
- Permission prompts for dangerous agent actions surfaced into Talk, answered
|
|
149
|
+
with `ja`/`immer`/`nein` and replied via `POST /permission/{id}/reply`.
|
|
150
|
+
- SQLite session store mapping each Talk conversation to an OpenCode session,
|
|
151
|
+
model, and last-known-message cursor; persists across restarts.
|
|
152
|
+
- Slash-commands: `/new`, `/session`, `/model`, `/stop`, `/status`, `/help`.
|
|
153
|
+
- File attachments for long output / code, written to a Nextcloud share folder
|
|
154
|
+
and shared into the conversation instead of posting a large text block.
|
|
155
|
+
- Atomic JSON status file as a stable contract for a supervising menubar app.
|
|
156
|
+
- CLI entrypoint with `--check` and graceful SIGINT/SIGTERM shutdown.
|
|
157
|
+
- launchd user-agent example (`deploy/`), README threat model, and the
|
|
158
|
+
`.env.example` template.
|
|
159
|
+
- Test suite (mocked Talk + OpenCode, no live calls) and CI matrix on
|
|
160
|
+
Python 3.10–3.13 with ruff lint + format checks.
|
|
161
|
+
|
|
162
|
+
### Dependencies
|
|
163
|
+
- `nextcloud-talk-core`, pinned to the `core-v1.0.0` git tag.
|
|
164
|
+
- `httpx >= 0.27`.
|
|
165
|
+
|
|
166
|
+
[Unreleased]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.7...HEAD
|
|
167
|
+
[0.2.7]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.6...v0.2.7
|
|
168
|
+
[0.2.6]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.5...v0.2.6
|
|
169
|
+
[0.2.5]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.4...v0.2.5
|
|
170
|
+
[0.2.4]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.3...v0.2.4
|
|
171
|
+
[0.2.3]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.2...v0.2.3
|
|
172
|
+
[0.2.2]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.1...v0.2.2
|
|
173
|
+
[0.2.1]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.0...v0.2.1
|
|
174
|
+
[0.2.0]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.1.1...v0.2.0
|
|
175
|
+
[0.1.1]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.1.0...v0.1.1
|
|
176
|
+
[0.1.0]: https://github.com/leiverkus/opencode-talk-bridge/releases/tag/v0.1.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Patrick Leiverkus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|