agent-brain-cli 10.3.2__tar.gz → 10.4.0__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 (49) hide show
  1. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/PKG-INFO +2 -2
  2. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/__init__.py +1 -1
  3. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/cli.py +4 -0
  4. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/client/transport.py +8 -1
  5. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/__init__.py +2 -0
  6. agent_brain_cli-10.4.0/agent_brain_cli/commands/graph.py +154 -0
  7. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/diagnostics.py +166 -0
  8. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/pyproject.toml +2 -2
  9. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/README.md +0 -0
  10. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/__main__.py +0 -0
  11. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/client/__init__.py +0 -0
  12. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/client/api_client.py +0 -0
  13. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/client/protocol.py +0 -0
  14. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/cache.py +0 -0
  15. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/config.py +0 -0
  16. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/doctor.py +0 -0
  17. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/folders.py +0 -0
  18. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/index.py +0 -0
  19. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/init.py +0 -0
  20. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/inject.py +0 -0
  21. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/install_agent.py +0 -0
  22. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/jobs.py +0 -0
  23. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/list_cmd.py +0 -0
  24. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/mcp.py +0 -0
  25. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/prompt.py +0 -0
  26. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/query.py +0 -0
  27. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/reset.py +0 -0
  28. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/resources.py +0 -0
  29. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/start.py +0 -0
  30. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/status.py +0 -0
  31. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/stop.py +0 -0
  32. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/types.py +0 -0
  33. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/commands/uninstall.py +0 -0
  34. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/config.py +0 -0
  35. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/config_migrate.py +0 -0
  36. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/config_schema.py +0 -0
  37. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/mcp_runtime.py +0 -0
  38. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/migration.py +0 -0
  39. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/__init__.py +0 -0
  40. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/claude_converter.py +0 -0
  41. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/codex_converter.py +0 -0
  42. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/converter_base.py +0 -0
  43. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/gemini_converter.py +0 -0
  44. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/opencode_converter.py +0 -0
  45. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/parser.py +0 -0
  46. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/skill_runtime_converter.py +0 -0
  47. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/tool_maps.py +0 -0
  48. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/agent_brain_cli/runtime/types.py +0 -0
  49. {agent_brain_cli-10.3.2 → agent_brain_cli-10.4.0}/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.3.2
3
+ Version: 10.4.0
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,7 +15,7 @@ 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.3.2,<11.0.0)
18
+ Requires-Dist: agent-brain-rag (>=10.4.0,<11.0.0)
19
19
  Requires-Dist: agent-brain-uds (>=10.3.0,<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)
@@ -1,3 +1,3 @@
1
1
  """Doc-Serve CLI - Command-line interface for managing Doc-Serve server."""
2
2
 
