caura-bus-cli 0.3.1__tar.gz → 0.3.4__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.
- {caura_bus_cli-0.3.1/src/caura_bus_cli.egg-info → caura_bus_cli-0.3.4}/PKG-INFO +3 -3
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/pyproject.toml +3 -3
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli/hooks.py +2 -2
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli/main.py +4 -4
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli/runtime.py +4 -4
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli/setup.py +81 -124
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4/src/caura_bus_cli.egg-info}/PKG-INFO +3 -3
- caura_bus_cli-0.3.4/src/caura_bus_cli.egg-info/requires.txt +3 -0
- caura_bus_cli-0.3.1/src/caura_bus_cli.egg-info/requires.txt +0 -3
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/LICENSE +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/NOTICE +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/setup.cfg +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli/__init__.py +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli/broker.py +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli/join.py +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli/peer_instructions.md +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli/py.typed +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli.egg-info/SOURCES.txt +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli.egg-info/dependency_links.txt +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli.egg-info/entry_points.txt +0 -0
- {caura_bus_cli-0.3.1 → caura_bus_cli-0.3.4}/src/caura_bus_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: caura-bus-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Caura messaging CLI: setup / doctor / replay / agents / threads / send / status
|
|
5
5
|
Author: Caura, Inc.
|
|
6
6
|
License: Apache-2.0
|
|
@@ -10,7 +10,7 @@ Project-URL: Changelog, https://github.com/caura-ai/caura/blob/main/clients/coll
|
|
|
10
10
|
Requires-Python: >=3.12
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
License-File: NOTICE
|
|
13
|
-
Requires-Dist: caura-bus-core==0.3.
|
|
14
|
-
Requires-Dist: caura-bus-mcp==0.3.
|
|
13
|
+
Requires-Dist: caura-bus-core==0.3.4
|
|
14
|
+
Requires-Dist: caura-bus-mcp==0.3.4
|
|
15
15
|
Requires-Dist: typer>=0.12
|
|
16
16
|
Dynamic: license-file
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "caura-bus-cli"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.4" # x-release-please-version
|
|
4
4
|
description = "Caura messaging CLI: setup / doctor / replay / agents / threads / send / status"
|
|
5
5
|
requires-python = ">=3.12"
|
|
6
6
|
license = { text = "Apache-2.0" }
|
|
7
7
|
authors = [{ name = "Caura, Inc." }]
|
|
8
8
|
dependencies = [
|
|
9
|
-
"caura-bus-core==0.3.
|
|
9
|
+
"caura-bus-core==0.3.4", # x-release-please-version
|
|
10
10
|
# `caura-bus setup` wires this MCP server into Claude Code / Codex.
|
|
11
|
-
"caura-bus-mcp==0.3.
|
|
11
|
+
"caura-bus-mcp==0.3.4", # x-release-please-version
|
|
12
12
|
"typer>=0.12",
|
|
13
13
|
]
|
|
14
14
|
|
|
@@ -102,7 +102,7 @@ def install_hooks(
|
|
|
102
102
|
written[event] = entry
|
|
103
103
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
104
104
|
temporary = path.with_suffix(".json.tmp")
|
|
105
|
-
temporary.write_text(json.dumps(settings, indent=2) + "\n")
|
|
105
|
+
temporary.write_text(json.dumps(settings, indent=2) + "\n", encoding="utf-8")
|
|
106
106
|
temporary.replace(path)
|
|
107
107
|
return {"path": str(path), "hooks": written}
|
|
108
108
|
|
|
@@ -117,7 +117,7 @@ def load_settings(path):
|
|
|
117
117
|
"""
|
|
118
118
|
if not path.exists():
|
|
119
119
|
return {}
|
|
120
|
-
text = path.read_text()
|
|
120
|
+
text = path.read_text(encoding="utf-8")
|
|
121
121
|
if not text.strip():
|
|
122
122
|
return {}
|
|
123
123
|
try:
|
|
@@ -238,7 +238,7 @@ def setup(
|
|
|
238
238
|
def tty_prompt(label: str, secret: bool = False) -> str:
|
|
239
239
|
"""Prompt on the controlling terminal, also when stdin is a pipe (``curl ... | sh``)."""
|
|
240
240
|
try:
|
|
241
|
-
tty = open("/dev/tty", "r+")
|
|
241
|
+
tty = open("/dev/tty", "r+", encoding="locale")
|
|
242
242
|
except OSError:
|
|
243
243
|
raise JoinError(f"no terminal to ask for the {label.lower()}") from None
|
|
244
244
|
with tty:
|
|
@@ -275,12 +275,12 @@ def join(
|
|
|
275
275
|
(`caura`) is installed, join prints the equivalent `caura agent connect`
|
|
276
276
|
command and offers to run it instead.
|
|
277
277
|
"""
|
|
278
|
+
# Remove sign-in secrets before broker discovery or any other child process.
|
|
279
|
+
password = os.environ.pop("CAURA_PASSWORD", "")
|
|
280
|
+
totp_env = os.environ.pop("CAURA_TOTP_CODE", "").strip()
|
|
278
281
|
if broker is not False:
|
|
279
282
|
prefer_broker(url, name, runtime, directory, description, tenant, not no_hooks, broker, not no_memory)
|
|
280
283
|
try:
|
|
281
|
-
# Take the secrets out of the environment so no child process (claude mcp add) inherits them.
|
|
282
|
-
password = os.environ.pop("CAURA_PASSWORD", "")
|
|
283
|
-
totp_env = os.environ.pop("CAURA_TOTP_CODE", "").strip()
|
|
284
284
|
if not email:
|
|
285
285
|
email = tty_prompt("Caura email")
|
|
286
286
|
password = password or tty_prompt("Caura password", secret=True)
|
|
@@ -95,12 +95,12 @@ class WakeState:
|
|
|
95
95
|
self.recheck_seconds = recheck_seconds
|
|
96
96
|
|
|
97
97
|
def load(self):
|
|
98
|
-
return json.loads(self.path.read_text()) if self.path.exists() else {}
|
|
98
|
+
return json.loads(self.path.read_text(encoding="utf-8")) if self.path.exists() else {}
|
|
99
99
|
|
|
100
100
|
def save(self, data):
|
|
101
101
|
temporary = self.path.with_suffix(".tmp")
|
|
102
102
|
fd = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
|
|
103
|
-
with os.fdopen(fd, "w") as stream:
|
|
103
|
+
with os.fdopen(fd, "w", encoding="utf-8") as stream:
|
|
104
104
|
json.dump(data, stream)
|
|
105
105
|
stream.flush()
|
|
106
106
|
os.fsync(stream.fileno())
|
|
@@ -212,7 +212,7 @@ def latest_codex_thread(directory, home=None):
|
|
|
212
212
|
rollouts = sorted(sessions.rglob("rollout-*.jsonl"), key=lambda p: p.name, reverse=True)
|
|
213
213
|
for rollout in rollouts:
|
|
214
214
|
try:
|
|
215
|
-
with rollout.open() as stream:
|
|
215
|
+
with rollout.open(encoding="utf-8") as stream:
|
|
216
216
|
meta = json.loads(stream.readline())
|
|
217
217
|
except (OSError, ValueError):
|
|
218
218
|
continue
|
|
@@ -548,7 +548,7 @@ def load_key(key_file=None):
|
|
|
548
548
|
path = Path(key_file)
|
|
549
549
|
if path.stat().st_mode & 0o077:
|
|
550
550
|
raise ValueError(f"{path} must be private to you (chmod 600 {path})")
|
|
551
|
-
key = path.read_text().strip()
|
|
551
|
+
key = path.read_text(encoding="utf-8").strip()
|
|
552
552
|
if not key:
|
|
553
553
|
return False
|
|
554
554
|
os.environ["CAURA_API_KEY"] = key
|
|
@@ -14,8 +14,8 @@ import os
|
|
|
14
14
|
import re
|
|
15
15
|
import shlex
|
|
16
16
|
import shutil
|
|
17
|
-
import subprocess
|
|
18
17
|
import sys
|
|
18
|
+
import tempfile
|
|
19
19
|
import tomllib
|
|
20
20
|
from collections.abc import Callable
|
|
21
21
|
from dataclasses import dataclass, field
|
|
@@ -130,7 +130,7 @@ def find_mcp_binary() -> Path | None:
|
|
|
130
130
|
|
|
131
131
|
|
|
132
132
|
def peer_template() -> str:
|
|
133
|
-
return files("caura_bus_cli").joinpath("peer_instructions.md").read_text()
|
|
133
|
+
return files("caura_bus_cli").joinpath("peer_instructions.md").read_text(encoding="utf-8")
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
# --- 1. verify the key ----------------------------------------------------
|
|
@@ -166,7 +166,7 @@ def render_config(url: str, insecure: bool, identity: dict, existing: Path) -> s
|
|
|
166
166
|
consultation: dict[str, Any] = {}
|
|
167
167
|
if existing.is_file():
|
|
168
168
|
try:
|
|
169
|
-
old = tomllib.loads(existing.read_text())
|
|
169
|
+
old = tomllib.loads(existing.read_text(encoding="utf-8"))
|
|
170
170
|
except (tomllib.TOMLDecodeError, OSError):
|
|
171
171
|
old = {}
|
|
172
172
|
if isinstance(old.get("peers"), list):
|
|
@@ -200,69 +200,75 @@ def render_config(url: str, insecure: bool, identity: dict, existing: Path) -> s
|
|
|
200
200
|
|
|
201
201
|
def write_private(path: Path, text: str) -> None:
|
|
202
202
|
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
|
|
203
|
-
temporary =
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
fd, temporary = tempfile.mkstemp(dir=path.parent, prefix=".caura-bus-")
|
|
204
|
+
try:
|
|
205
|
+
with os.fdopen(fd, "w", encoding="utf-8") as handle:
|
|
206
|
+
os.fchmod(handle.fileno(), 0o600)
|
|
207
|
+
handle.write(text)
|
|
208
|
+
handle.flush()
|
|
209
|
+
os.fsync(handle.fileno())
|
|
210
|
+
os.replace(temporary, path)
|
|
211
|
+
finally:
|
|
212
|
+
if os.path.exists(temporary):
|
|
213
|
+
os.unlink(temporary)
|
|
209
214
|
|
|
210
215
|
|
|
211
216
|
# --- 3. runtime wiring ----------------------------------------------------
|
|
212
217
|
|
|
213
218
|
|
|
214
|
-
def
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
"-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
"
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
219
|
+
def wire_claude_entries(directory: Path, entries: dict[str, dict]) -> str:
|
|
220
|
+
"""Update local-scope entries together, with one backup before a change."""
|
|
221
|
+
path = claude_config_file()
|
|
222
|
+
# Claude local scope uses the nearest repository root, or the launch directory
|
|
223
|
+
# outside a repository. A worktree's .git marker is a file rather than a directory.
|
|
224
|
+
project = next((p for p in (directory, *directory.parents) if (p / ".git").exists()), directory)
|
|
225
|
+
try:
|
|
226
|
+
exists = path.exists()
|
|
227
|
+
text = path.read_text(encoding="utf-8") if exists else ""
|
|
228
|
+
data = json.loads(text) if text else {}
|
|
229
|
+
if not isinstance(data, dict):
|
|
230
|
+
raise ValueError("expected a JSON object")
|
|
231
|
+
projects = data.setdefault("projects", {})
|
|
232
|
+
if not isinstance(projects, dict):
|
|
233
|
+
raise ValueError("projects must be an object")
|
|
234
|
+
settings = projects.setdefault(str(project), {})
|
|
235
|
+
if not isinstance(settings, dict):
|
|
236
|
+
raise ValueError("project settings must be an object")
|
|
237
|
+
servers = settings.setdefault("mcpServers", {})
|
|
238
|
+
if not isinstance(servers, dict):
|
|
239
|
+
raise ValueError("mcpServers must be an object")
|
|
240
|
+
servers.update(entries)
|
|
241
|
+
updated = json.dumps(data, indent=2) + "\n"
|
|
242
|
+
if updated == text:
|
|
243
|
+
os.chmod(path, 0o600)
|
|
244
|
+
else:
|
|
245
|
+
if exists:
|
|
246
|
+
write_private(path.with_name(path.name + ".caura-bus-setup.bak"), text)
|
|
247
|
+
write_private(path, updated)
|
|
248
|
+
except (OSError, ValueError) as exc:
|
|
249
|
+
# JSON decode errors can carry snippets of the original file; do not echo them.
|
|
243
250
|
raise SetupError(
|
|
244
|
-
"
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return f"claude mcp add --scope local {SERVER_NAME} (project {show(directory)})"
|
|
251
|
+
f"could not update private Claude config {show(path)} ({type(exc).__name__})"
|
|
252
|
+
) from None
|
|
253
|
+
return f"{', '.join(entries)} in {show(path)} (project {show(project)}; mode 600)"
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def wire_claude(directory: Path, key: str, config: Path, mcp: Path, server_url: str | None = None) -> str:
|
|
257
|
+
entries = {
|
|
258
|
+
SERVER_NAME: {
|
|
259
|
+
"type": "stdio",
|
|
260
|
+
"command": str(mcp),
|
|
261
|
+
"args": [],
|
|
262
|
+
"env": {"CAURA_API_KEY": key, "CAURA_BUS_AGENT_CONFIG": str(config)},
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
if server_url is not None:
|
|
266
|
+
entries[MEMORY_SERVER_NAME] = {
|
|
267
|
+
"type": "http",
|
|
268
|
+
"url": memory_url(server_url),
|
|
269
|
+
"headers": {MEMORY_HEADER: key},
|
|
270
|
+
}
|
|
271
|
+
return wire_claude_entries(directory, entries)
|
|
266
272
|
|
|
267
273
|
|
|
268
274
|
def codex_block(key: str, config: Path, mcp: Path) -> list[str]:
|
|
@@ -375,7 +381,7 @@ def update_codex_text(text: str, key: str, config: Path, mcp: Path) -> str:
|
|
|
375
381
|
def wire_codex(tables: list[CodexTable], path: Path | None = None) -> list[str]:
|
|
376
382
|
"""Update every table in one write, with one backup of the previous file."""
|
|
377
383
|
path = path or codex_config_path()
|
|
378
|
-
text = path.read_text() if path.exists() else ""
|
|
384
|
+
text = path.read_text(encoding="utf-8") if path.exists() else ""
|
|
379
385
|
updated = text
|
|
380
386
|
for table in tables:
|
|
381
387
|
updated = update_codex_table(updated, table)
|
|
@@ -451,7 +457,7 @@ def claude_config_file() -> Path:
|
|
|
451
457
|
|
|
452
458
|
def read_json(path: Path) -> dict:
|
|
453
459
|
try:
|
|
454
|
-
data = json.loads(path.read_text())
|
|
460
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
455
461
|
except (OSError, ValueError):
|
|
456
462
|
return {}
|
|
457
463
|
return data if isinstance(data, dict) else {}
|
|
@@ -492,57 +498,6 @@ def codex_memory_warnings(text: str, url: str) -> list[str]:
|
|
|
492
498
|
]
|
|
493
499
|
|
|
494
500
|
|
|
495
|
-
def claude_memory_argv(claude: str, url: str, key: str) -> list[str]:
|
|
496
|
-
# --header is variadic, so it goes after the name and URL.
|
|
497
|
-
return [
|
|
498
|
-
claude,
|
|
499
|
-
"mcp",
|
|
500
|
-
"add",
|
|
501
|
-
"--scope",
|
|
502
|
-
"local",
|
|
503
|
-
"--transport",
|
|
504
|
-
"http",
|
|
505
|
-
MEMORY_SERVER_NAME,
|
|
506
|
-
memory_url(url),
|
|
507
|
-
"--header",
|
|
508
|
-
f"{MEMORY_HEADER}: {key}",
|
|
509
|
-
]
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
def claude_memory_manual_command(directory: Path, url: str) -> str:
|
|
513
|
-
command = shlex.join(claude_memory_argv("claude", url, "KEYPLACEHOLDER")).replace(
|
|
514
|
-
f"'{MEMORY_HEADER}: KEYPLACEHOLDER'",
|
|
515
|
-
f'"{MEMORY_HEADER}: ${{CAURA_API_KEY:?export your agent key first}}"',
|
|
516
|
-
)
|
|
517
|
-
return f"cd {shlex.quote(str(directory))} && {command}"
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
def wire_claude_memory(directory: Path, url: str, key: str) -> str:
|
|
521
|
-
claude = shutil.which("claude")
|
|
522
|
-
if not claude:
|
|
523
|
-
raise SetupError(
|
|
524
|
-
"`claude` is not on PATH. Run this yourself (with CAURA_API_KEY exported):\n "
|
|
525
|
-
+ claude_memory_manual_command(directory, url)
|
|
526
|
-
)
|
|
527
|
-
subprocess.run(
|
|
528
|
-
[claude, "mcp", "remove", "--scope", "local", MEMORY_SERVER_NAME],
|
|
529
|
-
cwd=directory,
|
|
530
|
-
capture_output=True,
|
|
531
|
-
text=True,
|
|
532
|
-
check=False,
|
|
533
|
-
)
|
|
534
|
-
result = subprocess.run(
|
|
535
|
-
claude_memory_argv(claude, url, key), cwd=directory, capture_output=True, text=True, check=False
|
|
536
|
-
)
|
|
537
|
-
if result.returncode != 0:
|
|
538
|
-
detail = scrub((result.stderr or result.stdout).strip(), key)
|
|
539
|
-
raise SetupError(f"`claude mcp add` for the memory server failed ({result.returncode}): {detail}")
|
|
540
|
-
return (
|
|
541
|
-
f"claude mcp add --scope local --transport http {MEMORY_SERVER_NAME} {memory_url(url)} "
|
|
542
|
-
f"(project {show(directory)}; the key is stored in {show(claude_config_file())})"
|
|
543
|
-
)
|
|
544
|
-
|
|
545
|
-
|
|
546
501
|
# --- 4. peer instructions -------------------------------------------------
|
|
547
502
|
|
|
548
503
|
|
|
@@ -572,11 +527,11 @@ def merge_instructions(existing: str | None) -> tuple[str, str]:
|
|
|
572
527
|
|
|
573
528
|
|
|
574
529
|
def write_instructions(path: Path) -> str:
|
|
575
|
-
existing = path.read_text() if path.exists() else None
|
|
530
|
+
existing = path.read_text(encoding="utf-8") if path.exists() else None
|
|
576
531
|
updated, action = merge_instructions(existing)
|
|
577
532
|
if action != "unchanged":
|
|
578
533
|
temporary = path.with_name(path.name + ".tmp")
|
|
579
|
-
temporary.write_text(updated)
|
|
534
|
+
temporary.write_text(updated, encoding="utf-8")
|
|
580
535
|
if path.exists():
|
|
581
536
|
os.chmod(temporary, path.stat().st_mode & 0o777)
|
|
582
537
|
temporary.replace(path)
|
|
@@ -699,7 +654,7 @@ def run_setup(options: Options, echo: Callable[[str], None], run_async) -> int:
|
|
|
699
654
|
options.config_path = config_path
|
|
700
655
|
text = render_config(url, insecure, identity, config_path)
|
|
701
656
|
AgentConfig.model_validate(tomllib.loads(text))
|
|
702
|
-
unchanged = config_path.is_file() and config_path.read_text() == text
|
|
657
|
+
unchanged = config_path.is_file() and config_path.read_text(encoding="utf-8") == text
|
|
703
658
|
if options.dry_run:
|
|
704
659
|
echo(f" {prefix}write agent config {show(config_path)} (mode 600)")
|
|
705
660
|
else:
|
|
@@ -717,15 +672,15 @@ def run_setup(options: Options, echo: Callable[[str], None], run_async) -> int:
|
|
|
717
672
|
)
|
|
718
673
|
if runtime == "claude":
|
|
719
674
|
if options.dry_run:
|
|
720
|
-
echo(f" {prefix}
|
|
721
|
-
echo(" " + shlex.join(claude_add_argv("claude", mask(key), config_path, mcp)))
|
|
675
|
+
echo(f" {prefix}write local caura-bus entry in {show(claude_config_file())} (mode 600)")
|
|
722
676
|
if options.memory:
|
|
723
|
-
echo("
|
|
677
|
+
echo(f" {prefix}write local caura {memory_url(url)} entry in the same private config")
|
|
724
678
|
else:
|
|
725
679
|
try:
|
|
726
|
-
echo(
|
|
727
|
-
|
|
728
|
-
|
|
680
|
+
echo(
|
|
681
|
+
" [ok] MCP configuration "
|
|
682
|
+
+ wire_claude(directory, key, config_path, mcp, url if options.memory else None)
|
|
683
|
+
)
|
|
729
684
|
except SetupError as exc:
|
|
730
685
|
echo(f" [!!] {exc}")
|
|
731
686
|
return finish(options, runtime, directory, config_path, echo, run_async, key, failed=True)
|
|
@@ -740,7 +695,7 @@ def run_setup(options: Options, echo: Callable[[str], None], run_async) -> int:
|
|
|
740
695
|
tables = [bus_table(key, config_path, mcp)]
|
|
741
696
|
if options.memory:
|
|
742
697
|
tables.append(memory_table(url, key))
|
|
743
|
-
current = codex_path.read_text() if codex_path.exists() else ""
|
|
698
|
+
current = codex_path.read_text(encoding="utf-8") if codex_path.exists() else ""
|
|
744
699
|
if options.dry_run:
|
|
745
700
|
planned = current
|
|
746
701
|
for table in tables:
|
|
@@ -768,7 +723,9 @@ def finish(options, runtime, directory, config_path, echo, run_async, key, *, fa
|
|
|
768
723
|
prefix = "[dry-run] would " if options.dry_run else ""
|
|
769
724
|
instructions = directory / INSTRUCTION_FILES[runtime]
|
|
770
725
|
if options.dry_run:
|
|
771
|
-
_, action = merge_instructions(
|
|
726
|
+
_, action = merge_instructions(
|
|
727
|
+
instructions.read_text(encoding="utf-8") if instructions.exists() else None
|
|
728
|
+
)
|
|
772
729
|
verb = {"created": "create", "appended": "append to", "updated": "update", "unchanged": "keep"}[
|
|
773
730
|
action
|
|
774
731
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: caura-bus-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Caura messaging CLI: setup / doctor / replay / agents / threads / send / status
|
|
5
5
|
Author: Caura, Inc.
|
|
6
6
|
License: Apache-2.0
|
|
@@ -10,7 +10,7 @@ Project-URL: Changelog, https://github.com/caura-ai/caura/blob/main/clients/coll
|
|
|
10
10
|
Requires-Python: >=3.12
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
License-File: NOTICE
|
|
13
|
-
Requires-Dist: caura-bus-core==0.3.
|
|
14
|
-
Requires-Dist: caura-bus-mcp==0.3.
|
|
13
|
+
Requires-Dist: caura-bus-core==0.3.4
|
|
14
|
+
Requires-Dist: caura-bus-mcp==0.3.4
|
|
15
15
|
Requires-Dist: typer>=0.12
|
|
16
16
|
Dynamic: license-file
|
|
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
|