cortexdb-cli 0.5.1__py3-none-any.whl → 0.5.2__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.
cortexdb_cli/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """CortexDB CLI - command-line interface for the v1 memory API."""
2
2
 
3
- __version__ = "0.5.1"
3
+ __version__ = "0.5.2"
@@ -5,10 +5,12 @@ from __future__ import annotations
5
5
  import click
6
6
  import httpx
7
7
 
8
+ from datetime import datetime, timezone
9
+
8
10
  from cortexdb_cli.client import DEFAULT_ENDPOINT, signup
9
- from cortexdb_cli.config import config_path, save_config
10
- from cortexdb_cli.output import console
11
- from cortexdb_cli.state import save_state, state_path
11
+ from cortexdb_cli.config import config_path, resolve_config_dir, save_config
12
+ from cortexdb_cli.output import console, err_console
13
+ from cortexdb_cli.state import load_state, save_state, state_path
12
14
 
13
15
 
14
16
  def _inherit_group_flag(
@@ -38,6 +40,49 @@ def _inherit_group_flag(
38
40
  return own_value if own_value is not None else group_value
39
41
 
40
42
 
43
+ def _existing_identity() -> tuple[dict, str] | None:
44
+ """Return `(state, status)` for a usable identity already on disk.
45
+
46
+ KAN-145/156: `init` used to mint and overwrite unconditionally. Running
47
+ it twice in one directory replaced a working identity with a brand-new
48
+ anonymous one - and because the actor and scope change, everything
49
+ written under the old identity becomes unreachable from this machine.
50
+ Nothing warned, and nothing had to fail for it to happen: the second
51
+ `init` looked exactly as successful as the first.
52
+
53
+ `status` is "valid" or "expired"; both are treated as "do not silently
54
+ replace this", because an expired token still names the brain the user's
55
+ data is in.
56
+ """
57
+ state = load_state()
58
+ if not state.get("token"):
59
+ return None
60
+ expires = state.get("expires_at")
61
+ status = "valid"
62
+ if expires:
63
+ try:
64
+ when = datetime.fromisoformat(str(expires).replace("Z", "+00:00"))
65
+ if when.tzinfo is None:
66
+ when = when.replace(tzinfo=timezone.utc)
67
+ if when <= datetime.now(timezone.utc):
68
+ status = "expired"
69
+ except (TypeError, ValueError):
70
+ # An unparseable expiry is not evidence of expiry. Prefer the
71
+ # conservative reading: something is here, do not clobber it.
72
+ status = "valid"
73
+ return state, status
74
+
75
+
76
+ def _report_existing(state: dict, status: str) -> None:
77
+ console.print(f" [success]Existing identity reused[/success] ({status})")
78
+ console.print(f" [success]Actor:[/success] {state.get('user_id', '?')}")
79
+ console.print(f" [success]Default scope:[/success] {state.get('scope', '?')}")
80
+ if state.get("expires_at"):
81
+ console.print(f" [dim]Token expires: {state['expires_at']}[/dim]")
82
+ console.print(f"")
83
+ console.print(f"[dim]State directory: {resolve_config_dir()}[/dim]")
84
+
85
+
41
86
  @click.command("init")
42
87
  @click.option(
43
88
  "--endpoint",
@@ -59,6 +104,13 @@ def _inherit_group_flag(
59
104
  default=None,
60
105
  help="Default scope path. Defaults to the actor.",
61
106
  )
107
+ @click.option(
108
+ "--force",
109
+ is_flag=True,
110
+ help="Replace an existing identity. Backs the old one up first. "
111
+ "A new identity is a NEW brain: memories written under the old actor "
112
+ "stay where they are and are no longer reachable from this config.",
113
+ )
62
114
  @click.pass_context
63
115
  def init_cmd(
64
116
  ctx: click.Context,
@@ -66,6 +118,7 @@ def init_cmd(
66
118
  api_key: str | None,
67
119
  actor: str | None,
68
120
  scope: str | None,
121
+ force: bool,
69
122
  ) -> None:
70
123
  """Set up CortexDB CLI.
71
124
 
@@ -81,6 +134,54 @@ def init_cmd(
81
134
 
82
135
  console.print("\n[header]CortexDB CLI setup[/header]\n")
83
136
 
137
+ # Guard BEFORE any signup call or state write. `init` is read-only when a
138
+ # usable identity already exists: reuse and report it, never replace it
139
+ # silently. Reminting is a data-reachability event, not a retry.
140
+ existing = _existing_identity()
141
+ if existing and not force:
142
+ state, status = existing
143
+ if status == "valid":
144
+ _report_existing(state, status)
145
+ console.print(
146
+ "\n[dim]Nothing changed. Use --force to replace this identity, "
147
+ "or --config-dir / CORTEXDB_HOME for a separate one.[/dim]\n"
148
+ )
149
+ return
150
+ # Expired: still refuse. The token names the brain the user's data is
151
+ # in, so a silent remint strands it. Say so and make them choose.
152
+ err_console.print(
153
+ f"[error]The stored token for {state.get('user_id', '?')} has expired "
154
+ f"({state.get('expires_at')}).[/error]"
155
+ )
156
+ err_console.print(
157
+ "Refusing to mint a new identity automatically: a new identity is a "
158
+ "NEW brain, and memories written under the old actor would no longer "
159
+ "be reachable from this config."
160
+ )
161
+ err_console.print(
162
+ " To deliberately start a new brain: cortexdb init --force"
163
+ )
164
+ err_console.print(
165
+ " To use a token you already hold: "
166
+ "cortexdb init --api-key <token> --actor <actor>"
167
+ )
168
+ raise SystemExit(3)
169
+
170
+ if existing and force:
171
+ backup = state_path().with_suffix(".json.replaced")
172
+ try:
173
+ backup.write_text(
174
+ state_path().read_text(encoding="utf-8"), encoding="utf-8", newline="\n"
175
+ )
176
+ console.print(
177
+ f"[warning]Replacing the existing identity; "
178
+ f"previous state saved to {backup}[/warning]"
179
+ )
180
+ except OSError as exc:
181
+ console.print(
182
+ f"[warning]Could not back up existing state ({exc}); continuing[/warning]"
183
+ )
184
+
84
185
  if api_key:
85
186
  if not actor:
86
187
  raise click.UsageError("--actor is required when --api-key is supplied.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cortexdb-cli
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Command-line interface for CortexDB — the long-term memory layer for AI.
5
5
  Project-URL: Homepage, https://cortexdb.ai
6
6
  Project-URL: Documentation, https://cortexdb.ai/docs
@@ -1,4 +1,4 @@
1
- cortexdb_cli/__init__.py,sha256=lVn29OeWqhqDSv21Nj0l6DQV1Ai5_EmOTQGIodTvogw,90
1
+ cortexdb_cli/__init__.py,sha256=E9HyqRe9juxBYu8xwyA9tk6TUvi3rTeVOfrdIvcJFPA,90
2
2
  cortexdb_cli/client.py,sha256=CQwGo4Gn7cHDnfLUlJBZMsZ9-AyGVz8W6bJKxNMwlRA,2862
3
3
  cortexdb_cli/config.py,sha256=ee1qmOfqMwilL81ujaqjf6TjjlrFG7WZAHRIgeyif9U,5690
4
4
  cortexdb_cli/errors.py,sha256=xwxAWYY7KtNa-e7dyLQECnsKcciVcKC41CXFFF_-0VU,3924
@@ -25,7 +25,7 @@ cortexdb_cli/commands/export_cmd.py,sha256=IFkALD-zu2fVrpt1R_L4yvOgCEzZ9gPwcsQdF
25
25
  cortexdb_cli/commands/facts.py,sha256=R21T2x6fyKn8Mvg-tskoURBBiXtsIoiooT9WXRSrGzc,5401
26
26
  cortexdb_cli/commands/forget.py,sha256=fPGXqw-KetuuemirHfV7FUmKPihSAX8VEVjrVs3CgP8,5060
27
27
  cortexdb_cli/commands/import_cmd.py,sha256=wnV1bsf54z8W8alQOBj_ExfdV1nUYzl_Ghxv-atBRHA,8386
28
- cortexdb_cli/commands/init.py,sha256=S-A9V_xpdFdjYwcb2R1WLKHAjOVxHsh5oHKQoM8e7XY,4597
28
+ cortexdb_cli/commands/init.py,sha256=4hIaqqzMzddutBiOo8zJB8bhd00bsfGmgN8fszn-Sw0,8905
29
29
  cortexdb_cli/commands/interactive.py,sha256=_xDPMKQ_VnpLUMJn6pZL4aJ3VpY7ti5XDqKGC657zSI,9514
30
30
  cortexdb_cli/commands/onboard.py,sha256=Mz_pQUH0WC8IKcVm6B3CVQNuez0KqZlPvezOE4uOvIU,27414
31
31
  cortexdb_cli/commands/policy.py,sha256=FFBiVKNZJcUjTRL07yYQ8zsIWasGeF_jhM124hIKWeI,3354
@@ -34,7 +34,7 @@ cortexdb_cli/commands/scopes.py,sha256=Cx_zV-zyIrnDxwp_I4AX_Teh7UFu4EdvDOYe9hTEF
34
34
  cortexdb_cli/commands/search.py,sha256=4wsgNU47deb0x5o7xC9eWlhwdIIbz56q7ne8GIiCmYo,1953
35
35
  cortexdb_cli/commands/understanding.py,sha256=BktqOn-GloOzSSGJGK9xh5kGCpxcrwkNogtXhjj4pBI,5371
36
36
  cortexdb_cli/commands/wire.py,sha256=M3UUHScmvr_MDrX_RaMBg-YLTcHKUq9woNkT4KHJKfs,8131
37
- cortexdb_cli-0.5.1.dist-info/METADATA,sha256=7OGflYmFEJrIgfUJrG7OdlDN5S-b7GdtQNnVzGXfM3o,4429
38
- cortexdb_cli-0.5.1.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
39
- cortexdb_cli-0.5.1.dist-info/entry_points.txt,sha256=h3sEbdqqvtv8LBbRLUgybYPo9N2lpU85fQUSh5ToEvs,51
40
- cortexdb_cli-0.5.1.dist-info/RECORD,,
37
+ cortexdb_cli-0.5.2.dist-info/METADATA,sha256=CIgu0dksEWHPqVq3WHPmOq2kQRxkMf3U00ZlltMO620,4429
38
+ cortexdb_cli-0.5.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
39
+ cortexdb_cli-0.5.2.dist-info/entry_points.txt,sha256=h3sEbdqqvtv8LBbRLUgybYPo9N2lpU85fQUSh5ToEvs,51
40
+ cortexdb_cli-0.5.2.dist-info/RECORD,,