kd-cli 2.6.3__tar.gz → 2.6.4__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 (86) hide show
  1. {kd_cli-2.6.3/kd_cli.egg-info → kd_cli-2.6.4}/PKG-INFO +1 -1
  2. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/input.py +23 -3
  3. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/main.py +14 -7
  4. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/system/__init__.py +6 -6
  5. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/config.py +7 -7
  6. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/config_read.py +1 -1
  7. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/primer.py +1 -1
  8. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/resources/CHANGELOG.md +28 -0
  9. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/resources/operating-guide.md +1 -1
  10. {kd_cli-2.6.3 → kd_cli-2.6.4/kd_cli.egg-info}/PKG-INFO +1 -1
  11. {kd_cli-2.6.3 → kd_cli-2.6.4}/pyproject.toml +1 -1
  12. {kd_cli-2.6.3 → kd_cli-2.6.4}/LICENSE +0 -0
  13. {kd_cli-2.6.3 → kd_cli-2.6.4}/MANIFEST.in +0 -0
  14. {kd_cli-2.6.3 → kd_cli-2.6.4}/README.md +0 -0
  15. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/__init__.py +0 -0
  16. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/api/__init__.py +0 -0
  17. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/api/articles.py +0 -0
  18. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/api/http.py +0 -0
  19. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/api/hub.py +0 -0
  20. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/api/saved_queries.py +0 -0
  21. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/api/tags.py +0 -0
  22. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/api/youtrack.py +0 -0
  23. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/article_marker.py +0 -0
  24. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/auth.py +0 -0
  25. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cache.py +0 -0
  26. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/__init__.py +0 -0
  27. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/core/__init__.py +0 -0
  28. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/core/command_base.py +0 -0
  29. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/core/command_parser.py +0 -0
  30. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/core/confirm.py +0 -0
  31. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/core/namespaces.py +0 -0
  32. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/core/option_registry.py +0 -0
  33. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/__init__.py +0 -0
  34. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/alias/__init__.py +0 -0
  35. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/article/__init__.py +0 -0
  36. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/cache/__init__.py +0 -0
  37. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/init.py +0 -0
  38. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/issue/__init__.py +0 -0
  39. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/primer/__init__.py +0 -0
  40. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/project/__init__.py +0 -0
  41. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/query/__init__.py +0 -0
  42. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/release_notes.py +0 -0
  43. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/search/__init__.py +0 -0
  44. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/tag/__init__.py +0 -0
  45. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/time/__init__.py +0 -0
  46. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/namespaces/user/__init__.py +0 -0
  47. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/output.py +0 -0
  48. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/cli/tree.py +0 -0
  49. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/client.py +0 -0
  50. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/config_schema.py +0 -0
  51. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/connection.py +0 -0
  52. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/debug.py +0 -0
  53. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/exceptions.py +0 -0
  54. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/history.py +0 -0
  55. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/locking.py +0 -0
  56. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/__init__.py +0 -0
  57. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/article.py +0 -0
  58. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/assist.py +0 -0
  59. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/attachment.py +0 -0
  60. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/comment.py +0 -0
  61. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/common.py +0 -0
  62. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/issue.py +0 -0
  63. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/project.py +0 -0
  64. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/saved_query.py +0 -0
  65. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/search.py +0 -0
  66. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/tag.py +0 -0
  67. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/tag_entities.py +0 -0
  68. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/user.py +0 -0
  69. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/models/work_item.py +0 -0
  70. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/operating_guide.py +0 -0
  71. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/query_parser.py +0 -0
  72. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/release_notes.py +0 -0
  73. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/resources/__init__.py +0 -0
  74. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/resources/command-synonyms.yaml +0 -0
  75. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/resources/config-template.yaml +0 -0
  76. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/resources/error-messages.yaml +0 -0
  77. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/resources/primers/__init__.py +0 -0
  78. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/resources/primers/hitl.yaml +0 -0
  79. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/resources/sdlc-doctrine.md +0 -0
  80. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd/sdlc.py +0 -0
  81. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd_cli.egg-info/SOURCES.txt +0 -0
  82. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd_cli.egg-info/dependency_links.txt +0 -0
  83. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd_cli.egg-info/entry_points.txt +0 -0
  84. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd_cli.egg-info/requires.txt +0 -0
  85. {kd_cli-2.6.3 → kd_cli-2.6.4}/kd_cli.egg-info/top_level.txt +0 -0
  86. {kd_cli-2.6.3 → kd_cli-2.6.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kd-cli
3
- Version: 2.6.3
3
+ Version: 2.6.4
4
4
  Summary: Knowledge Dispatcher for issue trackers and knowledge bases
5
5
  Author: Sergiy Gladkyy
6
6
  License-Expression: MIT
@@ -25,9 +25,23 @@ def resolve_text_input(value: str | None) -> str | None:
25
25
  if not value:
26
26
  return value
27
27
  if value == "-":
28
- return sys.stdin.read()
28
+ try:
29
+ return sys.stdin.read()
30
+ except UnicodeDecodeError as e:
31
+ raise ValidationError(
32
+ f"Stdin input could not be decoded as UTF-8: {e.reason}",
33
+ suggestion="Ensure the upstream shell pipes UTF-8 bytes "
34
+ "(heredoc, pipe, or redirected file).",
35
+ ) from e
29
36
  if value == "@-":
30
- text = sys.stdin.read()
37
+ try:
38
+ text = sys.stdin.read()
39
+ except UnicodeDecodeError as e:
40
+ raise ValidationError(
41
+ f"Stdin input could not be decoded as UTF-8: {e.reason}",
42
+ suggestion="Ensure the upstream shell pipes UTF-8 bytes "
43
+ "(heredoc, pipe, or redirected file).",
44
+ ) from e
31
45
  if not text:
32
46
  raise ValidationError("No input received from stdin")
33
47
  return text
@@ -35,7 +49,13 @@ def resolve_text_input(value: str | None) -> str | None:
35
49
  file_path = Path(value[1:])
36
50
  if not file_path.is_file():
37
51
  raise ValidationError(f"File not found: {file_path}")
38
- text = file_path.read_text(encoding="utf-8")
52
+ try:
53
+ text = file_path.read_text(encoding="utf-8")
54
+ except UnicodeDecodeError as e:
55
+ raise ValidationError(
56
+ f"File {file_path} could not be decoded as UTF-8: {e.reason}",
57
+ suggestion="Save the file as UTF-8 (without a BOM) and retry.",
58
+ ) from e
39
59
  if not text:
40
60
  raise ValidationError(f"File is empty: {file_path}")
41
61
  return text
@@ -142,17 +142,24 @@ def _print_error(error: KdError) -> None:
142
142
 
143
143
 
144
144
  def _configure_windows_stdio() -> None:
145
- """Force UTF-8 on stdout/stderr when running on Windows.
146
-
147
- No-op on POSIX. Errors during reconfigure are swallowed; the wrapper's
148
- UnicodeEncodeError handler is the defensive backstop for the rare
149
- embedded-interpreter case where reconfigure is unavailable.
145
+ """Force UTF-8 on stdin/stdout/stderr when running on Windows.
146
+
147
+ No-op on POSIX. Stdout/stderr use ``errors="replace"`` so a single
148
+ corrupted byte never aborts a whole command's output. Stdin uses
149
+ ``errors="strict"`` so invalid bytes raise loudly rather than silently
150
+ writing replacement chars to disk via the input layer (see
151
+ ``kd/cli/input.py``). Errors during reconfigure are swallowed; embedded
152
+ interpreters and pytest captures may lack ``reconfigure`` on any of the
153
+ three streams.
150
154
  """
151
155
  if sys.platform != "win32":
152
156
  return
153
- for stream in (sys.stdout, sys.stderr):
157
+ for stream in (sys.stdin, sys.stdout, sys.stderr):
154
158
  try:
155
- stream.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr,unused-ignore]
159
+ stream.reconfigure( # type: ignore[union-attr,unused-ignore]
160
+ encoding="utf-8",
161
+ errors="strict" if stream is sys.stdin else "replace",
162
+ )
156
163
  except Exception:
157
164
  pass
158
165
 
@@ -709,7 +709,7 @@ def _resolve_target(name: str) -> tuple[Path, Path, str]:
709
709
 
710
710
  def _diff_summary(snapshot: SnapshotInfo, current_text: str) -> str:
711
711
  """One-line diff summary: ``+N -M`` lines vs current file."""
712
- snap_lines = snapshot.path.read_text().splitlines()
712
+ snap_lines = snapshot.path.read_text(encoding="utf-8").splitlines()
713
713
  curr_lines = current_text.splitlines()
714
714
  added = removed = 0
715
715
  for line in difflib.unified_diff(snap_lines, curr_lines, n=0):
@@ -751,7 +751,7 @@ class SystemHistoryCommand(Command):
751
751
  rows: list[dict[str, Any]] = []
752
752
  for target_name in targets:
753
753
  live_path, history_dir, filename = _resolve_target(target_name)
754
- current_text = live_path.read_text() if live_path.exists() else ""
754
+ current_text = live_path.read_text(encoding="utf-8") if live_path.exists() else ""
755
755
  for snap in list_snapshots(history_dir, filename):
756
756
  rows.append(
757
757
  {
@@ -791,7 +791,7 @@ class SystemRestoreCommand(Command):
791
791
  snap_path = get_snapshot_path(history_dir, filename, timestamp)
792
792
  # Snapshot current before restoring (so restore is undoable)
793
793
  snapshot_before_write(live_path)
794
- restored_text = snap_path.read_text()
794
+ restored_text = snap_path.read_text(encoding="utf-8")
795
795
  atomic_write_text(live_path, restored_text)
796
796
  return {
797
797
  "ok": True,
@@ -830,15 +830,15 @@ class SystemDiffCommand(Command):
830
830
  live_path, history_dir, filename = _resolve_target(target_name)
831
831
 
832
832
  snap_a = get_snapshot_path(history_dir, filename, args[1])
833
- text_a = snap_a.read_text()
833
+ text_a = snap_a.read_text(encoding="utf-8")
834
834
  label_a = f"{filename}.{args[1]}"
835
835
 
836
836
  if len(args) >= 3:
837
837
  snap_b = get_snapshot_path(history_dir, filename, args[2])
838
- text_b = snap_b.read_text()
838
+ text_b = snap_b.read_text(encoding="utf-8")
839
839
  label_b = f"{filename}.{args[2]}"
840
840
  else:
841
- text_b = live_path.read_text() if live_path.exists() else ""
841
+ text_b = live_path.read_text(encoding="utf-8") if live_path.exists() else ""
842
842
  label_b = filename
843
843
 
844
844
  result = diff_text(text_a, text_b, label_a, label_b)
@@ -406,7 +406,7 @@ def load_config(path: Path | None = None) -> YtctlConfig:
406
406
  if not config_path.exists():
407
407
  return YtctlConfig()
408
408
  try:
409
- raw = yaml.safe_load(config_path.read_text()) or {}
409
+ raw = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
410
410
  return YtctlConfig(**raw)
411
411
  except (yaml.YAMLError, TypeError, ValueError) as e:
412
412
  raise ConfigError(f"Invalid config at {config_path}: {e}") from e
@@ -511,7 +511,7 @@ def update_config_path(path: str, value: str, config_path: Path) -> tuple[str, A
511
511
  # Load raw YAML, capture original text for rollback.
512
512
  raw = _load_raw_yaml(config_path)
513
513
  original_text: str | None
514
- original_text = config_path.read_text() if config_path.exists() else None
514
+ original_text = config_path.read_text(encoding="utf-8") if config_path.exists() else None
515
515
 
516
516
  retention = _retention_from_raw(raw, DEFAULT_RETENTION)
517
517
  snapshot_before_write(config_path, retention=retention)
@@ -619,7 +619,7 @@ def _load_raw_yaml(path: Path) -> dict[str, Any]:
619
619
  if not path.exists():
620
620
  return {}
621
621
  try:
622
- data = yaml.safe_load(path.read_text())
622
+ data = yaml.safe_load(path.read_text(encoding="utf-8"))
623
623
  except yaml.YAMLError as e:
624
624
  raise ConfigError(f"Invalid YAML in {path}: {e}") from e
625
625
  return data or {}
@@ -1395,16 +1395,16 @@ def _manage_gitignore(directory: Path) -> str:
1395
1395
 
1396
1396
  gitignore = git_root / ".gitignore"
1397
1397
  if gitignore.exists():
1398
- content = gitignore.read_text()
1398
+ content = gitignore.read_text(encoding="utf-8")
1399
1399
  lines = {line.strip() for line in content.splitlines()}
1400
1400
  if lines & _GITIGNORE_PATTERNS:
1401
1401
  return "already_ignored"
1402
1402
  # Append with a trailing newline if file doesn't end with one
1403
1403
  sep = "" if content.endswith("\n") else "\n"
1404
- gitignore.write_text(f"{content}{sep}\n# kd local config\n.kd/\n")
1404
+ gitignore.write_text(f"{content}{sep}\n# kd local config\n.kd/\n", encoding="utf-8")
1405
1405
  return "added"
1406
1406
 
1407
- gitignore.write_text("# kd local config\n.kd/\n")
1407
+ gitignore.write_text("# kd local config\n.kd/\n", encoding="utf-8")
1408
1408
  return "created"
1409
1409
 
1410
1410
 
@@ -1466,7 +1466,7 @@ def init_project_config(
1466
1466
  )
1467
1467
 
1468
1468
  config_dir.mkdir(parents=True, exist_ok=True)
1469
- config_path.write_text(template)
1469
+ config_path.write_text(template, encoding="utf-8")
1470
1470
 
1471
1471
  if global_tier:
1472
1472
  gitignore_action = "not_applicable"
@@ -174,7 +174,7 @@ def _get_history(path: str, key: str) -> dict[str, Any] | None:
174
174
  if value is None:
175
175
  continue
176
176
  # Only surface values actually written to the file, not schema defaults.
177
- raw = yaml.safe_load(tier_path.read_text()) or {}
177
+ raw = yaml.safe_load(tier_path.read_text(encoding="utf-8")) or {}
178
178
  history_block = raw.get("history") if isinstance(raw.get("history"), dict) else {}
179
179
  if not isinstance(history_block, dict) or key not in history_block:
180
180
  continue
@@ -121,7 +121,7 @@ def load_primer(path: Path | None = None) -> PrimerData:
121
121
  if not primer_file.exists():
122
122
  return PrimerData()
123
123
  try:
124
- raw = yaml.safe_load(primer_file.read_text()) or {}
124
+ raw = yaml.safe_load(primer_file.read_text(encoding="utf-8")) or {}
125
125
  return PrimerData(**raw)
126
126
  except (yaml.YAMLError, TypeError, ValueError) as e:
127
127
  raise ConfigError(f"Invalid primer at {primer_file}: {e}") from e
@@ -4,6 +4,34 @@ All notable changes to kd-cli are recorded here. The project follows [Semantic V
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.6.4] — 2026-04-30
8
+
9
+ This release closes the Windows UTF-8 audit started in 2.6.3. The
10
+ stream-encoding side (stdout/stderr) shipped earlier; 2.6.4 closes the
11
+ file-IO and stdin sides so primer notes, `--content @file`, and heredoc
12
+ or piped input round-trip non-cp1252 characters cleanly.
13
+
14
+ ### Fixed
15
+ - File reads and writes on Windows are now explicit UTF-8 at every
16
+ kd-owned text-IO call site (primer, config, history/diff snapshots,
17
+ `--description @file` / `--content @file` content). The headline
18
+ reproducer was `kd /primer show` raising `'charmap' codec can't
19
+ decode byte 0x9d` whenever `.kd/primer.yaml` contained any non-cp1252
20
+ byte (em-dash, arrow, right double quotation mark) — a single primer
21
+ note authored on macOS/Linux was enough to read-block every
22
+ downstream Windows session (KDCLI-170).
23
+ - Stdin on Windows is now forced to UTF-8 with strict error handling,
24
+ so heredocs and pipes carrying non-ASCII content (em-dash, arrow,
25
+ right double quotation mark) into `kd /primer/note update -`,
26
+ `kd /article create --content @-`, `--description -`, or any other
27
+ stdin-consuming command no longer get cp1252-mojibaked at the input
28
+ layer before being persisted. Invalid UTF-8 bytes on stdin (and
29
+ non-UTF-8 `@file` content) now surface as a clean
30
+ `Error: Stdin input could not be decoded as UTF-8 ... / Hint: Ensure
31
+ the upstream shell pipes UTF-8 bytes ...` (or
32
+ `Hint: Save the file as UTF-8 ...`) instead of the generic "internal
33
+ error: ... This is a bug." block (KDCLI-169).
34
+
7
35
  ## [2.6.3] — 2026-04-30
8
36
 
9
37
  This release focuses on Windows shakedown: encoding crashes, primer
@@ -244,7 +244,7 @@ kd -DDD /issue list --project KDCLI
244
244
 
245
245
  Debug output goes to stderr and tokens are redacted. Use `-DDD` when investigating upstream API behavior because it includes request and response details.
246
246
 
247
- On Windows, kd forces UTF-8 stdout and stderr at the entry point so non-ASCII characters (`→`, `—`, `≤`, em-dash) render correctly regardless of the console's default code page (cp1252 on most installs). No `PYTHONIOENCODING` workaround is needed.
247
+ On Windows, kd forces UTF-8 on stdin, stdout, and stderr at the entry point so non-ASCII characters (`→`, `—`, `≤`, em-dash) render correctly regardless of the console's default code page (cp1252 on most installs), and every kd-owned file read/write (primer, config, history snapshots, `--content @file` and `--description @file`) uses explicit UTF-8 so primer/config files written by macOS or Linux load cleanly on Windows. Stdin uses strict decoding so invalid UTF-8 piped into `kd /primer/note update -` or `kd /article create --content @-` fails loudly with a clear diagnostic (`Error: Stdin input could not be decoded as UTF-8 ...`) rather than silently corrupting persisted content. No `PYTHONIOENCODING` or `PYTHONUTF8` workaround is needed.
248
248
 
249
249
  Unhandled exceptions render a one-line or one-paragraph friendly diagnostic and exit non-zero. To see the full traceback (for bug reports or local debugging), re-run with `--debug` / `-D`; the wrapper re-raises the original exception so the runtime prints the traceback. `KdError` (expected user-facing failures) keep their existing one-line `Error: ...` / optional `Hint: ...` shape on every platform.
250
250
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kd-cli
3
- Version: 2.6.3
3
+ Version: 2.6.4
4
4
  Summary: Knowledge Dispatcher for issue trackers and knowledge bases
5
5
  Author: Sergiy Gladkyy
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "kd-cli"
7
- version = "2.6.3"
7
+ version = "2.6.4"
8
8
  description = "Knowledge Dispatcher for issue trackers and knowledge bases"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes