kash-shell 0.3.9__py3-none-any.whl → 0.3.11__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.
Files changed (151) hide show
  1. kash/actions/__init__.py +4 -4
  2. kash/actions/core/format_markdown_template.py +2 -5
  3. kash/actions/core/markdownify.py +7 -6
  4. kash/actions/core/readability.py +7 -6
  5. kash/actions/core/render_as_html.py +37 -0
  6. kash/actions/core/show_webpage.py +6 -11
  7. kash/actions/core/strip_html.py +2 -6
  8. kash/actions/core/tabbed_webpage_config.py +31 -0
  9. kash/actions/core/{webpage_generate.py → tabbed_webpage_generate.py} +5 -4
  10. kash/commands/__init__.py +8 -20
  11. kash/commands/base/basic_file_commands.py +15 -0
  12. kash/commands/base/debug_commands.py +13 -0
  13. kash/commands/base/files_command.py +28 -10
  14. kash/commands/base/general_commands.py +21 -16
  15. kash/commands/base/logs_commands.py +4 -2
  16. kash/commands/base/model_commands.py +8 -8
  17. kash/commands/base/search_command.py +3 -2
  18. kash/commands/base/show_command.py +5 -3
  19. kash/commands/extras/parse_uv_lock.py +186 -0
  20. kash/commands/help/doc_commands.py +2 -31
  21. kash/commands/help/welcome.py +33 -0
  22. kash/commands/workspace/selection_commands.py +11 -6
  23. kash/commands/workspace/workspace_commands.py +19 -17
  24. kash/config/colors.py +3 -1
  25. kash/config/env_settings.py +14 -1
  26. kash/config/init.py +2 -2
  27. kash/config/logger.py +59 -56
  28. kash/config/logger_basic.py +3 -3
  29. kash/config/settings.py +116 -57
  30. kash/config/setup.py +28 -12
  31. kash/config/text_styles.py +3 -13
  32. kash/docs/load_api_docs.py +2 -1
  33. kash/docs/markdown/topics/a3_getting_started.md +3 -2
  34. kash/{concepts → embeddings}/text_similarity.py +2 -2
  35. kash/exec/__init__.py +20 -3
  36. kash/exec/action_decorators.py +24 -10
  37. kash/exec/action_exec.py +41 -23
  38. kash/exec/action_registry.py +13 -48
  39. kash/exec/command_registry.py +2 -1
  40. kash/exec/fetch_url_metadata.py +4 -6
  41. kash/exec/importing.py +56 -0
  42. kash/exec/llm_transforms.py +12 -10
  43. kash/exec/precondition_registry.py +2 -1
  44. kash/exec/preconditions.py +22 -1
  45. kash/exec/resolve_args.py +4 -0
  46. kash/exec/shell_callable_action.py +33 -19
  47. kash/file_storage/file_store.py +42 -27
  48. kash/file_storage/item_file_format.py +5 -2
  49. kash/file_storage/metadata_dirs.py +11 -2
  50. kash/help/assistant.py +1 -1
  51. kash/help/assistant_instructions.py +2 -1
  52. kash/help/function_param_info.py +1 -1
  53. kash/help/help_embeddings.py +2 -2
  54. kash/help/help_printing.py +7 -11
  55. kash/llm_utils/clean_headings.py +1 -1
  56. kash/llm_utils/llm_api_keys.py +4 -4
  57. kash/llm_utils/llm_features.py +68 -0
  58. kash/llm_utils/llm_messages.py +1 -2
  59. kash/llm_utils/llm_names.py +1 -1
  60. kash/llm_utils/llms.py +8 -3
  61. kash/local_server/__init__.py +5 -2
  62. kash/local_server/local_server.py +8 -5
  63. kash/local_server/local_server_commands.py +2 -2
  64. kash/local_server/local_server_routes.py +1 -7
  65. kash/local_server/local_url_formatters.py +1 -1
  66. kash/mcp/__init__.py +5 -2
  67. kash/mcp/mcp_cli.py +5 -5
  68. kash/mcp/mcp_server_commands.py +5 -5
  69. kash/mcp/mcp_server_routes.py +5 -5
  70. kash/mcp/mcp_server_sse.py +4 -2
  71. kash/media_base/media_cache.py +8 -8
  72. kash/media_base/media_services.py +1 -1
  73. kash/media_base/media_tools.py +6 -6
  74. kash/media_base/services/local_file_media.py +2 -2
  75. kash/media_base/{speech_transcription.py → transcription_deepgram.py} +25 -110
  76. kash/media_base/transcription_format.py +73 -0
  77. kash/media_base/transcription_whisper.py +38 -0
  78. kash/model/__init__.py +73 -5
  79. kash/model/actions_model.py +38 -4
  80. kash/model/concept_model.py +30 -0
  81. kash/model/items_model.py +115 -32
  82. kash/model/params_model.py +24 -0
  83. kash/shell/completions/completion_scoring.py +37 -5
  84. kash/shell/output/kerm_codes.py +1 -2
  85. kash/shell/output/shell_formatting.py +14 -4
  86. kash/shell/shell_main.py +2 -2
  87. kash/shell/utils/exception_printing.py +6 -0
  88. kash/shell/utils/native_utils.py +26 -20
  89. kash/shell/utils/shell_function_wrapper.py +15 -15
  90. kash/text_handling/custom_sliding_transforms.py +12 -4
  91. kash/text_handling/doc_normalization.py +6 -2
  92. kash/text_handling/markdown_render.py +118 -0
  93. kash/text_handling/markdown_utils.py +226 -0
  94. kash/utils/common/function_inspect.py +360 -110
  95. kash/utils/common/import_utils.py +12 -3
  96. kash/utils/common/type_utils.py +0 -29
  97. kash/utils/common/url.py +27 -3
  98. kash/utils/errors.py +6 -0
  99. kash/utils/file_utils/file_ext.py +4 -0
  100. kash/utils/file_utils/file_formats.py +2 -2
  101. kash/utils/file_utils/file_formats_model.py +20 -1
  102. kash/web_content/dir_store.py +1 -2
  103. kash/web_content/file_cache_utils.py +37 -10
  104. kash/web_content/file_processing.py +68 -0
  105. kash/web_content/local_file_cache.py +12 -9
  106. kash/web_content/web_extract.py +8 -3
  107. kash/web_content/web_fetch.py +12 -4
  108. kash/web_gen/__init__.py +0 -4
  109. kash/web_gen/simple_webpage.py +52 -0
  110. kash/web_gen/tabbed_webpage.py +24 -14
  111. kash/web_gen/template_render.py +37 -2
  112. kash/web_gen/templates/base_styles.css.jinja +169 -43
  113. kash/web_gen/templates/base_webpage.html.jinja +110 -45
  114. kash/web_gen/templates/content_styles.css.jinja +4 -2
  115. kash/web_gen/templates/item_view.html.jinja +49 -39
  116. kash/web_gen/templates/simple_webpage.html.jinja +24 -0
  117. kash/web_gen/templates/tabbed_webpage.html.jinja +42 -33
  118. kash/workspaces/__init__.py +15 -2
  119. kash/workspaces/selections.py +18 -3
  120. kash/workspaces/source_items.py +0 -1
  121. kash/workspaces/workspaces.py +5 -11
  122. kash/xonsh_custom/command_nl_utils.py +40 -19
  123. kash/xonsh_custom/custom_shell.py +43 -11
  124. kash/xonsh_custom/customize_prompt.py +39 -21
  125. kash/xonsh_custom/load_into_xonsh.py +22 -25
  126. kash/xonsh_custom/shell_load_commands.py +2 -2
  127. kash/xonsh_custom/xonsh_completers.py +2 -249
  128. kash/xonsh_custom/xonsh_keybindings.py +282 -0
  129. kash/xonsh_custom/xonsh_modern_tools.py +3 -3
  130. kash/xontrib/kash_extension.py +5 -6
  131. {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/METADATA +10 -8
  132. {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/RECORD +137 -136
  133. kash/actions/core/webpage_config.py +0 -21
  134. kash/concepts/concept_formats.py +0 -23
  135. kash/shell/clideps/api_keys.py +0 -100
  136. kash/shell/clideps/dotenv_setup.py +0 -115
  137. kash/shell/clideps/dotenv_utils.py +0 -98
  138. kash/shell/clideps/pkg_deps.py +0 -257
  139. kash/shell/clideps/platforms.py +0 -11
  140. kash/shell/clideps/terminal_features.py +0 -56
  141. kash/shell/utils/osc_utils.py +0 -95
  142. kash/shell/utils/terminal_images.py +0 -133
  143. kash/text_handling/markdown_util.py +0 -167
  144. kash/utils/common/atomic_var.py +0 -171
  145. kash/utils/common/string_replace.py +0 -93
  146. kash/utils/common/string_template.py +0 -101
  147. /kash/{concepts → embeddings}/cosine.py +0 -0
  148. /kash/{concepts → embeddings}/embeddings.py +0 -0
  149. {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/WHEEL +0 -0
  150. {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/entry_points.txt +0 -0
  151. {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,282 @@
1
+ import re
2
+ from dataclasses import dataclass
3
+
4
+ from prompt_toolkit import search
5
+ from prompt_toolkit.application import get_app
6
+ from prompt_toolkit.filters import Condition
7
+ from prompt_toolkit.key_binding import KeyBindings, merge_key_bindings
8
+ from prompt_toolkit.key_binding.key_processor import KeyPressEvent
9
+ from prompt_toolkit.shortcuts import print_formatted_text
10
+ from strif import AtomicVar
11
+ from xonsh.parsers.completion_context import CommandContext
12
+
13
+ from kash.actions.core.assistant_chat import assistant_chat
14
+ from kash.config.logger import get_logger
15
+ from kash.shell.completions.completion_types import ScoredCompletion
16
+ from kash.shell.completions.shell_completions import (
17
+ trace_completions,
18
+ )
19
+ from kash.shell.ui.shell_syntax import assist_request_str
20
+ from kash.xonsh_custom.shell_which import is_valid_command
21
+
22
+ log = get_logger(__name__)
23
+
24
+
25
+ @dataclass
26
+ class MultiTabState:
27
+ last_context: CommandContext | None = None
28
+ first_results_shown: bool = False
29
+ more_results_requested: bool = False
30
+ more_completions: set[ScoredCompletion] | None = None
31
+
32
+ def reset_first_results(self, context: CommandContext):
33
+ self.last_context = context
34
+ self.first_results_shown = True
35
+ self.more_results_requested = False
36
+ self.more_completions = None
37
+
38
+ def could_show_more(self) -> bool:
39
+ return self.first_results_shown and not self.more_results_requested
40
+
41
+
42
+ # Maintain state for help completions for single and double tab.
43
+ # TODO: Move this into the CompletionContext.
44
+ _MULTI_TAB_STATE = AtomicVar(MultiTabState())
45
+
46
+
47
+ @Condition
48
+ def is_unquoted_assist_request():
49
+ app = get_app()
50
+ buf = app.current_buffer
51
+ text = buf.text.strip()
52
+ is_default_buffer = buf.name == "DEFAULT_BUFFER"
53
+ has_prefix = text.startswith("?") and not (text.startswith('? "') or text.startswith("? '"))
54
+ return is_default_buffer and has_prefix
55
+
56
+
57
+ _command_regex = re.compile(r"^[a-zA-Z0-9_-]+$")
58
+
59
+ _python_keyword_regex = re.compile(
60
+ r"assert|async|await|break|class|continue|def|del|elif|else|except|finally|"
61
+ r"for|from|global|if|import|lambda|nonlocal|pass|raise|return|try|while|with|yield"
62
+ )
63
+
64
+
65
+ def _extract_command_name(text: str) -> str | None:
66
+ text = text.split()[0]
67
+ if _python_keyword_regex.match(text):
68
+ return None
69
+ if _command_regex.match(text):
70
+ return text
71
+ return None
72
+
73
+
74
+ @Condition
75
+ def whitespace_only() -> bool:
76
+ app = get_app()
77
+ buf = app.current_buffer
78
+ return not buf.text.strip()
79
+
80
+
81
+ @Condition
82
+ def is_typo_command() -> bool:
83
+ """
84
+ Is the command itself invalid? Should be conservative, so we can suppress
85
+ executing it if it is definitely a typo.
86
+ """
87
+
88
+ app = get_app()
89
+ buf = app.current_buffer
90
+ text = buf.text.strip()
91
+
92
+ is_default_buffer = buf.name == "DEFAULT_BUFFER"
93
+ if not is_default_buffer:
94
+ return False
95
+
96
+ # Assistant NL requests always allowed.
97
+ has_assistant_prefix = text.startswith("?") or text.rstrip().endswith("?")
98
+ if has_assistant_prefix:
99
+ return False
100
+
101
+ # Anything more complex is probably Python.
102
+ # TODO: Do a better syntax parse of this as Python, or use xonsh's algorithm.
103
+ for s in ["\n", "(", ")"]:
104
+ if s in text:
105
+ return False
106
+
107
+ # Empty command line allowed.
108
+ if not text:
109
+ return False
110
+
111
+ # Now look at the command.
112
+ command_name = _extract_command_name(text)
113
+
114
+ # Python or missing command is fine.
115
+ if not command_name:
116
+ return False
117
+
118
+ # Recognized command.
119
+ if is_valid_command(command_name):
120
+ return False
121
+
122
+ # Okay it's almost certainly a command typo.
123
+ return True
124
+
125
+
126
+ @Condition
127
+ def is_completion_menu_active() -> bool:
128
+ app = get_app()
129
+ return app.current_buffer.complete_state is not None
130
+
131
+
132
+ @Condition
133
+ def could_show_more_tab_completions() -> bool:
134
+ return _MULTI_TAB_STATE.value.could_show_more()
135
+
136
+
137
+ # Set up prompt_toolkit key bindings.
138
+ def add_key_bindings() -> None:
139
+ custom_bindings = KeyBindings()
140
+
141
+ # Need to be careful only to bind with a filter if the state is suitable.
142
+ # Only add more completions if we've seen some results but user hasn't pressed
143
+ # tab a second time yet. Otherwise the behavior should fall back to usual ptk
144
+ # tab behavior (selecting each completion one by one).
145
+ @custom_bindings.add("tab", filter=could_show_more_tab_completions)
146
+ def _(event: KeyPressEvent):
147
+ """
148
+ Add a second tab to show more completions.
149
+ """
150
+ with _MULTI_TAB_STATE.updates() as state:
151
+ state.more_results_requested = True
152
+
153
+ trace_completions("More completion results requested", state)
154
+
155
+ # Restart completions.
156
+ buf = event.app.current_buffer
157
+ buf.complete_state = None
158
+ buf.start_completion()
159
+
160
+ @custom_bindings.add("s-tab")
161
+ def _(event: KeyPressEvent):
162
+ with _MULTI_TAB_STATE.updates() as state:
163
+ state.more_results_requested = True
164
+
165
+ trace_completions("More completion results requested", state)
166
+
167
+ # Restart completions.
168
+ buf = event.app.current_buffer
169
+ buf.complete_state = None
170
+ buf.start_completion()
171
+
172
+ @custom_bindings.add(" ", filter=whitespace_only)
173
+ def _(event: KeyPressEvent):
174
+ """
175
+ Map space at the start of the line to `? ` to invoke an assistant question.
176
+ """
177
+ buf = event.app.current_buffer
178
+ if buf.text == " " or buf.text == "":
179
+ buf.delete_before_cursor(len(buf.text))
180
+ buf.insert_text("? ")
181
+ else:
182
+ buf.insert_text(" ")
183
+
184
+ @custom_bindings.add(" ", filter=is_typo_command)
185
+ def _(event: KeyPressEvent):
186
+ """
187
+ If the user types two words and the first word is likely an invalid
188
+ command, jump back to prefix the whole line with `? ` to make it clear we're
189
+ in natural language mode.
190
+ """
191
+
192
+ buf = event.app.current_buffer
193
+ text = buf.text.strip()
194
+
195
+ if (
196
+ buf.cursor_position == len(buf.text)
197
+ and len(text.split()) >= 2
198
+ and not text.startswith("?")
199
+ ):
200
+ buf.transform_current_line(lambda line: "? " + line)
201
+ buf.cursor_position += 2
202
+
203
+ buf.insert_text(" ")
204
+
205
+ @custom_bindings.add("enter", filter=whitespace_only)
206
+ def _(_event: KeyPressEvent):
207
+ """
208
+ Suppress enter if the command line is empty, but add a newline above the prompt.
209
+ """
210
+ print_formatted_text("")
211
+
212
+ @custom_bindings.add("enter", filter=is_unquoted_assist_request)
213
+ def _(event: KeyPressEvent):
214
+ """
215
+ Automatically add quotes around assistant questions, so there are not
216
+ syntax errors if the command line contains unclosed quotes etc.
217
+ """
218
+
219
+ buf = event.app.current_buffer
220
+ text = buf.text.strip()
221
+
222
+ question_text = text[1:].strip()
223
+ if not question_text:
224
+ # If the user enters an empty assistant request, treat it as a shortcut to go to the assistant chat.
225
+ buf.delete_before_cursor(len(buf.text))
226
+ buf.insert_text(assistant_chat.__name__)
227
+ else:
228
+ # Convert it to an assistant question starting with a `?`.
229
+ buf.delete_before_cursor(len(buf.text))
230
+ buf.insert_text(assist_request_str(question_text))
231
+
232
+ buf.validate_and_handle()
233
+
234
+ @custom_bindings.add("enter", filter=is_typo_command)
235
+ def _(event: KeyPressEvent):
236
+ """
237
+ Suppress enter and if possible give completions if the command is just not a valid command.
238
+ """
239
+
240
+ buf = event.app.current_buffer
241
+ buf.start_completion()
242
+
243
+ # TODO: Also suppress enter if a command or action doesn't meet the required args,
244
+ # selection, or preconditions.
245
+ # Perhaps also have a way to get confirmation if its a rarely used or unexpected command
246
+ # (based on history/suggestions).
247
+ # TODO: Add suggested replacements, e.g. df -> duf, top -> btm, etc.
248
+
249
+ @custom_bindings.add("@")
250
+ def _(event: KeyPressEvent):
251
+ """
252
+ Auto-trigger item completions after `@` sign.
253
+ """
254
+ buf = event.app.current_buffer
255
+ buf.insert_text("@")
256
+ buf.start_completion()
257
+
258
+ @custom_bindings.add("escape", eager=True, filter=is_completion_menu_active)
259
+ def _(event: KeyPressEvent):
260
+ """
261
+ Close the completion menu when escape is pressed.
262
+ """
263
+ event.app.current_buffer.cancel_completion()
264
+
265
+ @custom_bindings.add("c-c", eager=True)
266
+ def _(event):
267
+ """
268
+ Control-C to reset the current buffer. Similar to usual behavior but doesn't
269
+ leave ugly prompt chars.
270
+ """
271
+ print_formatted_text("")
272
+ buf = event.app.current_buffer
273
+ # Abort reverse search/filtering, clear any selection, and reset the buffer.
274
+ search.stop_search()
275
+ buf.exit_selection()
276
+ buf.reset()
277
+
278
+ existing_bindings = __xonsh__.shell.shell.prompter.app.key_bindings # noqa: F821 # pyright: ignore[reportUndefinedVariable]
279
+ merged_bindings = merge_key_bindings([existing_bindings, custom_bindings])
280
+ __xonsh__.shell.shell.prompter.app.key_bindings = merged_bindings # noqa: F821 # pyright: ignore[reportUndefinedVariable]
281
+
282
+ log.info("Added custom %s key bindings.", len(merged_bindings.bindings))
@@ -1,10 +1,10 @@
1
1
  import subprocess
2
2
 
3
+ from clideps.pkgs.pkg_check import pkg_check
3
4
  from xonsh.built_ins import XSH
4
5
  from xonsh.xontribs import xontribs_load
5
6
 
6
7
  from kash.config.settings import global_settings
7
- from kash.shell.clideps.pkg_deps import Pkg, pkg_check
8
8
 
9
9
 
10
10
  def modernize_shell() -> None:
@@ -25,7 +25,7 @@ def add_fnm() -> None:
25
25
  def enable_zoxide() -> None:
26
26
  installed_tools = pkg_check()
27
27
 
28
- if installed_tools.has(Pkg.zoxide):
28
+ if installed_tools.is_found("zoxide"):
29
29
  assert XSH.builtins
30
30
  zoxide_init = subprocess.check_output(["zoxide", "init", "xonsh"]).decode()
31
31
  XSH.builtins.execx(zoxide_init, "exec", XSH.ctx, filename="zoxide")
@@ -35,7 +35,7 @@ def add_aliases() -> None:
35
35
  installed_tools = pkg_check()
36
36
 
37
37
  assert XSH.aliases
38
- if installed_tools.has(Pkg.eza):
38
+ if installed_tools.is_found("eza"):
39
39
  if global_settings().use_nerd_icons:
40
40
  icons = ["--icons"]
41
41
  else:
@@ -9,15 +9,10 @@ Can run from the custom kash shell (main.py) or from a regular xonsh shell.
9
9
  """
10
10
 
11
11
  # Using absolute imports to avoid polluting the user's shell namespace.
12
- import kash.actions
13
12
  import kash.exec.command_registry
14
- import kash.shell.output.shell_output
15
- import kash.utils.common.format_utils
16
13
  import kash.xonsh_custom.load_into_xonsh
17
- import kash.xonsh_custom.shell_load_commands
18
14
  import kash.xonsh_custom.xonsh_env
19
15
  from kash.config.logger import get_logger
20
- from kash.exec.action_registry import reload_all_action_classes
21
16
 
22
17
 
23
18
  # We add action loading here directly in the xontrib so we expose `load` and
@@ -34,6 +29,10 @@ def load(*paths: str) -> None:
34
29
 
35
30
  from prettyfmt import fmt_path
36
31
 
32
+ import kash.shell.output.shell_output
33
+ import kash.xonsh_custom.shell_load_commands
34
+ from kash.exec.action_registry import refresh_action_classes
35
+
37
36
  for path in paths:
38
37
  if os.path.isfile(path) and path.endswith(".py"):
39
38
  runpy.run_path(path, run_name="__main__")
@@ -41,7 +40,7 @@ def load(*paths: str) -> None:
41
40
  importlib.import_module(path)
42
41
 
43
42
  # Now reload all actions into the environment so the new action is visible.
44
- actions = reload_all_action_classes()
43
+ actions = refresh_action_classes()
45
44
  kash.xonsh_custom.shell_load_commands._register_actions_in_shell(actions)
46
45
 
47
46
  kash.shell.output.shell_output.cprint(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kash-shell
3
- Version: 0.3.9
3
+ Version: 0.3.11
4
4
  Summary: The knowledge agent shell (core)
5
5
  Project-URL: Repository, https://github.com/jlevy/kash-shell
6
6
  Author-email: Joshua Levy <joshua@cal.berkeley.edu>
@@ -19,13 +19,14 @@ Requires-Python: <4.0,>=3.11
19
19
  Requires-Dist: anyio>=4.8.0
20
20
  Requires-Dist: audioop-lts>=0.2.1; python_version >= '3.13'
21
21
  Requires-Dist: cachetools>=5.5.2
22
- Requires-Dist: chopdiff>=0.1.3
22
+ Requires-Dist: chopdiff>=0.2.1
23
+ Requires-Dist: clideps>=0.1.1
23
24
  Requires-Dist: colour>=0.1.5
24
25
  Requires-Dist: cssselect>=1.2.0
25
26
  Requires-Dist: deepgram-sdk>=3.10.1
26
27
  Requires-Dist: dunamai>=1.23.0
27
28
  Requires-Dist: fastapi>=0.115.11
28
- Requires-Dist: flowmark>=0.3.1
29
+ Requires-Dist: flowmark>=0.4.5
29
30
  Requires-Dist: frontmatter-format>=0.2.1
30
31
  Requires-Dist: funlog>=0.2.0
31
32
  Requires-Dist: humanfriendly>=10.0
@@ -35,14 +36,14 @@ Requires-Dist: jinja2>=3.1.6
35
36
  Requires-Dist: justext>=3.0.2
36
37
  Requires-Dist: lazyasd>=0.1.4
37
38
  Requires-Dist: litellm>=1.63.11
38
- Requires-Dist: markdownify>=0.14.1
39
+ Requires-Dist: markdownify>=0.13.1
39
40
  Requires-Dist: mcp-proxy>=0.5.0
40
41
  Requires-Dist: mcp>=1.6.0
41
42
  Requires-Dist: openai>=1.66.3
42
43
  Requires-Dist: pandas>=2.2.3
43
44
  Requires-Dist: patch-ng>=1.18.1
44
45
  Requires-Dist: pathspec>=0.12.1
45
- Requires-Dist: prettyfmt>=0.3.0
46
+ Requires-Dist: prettyfmt>=0.3.1
46
47
  Requires-Dist: prompt-toolkit>=3.0.50
47
48
  Requires-Dist: pydantic>=2.10.6
48
49
  Requires-Dist: pydub>=0.25.1
@@ -58,7 +59,7 @@ Requires-Dist: rich>=14.0.0
58
59
  Requires-Dist: ripgrepy>=2.1.0
59
60
  Requires-Dist: send2trash>=1.8.3
60
61
  Requires-Dist: setproctitle>=1.3.5
61
- Requires-Dist: strif>=2.1.0
62
+ Requires-Dist: strif>=3.0.1
62
63
  Requires-Dist: tenacity>=9.0.0
63
64
  Requires-Dist: thefuzz>=0.22.1
64
65
  Requires-Dist: tiktoken>=0.9.0
@@ -589,8 +590,9 @@ A few of the most important commands for managing files and work are these:
589
590
  browser to view it.
590
591
 
591
592
  - `workspace` shows or selects or creates a new workspace.
592
- Initially you work in the `global` workspace but for more real work you'll want to
593
- create a workspace, which is a directory to hold the files you are working with.
593
+ Initially you work in the default global workspace (typically at `~/Kash/workspace`)
594
+ but for more real work you'll want to create a workspace, which is a directory to hold
595
+ the files you are working with.
594
596
 
595
597
  - `select` shows or sets selections, which are the set of files the next command will
596
598
  run on, within the current workspace.