getbased-agent-stack 0.5.6__tar.gz → 0.5.8__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.
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/PKG-INFO +27 -12
- getbased_agent_stack-0.5.6/src/getbased_agent_stack.egg-info/PKG-INFO → getbased_agent_stack-0.5.8/README.md +22 -26
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/pyproject.toml +6 -6
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack/__init__.py +1 -1
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack/cli.py +64 -26
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack/env_file.py +0 -1
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack/mcp_configs.py +16 -19
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack/units.py +1 -1
- getbased_agent_stack-0.5.6/README.md → getbased_agent_stack-0.5.8/src/getbased_agent_stack.egg-info/PKG-INFO +41 -7
- getbased_agent_stack-0.5.8/src/getbased_agent_stack.egg-info/requires.txt +11 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/tests/test_cli.py +58 -32
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/tests/test_units.py +1 -6
- getbased_agent_stack-0.5.6/src/getbased_agent_stack.egg-info/requires.txt +0 -11
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/LICENSE +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/setup.cfg +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack/systemd/getbased-dashboard.service +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack/systemd/getbased-rag.service +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack.egg-info/SOURCES.txt +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack.egg-info/dependency_links.txt +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack.egg-info/entry_points.txt +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack.egg-info/top_level.txt +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/tests/test_env_file.py +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/tests/test_integration.py +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/tests/test_mcp_configs.py +0 -0
- {getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/tests/test_systemd_units.py +0 -0
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: getbased-agent-stack
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.8
|
|
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
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE
|
|
9
|
-
Requires-Dist: getbased-mcp>=0.2.
|
|
10
|
-
Requires-Dist: getbased-rag>=0.7.
|
|
11
|
-
Requires-Dist: getbased-dashboard>=0.6.
|
|
9
|
+
Requires-Dist: getbased-mcp>=0.2.8
|
|
10
|
+
Requires-Dist: getbased-rag>=0.7.5
|
|
11
|
+
Requires-Dist: getbased-dashboard>=0.6.7
|
|
12
12
|
Provides-Extra: full
|
|
13
|
-
Requires-Dist: getbased-rag[full]>=0.7.
|
|
13
|
+
Requires-Dist: getbased-rag[full]>=0.7.5; extra == "full"
|
|
14
14
|
Provides-Extra: test
|
|
15
15
|
Requires-Dist: pytest>=8.0; extra == "test"
|
|
16
16
|
Requires-Dist: httpx>=0.27; extra == "test"
|
|
@@ -19,7 +19,7 @@ Dynamic: license-file
|
|
|
19
19
|
|
|
20
20
|
# getbased-agent-stack
|
|
21
21
|
|
|
22
|
-
Meta-package bundling the full [getbased](https://getbased.health) agent stack into one install: the MCP adapter, the
|
|
22
|
+
Meta-package bundling the full [getbased](https://getbased.health) agent stack into one install: the MCP adapter, the local knowledge server, the browser dashboard, an orchestration CLI (`init` / `install` / `connect` / `mcp-config`), systemd user units for the knowledge server + dashboard, and paste-ready configs for Claude Code, Claude Desktop, Cursor, Cline, Codex CLI, Hermes, and OpenClaw.
|
|
23
23
|
|
|
24
24
|
Part of the [getbased-agents monorepo](https://github.com/elkimek/getbased-agents).
|
|
25
25
|
|
|
@@ -31,7 +31,15 @@ Linux, one command:
|
|
|
31
31
|
curl -sSL https://getbased.health/install.sh | bash
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Runs end-to-end: installs `getbased-agent-stack[full]` via whichever of `uv` or `pipx` is available, exposes sibling binaries, runs
|
|
34
|
+
Runs end-to-end: installs `getbased-agent-stack[full]` via whichever of `uv` or `pipx` is available, exposes sibling binaries, runs a non-interactive local-only init, and starts the knowledge server + dashboard as systemd user services. [Read the script first](https://github.com/elkimek/get-based-site/blob/main/install.sh) if you're cautious.
|
|
35
|
+
|
|
36
|
+
If you are connecting a private getbased profile, copy the command from **Settings → Agent Access** in the app. It uses the same installer and then runs `getbased-stack connect` for the selected client:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
curl -fsSL https://getbased.health/install.sh | bash -s -- connect <target> --setup 'gbsetup_v1_...'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That setup payload contains private credentials. Keep it out of logs and public issues.
|
|
35
43
|
|
|
36
44
|
Manual — pipx:
|
|
37
45
|
|
|
@@ -56,7 +64,7 @@ uv tool install \
|
|
|
56
64
|
Pulls:
|
|
57
65
|
|
|
58
66
|
- [`getbased-mcp`](https://github.com/elkimek/getbased-agents/tree/main/packages/mcp) — stdio MCP server that Claude Code / Hermes / OpenClaw spawn
|
|
59
|
-
- [`getbased-rag`](https://github.com/elkimek/getbased-agents/tree/main/packages/rag) — local
|
|
67
|
+
- [`getbased-rag`](https://github.com/elkimek/getbased-agents/tree/main/packages/rag) — local knowledge server (FastAPI + Qdrant + MiniLM/BGE)
|
|
60
68
|
- [`getbased-dashboard`](https://github.com/elkimek/getbased-agents/tree/main/packages/dashboard) — web UI for library management, MCP config generation, and agent-activity inspection
|
|
61
69
|
- The `getbased-stack` discovery CLI
|
|
62
70
|
- `[full]` extra: PDF/DOCX parsers + ONNX runtime for hardware-accelerated embeddings
|
|
@@ -74,7 +82,7 @@ getbased-stack init
|
|
|
74
82
|
Non-interactive (for scripted installs and curl | bash; `install.sh` uses this):
|
|
75
83
|
|
|
76
84
|
```bash
|
|
77
|
-
getbased-stack init --yes
|
|
85
|
+
getbased-stack init --yes --local-only
|
|
78
86
|
```
|
|
79
87
|
|
|
80
88
|
The wizard (~30 seconds):
|
|
@@ -86,10 +94,16 @@ The wizard (~30 seconds):
|
|
|
86
94
|
|
|
87
95
|
On non-systemd hosts (Docker, macOS, WSL1) step 4 writes the unit files but skips activation with a clear message instead of crashing — re-run on a systemd-enabled host or start `lens serve` + `getbased-dashboard serve` manually.
|
|
88
96
|
|
|
89
|
-
|
|
97
|
+
Private setup from the app:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
getbased-stack connect hermes --setup 'gbsetup_v1_...'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Manual config helper:
|
|
90
104
|
|
|
91
105
|
```bash
|
|
92
|
-
getbased-stack mcp-config claude-desktop # or: claude-code, cursor, cline, hermes
|
|
106
|
+
getbased-stack mcp-config claude-desktop # or: claude-code, cursor, cline, codex, hermes, openclaw
|
|
93
107
|
```
|
|
94
108
|
|
|
95
109
|
The snippet carries only `GETBASED_STACK_MANAGED=1` in its env block. No secrets in client configs — every MCP spawn reads the shared env file and loads the token + rag URL + API key path from there.
|
|
@@ -144,7 +158,7 @@ Claude Code / Hermes / OpenClaw Browser
|
|
|
144
158
|
│ │ │ │
|
|
145
159
|
│ HTTP │ HTTP │ proxies │ spawns stdio for Test
|
|
146
160
|
▼ ▼ ▼ ▼
|
|
147
|
-
|
|
161
|
+
context gateway getbased-rag ◀────────┘ getbased-mcp
|
|
148
162
|
(localhost:8322)
|
|
149
163
|
```
|
|
150
164
|
|
|
@@ -162,6 +176,7 @@ The dashboard is likewise stateless — it proxies rag for Knowledge operations,
|
|
|
162
176
|
| 0.1.x | ≥0.2.0 | ≥0.1.0 | — | v1 (multi-library) |
|
|
163
177
|
| 0.2.x | ≥0.2.2 | ≥0.6.0 | ≥0.5.0 | v1 (+ streaming ingest, per-library models) |
|
|
164
178
|
| 0.4.x | ≥0.2.3 | ≥0.7.1 | ≥0.6.1 | v1 (+ shared env file, `getbased-stack init`, systemd units) |
|
|
179
|
+
| 0.5.x | ≥0.2.8 | ≥0.7.5 | ≥0.6.7 | v1 (+ `getbased-stack connect`, multi-client setup targets; explicit local-only scripted init) |
|
|
165
180
|
|
|
166
181
|
Bump the meta's major when sibling protocols break; bump siblings freely for normal features.
|
|
167
182
|
|
|
@@ -1,25 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: getbased-agent-stack
|
|
3
|
-
Version: 0.5.6
|
|
4
|
-
Summary: One-command install of the full getbased agent stack — getbased-mcp + getbased-rag + getbased-dashboard
|
|
5
|
-
License-Expression: AGPL-3.0-or-later
|
|
6
|
-
Requires-Python: >=3.10
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
License-File: LICENSE
|
|
9
|
-
Requires-Dist: getbased-mcp>=0.2.6
|
|
10
|
-
Requires-Dist: getbased-rag>=0.7.2
|
|
11
|
-
Requires-Dist: getbased-dashboard>=0.6.5
|
|
12
|
-
Provides-Extra: full
|
|
13
|
-
Requires-Dist: getbased-rag[full]>=0.7.2; extra == "full"
|
|
14
|
-
Provides-Extra: test
|
|
15
|
-
Requires-Dist: pytest>=8.0; extra == "test"
|
|
16
|
-
Requires-Dist: httpx>=0.27; extra == "test"
|
|
17
|
-
Requires-Dist: pytest-timeout>=2.3; extra == "test"
|
|
18
|
-
Dynamic: license-file
|
|
19
|
-
|
|
20
1
|
# getbased-agent-stack
|
|
21
2
|
|
|
22
|
-
Meta-package bundling the full [getbased](https://getbased.health) agent stack into one install: the MCP adapter, the
|
|
3
|
+
Meta-package bundling the full [getbased](https://getbased.health) agent stack into one install: the MCP adapter, the local knowledge server, the browser dashboard, an orchestration CLI (`init` / `install` / `connect` / `mcp-config`), systemd user units for the knowledge server + dashboard, and paste-ready configs for Claude Code, Claude Desktop, Cursor, Cline, Codex CLI, Hermes, and OpenClaw.
|
|
23
4
|
|
|
24
5
|
Part of the [getbased-agents monorepo](https://github.com/elkimek/getbased-agents).
|
|
25
6
|
|
|
@@ -31,7 +12,15 @@ Linux, one command:
|
|
|
31
12
|
curl -sSL https://getbased.health/install.sh | bash
|
|
32
13
|
```
|
|
33
14
|
|
|
34
|
-
Runs end-to-end: installs `getbased-agent-stack[full]` via whichever of `uv` or `pipx` is available, exposes sibling binaries, runs
|
|
15
|
+
Runs end-to-end: installs `getbased-agent-stack[full]` via whichever of `uv` or `pipx` is available, exposes sibling binaries, runs a non-interactive local-only init, and starts the knowledge server + dashboard as systemd user services. [Read the script first](https://github.com/elkimek/get-based-site/blob/main/install.sh) if you're cautious.
|
|
16
|
+
|
|
17
|
+
If you are connecting a private getbased profile, copy the command from **Settings → Agent Access** in the app. It uses the same installer and then runs `getbased-stack connect` for the selected client:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
curl -fsSL https://getbased.health/install.sh | bash -s -- connect <target> --setup 'gbsetup_v1_...'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
That setup payload contains private credentials. Keep it out of logs and public issues.
|
|
35
24
|
|
|
36
25
|
Manual — pipx:
|
|
37
26
|
|
|
@@ -56,7 +45,7 @@ uv tool install \
|
|
|
56
45
|
Pulls:
|
|
57
46
|
|
|
58
47
|
- [`getbased-mcp`](https://github.com/elkimek/getbased-agents/tree/main/packages/mcp) — stdio MCP server that Claude Code / Hermes / OpenClaw spawn
|
|
59
|
-
- [`getbased-rag`](https://github.com/elkimek/getbased-agents/tree/main/packages/rag) — local
|
|
48
|
+
- [`getbased-rag`](https://github.com/elkimek/getbased-agents/tree/main/packages/rag) — local knowledge server (FastAPI + Qdrant + MiniLM/BGE)
|
|
60
49
|
- [`getbased-dashboard`](https://github.com/elkimek/getbased-agents/tree/main/packages/dashboard) — web UI for library management, MCP config generation, and agent-activity inspection
|
|
61
50
|
- The `getbased-stack` discovery CLI
|
|
62
51
|
- `[full]` extra: PDF/DOCX parsers + ONNX runtime for hardware-accelerated embeddings
|
|
@@ -74,7 +63,7 @@ getbased-stack init
|
|
|
74
63
|
Non-interactive (for scripted installs and curl | bash; `install.sh` uses this):
|
|
75
64
|
|
|
76
65
|
```bash
|
|
77
|
-
getbased-stack init --yes
|
|
66
|
+
getbased-stack init --yes --local-only
|
|
78
67
|
```
|
|
79
68
|
|
|
80
69
|
The wizard (~30 seconds):
|
|
@@ -86,10 +75,16 @@ The wizard (~30 seconds):
|
|
|
86
75
|
|
|
87
76
|
On non-systemd hosts (Docker, macOS, WSL1) step 4 writes the unit files but skips activation with a clear message instead of crashing — re-run on a systemd-enabled host or start `lens serve` + `getbased-dashboard serve` manually.
|
|
88
77
|
|
|
89
|
-
|
|
78
|
+
Private setup from the app:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
getbased-stack connect hermes --setup 'gbsetup_v1_...'
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Manual config helper:
|
|
90
85
|
|
|
91
86
|
```bash
|
|
92
|
-
getbased-stack mcp-config claude-desktop # or: claude-code, cursor, cline, hermes
|
|
87
|
+
getbased-stack mcp-config claude-desktop # or: claude-code, cursor, cline, codex, hermes, openclaw
|
|
93
88
|
```
|
|
94
89
|
|
|
95
90
|
The snippet carries only `GETBASED_STACK_MANAGED=1` in its env block. No secrets in client configs — every MCP spawn reads the shared env file and loads the token + rag URL + API key path from there.
|
|
@@ -144,7 +139,7 @@ Claude Code / Hermes / OpenClaw Browser
|
|
|
144
139
|
│ │ │ │
|
|
145
140
|
│ HTTP │ HTTP │ proxies │ spawns stdio for Test
|
|
146
141
|
▼ ▼ ▼ ▼
|
|
147
|
-
|
|
142
|
+
context gateway getbased-rag ◀────────┘ getbased-mcp
|
|
148
143
|
(localhost:8322)
|
|
149
144
|
```
|
|
150
145
|
|
|
@@ -162,6 +157,7 @@ The dashboard is likewise stateless — it proxies rag for Knowledge operations,
|
|
|
162
157
|
| 0.1.x | ≥0.2.0 | ≥0.1.0 | — | v1 (multi-library) |
|
|
163
158
|
| 0.2.x | ≥0.2.2 | ≥0.6.0 | ≥0.5.0 | v1 (+ streaming ingest, per-library models) |
|
|
164
159
|
| 0.4.x | ≥0.2.3 | ≥0.7.1 | ≥0.6.1 | v1 (+ shared env file, `getbased-stack init`, systemd units) |
|
|
160
|
+
| 0.5.x | ≥0.2.8 | ≥0.7.5 | ≥0.6.7 | v1 (+ `getbased-stack connect`, multi-client setup targets; explicit local-only scripted init) |
|
|
165
161
|
|
|
166
162
|
Bump the meta's major when sibling protocols break; bump siblings freely for normal features.
|
|
167
163
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools>=
|
|
2
|
+
requires = ["setuptools>=83.0.0", "wheel"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "getbased-agent-stack"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.8"
|
|
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"
|
|
@@ -12,15 +12,15 @@ requires-python = ">=3.10"
|
|
|
12
12
|
# Pulls every sibling package. Bump this meta when a sibling protocol
|
|
13
13
|
# bump requires coordinated release.
|
|
14
14
|
dependencies = [
|
|
15
|
-
"getbased-mcp>=0.2.
|
|
16
|
-
"getbased-rag>=0.7.
|
|
17
|
-
"getbased-dashboard>=0.6.
|
|
15
|
+
"getbased-mcp>=0.2.8",
|
|
16
|
+
"getbased-rag>=0.7.5",
|
|
17
|
+
"getbased-dashboard>=0.6.7",
|
|
18
18
|
]
|
|
19
19
|
|
|
20
20
|
[project.optional-dependencies]
|
|
21
21
|
# `full` includes PDF/DOCX parsers and ONNX acceleration (pre-exported
|
|
22
22
|
# weights — no PyTorch/transformers/optimum dance).
|
|
23
|
-
full = ["getbased-rag[full]>=0.7.
|
|
23
|
+
full = ["getbased-rag[full]>=0.7.5"]
|
|
24
24
|
# For contributors running the integration test harness.
|
|
25
25
|
test = ["pytest>=8.0", "httpx>=0.27", "pytest-timeout>=2.3"]
|
|
26
26
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""getbased-stack — orchestration CLI.
|
|
2
2
|
|
|
3
3
|
Subcommands:
|
|
4
|
-
init — interactive one-time setup:
|
|
4
|
+
init — interactive one-time setup: API key, systemd units
|
|
5
5
|
install — install/refresh the bundled systemd user units
|
|
6
6
|
uninstall — stop, disable, and remove the systemd units
|
|
7
7
|
status — show env file, units, and linger state
|
|
@@ -93,6 +93,7 @@ def cmd_init(args: argparse.Namespace) -> int:
|
|
|
93
93
|
# for scripted installs (curl | bash) where stdin is unavailable and
|
|
94
94
|
# the EOF-returns-default path still triggers a getpass echo warning.
|
|
95
95
|
non_interactive = getattr(args, "yes", False)
|
|
96
|
+
local_only = getattr(args, "local_only", False)
|
|
96
97
|
|
|
97
98
|
print("getbased-stack init — one-time setup")
|
|
98
99
|
if non_interactive:
|
|
@@ -110,21 +111,43 @@ def cmd_init(args: argparse.Namespace) -> int:
|
|
|
110
111
|
masked = "****" + current_token[-4:] if current_token else "(unset)"
|
|
111
112
|
key_masked = "****" + current_context_key[-4:] if current_context_key else "(unset)"
|
|
112
113
|
print(f"[1/4] Agent Access token + context key (token: {masked}, key: {key_masked})")
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
114
|
+
token = current_token
|
|
115
|
+
context_key = current_context_key
|
|
116
|
+
gateway = existing.get("GETBASED_GATEWAY", "")
|
|
117
|
+
setup_code = (getattr(args, "setup", "") or "").strip()
|
|
118
|
+
if setup_code:
|
|
119
|
+
try:
|
|
120
|
+
setup_values = _decode_setup_payload(setup_code)
|
|
121
|
+
except ValueError as e:
|
|
122
|
+
print(f"Invalid setup: {e}", file=sys.stderr)
|
|
123
|
+
return 2
|
|
124
|
+
token = setup_values["token"]
|
|
125
|
+
context_key = setup_values["context_key"]
|
|
126
|
+
gateway = setup_values["gateway"]
|
|
127
|
+
print(" setup code accepted — Agent Access credentials will be stored.")
|
|
128
|
+
elif token and context_key:
|
|
129
|
+
print(" existing Agent Access credentials found — keeping them.")
|
|
130
|
+
elif local_only:
|
|
131
|
+
print(
|
|
132
|
+
" no complete Agent Access credentials yet — continuing local-only. "
|
|
133
|
+
"Blood-work Agent Access tools stay disabled until you run "
|
|
134
|
+
"`getbased-stack connect hermes --setup gbsetup_v1_…` or rerun "
|
|
135
|
+
"`getbased-stack init --setup gbsetup_v1_…`."
|
|
122
136
|
)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
137
|
+
elif non_interactive:
|
|
138
|
+
print(
|
|
139
|
+
" Agent Access setup code required for non-interactive first-run setup. "
|
|
140
|
+
"Pass `--setup gbsetup_v1_…`, or add `--local-only` to install only "
|
|
141
|
+
"rag/dashboard without Agent Access."
|
|
142
|
+
)
|
|
143
|
+
return 2
|
|
144
|
+
else:
|
|
145
|
+
print(
|
|
146
|
+
" Agent Access setup code required for full first-run setup. Rerun "
|
|
147
|
+
"with `getbased-stack init --setup gbsetup_v1_…`, or pass "
|
|
148
|
+
"`--local-only` if you only want rag/dashboard without Agent Access."
|
|
127
149
|
)
|
|
150
|
+
return 2
|
|
128
151
|
|
|
129
152
|
# 2. API key
|
|
130
153
|
key_path = Path(existing.get("LENS_API_KEY_FILE", str(_default_api_key_file())))
|
|
@@ -144,6 +167,8 @@ def cmd_init(args: argparse.Namespace) -> int:
|
|
|
144
167
|
merged["GETBASED_TOKEN"] = token
|
|
145
168
|
if context_key:
|
|
146
169
|
merged["GETBASED_AGENT_CONTEXT_KEY"] = context_key
|
|
170
|
+
if gateway:
|
|
171
|
+
merged["GETBASED_GATEWAY"] = gateway
|
|
147
172
|
merged["LENS_API_KEY_FILE"] = str(key_path)
|
|
148
173
|
merged.setdefault("LENS_URL", "http://127.0.0.1:8322")
|
|
149
174
|
path = env_file.write_env_file(merged)
|
|
@@ -166,17 +191,20 @@ def cmd_init(args: argparse.Namespace) -> int:
|
|
|
166
191
|
_print_linger_hint(strict=False)
|
|
167
192
|
|
|
168
193
|
# 6. MCP config pointers
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
print(
|
|
194
|
+
if token and context_key:
|
|
195
|
+
print("\nAgent Access credentials are configured ✓")
|
|
196
|
+
print(" Generate or refresh client config with:")
|
|
197
|
+
for client in mcp_configs.SUPPORTED_CLIENTS:
|
|
198
|
+
print(f" getbased-stack mcp-config {client}")
|
|
199
|
+
else:
|
|
200
|
+
print("\nNext steps for Agent Access:")
|
|
201
|
+
print(" 1. In getbased, enable Cross-device Sync and Agent Access.")
|
|
202
|
+
print(" 2. Copy the private setup code from Settings → Agent Access.")
|
|
203
|
+
print(" 3. Store it here and register your MCP client with:")
|
|
204
|
+
print(" getbased-stack connect hermes --setup gbsetup_v1_...")
|
|
205
|
+
print(" 4. Or generate a manual client config with:")
|
|
206
|
+
for client in mcp_configs.SUPPORTED_CLIENTS:
|
|
207
|
+
print(f" getbased-stack mcp-config {client}")
|
|
180
208
|
|
|
181
209
|
return 0
|
|
182
210
|
|
|
@@ -483,7 +511,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
483
511
|
sub = p.add_subparsers(dest="command")
|
|
484
512
|
|
|
485
513
|
pinit = sub.add_parser(
|
|
486
|
-
"init", help="Interactive one-time setup (
|
|
514
|
+
"init", help="Interactive one-time setup (API key, units)."
|
|
487
515
|
)
|
|
488
516
|
pinit.add_argument(
|
|
489
517
|
"-y",
|
|
@@ -491,6 +519,16 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
491
519
|
action="store_true",
|
|
492
520
|
help="Non-interactive: take defaults on every prompt. Use for scripted installs.",
|
|
493
521
|
)
|
|
522
|
+
pinit.add_argument(
|
|
523
|
+
"--setup",
|
|
524
|
+
default="",
|
|
525
|
+
help="Private gbsetup_v1_... setup code from getbased Settings → Agent Access.",
|
|
526
|
+
)
|
|
527
|
+
pinit.add_argument(
|
|
528
|
+
"--local-only",
|
|
529
|
+
action="store_true",
|
|
530
|
+
help="Install rag/dashboard without Agent Access credentials; run connect later.",
|
|
531
|
+
)
|
|
494
532
|
|
|
495
533
|
pi = sub.add_parser("install", help="Install + start the systemd user units.")
|
|
496
534
|
pi.add_argument("--no-enable", action="store_true", help="Copy files only; don't enable.")
|
{getbased_agent_stack-0.5.6 → getbased_agent_stack-0.5.8}/src/getbased_agent_stack/mcp_configs.py
RENAMED
|
@@ -215,22 +215,19 @@ def emit_hermes(resolver: Callable[[str], "str | None"] = shutil.which) -> str:
|
|
|
215
215
|
|
|
216
216
|
def emit(client: str, resolver: Callable[[str], "str | None"] = shutil.which) -> str:
|
|
217
217
|
"""Dispatch to the right emitter. Raises ValueError on unknown client."""
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
raise ValueError(
|
|
235
|
-
f"unknown client {client!r}. Supported: {', '.join(SUPPORTED_CLIENTS)}"
|
|
236
|
-
)
|
|
218
|
+
emitters = {
|
|
219
|
+
"claude-desktop": emit_claude_desktop,
|
|
220
|
+
"claude-code": emit_claude_code,
|
|
221
|
+
"cursor": emit_cursor,
|
|
222
|
+
"cline": emit_cline,
|
|
223
|
+
"hermes": emit_hermes,
|
|
224
|
+
"openclaw": emit_openclaw,
|
|
225
|
+
"codex": emit_codex,
|
|
226
|
+
}
|
|
227
|
+
try:
|
|
228
|
+
emitter = emitters[client]
|
|
229
|
+
except KeyError as e:
|
|
230
|
+
raise ValueError(
|
|
231
|
+
f"unknown client {client!r}. Supported: {', '.join(SUPPORTED_CLIENTS)}"
|
|
232
|
+
) from e
|
|
233
|
+
return emitter(resolver)
|
|
@@ -13,7 +13,7 @@ import subprocess
|
|
|
13
13
|
from dataclasses import dataclass
|
|
14
14
|
from importlib import resources
|
|
15
15
|
from pathlib import Path
|
|
16
|
-
from typing import Callable
|
|
16
|
+
from typing import Callable
|
|
17
17
|
|
|
18
18
|
# Units this package ships. Order matters for start: rag first (dashboard
|
|
19
19
|
# Wants=+After= rag), so systemctl picks the right order naturally anyway.
|
|
@@ -1,6 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: getbased-agent-stack
|
|
3
|
+
Version: 0.5.8
|
|
4
|
+
Summary: One-command install of the full getbased agent stack — getbased-mcp + getbased-rag + getbased-dashboard
|
|
5
|
+
License-Expression: AGPL-3.0-or-later
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: getbased-mcp>=0.2.8
|
|
10
|
+
Requires-Dist: getbased-rag>=0.7.5
|
|
11
|
+
Requires-Dist: getbased-dashboard>=0.6.7
|
|
12
|
+
Provides-Extra: full
|
|
13
|
+
Requires-Dist: getbased-rag[full]>=0.7.5; extra == "full"
|
|
14
|
+
Provides-Extra: test
|
|
15
|
+
Requires-Dist: pytest>=8.0; extra == "test"
|
|
16
|
+
Requires-Dist: httpx>=0.27; extra == "test"
|
|
17
|
+
Requires-Dist: pytest-timeout>=2.3; extra == "test"
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
1
20
|
# getbased-agent-stack
|
|
2
21
|
|
|
3
|
-
Meta-package bundling the full [getbased](https://getbased.health) agent stack into one install: the MCP adapter, the
|
|
22
|
+
Meta-package bundling the full [getbased](https://getbased.health) agent stack into one install: the MCP adapter, the local knowledge server, the browser dashboard, an orchestration CLI (`init` / `install` / `connect` / `mcp-config`), systemd user units for the knowledge server + dashboard, and paste-ready configs for Claude Code, Claude Desktop, Cursor, Cline, Codex CLI, Hermes, and OpenClaw.
|
|
4
23
|
|
|
5
24
|
Part of the [getbased-agents monorepo](https://github.com/elkimek/getbased-agents).
|
|
6
25
|
|
|
@@ -12,7 +31,15 @@ Linux, one command:
|
|
|
12
31
|
curl -sSL https://getbased.health/install.sh | bash
|
|
13
32
|
```
|
|
14
33
|
|
|
15
|
-
Runs end-to-end: installs `getbased-agent-stack[full]` via whichever of `uv` or `pipx` is available, exposes sibling binaries, runs
|
|
34
|
+
Runs end-to-end: installs `getbased-agent-stack[full]` via whichever of `uv` or `pipx` is available, exposes sibling binaries, runs a non-interactive local-only init, and starts the knowledge server + dashboard as systemd user services. [Read the script first](https://github.com/elkimek/get-based-site/blob/main/install.sh) if you're cautious.
|
|
35
|
+
|
|
36
|
+
If you are connecting a private getbased profile, copy the command from **Settings → Agent Access** in the app. It uses the same installer and then runs `getbased-stack connect` for the selected client:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
curl -fsSL https://getbased.health/install.sh | bash -s -- connect <target> --setup 'gbsetup_v1_...'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That setup payload contains private credentials. Keep it out of logs and public issues.
|
|
16
43
|
|
|
17
44
|
Manual — pipx:
|
|
18
45
|
|
|
@@ -37,7 +64,7 @@ uv tool install \
|
|
|
37
64
|
Pulls:
|
|
38
65
|
|
|
39
66
|
- [`getbased-mcp`](https://github.com/elkimek/getbased-agents/tree/main/packages/mcp) — stdio MCP server that Claude Code / Hermes / OpenClaw spawn
|
|
40
|
-
- [`getbased-rag`](https://github.com/elkimek/getbased-agents/tree/main/packages/rag) — local
|
|
67
|
+
- [`getbased-rag`](https://github.com/elkimek/getbased-agents/tree/main/packages/rag) — local knowledge server (FastAPI + Qdrant + MiniLM/BGE)
|
|
41
68
|
- [`getbased-dashboard`](https://github.com/elkimek/getbased-agents/tree/main/packages/dashboard) — web UI for library management, MCP config generation, and agent-activity inspection
|
|
42
69
|
- The `getbased-stack` discovery CLI
|
|
43
70
|
- `[full]` extra: PDF/DOCX parsers + ONNX runtime for hardware-accelerated embeddings
|
|
@@ -55,7 +82,7 @@ getbased-stack init
|
|
|
55
82
|
Non-interactive (for scripted installs and curl | bash; `install.sh` uses this):
|
|
56
83
|
|
|
57
84
|
```bash
|
|
58
|
-
getbased-stack init --yes
|
|
85
|
+
getbased-stack init --yes --local-only
|
|
59
86
|
```
|
|
60
87
|
|
|
61
88
|
The wizard (~30 seconds):
|
|
@@ -67,10 +94,16 @@ The wizard (~30 seconds):
|
|
|
67
94
|
|
|
68
95
|
On non-systemd hosts (Docker, macOS, WSL1) step 4 writes the unit files but skips activation with a clear message instead of crashing — re-run on a systemd-enabled host or start `lens serve` + `getbased-dashboard serve` manually.
|
|
69
96
|
|
|
70
|
-
|
|
97
|
+
Private setup from the app:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
getbased-stack connect hermes --setup 'gbsetup_v1_...'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Manual config helper:
|
|
71
104
|
|
|
72
105
|
```bash
|
|
73
|
-
getbased-stack mcp-config claude-desktop # or: claude-code, cursor, cline, hermes
|
|
106
|
+
getbased-stack mcp-config claude-desktop # or: claude-code, cursor, cline, codex, hermes, openclaw
|
|
74
107
|
```
|
|
75
108
|
|
|
76
109
|
The snippet carries only `GETBASED_STACK_MANAGED=1` in its env block. No secrets in client configs — every MCP spawn reads the shared env file and loads the token + rag URL + API key path from there.
|
|
@@ -125,7 +158,7 @@ Claude Code / Hermes / OpenClaw Browser
|
|
|
125
158
|
│ │ │ │
|
|
126
159
|
│ HTTP │ HTTP │ proxies │ spawns stdio for Test
|
|
127
160
|
▼ ▼ ▼ ▼
|
|
128
|
-
|
|
161
|
+
context gateway getbased-rag ◀────────┘ getbased-mcp
|
|
129
162
|
(localhost:8322)
|
|
130
163
|
```
|
|
131
164
|
|
|
@@ -143,6 +176,7 @@ The dashboard is likewise stateless — it proxies rag for Knowledge operations,
|
|
|
143
176
|
| 0.1.x | ≥0.2.0 | ≥0.1.0 | — | v1 (multi-library) |
|
|
144
177
|
| 0.2.x | ≥0.2.2 | ≥0.6.0 | ≥0.5.0 | v1 (+ streaming ingest, per-library models) |
|
|
145
178
|
| 0.4.x | ≥0.2.3 | ≥0.7.1 | ≥0.6.1 | v1 (+ shared env file, `getbased-stack init`, systemd units) |
|
|
179
|
+
| 0.5.x | ≥0.2.8 | ≥0.7.5 | ≥0.6.7 | v1 (+ `getbased-stack connect`, multi-client setup targets; explicit local-only scripted init) |
|
|
146
180
|
|
|
147
181
|
Bump the meta's major when sibling protocols break; bump siblings freely for normal features.
|
|
148
182
|
|
|
@@ -14,7 +14,7 @@ from pathlib import Path
|
|
|
14
14
|
import pytest
|
|
15
15
|
|
|
16
16
|
from getbased_agent_stack import cli, env_file, units
|
|
17
|
-
from getbased_agent_stack.units import CommandResult
|
|
17
|
+
from getbased_agent_stack.units import CommandResult
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
@pytest.fixture
|
|
@@ -351,6 +351,14 @@ def test_connect_skips_gateway_restart_when_running_inside_hermes(stack_home, mo
|
|
|
351
351
|
# ── init (non-interactive via EOF on stdin) ───────────────────────────
|
|
352
352
|
|
|
353
353
|
|
|
354
|
+
def test_init_requires_setup_or_local_only_on_clean_interactive_run(stack_home, fake_shell):
|
|
355
|
+
rc, out, _ = _run(["init"])
|
|
356
|
+
assert rc == 2
|
|
357
|
+
assert "--setup" in out
|
|
358
|
+
assert "--local-only" in out
|
|
359
|
+
assert env_file.read_env_file() == {}
|
|
360
|
+
|
|
361
|
+
|
|
354
362
|
def test_init_idempotent_with_empty_input(stack_home, fake_shell, monkeypatch):
|
|
355
363
|
"""Feed EOF for every prompt: init should complete using defaults
|
|
356
364
|
without crashing. This validates the wizard is non-blocking when
|
|
@@ -359,7 +367,7 @@ def test_init_idempotent_with_empty_input(stack_home, fake_shell, monkeypatch):
|
|
|
359
367
|
monkeypatch.setattr("builtins.input", lambda *a, **kw: "")
|
|
360
368
|
monkeypatch.setattr("getpass.getpass", lambda *a, **kw: "")
|
|
361
369
|
|
|
362
|
-
rc, out, _ = _run(["init"])
|
|
370
|
+
rc, out, _ = _run(["init", "--local-only"])
|
|
363
371
|
assert rc == 0
|
|
364
372
|
# Env file created
|
|
365
373
|
path = env_file.env_file_path()
|
|
@@ -373,32 +381,46 @@ def test_init_idempotent_with_empty_input(stack_home, fake_shell, monkeypatch):
|
|
|
373
381
|
|
|
374
382
|
|
|
375
383
|
def test_init_preserves_existing_token(stack_home, fake_shell, monkeypatch):
|
|
376
|
-
"""Re-running init
|
|
377
|
-
value. The wizard uses the previous token as default."""
|
|
384
|
+
"""Re-running init must not wipe an explicitly stored token."""
|
|
378
385
|
env_file.write_env_file(
|
|
379
386
|
{"GETBASED_TOKEN": "preserved_value", "GETBASED_STACK_MANAGED": "1"}
|
|
380
387
|
)
|
|
381
388
|
monkeypatch.setattr("builtins.input", lambda *a, **kw: "")
|
|
382
389
|
monkeypatch.setattr("getpass.getpass", lambda *a, **kw: "")
|
|
383
390
|
|
|
384
|
-
_run(["init"])
|
|
391
|
+
_run(["init", "--local-only"])
|
|
385
392
|
assert env_file.read_env_file()["GETBASED_TOKEN"] == "preserved_value"
|
|
386
393
|
|
|
387
394
|
|
|
388
|
-
def
|
|
395
|
+
def test_init_accepts_setup_blob(stack_home, fake_shell, monkeypatch):
|
|
396
|
+
"""First-run init can store the private Agent Access setup code without
|
|
397
|
+
prompting for raw token/context-key values separately."""
|
|
389
398
|
inputs = iter([""]) # accept install prompt with default
|
|
390
399
|
monkeypatch.setattr("builtins.input", lambda *a, **kw: next(inputs, ""))
|
|
391
|
-
monkeypatch.setattr(
|
|
400
|
+
monkeypatch.setattr(
|
|
401
|
+
"getpass.getpass",
|
|
402
|
+
lambda *a, **kw: (_ for _ in ()).throw(AssertionError("getpass called")),
|
|
403
|
+
)
|
|
392
404
|
|
|
393
|
-
_run([
|
|
394
|
-
|
|
405
|
+
rc, out, err = _run([
|
|
406
|
+
"init",
|
|
407
|
+
"--setup",
|
|
408
|
+
_setup_blob(token="brand_new_token", context_key="ctx_new", gateway="https://sync.example"),
|
|
409
|
+
])
|
|
410
|
+
assert rc == 0, err
|
|
411
|
+
data = env_file.read_env_file()
|
|
412
|
+
assert data["GETBASED_TOKEN"] == "brand_new_token"
|
|
413
|
+
assert data["GETBASED_AGENT_CONTEXT_KEY"] == "ctx_new"
|
|
414
|
+
assert data["GETBASED_GATEWAY"] == "https://sync.example"
|
|
415
|
+
assert "brand_new_token" not in out
|
|
416
|
+
assert "ctx_new" not in out
|
|
395
417
|
|
|
396
418
|
|
|
397
419
|
def test_init_generates_api_key(stack_home, fake_shell, monkeypatch):
|
|
398
420
|
monkeypatch.setattr("builtins.input", lambda *a, **kw: "")
|
|
399
421
|
monkeypatch.setattr("getpass.getpass", lambda *a, **kw: "")
|
|
400
422
|
|
|
401
|
-
_run(["init"])
|
|
423
|
+
_run(["init", "--local-only"])
|
|
402
424
|
key_file = Path(env_file.read_env_file()["LENS_API_KEY_FILE"])
|
|
403
425
|
assert key_file.exists()
|
|
404
426
|
key = key_file.read_text().strip()
|
|
@@ -419,15 +441,14 @@ def test_init_reuses_existing_api_key(stack_home, fake_shell, monkeypatch):
|
|
|
419
441
|
monkeypatch.setattr("builtins.input", lambda *a, **kw: "")
|
|
420
442
|
monkeypatch.setattr("getpass.getpass", lambda *a, **kw: "")
|
|
421
443
|
|
|
422
|
-
_run(["init"])
|
|
444
|
+
_run(["init", "--local-only"])
|
|
423
445
|
assert key_path.read_text().strip() == "preexisting_key"
|
|
424
446
|
|
|
425
447
|
|
|
426
|
-
def
|
|
448
|
+
def test_init_yes_requires_setup_or_local_only_without_prompts(stack_home, fake_shell, monkeypatch):
|
|
427
449
|
"""`init --yes` must not call input() or getpass() at all. Scripted
|
|
428
|
-
installers (curl | bash)
|
|
429
|
-
|
|
430
|
-
Strict assertion: any prompt call fails the test."""
|
|
450
|
+
installers (curl | bash) cannot service prompts, so a clean full setup
|
|
451
|
+
needs --setup; local-only installs must say so explicitly."""
|
|
431
452
|
def _forbid_input(*a, **kw):
|
|
432
453
|
raise AssertionError("input() called under --yes")
|
|
433
454
|
|
|
@@ -438,24 +459,25 @@ def test_init_yes_flag_skips_all_prompts(stack_home, fake_shell, monkeypatch):
|
|
|
438
459
|
monkeypatch.setattr("getpass.getpass", _forbid_getpass)
|
|
439
460
|
|
|
440
461
|
rc, out, _ = _run(["init", "--yes"])
|
|
441
|
-
assert rc ==
|
|
462
|
+
assert rc == 2
|
|
442
463
|
# Banner reflects the mode so the user sees what happened
|
|
443
464
|
assert "non-interactive" in out.lower()
|
|
444
|
-
assert "
|
|
445
|
-
assert "
|
|
446
|
-
#
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
465
|
+
assert "--setup" in out
|
|
466
|
+
assert "--local-only" in out
|
|
467
|
+
# A successful-looking first-run install without credentials would leave
|
|
468
|
+
# Agent Access broken, so --yes must stop before writing env/units unless
|
|
469
|
+
# the caller explicitly opts into --local-only.
|
|
470
|
+
assert not env_file.env_file_path().exists()
|
|
471
|
+
assert not (stack_home / "config" / "systemd" / "user" / "getbased-rag.service").exists()
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def test_init_yes_local_only_installs_units_without_asking(stack_home, fake_shell, monkeypatch):
|
|
475
|
+
"""When the caller explicitly chooses local-only, --yes must install
|
|
476
|
+
+ start without prompting."""
|
|
455
477
|
monkeypatch.setattr("builtins.input", lambda *a, **kw: "")
|
|
456
478
|
monkeypatch.setattr("getpass.getpass", lambda *a, **kw: "")
|
|
457
479
|
|
|
458
|
-
_run(["init", "--yes"])
|
|
480
|
+
_run(["init", "--yes", "--local-only"])
|
|
459
481
|
# UnitManager.install() writes service files under XDG_CONFIG_HOME
|
|
460
482
|
assert (stack_home / "config" / "systemd" / "user" / "getbased-rag.service").exists()
|
|
461
483
|
assert (stack_home / "config" / "systemd" / "user" / "getbased-dashboard.service").exists()
|
|
@@ -471,7 +493,7 @@ def test_init_yes_survives_missing_systemctl(stack_home, fake_shell, monkeypatch
|
|
|
471
493
|
monkeypatch.setattr("builtins.input", lambda *a, **kw: "")
|
|
472
494
|
monkeypatch.setattr("getpass.getpass", lambda *a, **kw: "")
|
|
473
495
|
|
|
474
|
-
rc, out, _ = _run(["init", "--yes"])
|
|
496
|
+
rc, out, _ = _run(["init", "--yes", "--local-only"])
|
|
475
497
|
assert rc == 0
|
|
476
498
|
# Unit files still written (for re-run on a systemd-enabled host)
|
|
477
499
|
assert (stack_home / "config" / "systemd" / "user" / "getbased-rag.service").exists()
|
|
@@ -484,7 +506,11 @@ def test_init_yes_preserves_existing_token(stack_home, fake_shell, monkeypatch):
|
|
|
484
506
|
"""Non-interactive mode must not nuke a previously-saved token —
|
|
485
507
|
it takes the 'keep current' default, same as pressing Enter."""
|
|
486
508
|
env_file.write_env_file(
|
|
487
|
-
{
|
|
509
|
+
{
|
|
510
|
+
"GETBASED_TOKEN": "keep_me",
|
|
511
|
+
"GETBASED_AGENT_CONTEXT_KEY": "ctx_keep",
|
|
512
|
+
"GETBASED_STACK_MANAGED": "1",
|
|
513
|
+
}
|
|
488
514
|
)
|
|
489
515
|
# No input/getpass expected, but stub defensively in case a future
|
|
490
516
|
# code path adds an unguarded prompt — test still catches it.
|
|
@@ -501,10 +527,10 @@ def test_init_is_reentrant(stack_home, fake_shell, monkeypatch):
|
|
|
501
527
|
monkeypatch.setattr("builtins.input", lambda *a, **kw: "")
|
|
502
528
|
monkeypatch.setattr("getpass.getpass", lambda *a, **kw: "")
|
|
503
529
|
|
|
504
|
-
_run(["init"])
|
|
530
|
+
_run(["init", "--local-only"])
|
|
505
531
|
key1 = (stack_home / "data" / "getbased" / "lens" / "api_key").read_text()
|
|
506
532
|
|
|
507
|
-
_run(["init"])
|
|
533
|
+
_run(["init", "--local-only"])
|
|
508
534
|
key2 = (stack_home / "data" / "getbased" / "lens" / "api_key").read_text()
|
|
509
535
|
|
|
510
536
|
assert key1 == key2, "init must not rotate an existing API key"
|
|
@@ -6,11 +6,6 @@ is contacted — these tests run on a dev laptop, CI, Windows, anywhere.
|
|
|
6
6
|
"""
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
from typing import Callable
|
|
11
|
-
|
|
12
|
-
import pytest
|
|
13
|
-
|
|
14
9
|
from getbased_agent_stack import units
|
|
15
10
|
from getbased_agent_stack.units import CommandResult, SERVICE_NAMES, UnitManager
|
|
16
11
|
|
|
@@ -230,7 +225,7 @@ def test_uninstall_sequence(tmp_path):
|
|
|
230
225
|
def test_uninstall_noop_when_nothing_installed(tmp_path):
|
|
231
226
|
shell = FakeShell()
|
|
232
227
|
mgr = UnitManager(unit_dir=tmp_path, shell=shell)
|
|
233
|
-
|
|
228
|
+
mgr.uninstall()
|
|
234
229
|
# Disable is still attempted (safe) but no daemon-reload because no files removed
|
|
235
230
|
reloads = [c for c in shell.calls if c == ["systemctl", "--user", "daemon-reload"]]
|
|
236
231
|
assert reloads == []
|
|
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
|