comate-cli 0.4.0__tar.gz → 0.4.1__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 (127) hide show
  1. {comate_cli-0.4.0 → comate_cli-0.4.1}/PKG-INFO +1 -1
  2. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/mention_completer.py +69 -0
  3. {comate_cli-0.4.0 → comate_cli-0.4.1}/pyproject.toml +1 -1
  4. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_mention_completer.py +34 -0
  5. comate_cli-0.4.1/uv.lock +2231 -0
  6. comate_cli-0.4.0/uv.lock +0 -2215
  7. {comate_cli-0.4.0 → comate_cli-0.4.1}/.gitignore +0 -0
  8. {comate_cli-0.4.0 → comate_cli-0.4.1}/README.md +0 -0
  9. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/__init__.py +0 -0
  10. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/__main__.py +0 -0
  11. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/main.py +0 -0
  12. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/mcp_cli.py +0 -0
  13. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/__init__.py +0 -0
  14. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/animations.py +0 -0
  15. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/app.py +0 -0
  16. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/assistant_render.py +0 -0
  17. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/codenames.py +0 -0
  18. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/custom_slash_commands.py +0 -0
  19. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/env_utils.py +0 -0
  20. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/error_display.py +0 -0
  21. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/event_renderer.py +0 -0
  22. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/fragment_utils.py +0 -0
  23. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/history_printer.py +0 -0
  24. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/input_geometry.py +0 -0
  25. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/layout_coordinator.py +0 -0
  26. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/logging_adapter.py +0 -0
  27. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/logo.py +0 -0
  28. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/markdown_render.py +0 -0
  29. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/message_style.py +0 -0
  30. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/models.py +0 -0
  31. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/path_context_hint.py +0 -0
  32. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/__init__.py +0 -0
  33. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/components/__init__.py +0 -0
  34. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/components/detail_view.py +0 -0
  35. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/components/plugin_list.py +0 -0
  36. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/components/search_box.py +0 -0
  37. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/components/tab_bar.py +0 -0
  38. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/marketplace_install_view.py +0 -0
  39. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/plugin_picker.py +0 -0
  40. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/tabs/__init__.py +0 -0
  41. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/tabs/discover_tab.py +0 -0
  42. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/tabs/errors_tab.py +0 -0
  43. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/tabs/installed_tab.py +0 -0
  44. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/plugins/tabs/marketplaces_tab.py +0 -0
  45. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/preflight.py +0 -0
  46. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/question_view.py +0 -0
  47. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/resume_selector.py +0 -0
  48. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/rewind_store.py +0 -0
  49. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/rpc_protocol.py +0 -0
  50. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/rpc_stdio.py +0 -0
  51. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/selection_menu.py +0 -0
  52. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/session_view.py +0 -0
  53. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/slash_commands.py +0 -0
  54. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/startup.py +0 -0
  55. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/status_bar.py +0 -0
  56. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/text_effects.py +0 -0
  57. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tips.py +0 -0
  58. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tool_view.py +0 -0
  59. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tui.py +0 -0
  60. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tui_parts/__init__.py +0 -0
  61. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tui_parts/commands.py +0 -0
  62. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tui_parts/history_sync.py +0 -0
  63. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tui_parts/input_behavior.py +0 -0
  64. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tui_parts/key_bindings.py +0 -0
  65. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tui_parts/render_panels.py +0 -0
  66. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tui_parts/slash_command_registry.py +0 -0
  67. {comate_cli-0.4.0 → comate_cli-0.4.1}/comate_cli/terminal_agent/tui_parts/ui_mode.py +0 -0
  68. {comate_cli-0.4.0 → comate_cli-0.4.1}/docs/superpowers/specs/2026-04-01-conditional-diff-subtitle-design.md +0 -0
  69. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/conftest.py +0 -0
  70. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_app_mcp_preload.py +0 -0
  71. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_app_preflight_gate.py +0 -0
  72. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_app_print_mode.py +0 -0
  73. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_app_shutdown.py +0 -0
  74. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_app_usage_line.py +0 -0
  75. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_cli_project_root.py +0 -0
  76. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_compact_command_semantics.py +0 -0
  77. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_completion_context_activation.py +0 -0
  78. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_completion_status_panel.py +0 -0
  79. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_context_command.py +0 -0
  80. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_custom_slash_commands.py +0 -0
  81. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_discover_tab.py +0 -0
  82. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_errors_tab.py +0 -0
  83. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_event_renderer.py +0 -0
  84. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_format_error.py +0 -0
  85. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_handle_error.py +0 -0
  86. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_history_printer.py +0 -0
  87. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_history_sync.py +0 -0
  88. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_input_behavior.py +0 -0
  89. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_input_history.py +0 -0
  90. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_installed_tab.py +0 -0
  91. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_interrupt_exit_semantics.py +0 -0
  92. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_layout_coordinator.py +0 -0
  93. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_logging_adapter.py +0 -0
  94. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_logo.py +0 -0
  95. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_main_args.py +0 -0
  96. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_marketplaces_tab.py +0 -0
  97. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_mcp_cli.py +0 -0
  98. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_mcp_slash_command.py +0 -0
  99. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_path_context_hint.py +0 -0
  100. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_plugin_slash_commands.py +0 -0
  101. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_plugin_tui_components.py +0 -0
  102. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_preflight.py +0 -0
  103. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_preflight_copilot.py +0 -0
  104. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_question_key_bindings.py +0 -0
  105. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_question_view.py +0 -0
  106. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_resume_selector.py +0 -0
  107. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_rewind_command_semantics.py +0 -0
  108. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_rewind_store.py +0 -0
  109. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_rpc_protocol.py +0 -0
  110. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_rpc_stdio_bridge.py +0 -0
  111. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_selection_menu.py +0 -0
  112. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_skills_slash_command.py +0 -0
  113. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_slash_argument_hint.py +0 -0
  114. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_slash_completer.py +0 -0
  115. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_slash_registry.py +0 -0
  116. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_status_bar.py +0 -0
  117. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_status_bar_transient.py +0 -0
  118. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_task_panel_format.py +0 -0
  119. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_task_panel_key_bindings.py +0 -0
  120. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_task_panel_rendering.py +0 -0
  121. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_task_poll.py +0 -0
  122. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_tool_view.py +0 -0
  123. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_tui_elapsed_status.py +0 -0
  124. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_tui_mcp_init_gate.py +0 -0
  125. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_tui_paste_placeholder.py +0 -0
  126. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_tui_split_invariance.py +0 -0
  127. {comate_cli-0.4.0 → comate_cli-0.4.1}/tests/test_update_check.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: comate-cli
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Comate terminal CLI built on comate-agent-sdk
5
5
  Project-URL: Homepage, https://github.com/AndyLee1024/agent-sdk
