getbased-agent-stack 0.5.5__tar.gz → 0.5.6__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 (24) hide show
  1. {getbased_agent_stack-0.5.5/src/getbased_agent_stack.egg-info → getbased_agent_stack-0.5.6}/PKG-INFO +2 -2
  2. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/pyproject.toml +2 -2
  3. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack/__init__.py +1 -1
  4. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack/mcp_configs.py +56 -1
  5. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6/src/getbased_agent_stack.egg-info}/PKG-INFO +2 -2
  6. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack.egg-info/requires.txt +1 -1
  7. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/tests/test_cli.py +36 -0
  8. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/tests/test_mcp_configs.py +29 -0
  9. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/LICENSE +0 -0
  10. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/README.md +0 -0
  11. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/setup.cfg +0 -0
  12. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack/cli.py +0 -0
  13. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack/env_file.py +0 -0
  14. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack/systemd/getbased-dashboard.service +0 -0
  15. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack/systemd/getbased-rag.service +0 -0
  16. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack/units.py +0 -0
  17. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack.egg-info/SOURCES.txt +0 -0
  18. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack.egg-info/dependency_links.txt +0 -0
  19. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack.egg-info/entry_points.txt +0 -0
  20. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/src/getbased_agent_stack.egg-info/top_level.txt +0 -0
  21. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/tests/test_env_file.py +0 -0
  22. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/tests/test_integration.py +0 -0
  23. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/tests/test_systemd_units.py +0 -0
  24. {getbased_agent_stack-0.5.5 → getbased_agent_stack-0.5.6}/tests/test_units.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: getbased-agent-stack
3
- Version: 0.5.5
3
+ Version: 0.5.6
4
4
  Summary: One-command install of the full getbased agent stack — getbased-mcp + getbased-rag + getbased-dashboard
5
5
  License-Expression: AGPL-3.0-or-later
6
6
  Requires-Python: >=3.10
@@ -8,7 +8,7 @@ Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Requires-Dist: getbased-mcp>=0.2.6
10
10
  Requires-Dist: getbased-rag>=0.7.2
11
- Requires-Dist: getbased-dashboard>=0.6.4
11
+ Requires-Dist: getbased-dashboard>=0.6.5
12
12
  Provides-Extra: full
13
13
  Requires-Dist: getbased-rag[full]>=0.7.2; extra == "full"
14
14
  Provides-Extra: test
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "getbased-agent-stack"
7
- version = "0.5.5"
7
+ version = "0.5.6"
8
8
  description = "One-command install of the full getbased agent stack — getbased-mcp + getbased-rag + getbased-dashboard"
9
9
  readme = "README.md"
10
10
  license = "AGPL-3.0-or-later"
@@ -14,7 +14,7 @@ requires-python = ">=3.10"
14
14
  dependencies = [
15
15
  "getbased-mcp>=0.2.6",
16
16
  "getbased-rag>=0.7.2",
17
- "getbased-dashboard>=0.6.4",
17
+ "getbased-dashboard>=0.6.5",
18
18
  ]
19
19
 
20
20
  [project.optional-dependencies]
@@ -5,4 +5,4 @@ plus a small CLI that proxies to the real binaries. Everything
5
5
  interesting lives in the sibling repos.
6
6
  """
7
7
 
8
- __version__ = "0.5.5"
8
+ __version__ = "0.5.6"
@@ -16,7 +16,15 @@ import shutil
16
16
  from typing import Callable
17
17
 
18
18
 
19
- SUPPORTED_CLIENTS = ("claude-desktop", "claude-code", "cursor", "cline", "hermes")
19
+ SUPPORTED_CLIENTS = (
20
+ "claude-desktop",
21
+ "claude-code",
22
+ "cursor",
23
+ "cline",
24
+ "hermes",
25
+ "openclaw",
26
+ "codex",
27
+ )
20
28
 
21
29
  # Single-token list for the Hermes snippet. Matches the lab-context +
22
30
  # knowledge tools exposed by current getbased-mcp. Keep alphabetical for
@@ -118,6 +126,49 @@ def emit_cline(resolver: Callable[[str], "str | None"] = shutil.which) -> str:
118
126
  return banner + json.dumps(payload, indent=2) + "\n"
119
127
 
120
128
 
129
+ def emit_openclaw(resolver: Callable[[str], "str | None"] = shutil.which) -> str:
130
+ """OpenClaw nests MCP servers under `mcp.servers.<name>` rather than
131
+ the Anthropic-style top-level `mcpServers` key."""
132
+ cmd = _resolve_mcp_binary(resolver)
133
+ body = {
134
+ "mcp": {
135
+ "servers": {
136
+ "getbased": {
137
+ "command": cmd,
138
+ "args": [],
139
+ "env": {"GETBASED_STACK_MANAGED": "1"},
140
+ }
141
+ }
142
+ }
143
+ }
144
+ banner = "// Paste into ~/.openclaw/openclaw.json, or adapt for `openclaw mcp set getbased`.\n"
145
+ banner = _prepend_warning(banner, _resolver_warning(cmd))
146
+ return banner + json.dumps(body, indent=2) + "\n"
147
+
148
+
149
+ def emit_codex(resolver: Callable[[str], "str | None"] = shutil.which) -> str:
150
+ """OpenAI Codex CLI uses TOML config under ~/.codex/config.toml."""
151
+ cmd = _resolve_mcp_binary(resolver)
152
+ warning = _resolver_warning(cmd)
153
+ lines = [
154
+ "# Paste into ~/.codex/config.toml",
155
+ "# Merge with existing [mcp_servers.*] tables if present.",
156
+ ]
157
+ if warning:
158
+ lines.append("#")
159
+ lines.extend(f"# {line}" for line in warning.splitlines())
160
+ lines.extend([
161
+ "",
162
+ '[mcp_servers.getbased]',
163
+ f'command = {json.dumps(cmd)}',
164
+ "args = []",
165
+ "",
166
+ '[mcp_servers.getbased.env]',
167
+ 'GETBASED_STACK_MANAGED = "1"',
168
+ ])
169
+ return "\n".join(lines) + "\n"
170
+
171
+
121
172
  def emit_hermes(resolver: Callable[[str], "str | None"] = shutil.which) -> str:
122
173
  """Hermes uses YAML — we emit by hand (no yaml dep) since the shape
123
174
  is trivial. Includes enabled_tools for parity with the existing
@@ -175,6 +226,10 @@ def emit(client: str, resolver: Callable[[str], "str | None"] = shutil.which) ->
175
226
  return emit_cline(resolver)
176
227
  case "hermes":
177
228
  return emit_hermes(resolver)
229
+ case "openclaw":
230
+ return emit_openclaw(resolver)
231
+ case "codex":
232
+ return emit_codex(resolver)
178
233
  case _:
