agent-brain-cli 10.2.0__tar.gz → 10.2.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 (42) hide show
  1. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/PKG-INFO +3 -3
  2. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/__init__.py +1 -1
  3. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/client/api_client.py +16 -2
  4. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/client/transport.py +10 -4
  5. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/init.py +31 -2
  6. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/start.py +6 -0
  7. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/config.py +52 -0
  8. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/pyproject.toml +3 -3
  9. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/README.md +0 -0
  10. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/cli.py +0 -0
  11. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/client/__init__.py +0 -0
  12. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/__init__.py +0 -0
  13. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/cache.py +0 -0
  14. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/config.py +0 -0
  15. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/doctor.py +0 -0
  16. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/folders.py +0 -0
  17. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/index.py +0 -0
  18. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/inject.py +0 -0
  19. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/install_agent.py +0 -0
  20. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/jobs.py +0 -0
  21. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/list_cmd.py +0 -0
  22. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/query.py +0 -0
  23. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/reset.py +0 -0
  24. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/status.py +0 -0
  25. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/stop.py +0 -0
  26. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/types.py +0 -0
  27. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/commands/uninstall.py +0 -0
  28. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/config_migrate.py +0 -0
  29. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/config_schema.py +0 -0
  30. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/diagnostics.py +0 -0
  31. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/migration.py +0 -0
  32. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/__init__.py +0 -0
  33. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/claude_converter.py +0 -0
  34. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/codex_converter.py +0 -0
  35. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/converter_base.py +0 -0
  36. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/gemini_converter.py +0 -0
  37. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/opencode_converter.py +0 -0
  38. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/parser.py +0 -0
  39. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/skill_runtime_converter.py +0 -0
  40. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/tool_maps.py +0 -0
  41. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/runtime/types.py +0 -0
  42. {agent_brain_cli-10.2.0 → agent_brain_cli-10.2.1}/agent_brain_cli/xdg_paths.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: agent-brain-cli
3
- Version: 10.2.0
3
+ Version: 10.2.1
4
4
  Summary: Agent Brain CLI - Command-line interface for managing AI agent memory and knowledge retrieval
5
5
  Home-page: https://github.com/SpillwaveSolutions/agent-brain
6
6
  License: MIT
@@ -15,8 +15,8 @@ Classifier: Programming Language :: Python :: 3
15
15
  Classifier: Programming Language :: Python :: 3.10
16
16
  Classifier: Programming Language :: Python :: 3.11
17
17
  Classifier: Programming Language :: Python :: 3.12
18
- Requires-Dist: agent-brain-rag (>=10.2.0,<11.0.0)
19
- Requires-Dist: agent-brain-uds (>=10.2.0,<11.0.0)
18
+ Requires-Dist: agent-brain-rag (>=10.2.1,<11.0.0)
19
+ Requires-Dist: agent-brain-uds (>=10.2.1,<11.0.0)
20
20
  Requires-Dist: click (>=8.1.0,<9.0.0)
21
21
  Requires-Dist: httpx (>=0.28.0,<0.29.0)
22
22
  Requires-Dist: pydantic (>=2.10.0,<3.0.0)
@@ -1,3 +1,3 @@
1
1
  """Doc-Serve CLI - Command-line interface for managing Doc-Serve server."""
2
2
 
3
- __version__ = "10.2.0"
3
+ __version__ = "10.2.1"
@@ -159,6 +159,7 @@ class DocServeClient:
159
159
  self,
160
160
  base_url: str = "http://127.0.0.1:8000",
161
161
  timeout: float = 30.0,
162
+ api_key: str | None = None,
162
163
  ):
163
164
  """
164
165
  Initialize the client.
@@ -166,13 +167,21 @@ class DocServeClient:
166
167
  Args:
167
168
  base_url: Server base URL.
168
169
  timeout: Request timeout in seconds.
170
+ api_key: Optional X-API-Key value (Issue #179). When supplied,
171
+ every outbound request carries the header. ``None`` means
172
+ no auth (legacy single-user loopback dev path).
169
173
  """
170
174
  self.base_url = base_url.rstrip("/")
171
175
  self.timeout = timeout
172
- self._client = httpx.Client(timeout=timeout)
176
+ headers = {"X-API-Key": api_key} if api_key else None
177
+ self._client = httpx.Client(timeout=timeout, headers=headers)
173
178
 
174
179
  @classmethod
