caura-bus-cli 0.3.0__tar.gz → 0.3.1__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.
Files changed (21) hide show
  1. {caura_bus_cli-0.3.0/src/caura_bus_cli.egg-info → caura_bus_cli-0.3.1}/PKG-INFO +3 -3
  2. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/pyproject.toml +3 -3
  3. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli/hooks.py +45 -5
  4. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1/src/caura_bus_cli.egg-info}/PKG-INFO +3 -3
  5. caura_bus_cli-0.3.1/src/caura_bus_cli.egg-info/requires.txt +3 -0
  6. caura_bus_cli-0.3.0/src/caura_bus_cli.egg-info/requires.txt +0 -3
  7. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/LICENSE +0 -0
  8. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/NOTICE +0 -0
  9. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/setup.cfg +0 -0
  10. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli/__init__.py +0 -0
  11. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli/broker.py +0 -0
  12. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli/join.py +0 -0
  13. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli/main.py +0 -0
  14. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli/peer_instructions.md +0 -0
  15. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli/py.typed +0 -0
  16. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli/runtime.py +0 -0
  17. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli/setup.py +0 -0
  18. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli.egg-info/SOURCES.txt +0 -0
  19. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli.egg-info/dependency_links.txt +0 -0
  20. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/src/caura_bus_cli.egg-info/entry_points.txt +0 -0
  21. {caura_bus_cli-0.3.0 → caura_bus_cli-0.3.1}/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.0
3
+ Version: 0.3.1
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.0
14
- Requires-Dist: caura-bus-mcp==0.3.0
13
+ Requires-Dist: caura-bus-core==0.3.1
14
+ Requires-Dist: caura-bus-mcp==0.3.1
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.0" # x-release-please-version
3
+ version = "0.3.1" # 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.0", # x-release-please-version
9
+ "caura-bus-core==0.3.1", # x-release-please-version
10
10
  # `caura-bus setup` wires this MCP server into Claude Code / Codex.
11
- "caura-bus-mcp==0.3.0", # x-release-please-version
11
+ "caura-bus-mcp==0.3.1", # x-release-please-version
12
12
  "typer>=0.12",
13
13
  ]
14
14
 
@@ -38,7 +38,7 @@ def install_hooks(
38
38
  raise ValueError("--shared applies only to --scope project")
39
39
  filename = "settings.local.json" if scope == "project" and not shared else "settings.json"
40
40
  path = root / ".claude" / filename
41
- settings = json.loads(path.read_text()) if path.exists() else {}
41
+ settings = load_settings(path)
42
42
  hooks = settings.setdefault("hooks", {})
43
43
  executable = shutil.which("caura-bus") or sibling_executable()
44
44
  if not executable:
@@ -73,21 +73,32 @@ def install_hooks(
73
73
  written = {}
74
74
  # Drop our entries everywhere first, so a reinstall also removes hooks an
75
75
  # older version installed under events it no longer uses.
76
+ # Anything that is not shaped like a hook group belongs to the user or
77
+ # another tool: leave it in place and do not look inside.
76
78
  for event, entries in list(hooks.items()):
77
79
  if not isinstance(entries, list):
78
80
  continue
79
81
  owned = False
80
82
  for group in entries:
81
- kept = [h for h in group.get("hooks", []) if not owned_command(h.get("command", ""))]
82
- owned = owned or len(kept) != len(group.get("hooks", []))
83
+ if not isinstance(group, dict) or not isinstance(group.get("hooks"), list):
84
+ continue
85
+ kept = [h for h in group["hooks"] if not owned_hook(h)]
86
+ owned = owned or len(kept) != len(group["hooks"])
83
87
  group["hooks"] = kept
84
88
  if owned:
85
- entries[:] = [group for group in entries if group.get("hooks")]
89
+ entries[:] = [
90
+ g
91
+ for g in entries
92
+ if not isinstance(g, dict) or not isinstance(g.get("hooks"), list) or g["hooks"]
93
+ ]
86
94
  if not entries:
87
95
  del hooks[event]
88
96
  for event, hook in entries_by_event.items():
97
+ entries = hooks.setdefault(event, [])
98
+ if not isinstance(entries, list):
99
+ raise ValueError(f'"hooks.{event}" in {path} must be a JSON array; not modified')
89
100
  entry = {"hooks": [hook]}
90
- hooks.setdefault(event, []).append(entry)
101
+ entries.append(entry)
91
102
  written[event] = entry
92
103
  path.parent.mkdir(parents=True, exist_ok=True)
93
104
  temporary = path.with_suffix(".json.tmp")
@@ -96,12 +107,41 @@ def install_hooks(
96
107
  return {"path": str(path), "hooks": written}
97
108
 
98
109
 
110
+ def load_settings(path):
111
+ """Read a Claude Code settings file, or refuse one the merge could not keep intact.
112
+
113
+ The file is the user's own configuration and may hold settings that are
114
+ not ours, so a shape ``install_hooks`` cannot merge into is reported with
115
+ its path and left exactly as it was, never rewritten. An empty file is the
116
+ same as a missing one.
117
+ """
118
+ if not path.exists():
119
+ return {}
120
+ text = path.read_text()
121
+ if not text.strip():
122
+ return {}
123
+ try:
124
+ settings = json.loads(text)
125
+ except ValueError as exc:
126
+ raise ValueError(f"{path} is not valid JSON ({exc}); not modified") from None
127
+ if not isinstance(settings, dict):
128
+ raise ValueError(f"{path} must hold a JSON object; not modified")
129
+ if "hooks" in settings and not isinstance(settings["hooks"], dict):
130
+ raise ValueError(f'"hooks" in {path} must be a JSON object; not modified')
131
+ return settings
132
+
133
+
99
134
  def sibling_executable():
100
135
  """caura-bus next to the running interpreter (a venv or pipx install not on PATH)."""
101
136
  candidate = Path(sys.executable).parent / "caura-bus"
102
137
  return str(candidate) if candidate.is_file() else None
103
138
 
104
139
 
140
+ def owned_hook(hook):
141
+ """A hook entry this installer wrote: a command hook whose argv is ours."""
142
+ return isinstance(hook, dict) and isinstance(hook.get("command"), str) and owned_command(hook["command"])
143
+
144
+
105
145
  def owned_command(command):
106
146
  try:
107
147
  parts = shlex.split(command)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: caura-bus-cli
3
- Version: 0.3.0
3
+ Version: 0.3.1
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.0
14
- Requires-Dist: caura-bus-mcp==0.3.0
13
+ Requires-Dist: caura-bus-core==0.3.1
14
+ Requires-Dist: caura-bus-mcp==0.3.1
15
15
  Requires-Dist: typer>=0.12
16
16
  Dynamic: license-file
@@ -0,0 +1,3 @@
1
+ caura-bus-core==0.3.1
2
+ caura-bus-mcp==0.3.1
3
+ typer>=0.12
@@ -1,3 +0,0 @@
1
- caura-bus-core==0.3.0
2
- caura-bus-mcp==0.3.0
3
- typer>=0.12
File without changes
File without changes
File without changes