179
234
  raise ValueError(
180
235
  f"unknown client {client!r}. Supported: {', '.join(SUPPORTED_CLIENTS)}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: getbased-agent-stack
3
- Version: 0.5.5
3
+ Version: 0.5.6
4
4
  Summary: One-command install of the full getbased agent stack — getbased-mcp + getbased-rag + getbased-dashboard
5
5
  License-Expression: AGPL-3.0-or-later
6
6
  Requires-Python: >=3.10
@@ -8,7 +8,7 @@ Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Requires-Dist: getbased-mcp>=0.2.6
10
10
  Requires-Dist: getbased-rag>=0.7.2
11
- Requires-Dist: getbased-dashboard>=0.6.4
11
+ Requires-Dist: getbased-dashboard>=0.6.5
12
12
  Provides-Extra: full
13
13
  Requires-Dist: getbased-rag[full]>=0.7.2; extra == "full"
14
14
  Provides-Extra: test
@@ -1,6 +1,6 @@
1
1
  getbased-mcp>=0.2.6
2
2
  getbased-rag>=0.7.2
3
- getbased-dashboard>=0.6.4
3
+ getbased-dashboard>=0.6.5
4
4
 
5
5
  [full]
6
6
  getbased-rag[full]>=0.7.2
@@ -217,6 +217,22 @@ def test_mcp_config_hermes(stack_home):
217
217
  assert "enabled_tools:" in out
218
218
 
219
219
 
220
+ def test_mcp_config_openclaw(stack_home):
221
+ rc, out, _ = _run(["mcp-config", "openclaw"])
222
+ assert rc == 0
223
+ assert '"mcp"' in out
224
+ assert '"servers"' in out
225
+ assert '"GETBASED_STACK_MANAGED": "1"' in out
226
+
227
+
228
+ def test_mcp_config_codex(stack_home):
229
+ rc, out, _ = _run(["mcp-config", "codex"])
230
+ assert rc == 0
231
+ assert "[mcp_servers.getbased]" in out
232
+ assert "[mcp_servers.getbased.env]" in out
233
+ assert 'GETBASED_STACK_MANAGED = "1"' in out
234
+
235
+
220
236
  def test_mcp_config_unknown_client():
221
237
  rc, _, _ = _run(["mcp-config", "vim"])
222
238
  # argparse rejects before our code runs — exit code 2, SystemExit
@@ -286,6 +302,26 @@ def test_connect_rejects_malformed_setup_blob(stack_home):
286
302
  assert env_file.read_env_file() == {}
287
303
 
288
304
 
305
+ def test_connect_non_hermes_clients_store_credentials_and_point_to_config(stack_home, monkeypatch):
306
+ monkeypatch.setattr(cli.shutil, "which", lambda name: "/usr/local/bin/getbased-mcp" if name == "getbased-mcp" else None)
307
+ rc, out, err = _run(["connect", "openclaw", "--setup", _setup_blob()])
308
+ assert rc == 0, err
309
+ data = env_file.read_env_file()
310
+ assert data["GETBASED_STACK_MANAGED"] == "1"
311
+ assert data["GETBASED_TOKEN"] == "tok_123"
312
+ assert data["GETBASED_AGENT_CONTEXT_KEY"] == "ctx_456"
313
+ assert "getbased-stack mcp-config openclaw" in out
314
+ assert "tok_123" not in out
315
+ assert "ctx_456" not in out
316
+
317
+
318
+ def test_connect_codex_is_an_allowed_setup_target(stack_home, monkeypatch):
319
+ monkeypatch.setattr(cli.shutil, "which", lambda name: "/usr/local/bin/getbased-mcp" if name == "getbased-mcp" else None)
320
+ rc, out, err = _run(["connect", "codex", "--setup", _setup_blob()])
321
+ assert rc == 0, err
322
+ assert "getbased-stack mcp-config codex" in out
323
+
324
+
289
325
  def test_connect_skips_gateway_restart_when_running_inside_hermes(stack_home, monkeypatch):
290
326
  monkeypatch.setenv("GETBASED_STACK_ASSUME_HERMES_CHILD", "1")
291
327
  calls = []
@@ -33,6 +33,8 @@ def test_supported_clients_stable_list():
33
33
  "cursor",
34
34
  "cline",
35
35
  "hermes",
36
+ "openclaw",
37
+ "codex",
36
38
  )
37
39
 
38
40
 
@@ -63,6 +65,27 @@ def test_hermes_emits_yaml_shape():
63
65
  assert " - knowledge_search" in out
64
66
 
65
67
 
68
+ def test_openclaw_emits_nested_mcp_servers_shape():
69
+ out = mcp_configs.emit("openclaw", resolver=_fake_resolver())
70
+ json_lines = [line for line in out.splitlines() if not line.startswith("//")]
71
+ payload = json.loads("\n".join(json_lines))
72
+ assert "mcpServers" not in payload
73
+ server = payload["mcp"]["servers"]["getbased"]
74
+ assert server["command"] == "/usr/local/bin/getbased-mcp"
75
+ assert server["args"] == []
76
+ assert server["env"] == {"GETBASED_STACK_MANAGED": "1"}
77
+
78
+
79
+ def test_codex_emits_toml_shape():
80
+ out = mcp_configs.emit("codex", resolver=_fake_resolver())
81
+ assert "# Paste into ~/.codex/config.toml" in out
82
+ assert "[mcp_servers.getbased]" in out
83
+ assert 'command = "/usr/local/bin/getbased-mcp"' in out
84
+ assert "args = []" in out
85
+ assert "[mcp_servers.getbased.env]" in out
86
+ assert 'GETBASED_STACK_MANAGED = "1"' in out
87
+
88
+
66
89
  def test_no_secret_values_in_snippets():
67
90
  """A snippet must never carry a concrete token or key value. Prose
68
91
  comments may mention these variable names for context, but the emitted
@@ -104,6 +127,12 @@ def test_fallback_emits_warning_for_hermes():
104
127
  assert "WARNING" in out
105
128
 
106
129
 
130
+ @pytest.mark.parametrize("client", ["openclaw", "codex"])
131
+ def test_fallback_emits_warning_for_new_agent_clients(client):
132
+ out = mcp_configs.emit(client, resolver=_fake_resolver(found=None))
133
+ assert "WARNING" in out
134
+
135
+
107
136
  def test_no_warning_when_binary_resolved():
108
137
  """When shutil.which does find the binary, the warning banner must
109
138
  not appear — we don't want to cry wolf on successful installs."""