mem0-cli 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,133 @@
1
+ """Entity management commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import time as _time
6
+
7
+ import typer
8
+ from rich.console import Console
9
+ from rich.table import Table
10
+
11
+ from mem0_cli.backend.base import Backend
12
+ from mem0_cli.branding import (
13
+ ACCENT_COLOR,
14
+ BRAND_COLOR,
15
+ DIM_COLOR,
16
+ print_error,
17
+ print_info,
18
+ print_success,
19
+ timed_status,
20
+ )
21
+ from mem0_cli.output import format_json
22
+
23
+ console = Console()
24
+ err_console = Console(stderr=True)
25
+
26
+
27
+ def cmd_entities_list(backend: Backend, entity_type: str, *, output: str) -> None:
28
+ """List entities of a given type."""
29
+ valid_types = {"users", "agents", "apps", "runs"}
30
+ if entity_type not in valid_types:
31
+ print_error(err_console, f"Invalid entity type: {entity_type}. Use: {', '.join(valid_types)}")
32
+ raise typer.Exit(1)
33
+
34
+ _start = _time.perf_counter()
35
+ with timed_status(err_console, f"Fetching {entity_type}...") as _ts:
36
+ try:
37
+ results = backend.entities(entity_type)
38
+ except Exception as e:
39
+ print_error(err_console, str(e), hint="This feature may require the mem0 Platform.")
40
+ raise typer.Exit(1) from None
41
+ _elapsed = _time.perf_counter() - _start
42
+
43
+ if output == "json":
44
+ format_json(console, results)
45
+ return
46
+
47
+ if not results:
48
+ print_info(console, f"No {entity_type} found.")
49
+ return
50
+
51
+ table = Table(border_style=BRAND_COLOR, header_style=f"bold {ACCENT_COLOR}", padding=(0, 1))
52
+ table.add_column("Name / ID", style="bold")
53
+ table.add_column("Created", max_width=12)
54
+
55
+ for entity in results:
56
+ name = entity.get("name", entity.get("id", "—"))
57
+ created = str(entity.get("created_at", "—"))[:10]
58
+ table.add_row(str(name), created)
59
+
60
+ console.print()
61
+ console.print(table)
62
+ console.print(f" [{DIM_COLOR}]{len(results)} {entity_type} ({_elapsed:.2f}s)[/]")
63
+ console.print()
64
+
65
+
66
+ def cmd_entities_delete(
67
+ backend: Backend,
68
+ *,
69
+ user_id: str | None,
70
+ agent_id: str | None,
71
+ app_id: str | None,
72
+ run_id: str | None,
73
+ force: bool,
74
+ dry_run: bool = False,
75
+ output: str,
76
+ ) -> None:
77
+ """Delete an entity and all its memories (cascade delete)."""
78
+ if not any([user_id, agent_id, app_id, run_id]):
79
+ print_error(err_console, "Provide at least one of --user-id, --agent-id, --app-id, --run-id.")
80
+ raise typer.Exit(1)
81
+
82
+ if dry_run:
83
+ scope_parts = []
84
+ if user_id:
85
+ scope_parts.append(f"user={user_id}")
86
+ if agent_id:
87
+ scope_parts.append(f"agent={agent_id}")
88
+ if app_id:
89
+ scope_parts.append(f"app={app_id}")
90
+ if run_id:
91
+ scope_parts.append(f"run={run_id}")
92
+ scope = ", ".join(scope_parts)
93
+ print_info(console, f"Would delete entity {scope} and all its memories.")
94
+ print_info(console, "No changes made (dry run).")
95
+ return
96
+
97
+ if not force:
98
+ scope_parts = []
99
+ if user_id:
100
+ scope_parts.append(f"user={user_id}")
101
+ if agent_id:
102
+ scope_parts.append(f"agent={agent_id}")
103
+ if app_id:
104
+ scope_parts.append(f"app={app_id}")
105
+ if run_id:
106
+ scope_parts.append(f"run={run_id}")
107
+ scope = ", ".join(scope_parts)
108
+
109
+ confirm = typer.confirm(
110
+ f"\n \u26a0 Delete entity {scope} AND all its memories? This cannot be undone."
111
+ )
112
+ if not confirm:
113
+ print_info(console, "Cancelled.")
114
+ raise typer.Exit(0)
115
+
116
+ _start = _time.perf_counter()
117
+ with timed_status(err_console, "Deleting entity...") as _ts:
118
+ try:
119
+ result = backend.delete_entities(
120
+ user_id=user_id,
121
+ agent_id=agent_id,
122
+ app_id=app_id,
123
+ run_id=run_id,
124
+ )
125
+ except Exception as e:
126
+ print_error(err_console, str(e))
127
+ raise typer.Exit(1) from None
128
+ _elapsed = _time.perf_counter() - _start
129
+
130
+ if output == "json":
131
+ format_json(console, result)
132
+ elif output != "quiet":
133
+ print_success(console, f"Entity deleted with all memories ({_elapsed:.2f}s)")
@@ -0,0 +1,195 @@
1
+ """mem0 init — interactive setup wizard."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+
7
+ import typer
8
+ from rich.console import Console
9
+ from rich.prompt import Prompt
10
+
11
+ from mem0_cli.branding import (
12
+ BRAND_COLOR,
13
+ DIM_COLOR,
14
+ print_banner,
15
+ print_error,
16
+ print_info,
17
+ print_success,
18
+ )
19
+ from mem0_cli.config import Mem0Config, save_config
20
+
21
+ console = Console()
22
+ err_console = Console(stderr=True)
23
+
24
+
25
+ def _prompt_secret(label: str) -> str:
26
+ """Prompt for a secret value, echoing '*' for each character typed."""
27
+ sys.stdout.write(label)
28
+ sys.stdout.flush()
29
+
30
+ chars: list[str] = []
31
+
32
+ if sys.platform == "win32":
33
+ import msvcrt
34
+
35
+ while True:
36
+ ch = msvcrt.getwch()
37
+ if ch in ("\r", "\n"):
38
+ sys.stdout.write("\n")
39
+ sys.stdout.flush()
40
+ break
41
+ if ch == "\x03":
42
+ raise KeyboardInterrupt
43
+ if ch in ("\x08", "\x7f"): # backspace
44
+ if chars:
45
+ chars.pop()
46
+ sys.stdout.write("\b \b")
47
+ sys.stdout.flush()
48
+ else:
49
+ chars.append(ch)
50
+ sys.stdout.write("*")
51
+ sys.stdout.flush()
52
+ else:
53
+ import termios
54
+ import tty
55
+
56
+ fd = sys.stdin.fileno()
57
+ old_settings = termios.tcgetattr(fd)
58
+ try:
59
+ tty.setraw(fd)
60
+ while True:
61
+ ch = sys.stdin.read(1)
62
+ if ch in ("\r", "\n"):
63
+ sys.stdout.write("\r\n")
64
+ sys.stdout.flush()
65
+ break
66
+ if ch == "\x03":
67
+ raise KeyboardInterrupt
68
+ if ch in ("\x7f", "\x08"): # backspace/delete
69
+ if chars:
70
+ chars.pop()
71
+ sys.stdout.write("\b \b")
72
+ sys.stdout.flush()
73
+ elif ch == "\x15": # Ctrl+U — clear line
74
+ sys.stdout.write("\b \b" * len(chars))
75
+ sys.stdout.flush()
76
+ chars = []
77
+ elif ch >= " ": # ignore other control characters
78
+ chars.append(ch)
79
+ sys.stdout.write("*")
80
+ sys.stdout.flush()
81
+ finally:
82
+ termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
83
+
84
+ return "".join(chars)
85
+
86
+
87
+ def run_init(*, api_key: str | None = None, user_id: str | None = None) -> None:
88
+ """Interactive setup wizard for mem0 CLI.
89
+
90
+ When both *api_key* and *user_id* are supplied, all prompts are skipped
91
+ (non-interactive mode). When running in a non-TTY without the required
92
+ flags, an error message is printed.
93
+ """
94
+ config = Mem0Config()
95
+
96
+ # Fully non-interactive when both flags provided
97
+ if api_key and user_id:
98
+ config.platform.api_key = api_key
99
+ config.defaults.user_id = user_id
100
+ _validate_platform(config)
101
+ save_config(config)
102
+ print_success(console, "Configuration saved to ~/.mem0/config.json")
103
+ return
104
+
105
+ # Non-TTY without full flags -> error
106
+ if not sys.stdin.isatty():
107
+ if not api_key or not user_id:
108
+ print_error(
109
+ err_console,
110
+ "Non-interactive terminal detected and required flags missing.",
111
+ hint="Run: mem0 init --api-key <key> --user-id <id>",
112
+ )
113
+ raise typer.Exit(1)
114
+
115
+ print_banner(console)
116
+ console.print()
117
+ print_info(console, "Welcome! Let's set up your mem0 CLI.\n")
118
+
119
+ # Use provided flags or prompt
120
+ if api_key:
121
+ config.platform.api_key = api_key
122
+ else:
123
+ _setup_platform(config)
124
+
125
+ if user_id:
126
+ config.defaults.user_id = user_id
127
+ else:
128
+ _setup_defaults(config)
129
+
130
+ _validate_platform(config)
131
+
132
+ save_config(config)
133
+ console.print()
134
+ print_success(console, "Configuration saved to ~/.mem0/config.json")
135
+ console.print()
136
+ console.print(f" [{DIM_COLOR}]Get started:[/]")
137
+ if config.defaults.user_id:
138
+ console.print(f' [{DIM_COLOR}] mem0 add "I prefer dark mode"[/]')
139
+ console.print(f' [{DIM_COLOR}] mem0 search "preferences"[/]')
140
+ else:
141
+ console.print(f' [{DIM_COLOR}] mem0 add "I prefer dark mode" --user-id alice[/]')
142
+ console.print(f' [{DIM_COLOR}] mem0 search "preferences" --user-id alice[/]')
143
+ console.print()
144
+
145
+
146
+ def _setup_platform(config: Mem0Config) -> None:
147
+ """Platform setup flow."""
148
+ console.print()
149
+ console.print(f" [{DIM_COLOR}]Get your API key at https://app.mem0.ai/dashboard/api-keys[/]")
150
+ console.print()
151
+
152
+ console.print(f" [{BRAND_COLOR}]API Key[/]: ", end="")
153
+ api_key = _prompt_secret("")
154
+ if not api_key:
155
+ print_error(err_console, "API key is required.")
156
+ raise typer.Exit(1)
157
+
158
+ config.platform.api_key = api_key
159
+
160
+
161
+ def _setup_defaults(config: Mem0Config) -> None:
162
+ """Collect default entity IDs."""
163
+ console.print()
164
+ print_info(console, "Set default entity IDs (press Enter to skip).\n")
165
+
166
+ user_id = Prompt.ask(
167
+ f" [{BRAND_COLOR}]Default User ID[/] [{DIM_COLOR}](recommended)[/]",
168
+ default="mem0-cli",
169
+ )
170
+ if user_id:
171
+ config.defaults.user_id = user_id
172
+
173
+
174
+ def _validate_platform(config: Mem0Config) -> None:
175
+ """Validate platform connection after all inputs are collected."""
176
+ console.print()
177
+ print_info(console, "Validating connection...")
178
+ try:
179
+ from mem0_cli.backend.platform import PlatformBackend
180
+
181
+ backend = PlatformBackend(config.platform)
182
+ status = backend.status(
183
+ user_id=config.defaults.user_id or None,
184
+ agent_id=config.defaults.agent_id or None,
185
+ )
186
+ if status.get("connected"):
187
+ print_success(console, "Connected to mem0 Platform!")
188
+ else:
189
+ print_error(
190
+ err_console,
191
+ f"Could not connect: {status.get('error', 'Unknown error')}",
192
+ hint="Check your API key and try again.",
193
+ )
194
+ except Exception as e:
195
+ print_error(err_console, f"Connection test failed: {e}")