nmem-cli 0.9.9__tar.gz → 0.9.12__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 (30) hide show
  1. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/PKG-INFO +1 -1
  2. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/pyproject.toml +1 -1
  3. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/__init__.py +1 -1
  4. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/cli.py +64 -0
  5. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/session_import.py +8 -2
  6. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/.gitignore +0 -0
  7. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/README.md +0 -0
  8. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/agent_profiles.py +0 -0
  9. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/claude_paths.py +0 -0
  10. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/data_transfer_paths.py +0 -0
  11. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/guidance_rules.py +0 -0
  12. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/kfs_cli.py +0 -0
  13. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/license_payload.py +0 -0
  14. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/memories_reclassify.py +0 -0
  15. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/memory_relations_cli.py +0 -0
  16. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/py.typed +0 -0
  17. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/__init__.py +0 -0
  18. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/__main__.py +0 -0
  19. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/api_client.py +0 -0
  20. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/app.py +0 -0
  21. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/screens/__init__.py +0 -0
  22. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/screens/dashboard.py +0 -0
  23. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/screens/graph.py +0 -0
  24. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/screens/help.py +0 -0
  25. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/screens/memories.py +0 -0
  26. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/screens/memory_detail.py +0 -0
  27. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/screens/settings.py +0 -0
  28. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/screens/thread_detail.py +0 -0
  29. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/screens/threads.py +0 -0
  30. {nmem_cli-0.9.9 → nmem_cli-0.9.12}/src/nmem_cli/tui/widgets/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nmem-cli
3
- Version: 0.9.9
3
+ Version: 0.9.12
4
4
  Summary: CLI and TUI for Nowledge Mem - AI memory management
5
5
  Project-URL: Homepage, https://mem.nowledge.co/
6
6
  Project-URL: Repository, https://github.com/nowledge-co/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nmem-cli"
3
- version = "0.9.9"
3
+ version = "0.9.12"
4
4
  description = "CLI and TUI for Nowledge Mem - AI memory management"