6
6
  Project-URL: Repository, https://github.com/AndyLee1024/agent-sdk
@@ -113,6 +113,7 @@ class LocalFileMentionCompleter(Completer):
113
113
 
114
114
  self._deep_cache_time: float = 0.0
115
115
  self._deep_cached_paths: list[str] = []
116
+ self._directory_cached_paths: dict[str, tuple[float, list[str]]] = {}
116
117
 
117
118
  @classmethod
118
119
  def _is_ignored(cls, name: str) -> bool:
@@ -146,6 +147,18 @@ class LocalFileMentionCompleter(Completer):
146
147
  return None
147
148
 
148
149
  fragment_lower = context.fragment.lower()
150
+ directory_source = self._get_directory_candidates(context.fragment)
151
+ if directory_source is not None:
152
+ matched = [
153
+ path
154
+ for path in directory_source
155
+ if not fragment_lower or path.lower().startswith(fragment_lower)
156
+ ]
157
+ if not matched:
158
+ return None
159
+ matched.sort(key=str.lower)
160
+ return context, matched[: max(max_items, 1)]
161
+
149
162
  source = self._candidate_paths(context.fragment)
150
163
  if not source:
151
164
  return None
@@ -203,6 +216,62 @@ class LocalFileMentionCompleter(Completer):
203
216
  return self._get_top_level_paths()
204
217
  return self._get_deep_paths()
205
218
 
219
+ def _get_directory_candidates(self, fragment: str) -> list[str] | None:
220
+ directory_fragment = self._directory_fragment(fragment)
221
+ if directory_fragment is None:
222
+ return None
223
+ return self._get_directory_paths(directory_fragment)
224
+
225
+ def _directory_fragment(self, fragment: str) -> str | None:
226
+ if "/" not in fragment:
227
+ return None
228
+ if fragment.startswith(("/", "~")):
229
+ return None
230
+ directory_fragment = fragment if fragment.endswith("/") else fragment.rpartition("/")[0]
231
+ if directory_fragment in ("", "."):
232
+ return ""
233
+ return directory_fragment
234
+
235
+ def _get_directory_paths(self, directory_fragment: str) -> list[str]:
236
+ cache_key = directory_fragment or "."
237
+ now = time.monotonic()
238
+ cached = self._directory_cached_paths.get(cache_key)
239
+ if cached is not None:
240
+ cached_at, cached_paths = cached
241
+ if now - cached_at <= self._refresh_interval:
242
+ return cached_paths
243
+
244
+ directory = self._resolve_directory(directory_fragment)
245
+ if directory is None:
246
+ return []
247
+
248
+ prefix = f"{directory_fragment.rstrip('/')}/" if directory_fragment else ""
249
+ entries: list[str] = []
250
+ try:
251
+ for entry in sorted(directory.iterdir(), key=lambda path: path.name):
252
+ name = entry.name
253
+ if self._is_ignored(name):
254
+ continue
255
+ entries.append(f"{prefix}{name}/" if entry.is_dir() else f"{prefix}{name}")
256
+ if len(entries) >= self._limit:
257
+ break
258
+ except OSError as exc:
259
+ logger.debug("directory mention scan failed for %s: %s", directory_fragment, exc)
260
+ return cached[1] if cached is not None else []
261
+
262
+ self._directory_cached_paths[cache_key] = (now, entries)
263
+ return entries
264
+
265
+ def _resolve_directory(self, directory_fragment: str) -> Path | None:
266
+ try:
267
+ candidate = (self._root / directory_fragment).resolve()
268
+ candidate.relative_to(self._root.resolve())
269
+ except (OSError, ValueError):
270
+ return None
271
+ if not candidate.is_dir():
272
+ return None
273
+ return candidate
274
+
206
275
  def _get_top_level_paths(self) -> list[str]:
207
276
  now = time.monotonic()
208
277
  if now - self._top_cache_time <= self._refresh_interval:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "comate-cli"
7
- version = "0.4.0"
7
+ version = "0.4.1"
8
8
  description = "Comate terminal CLI built on comate-agent-sdk"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -64,6 +64,40 @@ class TestLocalFileMentionCompleter(unittest.TestCase):
64
64
  texts = [completion.text for completion in completions]
65
65
  self.assertIn("main.py ", texts)
66
66
 
67
+ def test_directory_prefix_completion_is_not_lost_after_large_tree_scan(self) -> None:
68
+ for index in range(1200):
69
+ nested = self.root / "bulk" / f"dir{index}"
70
+ nested.mkdir(parents=True, exist_ok=True)
71
+ (nested / f"file{index}.txt").write_text("x", encoding="utf-8")
72
+
73
+ target_dir = self.root / "target" / "sub"
74
+ target_dir.mkdir(parents=True, exist_ok=True)
75
+ (target_dir / "wanted.py").write_text("pass", encoding="utf-8")
76
+
77
+ result = self.completer.suggest("@target/", max_items=8)
78
+
79
+ self.assertIsNotNone(result)
80
+ assert result is not None
81
+ _, candidates = result
82
+ self.assertIn("target/sub/", candidates)
83
+
84
+ def test_existing_directory_prefix_continues_to_suggest_children(self) -> None:
85
+ for index in range(1200):
86
+ nested = self.root / "bulk" / f"dir{index}"
87
+ nested.mkdir(parents=True, exist_ok=True)
88
+ (nested / f"file{index}.txt").write_text("x", encoding="utf-8")
89
+
90
+ target_dir = self.root / "target" / "sub"
91
+ target_dir.mkdir(parents=True, exist_ok=True)
92
+ (target_dir / "wanted.py").write_text("pass", encoding="utf-8")
93
+
94
+ result = self.completer.suggest("@target/s", max_items=8)
95
+
96
+ self.assertIsNotNone(result)
97
+ assert result is not None
98
+ _, candidates = result
99
+ self.assertIn("target/sub/", candidates)
100
+
67
101
 
68
102
  if __name__ == "__main__":
69
103
  unittest.main(verbosity=2)