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.
- kash/actions/__init__.py +4 -4
- kash/actions/core/format_markdown_template.py +2 -5
- kash/actions/core/markdownify.py +7 -6
- kash/actions/core/readability.py +7 -6
- kash/actions/core/render_as_html.py +37 -0
- kash/actions/core/show_webpage.py +6 -11
- kash/actions/core/strip_html.py +2 -6
- kash/actions/core/tabbed_webpage_config.py +31 -0
- kash/actions/core/{webpage_generate.py → tabbed_webpage_generate.py} +5 -4
- kash/commands/__init__.py +8 -20
- kash/commands/base/basic_file_commands.py +15 -0
- kash/commands/base/debug_commands.py +13 -0
- kash/commands/base/files_command.py +28 -10
- kash/commands/base/general_commands.py +21 -16
- kash/commands/base/logs_commands.py +4 -2
- kash/commands/base/model_commands.py +8 -8
- kash/commands/base/search_command.py +3 -2
- kash/commands/base/show_command.py +5 -3
- kash/commands/extras/parse_uv_lock.py +186 -0
- kash/commands/help/doc_commands.py +2 -31
- kash/commands/help/welcome.py +33 -0
- kash/commands/workspace/selection_commands.py +11 -6
- kash/commands/workspace/workspace_commands.py +19 -17
- kash/config/colors.py +3 -1
- kash/config/env_settings.py +14 -1
- kash/config/init.py +2 -2
- kash/config/logger.py +59 -56
- kash/config/logger_basic.py +3 -3
- kash/config/settings.py +116 -57
- kash/config/setup.py +28 -12
- kash/config/text_styles.py +3 -13
- kash/docs/load_api_docs.py +2 -1
- kash/docs/markdown/topics/a3_getting_started.md +3 -2
- kash/{concepts → embeddings}/text_similarity.py +2 -2
- kash/exec/__init__.py +20 -3
- kash/exec/action_decorators.py +24 -10
- kash/exec/action_exec.py +41 -23
- kash/exec/action_registry.py +13 -48
- kash/exec/command_registry.py +2 -1
- kash/exec/fetch_url_metadata.py +4 -6
- kash/exec/importing.py +56 -0
- kash/exec/llm_transforms.py +12 -10
- kash/exec/precondition_registry.py +2 -1
- kash/exec/preconditions.py +22 -1
- kash/exec/resolve_args.py +4 -0
- kash/exec/shell_callable_action.py +33 -19
- kash/file_storage/file_store.py +42 -27
- kash/file_storage/item_file_format.py +5 -2
- kash/file_storage/metadata_dirs.py +11 -2
- kash/help/assistant.py +1 -1
- kash/help/assistant_instructions.py +2 -1
- kash/help/function_param_info.py +1 -1
- kash/help/help_embeddings.py +2 -2
- kash/help/help_printing.py +7 -11
- kash/llm_utils/clean_headings.py +1 -1
- kash/llm_utils/llm_api_keys.py +4 -4
- kash/llm_utils/llm_features.py +68 -0
- kash/llm_utils/llm_messages.py +1 -2
- kash/llm_utils/llm_names.py +1 -1
- kash/llm_utils/llms.py +8 -3
- kash/local_server/__init__.py +5 -2
- kash/local_server/local_server.py +8 -5
- kash/local_server/local_server_commands.py +2 -2
- kash/local_server/local_server_routes.py +1 -7
- kash/local_server/local_url_formatters.py +1 -1
- kash/mcp/__init__.py +5 -2
- kash/mcp/mcp_cli.py +5 -5
- kash/mcp/mcp_server_commands.py +5 -5
- kash/mcp/mcp_server_routes.py +5 -5
- kash/mcp/mcp_server_sse.py +4 -2
- kash/media_base/media_cache.py +8 -8
- kash/media_base/media_services.py +1 -1
- kash/media_base/media_tools.py +6 -6
- kash/media_base/services/local_file_media.py +2 -2
- kash/media_base/{speech_transcription.py → transcription_deepgram.py} +25 -110
- kash/media_base/transcription_format.py +73 -0
- kash/media_base/transcription_whisper.py +38 -0
- kash/model/__init__.py +73 -5
- kash/model/actions_model.py +38 -4
- kash/model/concept_model.py +30 -0
- kash/model/items_model.py +115 -32
- kash/model/params_model.py +24 -0
- kash/shell/completions/completion_scoring.py +37 -5
- kash/shell/output/kerm_codes.py +1 -2
- kash/shell/output/shell_formatting.py +14 -4
- kash/shell/shell_main.py +2 -2
- kash/shell/utils/exception_printing.py +6 -0
- kash/shell/utils/native_utils.py +26 -20
- kash/shell/utils/shell_function_wrapper.py +15 -15
- kash/text_handling/custom_sliding_transforms.py +12 -4
- kash/text_handling/doc_normalization.py +6 -2
- kash/text_handling/markdown_render.py +118 -0
- kash/text_handling/markdown_utils.py +226 -0
- kash/utils/common/function_inspect.py +360 -110
- kash/utils/common/import_utils.py +12 -3
- kash/utils/common/type_utils.py +0 -29
- kash/utils/common/url.py +27 -3
- kash/utils/errors.py +6 -0
- kash/utils/file_utils/file_ext.py +4 -0
- kash/utils/file_utils/file_formats.py +2 -2
- kash/utils/file_utils/file_formats_model.py +20 -1
- kash/web_content/dir_store.py +1 -2
- kash/web_content/file_cache_utils.py +37 -10
- kash/web_content/file_processing.py +68 -0
- kash/web_content/local_file_cache.py +12 -9
- kash/web_content/web_extract.py +8 -3
- kash/web_content/web_fetch.py +12 -4
- kash/web_gen/__init__.py +0 -4
- kash/web_gen/simple_webpage.py +52 -0
- kash/web_gen/tabbed_webpage.py +24 -14
- kash/web_gen/template_render.py +37 -2
- kash/web_gen/templates/base_styles.css.jinja +169 -43
- kash/web_gen/templates/base_webpage.html.jinja +110 -45
- kash/web_gen/templates/content_styles.css.jinja +4 -2
- kash/web_gen/templates/item_view.html.jinja +49 -39
- kash/web_gen/templates/simple_webpage.html.jinja +24 -0
- kash/web_gen/templates/tabbed_webpage.html.jinja +42 -33
- kash/workspaces/__init__.py +15 -2
- kash/workspaces/selections.py +18 -3
- kash/workspaces/source_items.py +0 -1
- kash/workspaces/workspaces.py +5 -11
- kash/xonsh_custom/command_nl_utils.py +40 -19
- kash/xonsh_custom/custom_shell.py +43 -11
- kash/xonsh_custom/customize_prompt.py +39 -21
- kash/xonsh_custom/load_into_xonsh.py +22 -25
- kash/xonsh_custom/shell_load_commands.py +2 -2
- kash/xonsh_custom/xonsh_completers.py +2 -249
- kash/xonsh_custom/xonsh_keybindings.py +282 -0
- kash/xonsh_custom/xonsh_modern_tools.py +3 -3
- kash/xontrib/kash_extension.py +5 -6
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/METADATA +10 -8
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/RECORD +137 -136
- kash/actions/core/webpage_config.py +0 -21
- kash/concepts/concept_formats.py +0 -23
- kash/shell/clideps/api_keys.py +0 -100
- kash/shell/clideps/dotenv_setup.py +0 -115
- kash/shell/clideps/dotenv_utils.py +0 -98
- kash/shell/clideps/pkg_deps.py +0 -257
- kash/shell/clideps/platforms.py +0 -11
- kash/shell/clideps/terminal_features.py +0 -56
- kash/shell/utils/osc_utils.py +0 -95
- kash/shell/utils/terminal_images.py +0 -133
- kash/text_handling/markdown_util.py +0 -167
- kash/utils/common/atomic_var.py +0 -171
- kash/utils/common/string_replace.py +0 -93
- kash/utils/common/string_template.py +0 -101
- /kash/{concepts → embeddings}/cosine.py +0 -0
- /kash/{concepts → embeddings}/embeddings.py +0 -0
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/WHEEL +0 -0
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/entry_points.txt +0 -0
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/licenses/LICENSE +0 -0
kash/config/logger.py
CHANGED
|
@@ -2,7 +2,6 @@ import contextvars
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
|
-
import threading
|
|
6
5
|
from collections.abc import Generator
|
|
7
6
|
from contextlib import contextmanager
|
|
8
7
|
from dataclasses import dataclass
|
|
@@ -17,7 +16,7 @@ from rich._null_file import NULL_FILE
|
|
|
17
16
|
from rich.console import Console
|
|
18
17
|
from rich.logging import RichHandler
|
|
19
18
|
from rich.theme import Theme
|
|
20
|
-
from strif import atomic_output_file, new_timestamped_uid
|
|
19
|
+
from strif import AtomicVar, atomic_output_file, new_timestamped_uid
|
|
21
20
|
from typing_extensions import override
|
|
22
21
|
|
|
23
22
|
import kash.config.suppress_warnings # noqa: F401
|
|
@@ -38,55 +37,41 @@ from kash.utils.common.stack_traces import current_stack_traces
|
|
|
38
37
|
from kash.utils.common.task_stack import task_stack_prefix_str
|
|
39
38
|
|
|
40
39
|
|
|
41
|
-
@dataclass
|
|
40
|
+
@dataclass
|
|
42
41
|
class LogSettings:
|
|
43
42
|
log_console_level: LogLevel
|
|
44
43
|
log_file_level: LogLevel
|
|
45
|
-
|
|
44
|
+
|
|
46
45
|
global_log_dir: Path
|
|
46
|
+
"""Global directory for log files."""
|
|
47
47
|
|
|
48
48
|
# These directories can change based on the current workspace:
|
|
49
49
|
log_dir: Path
|
|
50
|
-
|
|
51
|
-
log_file_path: Path
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
_log_dir = get_system_logs_dir()
|
|
55
|
-
"""
|
|
56
|
-
Parent of the "logs" directory. Initially the global kash workspace.
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
LOG_NAME_GLOBAL = "global"
|
|
50
|
+
"""Parent of the "logs" directory. Initially the global kash workspace."""
|
|
61
51
|
|
|
62
|
-
|
|
63
|
-
"""
|
|
64
|
-
Name of the log file. By default the workspace name or "global" if
|
|
65
|
-
for the global workspace.
|
|
66
|
-
"""
|
|
52
|
+
log_name: str
|
|
53
|
+
"""Name of the log file. Typically the workspace name or "workspace" if for the global workspace."""
|
|
67
54
|
|
|
68
|
-
|
|
55
|
+
log_objects_dir: Path
|
|
56
|
+
log_file_path: Path
|
|
69
57
|
|
|
70
58
|
|
|
71
|
-
|
|
72
|
-
name = str(name).strip().rstrip("/").removesuffix(".log")
|
|
73
|
-
name = re.sub(r"[^\w-]", "_", name)
|
|
74
|
-
return name
|
|
59
|
+
LOG_NAME_GLOBAL = "workspace"
|
|
75
60
|
|
|
76
61
|
|
|
77
62
|
def _read_log_settings() -> LogSettings:
|
|
78
|
-
global _log_dir, _log_name
|
|
79
63
|
return LogSettings(
|
|
80
64
|
log_console_level=global_settings().console_log_level,
|
|
81
65
|
log_file_level=global_settings().file_log_level,
|
|
82
66
|
global_log_dir=get_system_logs_dir(),
|
|
83
|
-
log_dir=
|
|
84
|
-
|
|
85
|
-
|
|
67
|
+
log_dir=get_system_logs_dir(),
|
|
68
|
+
log_name=LOG_NAME_GLOBAL,
|
|
69
|
+
log_objects_dir=get_system_logs_dir() / "objects" / LOG_NAME_GLOBAL,
|
|
70
|
+
log_file_path=get_system_logs_dir() / f"{LOG_NAME_GLOBAL}.log",
|
|
86
71
|
)
|
|
87
72
|
|
|
88
73
|
|
|
89
|
-
_log_settings: LogSettings = _read_log_settings()
|
|
74
|
+
_log_settings: AtomicVar[LogSettings] = AtomicVar(_read_log_settings())
|
|
90
75
|
|
|
91
76
|
_setup_done = False
|
|
92
77
|
|
|
@@ -95,19 +80,13 @@ def get_log_settings() -> LogSettings:
|
|
|
95
80
|
"""
|
|
96
81
|
Currently active log settings.
|
|
97
82
|
"""
|
|
98
|
-
return _log_settings
|
|
83
|
+
return _log_settings.copy()
|
|
99
84
|
|
|
100
85
|
|
|
101
|
-
def
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
"""
|
|
106
|
-
global _log_lock, _log_base, _log_name
|
|
107
|
-
with _log_lock:
|
|
108
|
-
_log_base = log_root or get_system_logs_dir()
|
|
109
|
-
_log_name = make_valid_log_name(log_name or LOG_NAME_GLOBAL)
|
|
110
|
-
reload_rich_logging_setup()
|
|
86
|
+
def make_valid_log_name(name: str) -> str:
|
|
87
|
+
name = str(name).strip().rstrip("/").removesuffix(".log")
|
|
88
|
+
name = re.sub(r"[^\w-]", "_", name)
|
|
89
|
+
return name
|
|
111
90
|
|
|
112
91
|
|
|
113
92
|
console_context_var: contextvars.ContextVar[Console | None] = contextvars.ContextVar(
|
|
@@ -169,6 +148,30 @@ _file_handler: logging.FileHandler
|
|
|
169
148
|
_console_handler: logging.Handler
|
|
170
149
|
|
|
171
150
|
|
|
151
|
+
def reset_rich_logging(
|
|
152
|
+
log_root: Path | None = None,
|
|
153
|
+
log_name: str | None = None,
|
|
154
|
+
log_path: Path | None = None,
|
|
155
|
+
):
|
|
156
|
+
"""
|
|
157
|
+
Set or reset the logging root or log name, if it has changed. None means no change
|
|
158
|
+
and global default values. `log_name` is the name of the log, excluding
|
|
159
|
+
the `.log` extension. If `log_path` is provided, it will be used to infer
|
|
160
|
+
the log root and name.
|
|
161
|
+
"""
|
|
162
|
+
if log_path:
|
|
163
|
+
if not log_path.parent.exists():
|
|
164
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
165
|
+
log_root = log_path.parent
|
|
166
|
+
log_name = log_path.name
|
|
167
|
+
|
|
168
|
+
global _log_settings
|
|
169
|
+
with _log_settings.updates() as settings:
|
|
170
|
+
settings.log_dir = log_root or get_system_logs_dir()
|
|
171
|
+
settings.log_name = make_valid_log_name(log_name or LOG_NAME_GLOBAL)
|
|
172
|
+
reload_rich_logging_setup()
|
|
173
|
+
|
|
174
|
+
|
|
172
175
|
def reload_rich_logging_setup():
|
|
173
176
|
"""
|
|
174
177
|
Set up or reset logging setup. This is for rich/formatted console logging and
|
|
@@ -176,12 +179,12 @@ def reload_rich_logging_setup():
|
|
|
176
179
|
Call at initial run and again if log directory changes. Replaces all previous
|
|
177
180
|
loggers and handlers. Can be called to reset with different settings.
|
|
178
181
|
"""
|
|
179
|
-
global
|
|
180
|
-
with
|
|
182
|
+
global _setup_done, _log_settings
|
|
183
|
+
with _log_settings.lock:
|
|
181
184
|
new_log_settings = _read_log_settings()
|
|
182
|
-
if not _setup_done or new_log_settings != _log_settings:
|
|
185
|
+
if not _setup_done or new_log_settings != _log_settings.value:
|
|
183
186
|
_do_logging_setup(new_log_settings)
|
|
184
|
-
_log_settings
|
|
187
|
+
_log_settings.set(new_log_settings)
|
|
185
188
|
_setup_done = True
|
|
186
189
|
|
|
187
190
|
# get_console().print(
|
|
@@ -190,6 +193,15 @@ def reload_rich_logging_setup():
|
|
|
190
193
|
# )
|
|
191
194
|
|
|
192
195
|
|
|
196
|
+
@cache
|
|
197
|
+
def _init_rich_logging():
|
|
198
|
+
rich.reconfigure(theme=get_theme(), highlighter=get_highlighter())
|
|
199
|
+
|
|
200
|
+
logging.setLoggerClass(CustomLogger)
|
|
201
|
+
|
|
202
|
+
reload_rich_logging_setup()
|
|
203
|
+
|
|
204
|
+
|
|
193
205
|
def _do_logging_setup(log_settings: LogSettings):
|
|
194
206
|
from kash.config.suppress_warnings import demote_warnings, filter_warnings
|
|
195
207
|
|
|
@@ -319,7 +331,7 @@ class CustomLogger(logging.Logger):
|
|
|
319
331
|
filename = (
|
|
320
332
|
f"{prefix}{slugify_snake(description)}.{new_timestamped_uid()}.{file_ext.lstrip('.')}"
|
|
321
333
|
)
|
|
322
|
-
path = _log_settings.log_objects_dir / filename
|
|
334
|
+
path = _log_settings.copy().log_objects_dir / filename
|
|
323
335
|
with atomic_output_file(path, make_parents=True) as tmp_filename:
|
|
324
336
|
if isinstance(obj, bytes):
|
|
325
337
|
with open(tmp_filename, "wb") as f:
|
|
@@ -346,7 +358,7 @@ def get_logger(name: str) -> CustomLogger:
|
|
|
346
358
|
Get a logger that's compatible with system logging but has our additional custom
|
|
347
359
|
methods.
|
|
348
360
|
"""
|
|
349
|
-
|
|
361
|
+
_init_rich_logging()
|
|
350
362
|
logger = logging.getLogger(name)
|
|
351
363
|
# print("Logger is", logger)
|
|
352
364
|
return cast(CustomLogger, logger)
|
|
@@ -354,12 +366,3 @@ def get_logger(name: str) -> CustomLogger:
|
|
|
354
366
|
|
|
355
367
|
def get_log_file_stream():
|
|
356
368
|
return _file_handler.stream
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
@cache
|
|
360
|
-
def init_rich_logging():
|
|
361
|
-
rich.reconfigure(theme=get_theme(), highlighter=get_highlighter())
|
|
362
|
-
|
|
363
|
-
logging.setLoggerClass(CustomLogger)
|
|
364
|
-
|
|
365
|
-
reload_rich_logging_setup()
|
kash/config/logger_basic.py
CHANGED
|
@@ -30,7 +30,7 @@ def basic_stderr_handler(level: LogLevel) -> logging.StreamHandler:
|
|
|
30
30
|
return handler
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def basic_logging_setup(
|
|
33
|
+
def basic_logging_setup(log_path: Path | None, level: LogLevel):
|
|
34
34
|
"""
|
|
35
35
|
Set up basic logging to a file and to stderr.
|
|
36
36
|
"""
|
|
@@ -38,8 +38,8 @@ def basic_logging_setup(file_log_path: Path | None, level: LogLevel):
|
|
|
38
38
|
for h in root_logger.handlers[:]:
|
|
39
39
|
root_logger.removeHandler(h)
|
|
40
40
|
|
|
41
|
-
if
|
|
42
|
-
file_handler: FileHandler = basic_file_handler(
|
|
41
|
+
if log_path:
|
|
42
|
+
file_handler: FileHandler = basic_file_handler(log_path, level)
|
|
43
43
|
root_logger.addHandler(file_handler)
|
|
44
44
|
|
|
45
45
|
stderr_handler = basic_stderr_handler(level)
|
kash/config/settings.py
CHANGED
|
@@ -5,15 +5,16 @@ from logging import DEBUG, ERROR, INFO, WARNING
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
from pydantic.dataclasses import dataclass
|
|
8
|
+
from strif import AtomicVar
|
|
8
9
|
|
|
9
10
|
from kash.config.env_settings import KashEnv
|
|
10
|
-
from kash.utils.common.atomic_var import AtomicVar
|
|
11
11
|
|
|
12
12
|
APP_NAME = "kash"
|
|
13
13
|
|
|
14
14
|
DOT_DIR = ".kash"
|
|
15
15
|
|
|
16
|
-
GLOBAL_WS_NAME = "
|
|
16
|
+
GLOBAL_WS_NAME = "workspace"
|
|
17
|
+
"""Name of the global workspace."""
|
|
17
18
|
|
|
18
19
|
RECOMMENDED_API_KEYS = [
|
|
19
20
|
"OPENAI_API_KEY",
|
|
@@ -23,51 +24,28 @@ RECOMMENDED_API_KEYS = [
|
|
|
23
24
|
]
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
def
|
|
27
|
-
"""Default root directory for kash workspaces."""
|
|
28
|
-
return KashEnv.KASH_WS_ROOT.read_path(Path("~/Kash"))
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def get_global_ws_dir() -> Path:
|
|
32
|
-
"""Default global workspace directory."""
|
|
33
|
-
kash_ws_dir = KashEnv.KASH_GLOBAL_WS.read_path(None)
|
|
34
|
-
if kash_ws_dir:
|
|
35
|
-
return kash_ws_dir
|
|
36
|
-
else:
|
|
37
|
-
return get_ws_root_dir() / GLOBAL_WS_NAME
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def get_system_config_dir() -> Path:
|
|
41
|
-
return Path("~/.config/kash").expanduser().resolve()
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def get_rcfile_path() -> Path:
|
|
45
|
-
return get_system_config_dir() / "kashrc"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def get_system_logs_dir() -> Path:
|
|
49
|
-
"""Default global and system logs directory (for server logs, etc)."""
|
|
50
|
-
return KashEnv.KASH_SYSTEM_LOGS_DIR.read_path(get_ws_root_dir() / "logs")
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def get_system_cache_dir() -> Path:
|
|
54
|
-
"""Default global and system cache directory (for global media, content, etc)."""
|
|
55
|
-
return KashEnv.KASH_SYSTEM_CACHE_DIR.read_path(get_ws_root_dir() / "cache")
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def get_system_env_path() -> Path:
|
|
59
|
-
return get_system_config_dir() / "env.local"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def get_mcp_ws_dir() -> Path | None:
|
|
27
|
+
def get_all_common_api_env_vars() -> list[str]:
|
|
63
28
|
"""
|
|
64
|
-
Get the
|
|
29
|
+
Get all the common environment variables that are recommended to be set.
|
|
65
30
|
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
31
|
+
from clideps.env_vars.env_names import get_all_common_env_names
|
|
32
|
+
|
|
33
|
+
return list(set(get_all_common_env_names() + RECOMMENDED_API_KEYS))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
RECOMMENDED_PKGS = [
|
|
37
|
+
"less",
|
|
38
|
+
"eza",
|
|
39
|
+
"ripgrep",
|
|
40
|
+
"bat",
|
|
41
|
+
"zoxide",
|
|
42
|
+
"dust",
|
|
43
|
+
"duf",
|
|
44
|
+
"pygmentize",
|
|
45
|
+
"hexyl",
|
|
46
|
+
"ffmpeg",
|
|
47
|
+
"imagemagick",
|
|
48
|
+
]
|
|
71
49
|
|
|
72
50
|
|
|
73
51
|
MEDIA_CACHE_NAME = "media"
|
|
@@ -86,11 +64,6 @@ LOCAL_SERVER_PORTS_MAX = 30
|
|
|
86
64
|
LOCAL_SERVER_LOG_NAME = "local_server"
|
|
87
65
|
|
|
88
66
|
|
|
89
|
-
@cache
|
|
90
|
-
def local_server_log_path() -> Path:
|
|
91
|
-
return resolve_and_create_dirs(get_system_logs_dir() / f"{LOCAL_SERVER_LOG_NAME}.log")
|
|
92
|
-
|
|
93
|
-
|
|
94
67
|
class LogLevel(Enum):
|
|
95
68
|
debug = DEBUG
|
|
96
69
|
info = INFO
|
|
@@ -146,11 +119,15 @@ def find_in_cwd_or_parents(filename: Path | str) -> Path | None:
|
|
|
146
119
|
return None
|
|
147
120
|
|
|
148
121
|
|
|
122
|
+
def _get_rcfile_path() -> Path:
|
|
123
|
+
return _get_system_config_dir() / "kashrc"
|
|
124
|
+
|
|
125
|
+
|
|
149
126
|
def find_rcfiles() -> list[Path]:
|
|
150
127
|
"""
|
|
151
128
|
Find active rcfiles. Currently only supports one.
|
|
152
129
|
"""
|
|
153
|
-
rcfile_path =
|
|
130
|
+
rcfile_path = _get_rcfile_path()
|
|
154
131
|
if rcfile_path.exists():
|
|
155
132
|
return [rcfile_path]
|
|
156
133
|
else:
|
|
@@ -159,9 +136,30 @@ def find_rcfiles() -> list[Path]:
|
|
|
159
136
|
|
|
160
137
|
@dataclass
|
|
161
138
|
class Settings:
|
|
139
|
+
ws_root_dir: Path
|
|
140
|
+
"""A default root directory for kash workspaces (typically `~/Kash`)."""
|
|
141
|
+
|
|
142
|
+
global_ws_dir: Path
|
|
143
|
+
"""The directory for the default global workspace."""
|
|
144
|
+
|
|
145
|
+
system_config_dir: Path
|
|
146
|
+
"""The directory for system-wide configuration files."""
|
|
147
|
+
|
|
162
148
|
media_cache_dir: Path
|
|
163
149
|
"""The workspace media cache directory, for caching audio, video, and transcripts."""
|
|
164
150
|
|
|
151
|
+
system_logs_dir: Path
|
|
152
|
+
"""Default global and system logs directory (for server logs, etc)."""
|
|
153
|
+
|
|
154
|
+
system_cache_dir: Path
|
|
155
|
+
"""Default global and system cache directory (for global media, content, etc)."""
|
|
156
|
+
|
|
157
|
+
mcp_ws_dir: Path | None
|
|
158
|
+
"""The directory for the MCP workspace, if set."""
|
|
159
|
+
|
|
160
|
+
local_server_log_path: Path
|
|
161
|
+
"""The path to the local server log."""
|
|
162
|
+
|
|
165
163
|
content_cache_dir: Path
|
|
166
164
|
"""The workspace content cache directory, for caching web or local files."""
|
|
167
165
|
# TODO: Separate workspace cached content (e.g. thumbnails) vs global files
|
|
@@ -198,12 +196,60 @@ class Settings:
|
|
|
198
196
|
"""If true, use Nerd Icons in file listings. Requires a compatible font."""
|
|
199
197
|
|
|
200
198
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
199
|
+
ws_root_dir = Path("~/Kash").expanduser()
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _get_ws_root_dir() -> Path:
|
|
203
|
+
"""Default root directory for kash workspaces."""
|
|
204
|
+
return KashEnv.KASH_WS_ROOT.read_path(default=ws_root_dir)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _get_global_ws_dir() -> Path:
|
|
208
|
+
kash_ws_dir = KashEnv.KASH_GLOBAL_WS.read_path()
|
|
209
|
+
if kash_ws_dir:
|
|
210
|
+
return kash_ws_dir
|
|
211
|
+
else:
|
|
212
|
+
return _get_ws_root_dir() / GLOBAL_WS_NAME
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def get_system_logs_dir() -> Path:
|
|
216
|
+
return KashEnv.KASH_SYSTEM_LOGS_DIR.read_path(default=_get_ws_root_dir() / "logs")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _get_system_config_dir() -> Path:
|
|
220
|
+
return Path("~/.config/kash").expanduser().resolve()
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _get_system_cache_dir() -> Path:
|
|
224
|
+
return KashEnv.KASH_SYSTEM_CACHE_DIR.read_path(default=_get_ws_root_dir() / "cache")
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _get_mcp_ws_dir() -> Path | None:
|
|
228
|
+
mcp_dir = KashEnv.KASH_MCP_WS.read_str()
|
|
229
|
+
if mcp_dir:
|
|
230
|
+
return Path(mcp_dir).expanduser().resolve()
|
|
231
|
+
else:
|
|
232
|
+
return None
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@cache
|
|
236
|
+
def _get_local_server_log_path() -> Path:
|
|
237
|
+
return resolve_and_create_dirs(get_system_logs_dir() / f"{LOCAL_SERVER_LOG_NAME}.log")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _read_settings():
|
|
241
|
+
return Settings(
|
|
242
|
+
# Essential system settings for logs, workspaces, and configs:
|
|
243
|
+
ws_root_dir=_get_ws_root_dir(),
|
|
244
|
+
global_ws_dir=_get_global_ws_dir(),
|
|
245
|
+
system_config_dir=_get_system_config_dir(),
|
|
246
|
+
system_logs_dir=get_system_logs_dir(),
|
|
247
|
+
system_cache_dir=_get_system_cache_dir(),
|
|
248
|
+
mcp_ws_dir=_get_mcp_ws_dir(),
|
|
249
|
+
local_server_log_path=_get_local_server_log_path(),
|
|
204
250
|
# These default to the global but can be overridden by workspace settings.
|
|
205
|
-
media_cache_dir=
|
|
206
|
-
content_cache_dir=
|
|
251
|
+
media_cache_dir=_get_system_cache_dir() / MEDIA_CACHE_NAME,
|
|
252
|
+
content_cache_dir=_get_system_cache_dir() / CONTENT_CACHE_NAME,
|
|
207
253
|
debug_assistant=True,
|
|
208
254
|
default_editor="nano",
|
|
209
255
|
file_log_level=LogLevel.info,
|
|
@@ -215,7 +261,20 @@ _settings = AtomicVar(
|
|
|
215
261
|
use_kerm_codes=False,
|
|
216
262
|
use_nerd_icons=True,
|
|
217
263
|
)
|
|
218
|
-
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
# Initial default settings.
|
|
267
|
+
_settings = AtomicVar(_read_settings())
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def configure_ws_and_settings(root_dir: Path):
|
|
271
|
+
"""
|
|
272
|
+
Reset and reload all settings, deriving all paths from the new workspace
|
|
273
|
+
root. Good if embedding kash in another app.
|
|
274
|
+
"""
|
|
275
|
+
global ws_root_dir
|
|
276
|
+
ws_root_dir = root_dir
|
|
277
|
+
_settings.set(_read_settings())
|
|
219
278
|
|
|
220
279
|
|
|
221
280
|
def atomic_global_settings() -> AtomicVar[Settings]:
|
kash/config/setup.py
CHANGED
|
@@ -3,34 +3,50 @@ from functools import cache
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
+
from clideps.env_vars.dotenv_utils import load_dotenv_paths
|
|
7
|
+
|
|
8
|
+
from kash.config.logger import reset_rich_logging
|
|
6
9
|
from kash.config.logger_basic import basic_logging_setup
|
|
7
|
-
from kash.config.settings import LogLevel,
|
|
10
|
+
from kash.config.settings import LogLevel, configure_ws_and_settings, global_settings
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
@cache
|
|
11
|
-
def
|
|
14
|
+
def kash_setup(
|
|
15
|
+
*,
|
|
16
|
+
rich_logging: bool,
|
|
17
|
+
kash_ws_root: Path | None = None,
|
|
18
|
+
log_path: Path | None = None,
|
|
19
|
+
level: LogLevel = LogLevel.info,
|
|
20
|
+
):
|
|
12
21
|
"""
|
|
13
22
|
One-time top-level setup of essential logging, keys, directories, and configs.
|
|
14
23
|
Idempotent.
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
Can call this if embedding kash in another app.
|
|
26
|
+
Can be used to set the global default workspace and logs directory
|
|
27
|
+
and/or the default log file.
|
|
28
|
+
If `rich_logging` is True, then rich logging with warnings only for console use.
|
|
29
|
+
If `rich_logging` is False, then use basic logging to a file and stderr.
|
|
18
30
|
"""
|
|
19
|
-
from kash.config.logger import reload_rich_logging_setup
|
|
20
|
-
from kash.shell.clideps.dotenv_utils import load_dotenv_paths
|
|
21
31
|
from kash.utils.common.stack_traces import add_stacktrace_handler
|
|
22
32
|
|
|
33
|
+
add_stacktrace_handler()
|
|
34
|
+
|
|
35
|
+
# Settings may depend on environment variables, so load them first.
|
|
36
|
+
load_dotenv_paths(True, True, global_settings().system_config_dir)
|
|
37
|
+
|
|
38
|
+
# Then configure the workspace and settings before finalizing logging.
|
|
39
|
+
if kash_ws_root:
|
|
40
|
+
configure_ws_and_settings(kash_ws_root)
|
|
41
|
+
|
|
42
|
+
# Now set up logging, as it might depend on workspace root.
|
|
23
43
|
if rich_logging:
|
|
24
|
-
|
|
44
|
+
reset_rich_logging(log_path=log_path)
|
|
25
45
|
else:
|
|
26
|
-
basic_logging_setup(
|
|
46
|
+
basic_logging_setup(log_path=log_path, level=level)
|
|
27
47
|
|
|
28
48
|
_lib_setup()
|
|
29
49
|
|
|
30
|
-
add_stacktrace_handler()
|
|
31
|
-
|
|
32
|
-
load_dotenv_paths(True, True, get_system_config_dir())
|
|
33
|
-
|
|
34
50
|
|
|
35
51
|
def _lib_setup():
|
|
36
52
|
from frontmatter_format.yaml_util import add_default_yaml_customizer
|
kash/config/text_styles.py
CHANGED
|
@@ -46,7 +46,9 @@ SPINNER = "dots12"
|
|
|
46
46
|
|
|
47
47
|
BAT_THEME = "Coldark-Dark"
|
|
48
48
|
|
|
49
|
-
BAT_STYLE = "header-filename,header-filesize,grid,changes"
|
|
49
|
+
BAT_STYLE = "header-filename,header-filesize,grid,numbers,changes"
|
|
50
|
+
|
|
51
|
+
BAT_STYLE_PLAIN = "plain"
|
|
50
52
|
|
|
51
53
|
|
|
52
54
|
## Colors
|
|
@@ -296,18 +298,6 @@ EMOJI_MSG_INDENT = "⋮"
|
|
|
296
298
|
|
|
297
299
|
EMOJI_BREADCRUMB_SEP = "›"
|
|
298
300
|
|
|
299
|
-
EMOJI_TRUE = "✔︎"
|
|
300
|
-
|
|
301
|
-
EMOJI_FALSE = "✘"
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
def success_emoji(value: bool, success_only: bool = False) -> str:
|
|
305
|
-
return EMOJI_TRUE if value else " " if success_only else EMOJI_FALSE
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
def format_success_emoji(value: bool, success_only: bool = False) -> Text:
|
|
309
|
-
return Text(success_emoji(value, success_only), style=COLOR_SUCCESS if value else COLOR_FAILURE)
|
|
310
|
-
|
|
311
301
|
|
|
312
302
|
## Special headings
|
|
313
303
|
|
kash/docs/load_api_docs.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
from strif import StringTemplate
|
|
2
|
+
|
|
1
3
|
from kash.config.logger import get_logger
|
|
2
4
|
from kash.docs.load_help_topics import load_help_src
|
|
3
5
|
from kash.docs.load_source_code import load_source_code
|
|
4
|
-
from kash.utils.common.string_template import StringTemplate
|
|
5
6
|
|
|
6
7
|
log = get_logger(__name__)
|
|
7
8
|
|
|
@@ -243,8 +243,9 @@ A few of the most important commands for managing files and work are these:
|
|
|
243
243
|
browser to view it.
|
|
244
244
|
|
|
245
245
|
- `workspace` shows or selects or creates a new workspace.
|
|
246
|
-
Initially you work in the
|
|
247
|
-
create a workspace, which is a directory to hold
|
|
246
|
+
Initially you work in the default global workspace (typically at `~/Kash/workspace`)
|
|
247
|
+
but for more real work you'll want to create a workspace, which is a directory to hold
|
|
248
|
+
the files you are working with.
|
|
248
249
|
|
|
249
250
|
- `select` shows or sets selections, which are the set of files the next command will
|
|
250
251
|
run on, within the current workspace.
|
|
@@ -5,9 +5,9 @@ from funlog import log_calls
|
|
|
5
5
|
from litellm import embedding
|
|
6
6
|
from litellm.types.utils import EmbeddingResponse
|
|
7
7
|
|
|
8
|
-
from kash.concepts.cosine import ArrayLike, cosine
|
|
9
|
-
from kash.concepts.embeddings import Embeddings
|
|
10
8
|
from kash.config.logger import get_logger
|
|
9
|
+
from kash.embeddings.cosine import ArrayLike, cosine
|
|
10
|
+
from kash.embeddings.embeddings import Embeddings
|
|
11
11
|
from kash.llm_utils.llms import DEFAULT_EMBEDDING_MODEL, EmbeddingModel
|
|
12
12
|
from kash.utils.errors import ApiResultError
|
|
13
13
|
|
kash/exec/__init__.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
# flake8: noqa: F401
|
|
2
|
-
|
|
3
1
|
from kash.exec.action_decorators import kash_action, kash_action_class
|
|
4
2
|
from kash.exec.action_exec import SkipItem, prepare_action_input, run_action_with_shell_context
|
|
5
|
-
from kash.exec.action_registry import import_action_subdirs
|
|
6
3
|
from kash.exec.command_registry import kash_command
|
|
4
|
+
from kash.exec.importing import import_and_register
|
|
7
5
|
from kash.exec.llm_transforms import llm_transform_item, llm_transform_str
|
|
8
6
|
from kash.exec.precondition_registry import kash_precondition
|
|
9
7
|
from kash.exec.resolve_args import (
|
|
@@ -14,3 +12,22 @@ from kash.exec.resolve_args import (
|
|
|
14
12
|
resolve_locator_arg,
|
|
15
13
|
resolve_path_arg,
|
|
16
14
|
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"kash_action",
|
|
18
|
+
"kash_action_class",
|
|
19
|
+
"SkipItem",
|
|
20
|
+
"prepare_action_input",
|
|
21
|
+
"run_action_with_shell_context",
|
|
22
|
+
"kash_command",
|
|
23
|
+
"import_and_register",
|
|
24
|
+
"llm_transform_item",
|
|
25
|
+
"llm_transform_str",
|
|
26
|
+
"kash_precondition",
|
|
27
|
+
"assemble_path_args",
|
|
28
|
+
"assemble_store_path_args",
|
|
29
|
+
"import_locator_args",
|
|
30
|
+
"resolvable_paths",
|
|
31
|
+
"resolve_locator_arg",
|
|
32
|
+
"resolve_path_arg",
|
|
33
|
+
]
|