3
- __version__ = "10.3.2"
3
+ __version__ = "10.4.0"
@@ -12,6 +12,7 @@ from .commands import (
12
12
  config_group,
13
13
  doctor_command,
14
14
  folders_group,
15
+ graph_group,
15
16
  index_command,
16
17
  init_command,
17
18
  inject_command,
@@ -164,6 +165,9 @@ cli.add_command(mcp_group, name="mcp")
164
165
  cli.add_command(prompt_command, name="prompt")
165
166
  cli.add_command(resources_group, name="resources")
166
167
 
168
+ # Register graph management commands
169
+ cli.add_command(graph_group, name="graph")
170
+
167
171
  # Register server interaction commands
168
172
  cli.add_command(status_command, name="status")
169
173
  cli.add_command(query_command, name="query")
@@ -186,7 +186,14 @@ def open_backend(ctx: click.Context, *, timeout: float = 30.0) -> BackendClient:
186
186
  # mcp_transport == "http" — resolve_mcp_transport guarantees
187
187
  # mcp_target is not None for the http branch.
188
188
  assert mcp_target is not None # noqa: S101
189
- return cast(BackendClient, McpHttpBackend(url=mcp_target, timeout=timeout))
189
+ # Thread state_dir so FileTokenStorage is keyed correctly when
190
+ # AGENT_BRAIN_MCP_AUTH=oauth is set (Phase 69 Plan 03).
191
+ # The opt-in flows via the AGENT_BRAIN_MCP_AUTH env var — no extra
192
+ # param needed here.
193
+ return cast(
194
+ BackendClient,
195
+ McpHttpBackend(url=mcp_target, timeout=timeout, state_dir=state_dir),
196
+ )
190
197
 
191
198
  # --- HTTP / UDS branch (existing v1/v2 path) -----------------
192
199
  transport, target = resolve_transport(
@@ -4,6 +4,7 @@ from .cache import cache_group
4
4
  from .config import config_group
5
5
  from .doctor import doctor_command
6
6
  from .folders import folders_group
7
+ from .graph import graph_group
7
8
  from .index import index_command
8
9
  from .init import init_command
9
10
  from .inject import inject_command
@@ -26,6 +27,7 @@ __all__ = [
26
27
  "config_group",
27
28
  "doctor_command",
28
29
  "folders_group",
30
+ "graph_group",
29
31
  "index_command",
30
32
  "inject_command",
31
33
  "init_command",
@@ -0,0 +1,154 @@
1
+ """`agent-brain graph` Click sub-group for graph management commands (Phase 64).
2
+
3
+ Subcommands:
4
+ restore-from-snapshot — replay the latest (or a specific) kuzu snapshot
5
+ back into the live graph. Confirm-by-default; --yes skips the prompt
6
+ for non-interactive/CI use; --dry-run reports the plan without mutating.
7
+
8
+ Closes #184 bug 1: when kuzu opens cleanly but the live graph is STALE after
9
+ an AGENT_BRAIN_JOB_TIMEOUT rollback, operators can replay the latest valid
10
+ snapshot to bring the graph back in sync.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from pathlib import Path
16
+
17
+ import click
18
+ from rich.console import Console
19
+
20
+ from agent_brain_cli.config import STATE_DIR_NAME, resolve_project_root
21
+
22
+ # Re-use diagnostics helpers for state-dir + store-type resolution and the
23
+ # server-running guard. These are local imports inside the CLI so the module
24
+ # loads without requiring the server package to be installed.
25
+ from agent_brain_cli.diagnostics import (
26
+ _graph_index_dir,
27
+ _read_graphrag_block,
28
+ _server_is_running,
29
+ )
30
+
31
+ # agent-brain-rag is a declared dependency of agent-brain-cli (^10.x), so this
32
+ # import is safe at module level. The lazy try/except below is a belt-and-braces
33
+ # guard for edge cases where the server wheel is not installed in the env.
34
+ try:
35
+ from agent_brain_server.storage.graph_store import GraphStoreManager
36
+ except ImportError: # pragma: no cover
37
+ GraphStoreManager = None
38
+
39
+ console = Console()
40
+
41
+
42
+ @click.group(name="graph")
43
+ def graph_group() -> None:
44
+ """Manage the GraphRAG graph index (kuzu backend).
45
+
46
+ \b
47
+ Commands:
48
+ restore-from-snapshot Replay a snapshot back into kuzu.
49
+ """
50
+
51
+
52
+ @graph_group.command("restore-from-snapshot")
53
+ @click.option(
54
+ "--snapshot",
55
+ "snapshot_path",
56
+ type=click.Path(exists=True, path_type=Path),
57
+ default=None,
58
+ help=(
59
+ "Snapshot file to restore (default: latest valid snapshot on disk). "
60
+ "Must be a .json snapshot written by the agent-brain-server."
61
+ ),
62
+ )
63
+ @click.option(
64
+ "--dry-run",
65
+ is_flag=True,
66
+ help="Report what would be restored and exit without mutating kuzu.",
67
+ )
68
+ @click.option(
69
+ "--yes",
70
+ "assume_yes",
71
+ is_flag=True,
72
+ help="Skip the confirmation prompt (non-interactive/CI use).",
73
+ )
74
+ def restore_from_snapshot(
75
+ snapshot_path: Path | None,
76
+ dry_run: bool,
77
+ assume_yes: bool,
78
+ ) -> None:
79
+ """Replay a kuzu snapshot back into the live graph.
80
+
81
+ Resolves the project's graph_index directory, reads the store type from
82
+ config, then replays the latest valid (or a specific) snapshot back into
83
+ the kuzu database.
84
+
85
+ Default (no flags): prints a summary of what WILL be restored and prompts
86
+ for confirmation. Use --yes for CI/scripted invocations; --dry-run to
87
+ preview without touching the database.
88
+
89
+ The server MUST be stopped before running this command because kuzu does
90
+ not allow concurrent writers.
91
+ """
92
+ # --- Resolve state dir + store type ----------------------------------- #
93
+ project_root = resolve_project_root()
94
+ state_dir = project_root / STATE_DIR_NAME
95
+
96
+ block = _read_graphrag_block(state_dir)
97
+ store_type = str((block or {}).get("store_type") or "simple").lower()
98
+
99
+ if store_type != "kuzu":
100
+ console.print(
101
+ "[yellow]Graph restore only applies to the kuzu backend "
102
+ f"(configured store_type={store_type!r}). Nothing to do.[/yellow]"
103
+ )
104
+ return
105
+
106
+ # --- Guard: server must be stopped ------------------------------------ #
107
+ if _server_is_running(state_dir):
108
+ console.print(
109
+ "[red]Stop the server first (`agent-brain stop`) — restore "
110
+ "mutates the kuzu database the server holds open.[/red]"
111
+ )
112
+ raise SystemExit(1)
113
+
114
+ # --- Build the graph store manager ------------------------------------ #
115
+ graph_dir = _graph_index_dir(state_dir)
116
+ if GraphStoreManager is None: # pragma: no cover
117
+ console.print(
118
+ "[red]Cannot import agent-brain-server. Install it with "
119
+ "`uv pip install agent-brain-rag`.[/red]"
120
+ )
121
+ raise SystemExit(1)
122
+
123
+ mgr = GraphStoreManager(graph_dir, "kuzu")
124
+
125
+ # --- Preview (plan) --------------------------------------------------- #
126
+ plan = mgr.plan_restore(snapshot_path)
127
+ if plan is None:
128
+ console.print(
129
+ "[yellow]No snapshot available to restore at "
130
+ f"{graph_dir / 'snapshots'}.[/yellow]"
131
+ )
132
+ raise SystemExit(1)
133
+
134
+ snap_file, triplet_count = plan
135
+ kuzu_db_path = graph_dir / "kuzu_db"
136
+ console.print(
137
+ f"Will restore [bold]{triplet_count}[/bold] triplets from "
138
+ f"[cyan]{snap_file.name}[/cyan] into [cyan]{kuzu_db_path}[/cyan]."
139
+ )
140
+
141
+ if dry_run:
142
+ console.print("(dry run — nothing changed)")
143
+ return
144
+
145
+ # --- Interactive confirmation ------------------------------------------ #
146
+ if not assume_yes:
147
+ confirmed = click.confirm("Proceed with restore?", default=False)
148
+ if not confirmed:
149
+ console.print("Aborted.")
150
+ return
151
+
152
+ # --- Execute restore --------------------------------------------------- #
153
+ restored = mgr.restore_from_snapshot(snapshot_path)
154
+ console.print(f"Restored [bold]{restored}[/bold] triplets.")
@@ -29,6 +29,15 @@ from agent_brain_cli.config import (
29
29
  resolve_project_root_with_strategy,
30
30
  )
31
31
 
32
+ # agent-brain-rag is a declared dependency of agent-brain-cli. Import at module
33
+ # level so apply_safe_fixes can be patched cleanly in tests.
34
+ try:
35
+ from agent_brain_server.storage.graph_store import (
36
+ GraphStoreManager as GraphStoreManager,
37
+ )
38
+ except ImportError: # pragma: no cover
39
+ GraphStoreManager = None
40
+
32
41
  #: Severity returned by every diagnostic check.
33
42
  SEVERITY_OK = "ok"
34
43
  SEVERITY_WARN = "warn"
@@ -463,6 +472,130 @@ def _check_graph_store_health(state_dir: Path) -> CheckResult | None:
463
472
  )
464
473
 
465
474
 
475
+ def _get_live_kuzu_relationship_count(graph_dir: Path) -> int | None:
476
+ """Open the kuzu DB read-only and return the live relationship count.
477
+
478
+ Returns ``None`` on any failure (not-installed, corrupt, etc.) — the
479
+ caller treats a None as "can't determine" and skips the staleness check.
480
+
481
+ Args:
482
+ graph_dir: The graph_index directory containing ``kuzu_db``.
483
+ """
484
+ try:
485
+ import kuzu # noqa: PLC0415
486
+ except ImportError:
487
+ return None
488
+ kuzu_db_path = graph_dir / "kuzu_db"
489
+ try:
490
+ db = kuzu.Database(str(kuzu_db_path), read_only=True)
491
+ conn = kuzu.Connection(db)
492
+ result = conn.execute("MATCH ()-[r]->() RETURN COUNT(r)")
493
+ row = result.get_next()
494
+ return int(row[0]) if row else 0
495
+ except (IndexError, RuntimeError, OSError, TypeError, Exception): # noqa: BLE001
496
+ return None
497
+
498
+
499
+ def _check_graph_staleness(state_dir: Path) -> CheckResult | None:
500
+ """Warn when the live kuzu graph appears STALE (snapshot > live contents).
501
+
502
+ This check is SEPARATE from ``_check_graph_store_health`` — that one
503
+ verifies the DB opens without corruption; this one verifies the live
504
+ relationship count is not significantly below the latest snapshot count,
505
+ which signals an ``AGENT_BRAIN_JOB_TIMEOUT`` rollback left the graph
506
+ partially empty.
507
+
508
+ Returns ``None`` when:
509
+ - GraphRAG is not configured or store_type != "kuzu"
510
+ - The kuzu DB does not exist on disk yet
511
+ - No snapshot exists (nothing to compare against)
512
+ - The live COUNT query fails (could be a format change; don't FAIL here)
513
+
514
+ Args:
515
+ state_dir: Project state directory.
516
+ """
517
+ block = _read_graphrag_block(state_dir)
518
+ if not block or not block.get("enabled"):
519
+ return None
520
+ store_type = str(block.get("store_type") or "simple").lower()
521
+ if store_type != "kuzu":
522
+ return None
523
+
524
+ graph_dir = _graph_index_dir(state_dir)
525
+ kuzu_db_path = graph_dir / "kuzu_db"
526
+ if not kuzu_db_path.exists():
527
+ return None
528
+
529
+ # Check that at least one snapshot exists.
530
+ try:
531
+ from agent_brain_server.storage.graph_snapshot import ( # noqa: PLC0415
532
+ GraphSnapshotManager,
533
+ )
534
+ except ImportError:
535
+ # Server package not installed — fall back to manual JSON scan.
536
+ snap_dir = graph_dir / "snapshots"
537
+ if not snap_dir.is_dir() or not any(snap_dir.iterdir()):
538
+ return None
539
+ # Best-effort: pick the newest file and count triplets.
540
+ candidates = sorted(
541
+ (p for p in snap_dir.iterdir() if p.is_file() and p.suffix == ".json"),
542
+ key=lambda p: (p.stat().st_mtime, p.name),
543
+ reverse=True,
544
+ )
545
+ snapshot_count = 0
546
+ for snap in candidates:
547
+ try:
548
+ payload = json.loads(snap.read_text())
549
+ snapshot_count = len(payload.get("triplets") or [])
550
+ break
551
+ except (OSError, json.JSONDecodeError):
552
+ continue
553
+ else:
554
+ snap_mgr = GraphSnapshotManager(graph_dir)
555
+ if snap_mgr.latest() is None:
556
+ return None
557
+ loaded = snap_mgr.load_latest_valid()
558
+ if loaded is None:
559
+ return None
560
+ _snap_path, triplets = loaded
561
+ snapshot_count = len(triplets)
562
+
563
+ if snapshot_count == 0:
564
+ return None
565
+
566
+ live_count = _get_live_kuzu_relationship_count(graph_dir)
567
+ if live_count is None:
568
+ # Can't determine live count — skip rather than raise a false alarm.
569
+ return None
570
+
571
+ if snapshot_count > live_count:
572
+ return CheckResult(
573
+ "graph_staleness",
574
+ SEVERITY_WARN,
575
+ f"Live kuzu graph has {live_count} relationships but the latest "
576
+ f"snapshot has {snapshot_count} — the graph looks stale (likely an "
577
+ "AGENT_BRAIN_JOB_TIMEOUT rollback).",
578
+ fix=(
579
+ "Run `agent-brain graph restore-from-snapshot` (or "
580
+ "`agent-brain doctor --fix`) to replay the snapshot."
581
+ ),
582
+ details={
583
+ "live_relationships": live_count,
584
+ "snapshot_triplets": snapshot_count,
585
+ },
586
+ )
587
+
588
+ return CheckResult(
589
+ "graph_staleness",
590
+ SEVERITY_OK,
591
+ "Live kuzu graph is consistent with the latest snapshot.",
592
+ details={
593
+ "live_relationships": live_count,
594
+ "snapshot_triplets": snapshot_count,
595
+ },
596
+ )
597
+
598
+
466
599
  def _server_is_running(state_dir: Path) -> bool:
467
600
  """Best-effort check for an active server lock under state_dir."""
468
601
  return (state_dir / "server.lock").exists() or (state_dir / "lock").exists()
@@ -538,6 +671,11 @@ def run_doctor(server_url_override: str | None = None) -> DoctorReport:
538
671
  if graph_check is not None:
539
672
  checks.append(graph_check)
540
673
 
674
+ # Phase 64 GSTAB-02 — warn when live kuzu is stale (snapshot > live count).
675
+ stale_check = _check_graph_staleness(state_dir)
676
+ if stale_check is not None:
677
+ checks.append(stale_check)
678
+
541
679
  checks.append(_check_gitignore(project_root))
542
680
 
543
681
  checks.append(_check_server(server_url, runtime_file))
@@ -627,6 +765,34 @@ def apply_safe_fixes(report: DoctorReport) -> list[str]:
627
765
  "start empty. Re-run `agent-brain index <folder>` to "
628
766
  "rebuild."
629
767
  )
768
+ elif check.name == "graph_staleness" and check.status == SEVERITY_WARN:
769
+ # Phase 64 GSTAB-02 — restore a stale (but non-corrupt) kuzu graph.
770
+ if _server_is_running(state_dir):
771
+ actions.append(
772
+ "Skipped graph restore: server appears to be running. "
773
+ "Stop it with `agent-brain stop` first, then re-run "
774
+ "`agent-brain doctor --fix`."
775
+ )
776
+ continue
777
+ graph_dir = _graph_index_dir(state_dir)
778
+ if GraphStoreManager is None: # pragma: no cover
779
+ actions.append(
780
+ "Could not import agent-brain-server to perform restore. "
781
+ "Run `agent-brain graph restore-from-snapshot` manually."
782
+ )
783
+ continue
784
+ try:
785
+ mgr = GraphStoreManager(graph_dir, "kuzu")
786
+ restored_count = mgr.restore_from_snapshot(None)
787
+ actions.append(
788
+ f"Restored {restored_count} triplets from the latest "
789
+ f"snapshot into {graph_dir}."
790
+ )
791
+ except Exception as exc: # noqa: BLE001
792
+ actions.append(
793
+ f"Graph restore failed: {exc}. "
794
+ "Run `agent-brain graph restore-from-snapshot` manually."
795
+ )
630
796
  return actions
631
797
 
632
798
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "agent-brain-cli"
3
- version = "10.3.2"
3
+ version = "10.4.0"
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,7 +27,7 @@ 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.3.2"
30
+ agent-brain-rag = "^10.4.0"
31
31
  agent-brain-uds = "^10.3.0"
32
32
  psutil = "^6.0"
33
33