175
- def from_httpx(cls, client: httpx.Client) -> "DocServeClient":
180
+ def from_httpx(
181
+ cls,
182
+ client: httpx.Client,
183
+ api_key: str | None = None,
184
+ ) -> "DocServeClient":
176
185
  """Build a DocServeClient that uses a pre-constructed httpx.Client.
177
186
 
178
187
  Used by the transport selector to inject a UDS-backed client
@@ -183,6 +192,9 @@ class DocServeClient:
183
192
  Args:
184
193
  client: An already-configured ``httpx.Client``. The wrapper
185
194
  takes ownership and will close it on ``__exit__``.
195
+ api_key: Optional X-API-Key to merge into the client's
196
+ default headers (Issue #179). Caller may also have set
197
+ the header on ``client`` directly; both paths work.
186
198
 
187
199
  Returns:
188
200
  A DocServeClient backed by ``client``.
@@ -191,6 +203,8 @@ class DocServeClient:
191
203
  instance.base_url = "" # inner client carries the real base_url
192
204
  timeout = client.timeout
193
205
  instance.timeout = timeout.read or 30.0
206
+ if api_key:
207
+ client.headers["X-API-Key"] = api_key
194
208
  instance._client = client
195
209
  return instance
196
210
 
@@ -17,7 +17,7 @@ from pathlib import Path
17
17
 
18
18
  import click
19
19
 
20
- from ..config import resolve_transport
20
+ from ..config import resolve_api_key, resolve_transport
21
21
  from .api_client import DocServeClient
22
22
 
23
23
 
@@ -41,14 +41,20 @@ def open_client(ctx: click.Context, *, timeout: float = 30.0) -> DocServeClient:
41
41
  base_url_override=obj.get("base_url_override"),
42
42
  socket_path_override=obj.get("socket_path_override"),
43
43
  )
44
+ # Issue #179: resolve the API key alongside the transport so the same
45
+ # CLI invocation works against an authed and an unauthed server.
46
+ api_key = resolve_api_key()
44
47
  if obj.get("debug_transport"):
45
- click.echo(f"[debug-transport] {transport} -> {target}", err=True)
48
+ auth_marker = "with X-API-Key" if api_key else "no auth"
49
+ click.echo(
50
+ f"[debug-transport] {transport} -> {target} ({auth_marker})", err=True
51
+ )
46
52
 
47
53
  if transport == "http":
48
- return DocServeClient(base_url=target, timeout=timeout)
54
+ return DocServeClient(base_url=target, timeout=timeout, api_key=api_key)
49
55
 
50
56
  # UDS: import lazily so HTTP-only invocations don't pay the cost.
51
57
  from agent_brain_uds import make_client
52
58
 
53
59
  inner = make_client(socket_path=Path(target), timeout=timeout)
54
- return DocServeClient.from_httpx(inner)
60
+ return DocServeClient.from_httpx(inner, api_key=api_key)
@@ -1,6 +1,7 @@
1
1
  """Init command for initializing an Agent Brain project."""
2
2
 
3
3
  import json
4
+ import secrets
4
5
  from pathlib import Path
5
6
 
6
7
  import click
@@ -69,6 +70,14 @@ STATE_DIR_NAME = ".agent-brain"
69
70
  type=click.Path(file_okay=False, resolve_path=True),
70
71
  help="Custom state directory for index data (default: .agent-brain)",
71
72
  )
73
+ @click.option(
74
+ "--no-api-key",
75
+ is_flag=True,
76
+ help=(
77
+ "Skip auto-generating an API key (Issue #179). Use for single-user "
78
+ "loopback dev when no auth is desired. Server still starts without auth."
79
+ ),
80
+ )
72
81
  def init_command(
73
82
  path: str | None,
74
83
  host: str,
@@ -76,6 +85,7 @@ def init_command(
76
85
  force: bool,
77
86
  json_output: bool,
78
87
  state_dir: str | None,
88
+ no_api_key: bool,
79
89
  ) -> None:
80
90
  """Initialize a new Agent Brain project.
81
91
 
