kash-shell 0.3.33__py3-none-any.whl → 0.3.35__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.
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ import ssl
5
+ from collections.abc import Iterable
4
6
  from dataclasses import dataclass
5
7
  from enum import Enum
6
8
  from functools import cache, cached_property
@@ -12,17 +14,145 @@ from cachetools import TTLCache
12
14
  from strif import atomic_output_file, copyfile_atomic
13
15
 
14
16
  from kash.config.env_settings import KashEnv
17
+ from kash.utils.common.s3_utils import s3_download_file
15
18
  from kash.utils.common.url import Url
16
19
  from kash.utils.file_utils.file_formats import MimeType
17
20
 
21
+ log = logging.getLogger(__name__)
22
+
23
+
24
+ def _httpx_verify_context() -> ssl.SSLContext | bool:
25
+ """
26
+ Return an SSLContext that uses the system trust store via truststore, if available.
27
+ Falls back to certifi bundle; otherwise True to use httpx defaults.
28
+ """
29
+ try:
30
+ import truststore
31
+
32
+ return truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
33
+ except Exception:
34
+ try:
35
+ import certifi
36
+
37
+ return ssl.create_default_context(cafile=certifi.where())
38
+ except Exception:
39
+ return True
40
+
41
+
42
+ def _stream_to_file(
43
+ target_filename: str | Path,
44
+ response_iterator: Iterable[bytes],
45
+ total_size: int,
46
+ show_progress: bool,
47
+ ) -> None:
48
+ with atomic_output_file(target_filename, make_parents=True) as temp_filename:
49
+ with open(temp_filename, "wb") as f:
50
+ if not show_progress:
51
+ for chunk in response_iterator:
52
+ if chunk:
53
+ f.write(chunk)
54
+ else:
55
+ from tqdm import tqdm
56
+
57
+ with tqdm(
58
+ total=total_size,
59
+ unit="B",
60
+ unit_scale=True,
61
+ desc=f"Downloading {Path(str(target_filename)).name}",
62
+ ) as progress:
63
+ for chunk in response_iterator:
64
+ if chunk:
65
+ f.write(chunk)
66
+ progress.update(len(chunk))
67
+
68
+
69
+ def _httpx_fetch(
70
+ url: Url,
71
+ *,
72
+ timeout: int,
73
+ auth: Any | None,
74
+ headers: dict[str, str] | None,
75
+ mode: ClientMode,
76
+ log_label: str,
77
+ ):
78
+ import httpx
79
+
80
+ req_headers = _get_req_headers(mode, headers)
81
+ parsed_url = urlparse(str(url))
82
+ with httpx.Client(
83
+ follow_redirects=True,
84
+ timeout=timeout,
85
+ auth=auth,
86
+ headers=req_headers,
87
+ verify=_httpx_verify_context(),
88
+ ) as client:
89
+ log.debug("fetch_url (%s): using headers: %s", log_label, client.headers)
90
+ if mode is ClientMode.BROWSER_HEADERS:
91
+ _prime_host(parsed_url.netloc, client, timeout)
92
+ response = client.get(url)
93
+ log.info(
94
+ "Fetched (%s): %s (%s bytes): %s",
95
+ log_label,
96
+ response.status_code,
97
+ len(response.content),
98
+ url,
99
+ )
100
+ response.raise_for_status()
101
+ return response
102
+
103
+
104
+ def _httpx_download(
105
+ url: Url,
106
+ target_filename: str | Path,
107
+ *,
108
+ show_progress: bool,
109
+ timeout: int,
110
+ auth: Any | None,
111
+ headers: dict[str, str] | None,
112
+ mode: ClientMode,
113
+ log_label: str,
114
+ ) -> dict[str, str]:
115
+ import httpx
116
+
117
+ req_headers = _get_req_headers(mode, headers)
118
+ parsed_url = urlparse(str(url))
119
+ with httpx.Client(
120
+ follow_redirects=True,
121
+ timeout=timeout,
122
+ headers=req_headers,
123
+ verify=_httpx_verify_context(),
124
+ ) as client:
125
+ if mode is ClientMode.BROWSER_HEADERS:
126
+ _prime_host(parsed_url.netloc, client, timeout)
127
+ log.debug("download_url (%s): using headers: %s", log_label, client.headers)
128
+ with client.stream("GET", url, auth=auth, follow_redirects=True) as response:
129
+ response.raise_for_status()
130
+ response_headers = dict(response.headers)
131
+ total = int(response.headers.get("content-length", "0"))
132
+ _stream_to_file(target_filename, response.iter_bytes(), total, show_progress)
133
+ return response_headers
134
+
135
+
136
+ def _is_tls_cert_error(exc: Exception) -> bool:
137
+ """
138
+ Heuristic detection of TLS/certificate verification errors coming from curl_cffi/libcurl.
139
+ """
140
+ s = str(exc).lower()
141
+ if "curl: (60)" in s:
142
+ return True
143
+ if "certificate verify failed" in s:
144
+ return True
145
+ if "ssl" in s and ("certificate" in s or "cert" in s or "handshake" in s):
146
+ return True
147
+ return False
148
+
149
+
18
150
  if TYPE_CHECKING:
19
151
  from curl_cffi.requests import Response as CurlCffiResponse
20
152
  from curl_cffi.requests import Session as CurlCffiSession
21
153
  from httpx import Client as HttpxClient
22
154
  from httpx import Response as HttpxResponse
23
155
 
24
- log = logging.getLogger(__name__)
25
-
26
156
 
27
157
  DEFAULT_TIMEOUT = 30
28
158
  CURL_CFFI_IMPERSONATE_VERSION = "chrome120"