5
5
  authors = [
6
6
  {name = "Nowledge Labs"}
@@ -20,7 +20,7 @@ Environment (overrides config file):
20
20
  NMEM_API_KEY Optional API key (Bearer auth)
21
21
  """
22
22
 
23
- __version__ = "0.9.9"
23
+ __version__ = "0.9.12"
24
24
  __author__ = "Nowledge Labs"
25
25
 
26
26
  from .cli import main
@@ -1515,6 +1515,17 @@ def _format_cli_upgrade_hint(*, context: _CliInstallContext, server_newer: bool)
1515
1515
  )
1516
1516
 
1517
1517
 
1518
+ def _api_release_base(version: str) -> str:
1519
+ """Return the numeric X.Y.Z base for API compatibility checks.
1520
+
1521
+ Post/dev/pre releases (e.g. ``0.9.11.post1``) stay compatible with the
1522
+ matching server release (``0.9.11``).
1523
+ """
1524
+ normalized = str(version or "").strip().lstrip("v")
1525
+ match = re.match(r"^(\d+\.\d+\.\d+)", normalized)
1526
+ return match.group(1) if match else normalized
1527
+
1528
+
1518
1529
  def _status_version_warning(
1519
1530
  *,
1520
1531
  cli_version: str,
@@ -1525,6 +1536,8 @@ def _status_version_warning(
1525
1536
  normalized_cli = str(cli_version or "").strip()
1526
1537
  if not normalized_server or normalized_server == normalized_cli:
1527
1538
  return None
1539
+ if _api_release_base(normalized_cli) == _api_release_base(normalized_server):
1540
+ return None
1528
1541
 
1529
1542
  message = "CLI is v{}, but the server at {} reports v{}.".format(
1530
1543
  normalized_cli,
@@ -3039,6 +3052,7 @@ def cmd_memories_search(
3039
3052
  include_history: bool = False,
3040
3053
  space_id: str | None = None,
3041
3054
  unit_type: str | None = None,
3055
+ metadata_filters: list[str] | None = None,
3042
3056
  ) -> None:
3043
3057
  params: dict[str, Any] = {"q": query, "limit": limit}
3044
3058
  if space_id:
@@ -3064,6 +3078,8 @@ def cmd_memories_search(
3064
3078
  params["include_history"] = "true"
3065
3079
  if unit_type:
3066
3080
  params["unit_type"] = unit_type
3081
+ if metadata_filters:
3082
+ params["metadata"] = metadata_filters
3067
3083
  # Map CLI mode to API mode: "normal" -> "fast", "deep" -> "deep"
3068
3084
  api_mode = "fast" if mode == "normal" else "deep"
3069
3085
  params["mode"] = api_mode
@@ -3133,6 +3149,8 @@ def cmd_memories_search(
3133
3149
  filter_info.append(f"importance>={importance_min}")
3134
3150
  if unit_type:
3135
3151
  filter_info.append(f"type={unit_type}")
3152
+ if metadata_filters:
3153
+ filter_info.append(f"metadata={','.join(metadata_filters)}")
3136
3154
  if filter_info:
3137
3155
  console.print(
3138
3156
  f"[dim]No results for '{query}' with filters: {' '.join(filter_info)}[/dim]"
@@ -3157,6 +3175,8 @@ def cmd_memories_search(
3157
3175
  filter_parts.append(f"[green]imp>={importance_min}[/green]")
3158
3176
  if unit_type:
3159
3177
  filter_parts.append(f"[blue]type:{unit_type}[/blue]")
3178
+ if metadata_filters:
3179
+ filter_parts.append(f"[cyan]metadata:{','.join(metadata_filters)}[/cyan]")
3160
3180
 
3161
3181
  if filter_parts:
3162
3182
  console.print(
@@ -6030,6 +6050,8 @@ def cmd_sources_list(
6030
6050
  source_type: str | None = None,
6031
6051
  lifecycle_state: str | None = None,
6032
6052
  space_id: str | None = None,
6053
+ labels: list[str] | None = None,
6054
+ metadata_filters: list[str] | None = None,
6033
6055
  ) -> None:
6034
6056
  params: dict[str, Any] = {"limit": limit, "offset": 0}
6035
6057
  if source_type:
@@ -6038,6 +6060,11 @@ def cmd_sources_list(
6038
6060
  params["lifecycle_state"] = lifecycle_state
6039
6061
  if space_id:
6040
6062
  params["space_id"] = space_id
6063
+ normalized_labels = _normalize_labels(labels)
6064
+ if normalized_labels:
6065
+ params["labels"] = normalized_labels
6066
+ if metadata_filters:
6067
+ params["metadata"] = metadata_filters
6041
6068
 
6042
6069
  if not is_json_mode():
6043
6070
  with Progress(
@@ -6263,11 +6290,18 @@ def cmd_sources_search(
6263
6290
  query: str,
6264
6291
  limit: int = 20,
6265
6292
  space_id: str | None = None,
6293
+ labels: list[str] | None = None,
6294
+ metadata_filters: list[str] | None = None,
6266
6295
  ) -> None:
6267
6296
  """Search across Library artifact names and summaries (FTS)."""
6268
6297
  params: dict[str, Any] = {"q": query, "limit": limit}
6269
6298
  if space_id:
6270
6299
  params["space_id"] = space_id
6300
+ normalized_labels = _normalize_labels(labels)
6301
+ if normalized_labels:
6302
+ params["labels"] = normalized_labels
6303
+ if metadata_filters:
6304
+ params["metadata"] = metadata_filters
6271
6305
 
6272
6306
  if not is_json_mode():
6273
6307
  with Progress(
@@ -10059,6 +10093,13 @@ PRIORITY
10059
10093
  choices=["fact", "preference", "decision", "plan", "procedure", "learning", "context", "event"],
10060
10094
  help="Filter by memory unit type",
10061
10095
  )
10096
+ s.add_argument(
10097
+ "--metadata",
10098
+ "--meta",
10099
+ dest="metadata_filters",
10100
+ action="append",
10101
+ help="Filter by memory metadata key=value. Repeat for AND filters.",
10102
+ )
10062
10103
  s.add_argument(
10063
10104
  "--mode",
10064
10105
  choices=["normal", "deep"],
@@ -11120,6 +11161,15 @@ PRIORITY
11120
11161
  "--state", dest="lifecycle_state",
11121
11162
  help="Filter by state: ingested, parsed, chunked, indexed, error",
11122
11163
  )
11164
+ ls.add_argument(
11165
+ "-l", "--label", dest="labels", action="append",
11166
+ help="Filter by source label (repeatable)",
11167
+ )
11168
+ ls.add_argument(
11169
+ "--metadata", "--meta", dest="metadata_filters", action="append",
11170
+ metavar="KEY=VALUE",
11171
+ help="Filter by source metadata (repeatable, e.g. customer=acme)",
11172
+ )
11123
11173
 
11124
11174
  add = src_subs.add_parser(
11125
11175
  "add",
@@ -11185,6 +11235,15 @@ PRIORITY
11185
11235
  srch.add_argument(
11186
11236
  "-n", "--limit", type=int, default=20, help="Max results (default 20)"
11187
11237
  )
11238
+ srch.add_argument(
11239
+ "-l", "--label", dest="labels", action="append",
11240
+ help="Filter by source label (repeatable)",
11241
+ )
11242
+ srch.add_argument(
11243
+ "--metadata", "--meta", dest="metadata_filters", action="append",
11244
+ metavar="KEY=VALUE",
11245
+ help="Filter by source metadata (repeatable, e.g. customer=acme)",
11246
+ )
11188
11247
 
11189
11248
  rd = src_subs.add_parser(
11190
11249
  "read",
@@ -11626,6 +11685,7 @@ def main() -> int:
11626
11685
  getattr(args, "include_history", False),
11627
11686
  getattr(args, "space", None),
11628
11687
  getattr(args, "unit_type", None),
11688
+ getattr(args, "metadata_filters", None),
11629
11689
  )
11630
11690
  elif action == "reclassify-types":
11631
11691
  run_memories_reclassify_types_command(
@@ -12048,6 +12108,8 @@ def main() -> int:
12048
12108
  query=args.query,
12049
12109
  limit=getattr(args, "limit", 20),
12050
12110
  space_id=getattr(args, "space", None),
12111
+ labels=getattr(args, "labels", None),
12112
+ metadata_filters=getattr(args, "metadata_filters", None),
12051
12113
  )
12052
12114
  elif action == "read":
12053
12115
  cmd_sources_read(
@@ -12076,6 +12138,8 @@ def main() -> int:
12076
12138
  source_type=getattr(args, "source_type", None),
12077
12139
  lifecycle_state=getattr(args, "lifecycle_state", None),
12078
12140
  space_id=getattr(args, "space", None),
12141
+ labels=getattr(args, "labels", None),
12142
+ metadata_filters=getattr(args, "metadata_filters", None),
12079
12143
  )
12080
12144
  elif cmd == "license":
12081
12145
  action = args.action
@@ -2541,7 +2541,11 @@ def _decode_project_path_enhanced(encoded: str) -> Optional[str]:
2541
2541
 
2542
2542
 
2543
2543
  def _decode_project_path_windows(encoded: str) -> Optional[str]:
2544
- drive_match = re.match(r"^([A-Za-z])-(.*)$", encoded)
2544
+ drive_match = re.match(r"^([A-Za-z])--(.*)$", encoded)
2545
+ if not drive_match:
2546
+ # Compatibility with older nmem-created expectations before we matched
2547
+ # Claude Code's drive-colon encoding on Windows.
2548
+ drive_match = re.match(r"^([A-Za-z])-(.*)$", encoded)
2545
2549
  if not drive_match:
2546
2550
  return None
2547
2551
 
@@ -2576,7 +2580,9 @@ def _encode_claude_project_path_variant(
2576
2580
  for segment in re.split(r"[\\/]+", rest)
2577
2581
  if segment
2578
2582
  ]
2579
- return "-".join([drive_letter, *segments]) if segments else drive_letter
2583
+ if not segments:
2584
+ return f"{drive_letter}--"
2585
+ return f"{drive_letter}--{'-'.join(segments)}"
2580
2586
 
2581
2587
  segments = [
2582
2588
  _encode_claude_path_segment(segment, dot_mode=dot_mode)
File without changes
File without changes