@@ -145,8 +155,21 @@ def init_command(
145
155
  config["port"] = port
146
156
  config["auto_port"] = False
147
157
 
148
- # Write configuration
158
+ # Issue #179: auto-generate an API key so the server boots with auth
159
+ # by default. Stored in config.json (project-local); the `start`
160
+ # command exports it as AGENT_BRAIN_API_KEY for the server
161
+ # subprocess, and `resolve_api_key` reads it for the CLI side. Opt
162
+ # out with --no-api-key for single-user loopback workflows.
163
+ if not no_api_key:
164
+ config["api_key"] = secrets.token_urlsafe(32)
165
+
166
+ # Write configuration with mode 0o600 since it may carry a secret.
149
167
  config_path.write_text(json.dumps(config, indent=2))
168
+ try:
169
+ config_path.chmod(0o600)
170
+ except OSError:
171
+ # Best-effort; filesystems without POSIX modes (FAT) still work.
172
+ pass
150
173
 
151
174
  if json_output:
152
175
  click.echo(
@@ -162,12 +185,18 @@ def init_command(
162
185
  )
163
186
  )
164
187
  else:
188
+ api_key_note = (
189
+ f"[bold]API Key:[/] generated ({config_path.name}, mode 0o600)"
190
+ if not no_api_key
191
+ else "[bold]API Key:[/] [yellow]disabled[/] (--no-api-key)"
192
+ )
165
193
  console.print(
166
194
  Panel(
167
195
  f"[green]Project initialized successfully![/]\n\n"
168
196
  f"[bold]Project Root:[/] {project_root}\n"
169
197
  f"[bold]State Directory:[/] {resolved_state_dir}\n"
170
- f"[bold]Configuration:[/] {config_path}",
198
+ f"[bold]Configuration:[/] {config_path}\n"
199
+ f"{api_key_note}",
171
200
  title="Agent Brain Initialized",
172
201
  border_style="green",
173
202
  )
@@ -368,6 +368,12 @@ def start_command(
368
368
  env = os.environ.copy()
369
369
  env["AGENT_BRAIN_PROJECT_ROOT"] = str(project_root)
370
370
  env["AGENT_BRAIN_STATE_DIR"] = str(state_dir)
371
+ # Issue #179: propagate the project-local API key from config.json
372
+ # into the server subprocess. Existing env value wins so operators
373
+ # can override the file-stored key without re-running init.
374
+ config_api_key = config.get("api_key")
375
+ if config_api_key and not env.get("AGENT_BRAIN_API_KEY"):
376
+ env["AGENT_BRAIN_API_KEY"] = str(config_api_key)
371
377
  if strict:
372
378
  env["AGENT_BRAIN_STRICT_MODE"] = "true"
373
379
  if enable_uds:
@@ -414,6 +414,58 @@ def get_server_url(config: AgentBrainConfig | None = None) -> str:
414
414
  return config.server.url
415
415
 
416
416
 
417
+ def resolve_api_key(state_dir: Path | None = None) -> str | None:
418
+ """Resolve the X-API-Key value the CLI should send (Issue #179).
419
+
420
+ Precedence (first non-empty wins):
421
+ 1. ``AGENT_BRAIN_API_KEY`` environment variable
422
+ 2. ``runtime.json::api_key`` for the resolved state directory
423
+ (set by the running server)
424
+ 3. ``config.json::api_key`` for the resolved state directory
425
+ (set by ``agent-brain init``, used when the server hasn't
426
+ started yet)
427
+
428
+ Returns ``None`` when no source provides a value, which is the
429
+ correct behavior for a server running in default no-auth loopback
430
+ mode — the client sends no header and the server's no-op dependency
431
+ accepts the request.
432
+
433
+ Args:
434
+ state_dir: Optional state directory to read from. Defaults to
435
+ ``get_state_dir()`` so callers in CLI commands don't need
436
+ to thread the path through.
437
+
438
+ Returns:
439
+ The resolved API key or ``None``.
440
+ """
441
+ import json
442
+
443
+ env_key = os.getenv("AGENT_BRAIN_API_KEY")
444
+ if env_key:
445
+ return env_key
446
+
447
+ if state_dir is None:
448
+ try:
449
+ state_dir = get_state_dir()
450
+ except Exception:
451
+ return None
452
+
453
+ for filename in ("runtime.json", "config.json"):
454
+ candidate = state_dir / filename
455
+ if not candidate.exists():
456
+ continue
457
+ try:
458
+ with open(candidate) as f:
459
+ payload = json.load(f)
460
+ except (json.JSONDecodeError, OSError):
461
+ continue
462
+ api_key = payload.get("api_key")
463
+ if api_key:
464
+ return str(api_key)
465
+
466
+ return None
467
+
468
+
417
469
  def resolve_transport(
418
470
  *,
419
471
  transport_hint: str | None = None,
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "agent-brain-cli"
3
- version = "10.2.0"
3
+ version = "10.2.1"
4
4
  description = "Agent Brain CLI - Command-line interface for managing AI agent memory and knowledge retrieval"
5
5
  authors = ["Spillwave Solutions"]
6
6
  readme = "README.md"
@@ -27,8 +27,8 @@ httpx = "^0.28.0"
27
27
  rich = "^13.9.0"
28
28
  pyyaml = "^6.0.0"
29
29
  pydantic = "^2.10.0"
30
- agent-brain-rag = "^10.2.0"
31
- agent-brain-uds = "^10.2.0"
30
+ agent-brain-rag = "^10.2.1"
31
+ agent-brain-uds = "^10.2.1"
32
32
 
33
33
  [tool.poetry.group.dev.dependencies]
34
34
  pytest = "^8.3.0"