@@ -199,54 +329,57 @@ def fetch_url(
199
329
 
200
330
  from curl_cffi.requests import Session
201
331
 
202
- with Session() as client:
203
- # Set headers on the session - they will be sent with all requests
204
- client.headers.update(req_headers)
205
- _prime_host(
206
- parsed_url.netloc, client, timeout, impersonate=CURL_CFFI_IMPERSONATE_VERSION
332
+ exc: Exception | None = None
333
+ try:
334
+ with Session() as client:
335
+ # Set headers on the session - they will be sent with all requests
336
+ client.headers.update(req_headers)
337
+ _prime_host(
338
+ parsed_url.netloc, client, timeout, impersonate=CURL_CFFI_IMPERSONATE_VERSION
339
+ )
340
+ log.debug("fetch_url (curl_cffi): using session headers: %s", client.headers)
341
+ response = client.get(
342
+ url,
343
+ impersonate=CURL_CFFI_IMPERSONATE_VERSION,
344
+ timeout=timeout,
345
+ auth=auth,
346
+ allow_redirects=True,
347
+ )
348
+ log.info(
349
+ "Fetched (curl_cffi): %s (%s bytes): %s",
350
+ response.status_code,
351
+ len(response.content),
352
+ url,
353
+ )
354
+ response.raise_for_status()
355
+ return response
356
+ except Exception as e:
357
+ exc = e
358
+
359
+ if exc and _is_tls_cert_error(exc):
360
+ log.warning(
361
+ "TLS/SSL verification failed with curl_cffi for %s: %s; falling back to httpx",
362
+ url,
363
+ exc,
207
364
  )
208
- log.debug("fetch_url (curl_cffi): using session headers: %s", client.headers)
209
- response = client.get(
365
+ # Fallback to httpx with browser-like headers (uses system trust if available)
366
+ return _httpx_fetch(
210
367
  url,
211
- impersonate=CURL_CFFI_IMPERSONATE_VERSION,
212
368
  timeout=timeout,
213
369
  auth=auth,
214
- allow_redirects=True,
215
- )
216
- log.info(
217
- "Fetched (curl_cffi): %s (%s bytes): %s",
218
- response.status_code,
219
- len(response.content),
220
- url,
370
+ headers=headers,
371
+ mode=ClientMode.BROWSER_HEADERS,
372
+ log_label="httpx fallback",
221
373
  )
222
- response.raise_for_status()
223
- return response
374
+
375
+ if exc:
376
+ raise exc
224
377
 
225
378
  # Handle httpx modes
226
379
  else:
227
- import httpx
228
-
229
- with httpx.Client(
230
- follow_redirects=True,
231
- timeout=timeout,
232
- auth=auth,
233
- headers=req_headers,
234
- ) as client:
235
- log.debug("fetch_url (httpx): using headers: %s", client.headers)
236
-
237
- # Cookie priming only makes sense for the browser-like mode
238
- if mode is ClientMode.BROWSER_HEADERS:
239
- _prime_host(parsed_url.netloc, client, timeout)
240
-
241
- response = client.get(url)
242
- log.info(
243
- "Fetched (httpx): %s (%s bytes): %s",
244
- response.status_code,
245
- len(response.content),
246
- url,
247
- )
248
- response.raise_for_status()
249
- return response
380
+ return _httpx_fetch(
381
+ url, timeout=timeout, auth=auth, headers=headers, mode=mode, log_label="httpx"
382
+ )
250
383
 
251
384
 
252
385
  @dataclass(frozen=True)
@@ -289,38 +422,13 @@ def download_url(
289
422
  copyfile_atomic(parsed_url.netloc + parsed_url.path, target_filename, make_parents=True)
290
423
  return None
291
424
  elif parsed_url.scheme == "s3":
292
- import boto3 # pyright: ignore
293
-
294
- s3 = boto3.resource("s3")
295
- s3_path = parsed_url.path.lstrip("/")
296
425
  with atomic_output_file(target_filename, make_parents=True) as temp_filename:
297
- s3.Bucket(parsed_url.netloc).download_file(s3_path, temp_filename)
426
+ s3_download_file(url, temp_filename)
298
427
  return None
299
428
 
300
429
  req_headers = _get_req_headers(mode, headers)
301
430
  response_headers = None
302
431
 
303
- def stream_to_file(response_iterator, total_size):
304
- with atomic_output_file(target_filename, make_parents=True) as temp_filename:
305
- with open(temp_filename, "wb") as f:
306
- if not show_progress:
307
- for chunk in response_iterator:
308
- if chunk: # Skip empty chunks
309
- f.write(chunk)
310
- else:
311
- from tqdm import tqdm
312
-
313
- with tqdm(
314
- total=total_size,
315
- unit="B",
316
- unit_scale=True,
317
- desc=f"Downloading {Path(target_filename).name}",
318
- ) as progress:
319
- for chunk in response_iterator:
320
- if chunk: # Skip empty chunks
321
- f.write(chunk)
322
- progress.update(len(chunk))
323
-
324
432
  # Handle curl_cffi mode
325
433
  if mode is ClientMode.CURL_CFFI:
326
434
  if not _have_curl_cffi():
@@ -328,47 +436,111 @@ def download_url(
328
436
 
329
437
  from curl_cffi.requests import Session
330
438
 
331
- with Session() as client:
332
- # Set headers on the session; they will be sent with all requests
333
- client.headers.update(req_headers)
334
- _prime_host(
335
- parsed_url.netloc, client, timeout, impersonate=CURL_CFFI_IMPERSONATE_VERSION
336
- )
337
- log.debug("download_url (curl_cffi): using session headers: %s", client.headers)
439
+ exc: Exception | None = None
440
+ try:
441
+ with Session() as client:
442
+ # Set headers on the session; they will be sent with all requests
443
+ client.headers.update(req_headers)
444
+ _prime_host(
445
+ parsed_url.netloc, client, timeout, impersonate=CURL_CFFI_IMPERSONATE_VERSION
446
+ )
447
+ log.debug("download_url (curl_cffi): using session headers: %s", client.headers)
448
+ response = client.get(
449
+ url,
450
+ impersonate=CURL_CFFI_IMPERSONATE_VERSION,
451
+ timeout=timeout,
452
+ auth=auth,
453
+ allow_redirects=True,
454
+ stream=True,
455
+ )
456
+ response.raise_for_status()
457
+ response_headers = dict(response.headers)
458
+ total = int(response.headers.get("content-length", "0"))
459
+
460
+ # Use iter_content for streaming; this is the standard method for curl_cffi
461
+ chunk_iterator = response.iter_content(chunk_size=8192)
462
+ _stream_to_file(target_filename, chunk_iterator, total, show_progress)
463
+ except Exception as e:
464
+ exc = e
338
465
 
339
- response = client.get(
466
+ if exc and _is_tls_cert_error(exc):
467
+ log.warning(
468
+ "TLS/SSL verification failed with curl_cffi for %s: %s; falling back to httpx",
340
469
  url,
341
- impersonate=CURL_CFFI_IMPERSONATE_VERSION,
470
+ exc,
471
+ )
472
+ # Fallback to httpx streaming with browser-like headers (system trust store if available)
473
+ response_headers = _httpx_download(
474
+ url,
475
+ target_filename,
476
+ show_progress=show_progress,
342
477
  timeout=timeout,
343
478
  auth=auth,
344
- allow_redirects=True,
345
- stream=True,
479
+ headers=headers,
480
+ mode=ClientMode.BROWSER_HEADERS,
481
+ log_label="httpx fallback",
346
482
  )
347
- response.raise_for_status()
348
- response_headers = dict(response.headers)
349
- total = int(response.headers.get("content-length", "0"))
350
-
351
- # Use iter_content for streaming; this is the standard method for curl_cffi
352
- chunk_iterator = response.iter_content(chunk_size=8192)
353
- stream_to_file(chunk_iterator, total)
483
+ elif exc:
484
+ raise exc
354
485
 
355
486
  # Handle httpx modes
356
487
  else:
357
- import httpx
358
-
359
- with httpx.Client(follow_redirects=True, timeout=timeout, headers=req_headers) as client:
360
- if mode is ClientMode.BROWSER_HEADERS:
361
- _prime_host(parsed_url.netloc, client, timeout)
362
-
363
- log.debug("download_url (httpx): using headers: %s", client.headers)
364
- with client.stream("GET", url, auth=auth, follow_redirects=True) as response:
365
- response.raise_for_status()
366
- response_headers = dict(response.headers)
367
- total = int(response.headers.get("content-length", "0"))
368
- stream_to_file(response.iter_bytes(), total)
488
+ response_headers = _httpx_download(
489
+ url,
490
+ target_filename,
491
+ show_progress=show_progress,
492
+ timeout=timeout,
493
+ auth=auth,
494
+ headers=headers,
495
+ mode=mode,
496
+ log_label="httpx",
497
+ )
369
498
 
370
499
  # Filter out None values from headers for HttpHeaders type compatibility
371
500
  if response_headers:
372
501
  clean_headers = {k: v for k, v in response_headers.items() if v is not None}
373
502
  return HttpHeaders(clean_headers)
374
503
  return None
504
+
505
+
506
+ def main() -> None:
507
+ """
508
+ Simple CLI test harness for fetch and download.
509
+
510
+ Usage examples:
511
+ uv run python -m kash.web_content.web_fetch
512
+ uv run python -m kash.web_content.web_fetch https://www.example.com
513
+ """
514
+ import sys
515
+ import traceback
516
+
517
+ # Try to use the system trust store for TLS like command-line curl
518
+ try:
519
+ import truststore # type: ignore
520
+
521
+ truststore.inject_into_ssl()
522
+ log.warning("truststore initialized for test harness: using system TLS trust store")
523
+ except Exception as exc:
524
+ log.info("truststore not available for test harness; using default TLS trust (%s)", exc)
525
+
526
+ urls = [
527
+ "https://www.example.com",
528
+ "https://www.businessdefense.gov/ibr/mceip/dpai/dpat3/index.html",
529
+ ]
530
+
531
+ args = [a for a in sys.argv[1:] if a and a.strip()]
532
+ if args:
533
+ urls = args
534
+
535
+ for u in urls:
536
+ try:
537
+ log.warning("Testing fetch_url: %s", u)
538
+ r = fetch_url(Url(u))
539
+ log.warning("fetch_url OK: %s -> %s bytes", u, len(r.content))
540
+ except Exception as exc:
541
+ log.exception("fetch_url FAILED for %s: %s", u, exc)
542
+ traceback.print_exc()
543
+
544
+
545
+ if __name__ == "__main__":
546
+ main()
@@ -95,6 +95,8 @@ def get_ws(name_or_path: str | Path, auto_init: bool = True) -> FileStore:
95
95
  Get a workspace by name or path. Adds to the in-memory registry so we reuse it.
96
96
  With `auto_init` true, will initialize the workspace if it is not already initialized.
97
97
  """
98
+ if isinstance(name_or_path, Path):
99
+ name_or_path = name_or_path.expanduser().absolute()
98
100
  name = Path(name_or_path).name
99
101
  name = check_strict_workspace_name(name)
100
102
  info = resolve_ws(name_or_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kash-shell
3
- Version: 0.3.33
3
+ Version: 0.3.35
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>
@@ -20,7 +20,7 @@ Requires-Dist: aiolimiter>=1.2.1
20
20
  Requires-Dist: anyio>=4.8.0
21
21
  Requires-Dist: audioop-lts>=0.2.1; python_version >= '3.13'
22
22
  Requires-Dist: cachetools>=5.5.2
23
- Requires-Dist: chopdiff>=0.2.5
23
+ Requires-Dist: chopdiff>=0.2.6
24
24
  Requires-Dist: clideps>=0.1.4
25
25
  Requires-Dist: colour>=0.1.5
26
26
  Requires-Dist: cssselect>=1.2.0
@@ -41,7 +41,7 @@ Requires-Dist: litellm>=1.74.15.post1
41
41
  Requires-Dist: markdownify>=0.13.1
42
42
  Requires-Dist: mcp-proxy>=0.5.0
43
43
  Requires-Dist: mcp>=1.6.0
44
- Requires-Dist: openai>=1.66.3
44
+ Requires-Dist: openai==1.99.9
45
45
  Requires-Dist: pandas>=2.2.3
46
46
  Requires-Dist: patch-ng>=1.18.1
47
47
  Requires-Dist: pathspec>=0.12.1
@@ -72,6 +72,7 @@ Requires-Dist: thefuzz>=0.22.1
72
72
  Requires-Dist: tiktoken>=0.9.0
73
73
  Requires-Dist: tldr>=3.3.0
74
74
  Requires-Dist: tminify>=0.1.6
75
+ Requires-Dist: truststore>=0.10.4
75
76
  Requires-Dist: typing-extensions>=4.12.2
76
77
  Requires-Dist: uvicorn>=0.34.0
77
78
  Requires-Dist: xonsh>=0.19.3
@@ -6,14 +6,14 @@ kash/actions/core/chat.py,sha256=9_xh9cWwXjkC_SYme-ScOg6Miqeydv15ccrwHqQvgq8,272
6
6
  kash/actions/core/combine_docs.py,sha256=5bTU7n_ICavvTXfC7fs5BDMeZYn7Xh5FkU7DVQqDHAQ,1536
7
7
  kash/actions/core/concat_docs.py,sha256=Umx3VzFiHJGY-76AEs4ju_1HnB9SbQsBux03Mkeig24,1345
8
8
  kash/actions/core/format_markdown_template.py,sha256=ZJbtyTSypPo2ewLiGRSyIpVf711vQMhI_-Ng-FgCs80,2991
9
- kash/actions/core/markdownify_html.py,sha256=0ZPH4b7IUWbMGi1mi0RzDPQKlqpLIsOy6ax_Gn7SSyA,1770
9
+ kash/actions/core/markdownify_html.py,sha256=Oqpq9b9JgMItOwJwbC5b5rG8UR0pXhxernjsdHyVB-o,1749
10
10
  kash/actions/core/minify_html.py,sha256=TRhyn7Gvcowou8pzq9vzDTtcCFOA4eC5217pJ9rPuOw,1386
11
11
  kash/actions/core/readability.py,sha256=P1whiDanaAKTPw2KwHG15QNcjHzwpuTWne0s4LyUfuQ,990
12
12
  kash/actions/core/render_as_html.py,sha256=i0WgtDgEJAeTTpVLS_CxDloDCb1Mhkzrcvv0VmoOyQ8,1901
13
13
  kash/actions/core/save_sidematter_meta.py,sha256=fKLE5eWIorOdw_FW46AUivXACQ6cxWvKWllcEjT6mz8,1440
14
14
  kash/actions/core/show_webpage.py,sha256=2A8u29Wf-iWNbPRfnz7u6MUhcXk_b8B8ruUT825d_mA,978
15
15
  kash/actions/core/strip_html.py,sha256=FDLN_4CKB11q5cU4NixTf7PGrAq92AjQNbKAdvQDwCY,849
16
- kash/actions/core/summarize_as_bullets.py,sha256=Zwr8lNzL77pwpnW_289LQjNBijNDpTPANfFdOJA-PZ4,2070
16
+ kash/actions/core/summarize_as_bullets.py,sha256=bzEH43BwwdqMJCt6m01iIME8sfmVPylBtF1PNbDdrBw,2055
17
17
  kash/actions/core/tabbed_webpage_config.py,sha256=rIbzEhBTmnkbSiRZC-Rj46T1J6c0jOztiKE9Usa4nsc,980
18
18
  kash/actions/core/tabbed_webpage_generate.py,sha256=935HkDSuP4eZ1e0xf-LhjPOdicU3wI5Kuh79r61QCl8,988
19
19
  kash/actions/core/zip_sidematter.py,sha256=E7ae0g9Bz7uXApYdNY-a8GvSIIPoqXcD95mjMaKQlsM,1557
@@ -43,18 +43,19 @@ kash/commands/workspace/workspace_commands.py,sha256=GE_wHdeYFJ1ruRi4spZtyyTjYXJ
43
43
  kash/config/__init__.py,sha256=ytly9Typ1mWV4CXfV9G3CIPtPQ02u2rpZ304L3GlFro,148
44
44
  kash/config/capture_output.py,sha256=ud3uUVNuDicHj3mI_nBUBO-VmOrxtBdA3z-I3D1lSCU,2398
45
45
  kash/config/colors.py,sha256=cV3LRBegDZxZXjV-XEjc3fystFY_defhz1LN8QPdaKc,13727
46
- kash/config/env_settings.py,sha256=uhCdfs9-TzJ15SzbuIQP1yIORaLUqYXCxh9qq_Z8cJc,996
46
+ kash/config/env_settings.py,sha256=HmXmlOQ8i4b3vqEaRHF2PnHHNOjITPN7U27hiG4dsZ4,904
47
47
  kash/config/init.py,sha256=aE4sZ6DggBmmoZEx9C5mQKrEbcDiswX--HF7pfCFKzc,526
48
48
  kash/config/lazy_imports.py,sha256=MCZXLnKvNyfHi0k7MU5rNwcdJtUF28naCixuogsAOAA,805
49
- kash/config/logger.py,sha256=Wrhau5gPYwGSmA1V2IbMhyApTRgB8p4Pyk8JL7OCTaE,12189
50
- kash/config/logger_basic.py,sha256=Gsxitz7xeMGCUr5qjWK6y72qeMsIz4mcDZP5xyzK0WU,1598
49
+ kash/config/logger.py,sha256=gkE3yV6WMawduxbQpiKwmIqglThXv9qEJ8_YR1uKy3Y,12226
50
+ kash/config/logger_basic.py,sha256=_a42XrXOGzuHEIU0LkXcBiZ3u4JTnMmCVChXZCv9U68,1870
51
51
  kash/config/logo.txt,sha256=P4RO1cJ9HRF1BavTp3Kae9iByDNhzhEC-qLAa6ww1RA,217
52
52
  kash/config/server_config.py,sha256=eQ1yxDk031QI0Efp0I1VetqQd9wG7MrLVBCHFm4gp2g,1790
53
- kash/config/settings.py,sha256=Tja5MNZJDjo5SRaCngfQQFTTjmVGUlmkCZ7UEAhvXqw,9087
54
- kash/config/setup.py,sha256=SepMs7CvWdIXCjs03_noA16PETW_YOxH33F8cdP8kYc,2643
53
+ kash/config/settings.py,sha256=XfD5xgxREMAnJ5YMGmwmpN6dmRJ8tw0aQV398fvHj1s,8770
54
+ kash/config/setup.py,sha256=D9hvg-Y5X9mXiDoIzqNPJIgOleA6nDZyANgxBYWewYk,3135
55
55
  kash/config/suppress_warnings.py,sha256=yty5ZodMLIpmjphRtcVmRamXfiWbyfga9annve6qxb0,1475
56
- kash/config/text_styles.py,sha256=pQ0FKJW7eSXU6ol5LhyaGZewxF40L6Q0o92mfsNNCYQ,13843
56
+ kash/config/text_styles.py,sha256=hDIxP-uTio6FYVz8xI1AwyS5XpRRwjU3A-V7AdDF_ug,13841
57
57
  kash/config/unified_live.py,sha256=tUEnTWMSYKYSJkEoAPbaJET-bJ1HnfU2Ar-XeyBOtlo,8420
58
+ kash/config/warm_slow_imports.py,sha256=65nUsVBMCp6VmKqPPidxrYLXkWixU2RTr86VlGYRVP4,2241
58
59
  kash/docs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
60
  kash/docs/all_docs.py,sha256=NutfgU8VOA7_K2HX18FoOHVvvLL14dALoCxK9qDbQ04,3157
60
61
  kash/docs/load_actions_info.py,sha256=D9uv8gdBtkBmdbFZeyIigsupPF9_WfidHVwWQrlggI0,937
@@ -87,13 +88,13 @@ kash/embeddings/cosine.py,sha256=QTWPWUHivXjxCM6APSqij_-4mywM2BVVm0xb0hu7FHA,158
87
88
  kash/embeddings/embeddings.py,sha256=DirB5DjowEQADfxtp1BTROINyIxU2QEUj79_tXipRfo,6664
88
89
  kash/embeddings/text_similarity.py,sha256=2jp0A27dOto6kItzqe95-f-lx6Mop68d-MJevyCHj9o,1817
89
90
  kash/exec/__init__.py,sha256=Najls8No143yoj_KAaOQgo8ufC2LWCB_DwwEQ-8nDM0,1277
90
- kash/exec/action_decorators.py,sha256=omCr3oxB7LRBWksRrB8nif1bSgFv2ZBKhfMGQuTBp2k,16956
91
- kash/exec/action_exec.py,sha256=HZ7ZtWhpkRxjzai_ZIeTf33Ak_4HmmLujjvSud8yGsw,20943
91
+ kash/exec/action_decorators.py,sha256=bb4O8TcCFw3Oe5bFfnUZ1AeBwEwnNCL0GLwrMDv_UDI,16954
92
+ kash/exec/action_exec.py,sha256=KWvJdD9Ndelr-wEqZF3pJRujKO4n4gBLdwNz4S39Q5A,20942
92
93
  kash/exec/action_registry.py,sha256=numU9pH_W5RgIrYmfi0iYMYy_kLJl6vup8PMrhxAfdc,2627
93
94
  kash/exec/combiners.py,sha256=AJ6wgPUHsmwanObsUw64B83XzU26yuh5t4l7igLn82I,4291
94
95
  kash/exec/command_exec.py,sha256=zc-gWm7kyB5J5Kp8xhULQ9Jj9AL927KkDPXXk-Yr1Bw,1292
95
96
  kash/exec/command_registry.py,sha256=1s2ogU8b8nqK_AEtslbr1eYrXCGDkeT30UrB7L0BRoM,2027
96
- kash/exec/fetch_url_items.py,sha256=BNqAPL4VaXUGZ_q3pNt5QLNKMfU0PMLDrdw8f6xQRo8,6211
97
+ kash/exec/fetch_url_items.py,sha256=Bb8i9YW_XfJHwIAh5yf2_zLXagyESkQF1LL1uNaQQx0,6345
97
98
  kash/exec/history.py,sha256=l2XwHGBR1UgTGSFPSBE9mltmxvjR_5qFFO6d-Z008nc,1208
98
99
  kash/exec/importing.py,sha256=xunmBapeUMNc6Zox7y6e_DZkidyWeouiFZpphajwSzc,1843
99
100
  kash/exec/llm_transforms.py,sha256=jQAnxHhcvF3oILjpSHx0YRw8Qw-ZnioukXaJuaqjNVk,4626
@@ -146,10 +147,10 @@ kash/local_server/local_url_formatters.py,sha256=SqHjGMEufvm43n34SCa_8Asdwm7utx9
146
147
  kash/local_server/port_tools.py,sha256=oFfOvO6keqS5GowTpVg2FTu5KqkPHBq-dWAEomUIgGo,2008
147
148
  kash/local_server/rich_html_template.py,sha256=O9CnkMYkWuMvKJkqD0P8jaZqfUe6hMP4LXFvcLpwN8Q,196
148
149
  kash/mcp/__init__.py,sha256=HA_aFskEchpAwA0wOKi5nasytx2JZfH8z9oCVXUI7MQ,160
149
- kash/mcp/mcp_cli.py,sha256=UC0Jwd7DLxx2zEFj0hK1UWPkXXXGntV1te33CensyHM,3849
150
+ kash/mcp/mcp_cli.py,sha256=lWV7mbsj7qMgA42aW5MMkXxLwb66kGrjuaXLsDsTRTo,4300
150
151
  kash/mcp/mcp_main.py,sha256=6PhjKwp631mezDTUAd-pL8lUZx9Gl7yCrCQFW61pqJU,3167
151
152
  kash/mcp/mcp_server_commands.py,sha256=sKPBD4DptUArxo833eJRRYYRt32E5Dwpr0k8Qe6U8ec,4349
152
- kash/mcp/mcp_server_routes.py,sha256=gWsr9WkEVzSslF-XaiO7wMUD9bJeabXj4xNy6WwqHaM,11757
153
+ kash/mcp/mcp_server_routes.py,sha256=dfeCFK6FedRG3OXVd-53Hk5uX2TkWWQ0mAxllm8gJc8,11803
153
154
  kash/mcp/mcp_server_sse.py,sha256=7zAOJodrCVfLtChUTRxzgxWGymQnmj1e9fRG7H_yqXg,5678
154
155
  kash/mcp/mcp_server_stdio.py,sha256=u-oeIZKwzIAGlKmBpipC-hfNQKx36Md9hST11y3AZUY,1174
155
156
  kash/media_base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -163,13 +164,13 @@ kash/media_base/transcription_format.py,sha256=rOVPTpwvW22c27BRwYF-Tc_xzqK_wOtUZ
163
164
  kash/media_base/transcription_whisper.py,sha256=GqvroW9kBAH4-gcbYkMgNCfs2MpMIgm1ip3NMWtJ0IE,1169
164
165
  kash/media_base/services/local_file_media.py,sha256=_NV-T90rShJ8ucUjQXMPCKKJ50GSFE9PyyVzhXp5z9w,5624
165
166
  kash/model/__init__.py,sha256=kFfBKb5N70NWYUfpRRxn_Sb9p_vXlB6BBaTCqWmSReo,2978
166
- kash/model/actions_model.py,sha256=-41qz76Z9NZZhRQcPDRopyHAGxHCrTvbMRDv8fnb7CQ,23185
167
+ kash/model/actions_model.py,sha256=Y_MyZ6ATxr7-0AAnBFyWOJ8_81DCeWviNc2U4ig59bM,23705
167
168
  kash/model/assistant_response_model.py,sha256=6eDfC27nyuBDFjv5nCYMa_Qb2mPbKwDzZy7uLOIyskI,2653
168
169
  kash/model/compound_actions_model.py,sha256=oYEtVKtQv-mA1abZkK7PvaM9xazVBUuk1z0geKBulak,6965
169
170
  kash/model/concept_model.py,sha256=we2qOcy9Mv1q7XPfkDLp_CyO_-8DwAUfUYlpgy_jrFs,1011
170
171
  kash/model/exec_model.py,sha256=3Su3NEmEtDoSuQSxvg75FYY_EdClSM5pwQK1i7_S88A,3131
171
172
  kash/model/graph_model.py,sha256=T034y0E9OJtITd1g9zp9vll5pLscdatq6JoT08KvPZE,2724
172
- kash/model/items_model.py,sha256=V7so_AWc7skRZGlByIK5m3ETUaHEw8IYx9OB9pmzNEA,39545
173
+ kash/model/items_model.py,sha256=1WXNNmiqDs32XR3d8v_dUY4Y6T-3ow3XKuTJOoF_how,39937
173
174
  kash/model/language_list.py,sha256=I3RIbxTseVmPdhExQimimEv18Gmy2ImMbpXe0-_t1Qw,450
174
175
  kash/model/llm_actions_model.py,sha256=a29uXVNfS2CiqvM7HPdC6H9A23rSQQihAideuBLMH8g,2110
175
176
  kash/model/media_model.py,sha256=ZnlZ-FkswbAIGpUAuNqLce1WDZK-WbnwHn2ipg8x7-0,3511
@@ -178,7 +179,7 @@ kash/model/params_model.py,sha256=NHW-74_sFCY58spf9bzU1EaVxLDpdbqmiw8SCSKASCw,15
178
179
  kash/model/paths_model.py,sha256=KDFm7wan7hjObHbnV2rR8-jsyLTVqbKcwFdKeLFRtdM,15889
179
180
  kash/model/preconditions_model.py,sha256=-IfsVR0NkQhq_3hUTXzK2bFYAd--3YjSwUiDKHVQQqk,2887
180
181
  kash/shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
181
- kash/shell/shell_main.py,sha256=thpGEN2kiruTiMaocdwnzfIAs-WCX-Pvi8jiea3V2q0,3896
182
+ kash/shell/shell_main.py,sha256=mG_QoyOeHjcXpPUARjmHEtCjPGpc3IT28kdu8i8NkwM,3401
182
183
  kash/shell/version.py,sha256=Si8MgIwAwTOSdXY7znWHTsvzdR2vlZdkmcF5n_oUigE,1400
183
184
  kash/shell/completions/completion_scoring.py,sha256=-svesm2cR1AA86jYcxlynXCBZON26eUJce93FlL2nQo,10209
184
185
  kash/shell/completions/completion_types.py,sha256=FocRXd6Df3Df0nL2Y1GevMx3FsljJwbQdVgWsIngpaQ,4793
@@ -208,18 +209,18 @@ kash/utils/api_utils/api_retries.py,sha256=TtgxLxoMnXIzYMKbMUzsnVcPf-aKFm3cJ95zO
208
209
  kash/utils/api_utils/cache_requests_limited.py,sha256=TA5buZ9Dgbj4I1zHhwerTXre018i0TCACGsezsjX9Uc,3140
209
210
  kash/utils/api_utils/gather_limited.py,sha256=6K0Z3u_NeX9wBfFFk21wUQeSimaDIm53AHlGYRLD6LQ,33018
210
211
  kash/utils/api_utils/http_utils.py,sha256=Ou6QNiba5w7n71cgNmV168OFTLmMDNxWW5MM-XkFEME,1461
211
- kash/utils/api_utils/multitask_gather.py,sha256=iC1UlZXZV7YMevDD--mCi1eR0Rmd7wAWrOy-C_l0ACw,2594
212
+ kash/utils/api_utils/multitask_gather.py,sha256=LAylwWZ2APbv-O_l0kLwBfP762D0qswMBV8ID4eCOA0,4446
212
213
  kash/utils/api_utils/progress_protocol.py,sha256=6cT5URY6cScHYd6UZoTT_rHI0mbsE52joBf88regEN8,8816
213
214
  kash/utils/common/__init__.py,sha256=ggeWw1xmbl1mgCQD3c4CNN2h5WXFCsN2wXlCWurEUEI,161
214
215
  kash/utils/common/format_utils.py,sha256=83FhAwbMnOQIFudpnOGMuCqCiyoAlWGS6cc8q6xgZus,2072
215
216
  kash/utils/common/function_inspect.py,sha256=KE5QgIPx16iupCZrMlcvU6MuA5fUFboPEkqmltpFw3E,19824
216
- kash/utils/common/import_utils.py,sha256=zyCa5sG_vTxzgIgjOS98xAwqkSeCQzN-8UkM6k9ZZOI,4615
217
+ kash/utils/common/import_utils.py,sha256=j3_xZS__647YjlszmKCwtS2agZPOi9ZaQ7SNbz99RhM,8988
217
218
  kash/utils/common/lazyobject.py,sha256=9dmOfSheblOXgo2RRakMwgfPIKdTgtyrlm6dCKAze04,5157
218
219
  kash/utils/common/obj_replace.py,sha256=AuiXptUOnuDNcWDgAJ3jEHkLh89XIqCP_SOkgaVyFIQ,2075
219
220
  kash/utils/common/parse_docstring.py,sha256=oM1ecGGySRA3L_poddjReJ_qPY5506Le7E8_CDUrU8k,10922
220
221
  kash/utils/common/parse_key_vals.py,sha256=yZRZIa5GD9SlnBSn2YNZm8PRVKoSJMY8DCmdGujQj_I,2418
221
222
  kash/utils/common/parse_shell_args.py,sha256=UZXTZDbV5m5Jy39jdAQ6W8uilr1TNa0__RqnE8UmQ_M,10604
222
- kash/utils/common/s3_utils.py,sha256=YZ_qTKtuUtb_oJd8Ke0PgVdg8sYa47PwUkTZVsJ0rWM,3311
223
+ kash/utils/common/s3_utils.py,sha256=wt-ieT9DPwsqe8_w-KCeyUAbDCvsIaCiD9lsOfHvd1A,5534
223
224
  kash/utils/common/stack_traces.py,sha256=a2NwlK_0xxnjMCDC4LrQu7ueFylF-OImFG3bAAHpPwY,1392
224
225
  kash/utils/common/task_stack.py,sha256=XkeBz3BwYY1HxxTqd3f7CulV0s61PePAKw1Irrtvf5o,4536
225
226
  kash/utils/common/testing.py,sha256=9at6m_2YwRYitQoo-KeGsd2aoA59YUPs-x7cKcmy1C4,1802
@@ -244,15 +245,15 @@ kash/utils/lang_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
244
245
  kash/utils/lang_utils/capitalization.py,sha256=5XbqBvjkzlxsm1Ue5AQP3P1J1IG0PubMVmGnoKVTF-c,3903
245
246
  kash/utils/rich_custom/__init__.py,sha256=_g2F3Bqc1UnLTdAdCwkvzXmW7OvmqXrA8DpfT1dKy6w,75
246
247
  kash/utils/rich_custom/ansi_cell_len.py,sha256=oQlNrqWB0f6pmigkbRRyeK6oWlGHMPbV_YLO_qmDH5E,2356
247
- kash/utils/rich_custom/multitask_status.py,sha256=eOON62evEAOmmNyVBSjfYkh5y9OTejQrs02rc2L55VE,24375
248
+ kash/utils/rich_custom/multitask_status.py,sha256=3hMxXNAClxcQzzQdBA0rPDNp19Y_6gT8NRIuT8OkO7Q,27667
248
249
  kash/utils/rich_custom/rich_char_transform.py,sha256=3M89tViKM0y31VHsDoHi5eHFWlv5ME7F4p35IdDxnrw,2616
249
250
  kash/utils/rich_custom/rich_indent.py,sha256=nz72yNpUuYjOsaPNVmxM81oEQm-GKEfQkNsuWmv16G0,2286
250
251
  kash/utils/rich_custom/rich_markdown_fork.py,sha256=M_JRaSAyHrSg-wuLv9C9P7SkehSim3lwkqQPuMIFkVw,26551
251
252
  kash/utils/text_handling/doc_normalization.py,sha256=GsK8J8HSVINYYIeO2XQvWYK1ZSiQ6mX34mVb9UOjgG8,3029
252
253
  kash/utils/text_handling/escape_html_tags.py,sha256=8pC3JgoKRtdnbnOu8DiWrlvNR6GAqjwhGbQgl3jiFG4,6441
253
- kash/utils/text_handling/markdown_footnotes.py,sha256=4_ZOez-xHjiSn_XHyqXPk9MNbjts1hiHOh1ARs9vVZA,7494
254
+ kash/utils/text_handling/markdown_footnotes.py,sha256=TgS3un4h_qmZB1KnDUVKaOYLZWhljlUZ-QjLfL6gkgg,6480
254
255
  kash/utils/text_handling/markdown_render.py,sha256=LHPdJc__2ejBx7iwkp_P9wIePNmiVSgwu4-uhamVjms,3791
255
- kash/utils/text_handling/markdown_utils.py,sha256=Yf57dVljpbg8vuHbtcOSHZqz1PafOSBal6R8ESJz1Bs,49220
256
+ kash/utils/text_handling/markdown_utils.py,sha256=ufVYSBvBl9jRYP6Bfsoxhgv754SW3KDxo8rN67OK6a4,52274
256
257
  kash/utils/text_handling/markdownify_utils.py,sha256=fXl3uSUk9aHXL0PDqxdlvWvIvBXUQTOfQxnK9uicQcg,2964
257
258
  kash/utils/text_handling/unified_diffs.py,sha256=JfHSakISkT_GuBPBI4fTooHrp2aenWzDKiVvDewVfMk,2655
258
259
  kash/web_content/canon_url.py,sha256=Zv2q7xQdIHBFkxxwyJn3_ME-qqMFRi_fKxE_IgV2Z50,742
@@ -260,10 +261,10 @@ kash/web_content/dir_store.py,sha256=BJc-s-RL5CC-GwhFTC_lhLXSMWluPPnLVmVBx-66DiM
260
261
  kash/web_content/file_cache_utils.py,sha256=JRXUCAmrc83iAgdiICU2EYGWcoORflWNl6GAVq-O80I,5529
261
262
  kash/web_content/file_processing.py,sha256=cQC-MnJMM5qG9-y0S4yobkmRi6A75qhHjV6xTwbtYDY,1904
262
263
  kash/web_content/local_file_cache.py,sha256=PEDKU5VIwhCnSC-HXG4EkO2OzrOUDuuDBMuo3lP2EN0,9466
263
- kash/web_content/web_extract.py,sha256=TrGOohn99LF1F0zbycgXqYiIR-V3leefFFEVk3tnW6Y,2979
264
+ kash/web_content/web_extract.py,sha256=2CTxNJTYRGJ5ZfBvNVKxNGwNlbUyTnfHRPL6qRIrYxI,2978
264
265
  kash/web_content/web_extract_justext.py,sha256=74HLJBKDGKatwxyRDX6za70bZG9LrVmtj9jLX7UJzg4,2540
265
266
  kash/web_content/web_extract_readabilipy.py,sha256=IT7ET5IoU2-Nf37-Neh6CkKMvLL3WTNVJjq7ZMOx6OM,808
266
- kash/web_content/web_fetch.py,sha256=TGzGRyG9KW26V8WhQJkK-MwFN2MJBtMX-j4iY72tVtg,12217
267
+ kash/web_content/web_fetch.py,sha256=xBTd63oi3j2kwwTUYTF5mJ7ZXEEHa51wZB60KzCgG5k,17046
267
268
  kash/web_content/web_page_model.py,sha256=TWgWreGOoOvl7lUkjMSd0rxoDf2VuaKOq7WijwydW0Q,1387
268
269
  kash/web_gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
269
270
  kash/web_gen/tabbed_webpage.py,sha256=e0GGG1bQ4CQegpJgOIT2KpyM6cmwN_BQ9eJSsi4BjgY,4945
@@ -290,7 +291,7 @@ kash/workspaces/source_items.py,sha256=Pwnw3OhjR2IJEMEeHf6hpKloj-ellM5vsY7LgkGev
290
291
  kash/workspaces/workspace_dirs.py,sha256=kjuY4t7mSSXq00fZmln7p9TWq4kAZoPTCDM0DG7uEaI,1545
291
292
  kash/workspaces/workspace_output.py,sha256=MMg_KumkHKFGc0DOUFaW5ImpgqIfdlsLtvXbLEt1hwI,5692
292
293
  kash/workspaces/workspace_registry.py,sha256=SQt2DZgBEu95Zj9fpy67XdJPgJyKFDCU2laSuiZswNo,2200
293
- kash/workspaces/workspaces.py,sha256=H-VpigO2zvWvWCZIT2G-cqEqcZATiwCLFX2jwFW08bw,6781
294
+ kash/workspaces/workspaces.py,sha256=LBqrl_NVpXb7Lnjg_aIhQ0BZxNzEWK7p0jv0VEy0L7A,6880
294
295
  kash/xonsh_custom/command_nl_utils.py,sha256=6Xcx98HXL5HywziHi0XskwFx6kfvz7oCmMX-siJib1A,3392
295
296
  kash/xonsh_custom/custom_shell.py,sha256=wTYwDt6zJzVtljcDh1j__cJXkoMy9w687vhgDk6nlqU,19024
296
297
  kash/xonsh_custom/customize_prompt.py,sha256=u-jRY-ftXYflBkbJVetEg6GYelPUvqZEpjrPRUTfy8w,6896
@@ -304,8 +305,8 @@ kash/xonsh_custom/xonsh_modern_tools.py,sha256=mj_b34LZXfE8MJe9EpDmp5JZ0tDM1biYN
304
305
  kash/xonsh_custom/xonsh_ranking_completer.py,sha256=ZRGiAfoEgqgnlq2-ReUVEaX5oOgW1DQ9WxIv2OJLuTo,5620
305
306
  kash/xontrib/fnm.py,sha256=V2tsOdmIDgbFbZSfMLpsvDIwwJJqiYnOkOySD1cXNXw,3700
306
307
  kash/xontrib/kash_extension.py,sha256=FLIMlgR3C_6A1fwKE-Ul0nmmpJSszVPbAriinUyQ8Zg,1896
307
- kash_shell-0.3.33.dist-info/METADATA,sha256=rEXEktz-jYfIDY2XI0fmEQbBVnLYoo1omDU6B0LQLhw,33547
308
- kash_shell-0.3.33.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
309
- kash_shell-0.3.33.dist-info/entry_points.txt,sha256=SQraWDAo8SqYpthLXThei0mf_hGGyhYBUO-Er_0HcwI,85
310
- kash_shell-0.3.33.dist-info/licenses/LICENSE,sha256=rCh2PsfYeiU6FK_0wb58kHGm_Fj5c43fdcHEexiVzIo,34562
311
- kash_shell-0.3.33.dist-info/RECORD,,
308
+ kash_shell-0.3.35.dist-info/METADATA,sha256=tiHz-9gjkl9cyzEt8XxLl7kHDYbCb86dW9xpeU7qSGg,33581
309
+ kash_shell-0.3.35.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
310
+ kash_shell-0.3.35.dist-info/entry_points.txt,sha256=SQraWDAo8SqYpthLXThei0mf_hGGyhYBUO-Er_0HcwI,85
311
+ kash_shell-0.3.35.dist-info/licenses/LICENSE,sha256=rCh2PsfYeiU6FK_0wb58kHGm_Fj5c43fdcHEexiVzIo,34562
312
+ kash_shell-0.3.35.dist-info/RECORD,,