coding-bridge 2026.7.2.1__tar.gz → 2026.7.2.2__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.
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/PKG-INFO +1 -1
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/connection.py +12 -4
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/history.py +48 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/pyproject.toml +1 -1
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_history.py +59 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/.env.example +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/.github/workflows/ci.yaml +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/.github/workflows/publish.yml +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/.gitignore +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/LICENSE +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/NOTICE +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/README.md +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/__init__.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/__main__.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/attachments.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/capabilities.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/cli.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/config.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/fs.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/images.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/locking.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/logs.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/pairing.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/permissions.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/protocol.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/providers/__init__.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/providers/base.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/providers/claude.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/providers/codex.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/providers/copilot.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/session.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/session_meta.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/coding_bridge/store.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/docs/design/reliable-event-delivery.md +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/conftest.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_ask_user_question.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_attachments.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_capabilities.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_codex.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_config.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_connection.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_copilot.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_edit_fork.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_fs.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_images.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_locking.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_outbox.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_pairing.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_permissions.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_protocol.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_resume_guard.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_session.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_session_meta.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_slash_commands.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_store.py +0 -0
- {coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/tests/test_streaming.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coding-bridge
|
|
3
|
-
Version: 2026.7.2.
|
|
3
|
+
Version: 2026.7.2.2
|
|
4
4
|
Summary: Node daemon for AceDataCloud Coding Bridge — run Claude Code on your own machine and drive it from the web.
|
|
5
5
|
Project-URL: Homepage, https://github.com/AceDataCloud/CodingBridge
|
|
6
6
|
Project-URL: Issues, https://github.com/AceDataCloud/CodingBridge/issues
|
|
@@ -334,6 +334,16 @@ class BridgeConnection:
|
|
|
334
334
|
**_session_overrides(payload),
|
|
335
335
|
)
|
|
336
336
|
return
|
|
337
|
+
resume = payload.get("resume_session_id") or None
|
|
338
|
+
prompt = payload.get("prompt", "")
|
|
339
|
+
# Continue a Copilot session the CLI can't natively resume (e.g. a VS Code
|
|
340
|
+
# Copilot Chat session opened from history): seed its transcript into a
|
|
341
|
+
# fresh session instead of a doomed session/resume.
|
|
342
|
+
if provider == "copilot" and resume and not history.copilot_native(resume):
|
|
343
|
+
seed = await asyncio.to_thread(history.build_seed, resume)
|
|
344
|
+
if seed:
|
|
345
|
+
prompt = f"{seed}\n\n{prompt}".strip() if prompt else seed
|
|
346
|
+
resume = None
|
|
337
347
|
session = Session(
|
|
338
348
|
session_id,
|
|
339
349
|
self.provider_factory,
|
|
@@ -344,14 +354,12 @@ class BridgeConnection:
|
|
|
344
354
|
permission_mode=payload.get("permission_mode") or "default",
|
|
345
355
|
provider=provider,
|
|
346
356
|
effort=payload.get("effort") or None,
|
|
347
|
-
resume=
|
|
357
|
+
resume=resume,
|
|
348
358
|
trace_id=payload.get("trace_id"),
|
|
349
359
|
on_rekey=self._rekey_session,
|
|
350
360
|
)
|
|
351
361
|
self.sessions[session_id] = session
|
|
352
|
-
await session.start(
|
|
353
|
-
payload.get("prompt", ""), payload.get("images"), payload.get("attachments")
|
|
354
|
-
)
|
|
362
|
+
await session.start(prompt, payload.get("images"), payload.get("attachments"))
|
|
355
363
|
|
|
356
364
|
def _session(self, session_id: str | None) -> Session | None:
|
|
357
365
|
"""Resolve a session by its canonical id or a still-live provisional alias."""
|
|
@@ -131,6 +131,54 @@ def claude_user_uuid_after(session_id: str, cut_uuid: str | None) -> str | None:
|
|
|
131
131
|
return None
|
|
132
132
|
|
|
133
133
|
|
|
134
|
+
# Cap the seeded transcript so continuing a huge conversation doesn't blow the
|
|
135
|
+
# first prompt; keep the most recent turns (the live context).
|
|
136
|
+
_SEED_MAX_CHARS = 40000
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def copilot_native(session_id: str) -> bool:
|
|
140
|
+
"""True if a Copilot session id belongs to the CLI store (natively resumable).
|
|
141
|
+
|
|
142
|
+
VS Code Copilot Chat sessions live in a different store the CLI can't resume,
|
|
143
|
+
so they must be continued by seeding the transcript into a fresh session.
|
|
144
|
+
"""
|
|
145
|
+
return _copilot_path(session_id) is not None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def build_seed(session_id: str) -> str:
|
|
149
|
+
"""Render a Copilot transcript as a compact preamble to continue it elsewhere.
|
|
150
|
+
|
|
151
|
+
Used when a session can't be natively resumed (e.g. a VS Code Copilot Chat
|
|
152
|
+
session continued from the phone): the prior user/assistant turns are replayed
|
|
153
|
+
as context in a fresh session. Tool calls and thinking are omitted; only typed
|
|
154
|
+
prompts and assistant text are kept, tail-capped at ``_SEED_MAX_CHARS``.
|
|
155
|
+
"""
|
|
156
|
+
try:
|
|
157
|
+
detail = read_session("copilot", session_id)
|
|
158
|
+
except (FileNotFoundError, OSError, ValueError):
|
|
159
|
+
return ""
|
|
160
|
+
lines: list[str] = []
|
|
161
|
+
for event in detail.get("events", []):
|
|
162
|
+
kind = event.get("kind")
|
|
163
|
+
text = event.get("text")
|
|
164
|
+
if not isinstance(text, str) or not text.strip():
|
|
165
|
+
continue
|
|
166
|
+
if kind == "prompt":
|
|
167
|
+
lines.append(f"User: {text.strip()}")
|
|
168
|
+
elif kind == "text":
|
|
169
|
+
lines.append(f"Assistant: {text.strip()}")
|
|
170
|
+
if not lines:
|
|
171
|
+
return ""
|
|
172
|
+
body = "\n\n".join(lines)
|
|
173
|
+
if len(body) > _SEED_MAX_CHARS:
|
|
174
|
+
body = "…(earlier turns omitted)…\n\n" + body[-_SEED_MAX_CHARS:]
|
|
175
|
+
return (
|
|
176
|
+
"[Continuing a previous conversation. Transcript so far:]\n\n"
|
|
177
|
+
+ body
|
|
178
|
+
+ "\n\n[End of previous transcript — continue from here.]"
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
134
182
|
def read_session(provider: str, session_id: str) -> dict[str, Any]:
|
|
135
183
|
"""Return a normalised transcript ``{provider,title,cwd,model,...,events}``."""
|
|
136
184
|
if provider == "claude":
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "coding-bridge"
|
|
7
|
-
version = "2026.7.2.
|
|
7
|
+
version = "2026.7.2.2"
|
|
8
8
|
description = "Node daemon for AceDataCloud Coding Bridge — run Claude Code on your own machine and drive it from the web."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -705,3 +705,62 @@ def test_vscode_chat_tolerates_malformed(monkeypatch, tmp_path):
|
|
|
705
705
|
detail = history.read_session("copilot", VSCODE_SID)
|
|
706
706
|
prompts = [e["text"] for e in detail["events"] if e["kind"] == "prompt"]
|
|
707
707
|
assert prompts == ["real"]
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def test_copilot_native_and_build_seed(monkeypatch, tmp_path):
|
|
711
|
+
# A VS Code chat session is NOT natively resumable but seeds fine.
|
|
712
|
+
storage = tmp_path / "workspaceStorage"
|
|
713
|
+
_seed_vscode_chat(storage)
|
|
714
|
+
monkeypatch.setattr(history, "VSCODE_CHAT_ROOTS", [storage])
|
|
715
|
+
monkeypatch.setattr(history, "COPILOT_ROOT", tmp_path / "none")
|
|
716
|
+
|
|
717
|
+
assert history.copilot_native(VSCODE_SID) is False
|
|
718
|
+
seed = history.build_seed(VSCODE_SID)
|
|
719
|
+
assert "User: fix the parser" in seed
|
|
720
|
+
assert "Assistant: Here is the fix." in seed
|
|
721
|
+
assert seed.startswith("[Continuing a previous conversation")
|
|
722
|
+
assert seed.rstrip().endswith("continue from here.]")
|
|
723
|
+
# tool_use / thinking are omitted from the seed
|
|
724
|
+
assert "copilot_readFile" not in seed
|
|
725
|
+
assert "let me look" not in seed
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
def test_build_seed_missing_returns_empty(monkeypatch, tmp_path):
|
|
729
|
+
monkeypatch.setattr(history, "VSCODE_CHAT_ROOTS", [tmp_path / "none-vs"])
|
|
730
|
+
monkeypatch.setattr(history, "COPILOT_ROOT", tmp_path / "none-cli")
|
|
731
|
+
assert history.build_seed("00000000-0000-0000-0000-000000000000") == ""
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
def test_build_seed_tail_caps(monkeypatch, tmp_path):
|
|
735
|
+
storage = tmp_path / "workspaceStorage"
|
|
736
|
+
ws = storage / "h" / "chatSessions"
|
|
737
|
+
ws.mkdir(parents=True, exist_ok=True)
|
|
738
|
+
big = "x" * 60000
|
|
739
|
+
_write_jsonl(
|
|
740
|
+
ws / f"{VSCODE_SID}.jsonl",
|
|
741
|
+
[
|
|
742
|
+
{
|
|
743
|
+
"kind": 2,
|
|
744
|
+
"v": [
|
|
745
|
+
{
|
|
746
|
+
"requestId": "r1",
|
|
747
|
+
"timestamp": 1,
|
|
748
|
+
"message": {"text": "early turn " + big},
|
|
749
|
+
"response": [{"value": "ok"}],
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
"requestId": "r2",
|
|
753
|
+
"timestamp": 2,
|
|
754
|
+
"message": {"text": "latest question"},
|
|
755
|
+
"response": [{"value": "latest answer"}],
|
|
756
|
+
},
|
|
757
|
+
],
|
|
758
|
+
}
|
|
759
|
+
],
|
|
760
|
+
)
|
|
761
|
+
monkeypatch.setattr(history, "VSCODE_CHAT_ROOTS", [storage])
|
|
762
|
+
monkeypatch.setattr(history, "COPILOT_ROOT", tmp_path / "none")
|
|
763
|
+
seed = history.build_seed(VSCODE_SID)
|
|
764
|
+
assert len(seed) < 45000 # capped
|
|
765
|
+
assert "latest question" in seed # tail kept
|
|
766
|
+
assert "omitted" in seed
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_bridge-2026.7.2.1 → coding_bridge-2026.7.2.2}/docs/design/reliable-event-delivery.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|