lkr-dev-cli 0.0.21__py3-none-any.whl → 0.0.23__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.
lkr/auth/oauth.py CHANGED
@@ -19,21 +19,23 @@ def kill_process_on_port(port: int, retries: int = 5, delay: float = 1) -> None:
19
19
  # Try to create a socket binding to check if port is in use
20
20
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
21
21
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
22
- sock.bind(('localhost', port))
22
+ sock.bind(("localhost", port))
23
23
  sock.close()
24
24
  return # Port is free, no need to kill anything
25
25
  except socket.error:
26
26
  # Port is in use, try to kill the process
27
- if os.name == 'posix': # macOS/Linux
28
- os.system(f'lsof -ti tcp:{port} | xargs kill -9 2>/dev/null')
29
- elif os.name == 'nt': # Windows
30
- os.system(f'for /f "tokens=5" %a in (\'netstat -aon ^| find ":{port}"\') do taskkill /F /PID %a 2>nul')
27
+ if os.name == "posix": # macOS/Linux
28
+ os.system(f"lsof -ti tcp:{port} | xargs kill -9 2>/dev/null")
29
+ elif os.name == "nt": # Windows
30
+ os.system(
31
+ f'for /f "tokens=5" %a in (\'netstat -aon ^| find ":{port}"\') do taskkill /F /PID %a 2>nul'
32
+ )
31
33
  # After killing, wait for the port to be free
32
34
  for _ in range(retries):
33
35
  try:
34
36
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
35
37
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
36
- sock.bind(('localhost', port))
38
+ sock.bind(("localhost", port))
37
39
  sock.close()
38
40
  return
39
41
  except socket.error:
@@ -45,19 +47,21 @@ class OAuthCallbackHandler(http.server.BaseHTTPRequestHandler):
45
47
  def do_GET(self):
46
48
  """Handle the callback from OAuth authorization"""
47
49
  self.send_response(200)
48
- self.send_header('Content-type', 'text/html')
50
+ self.send_header("Content-type", "text/html")
49
51
  self.end_headers()
50
-
52
+
51
53
  # Parse the authorization code from query parameters
52
54
  query_components = parse_qs(urllib.parse.urlparse(self.path).query)
53
-
55
+
54
56
  # Store the code in the server instance
55
- if 'code' in query_components:
56
- self.server.auth_code = query_components['code'][0] # type: ignore
57
-
57
+ if "code" in query_components:
58
+ self.server.auth_code = query_components["code"][0] # type: ignore
59
+
58
60
  # Display a success message to the user
59
- self.wfile.write(b"Authentication successful! You can close this window.")
60
-
61
+ self.wfile.write(
62
+ b"Successfully authenticated to Looker OAuth! You can close this window."
63
+ )
64
+
61
65
  # Shutdown the server
62
66
  threading.Thread(target=self.server.shutdown).start()
63
67
 
@@ -65,18 +69,22 @@ class OAuthCallbackHandler(http.server.BaseHTTPRequestHandler):
65
69
  """Suppress logging of requests"""
66
70
  pass
67
71
 
72
+
68
73
  class OAuthCallbackServer(socketserver.TCPServer):
69
74
  def __init__(self, server_address):
70
75
  super().__init__(server_address, OAuthCallbackHandler)
71
76
  self.auth_code: str | None = None
72
77
 
78
+
73
79
  class LoginResponse(TypedDict):
74
80
  auth_code: Optional[str]
75
81
  code_verifier: Optional[str]
76
82
 
83
+
77
84
  class OAuth2PKCE:
78
85
  def __init__(self, new_token_callback: NewTokenCallback, use_production: bool):
79
86
  from lkr.auth_service import DbOAuthSession
87
+
80
88
  self.auth_code: Optional[str] = None
81
89
  self.state = secrets.token_urlsafe(16)
82
90
  self.new_token_callback: NewTokenCallback = new_token_callback
@@ -85,7 +93,7 @@ class OAuth2PKCE:
85
93
  self.server: OAuthCallbackServer | None = None
86
94
  self.port: int = 8000
87
95
  self.use_production: bool = use_production
88
-
96
+
89
97
  def cleanup(self):
90
98
  """Clean up the server and its thread."""
91
99
  if self.server:
@@ -100,51 +108,64 @@ class OAuth2PKCE:
100
108
  """
101
109
  Initiates the OAuth2 PKCE login flow by opening the browser with the authorization URL
102
110
  and starting a local server to catch the callback.
103
-
111
+
104
112
  Returns:
105
113
  Optional[str]: The authorization code if successful, None otherwise
106
114
  """
107
115
  from lkr.auth_service import get_auth_session
108
-
116
+
109
117
  # Kill any process using port 8000
110
118
  kill_process_on_port(self.port)
111
-
119
+
112
120
  # Start the local server
113
- self.server = OAuthCallbackServer(('localhost', self.port))
114
-
121
+ self.server = OAuthCallbackServer(("localhost", self.port))
122
+
115
123
  # Start the server in a separate thread
116
124
  self.server_thread = threading.Thread(target=self.server.serve_forever)
117
125
  self.server_thread.daemon = True
118
126
  self.server_thread.start()
119
127
 
120
128
  # Construct and open the OAuth URL
121
- self.auth_session = get_auth_session(base_url, self.new_token_callback, use_production=self.use_production)
122
- oauth_url = self.auth_session.create_auth_code_request_url('cors_api', self.state)
123
-
129
+ self.auth_session = get_auth_session(
130
+ base_url, self.new_token_callback, use_production=self.use_production
131
+ )
132
+ oauth_url = self.auth_session.create_auth_code_request_url(
133
+ "cors_api", self.state
134
+ )
135
+
124
136
  webbrowser.open(oauth_url)
125
-
137
+
126
138
  # Wait for the callback
127
139
  self.server_thread.join()
128
-
140
+
129
141
  # Get the authorization code
130
- return LoginResponse(auth_code=self.server.auth_code, code_verifier=self.auth_session.code_verifier)
142
+ return LoginResponse(
143
+ auth_code=self.server.auth_code,
144
+ code_verifier=self.auth_session.code_verifier,
145
+ )
131
146
 
132
147
  def exchange_code_for_token(self):
133
148
  """
134
149
  Exchange the authorization code for access and refresh tokens.
135
-
150
+
136
151
  Args:
137
152
  base_url: The base URL of the Looker instance
138
153
  client_id: The OAuth client ID
139
-
154
+
140
155
  Returns:
141
156
  Dict containing access_token, refresh_token, token_type, and expires_in
142
157
  """
143
158
  if not self.auth_code:
144
- raise ValueError("No authorization code available. Must call initiate_login first.")
159
+ raise ValueError(
160
+ "No authorization code available. Must call initiate_login first."
161
+ )
145
162
  if not self.auth_session:
146
- raise ValueError("No auth session available. Must call initiate_login first.")
147
- self.auth_session.redeem_auth_code(self.auth_code, self.auth_session.code_verifier)
163
+ raise ValueError(
164
+ "No auth session available. Must call initiate_login first."
165
+ )
166
+ self.auth_session.redeem_auth_code(
167
+ self.auth_code, self.auth_session.code_verifier
168
+ )
148
169
  self.cleanup()
149
170
  return self.auth_session.token
150
171
 
lkr/auth_service.py CHANGED
@@ -20,7 +20,7 @@ from lkr.constants import LOOKER_API_VERSION, OAUTH_CLIENT_ID, OAUTH_REDIRECT_UR
20
20
  from lkr.logging import logger
21
21
  from lkr.types import NewTokenCallback
22
22
 
23
- __all__ = ["get_auth"]
23
+ __all__ = ["get_auth", "ApiKeyAuthSession", "DbOAuthSession"]
24
24
 
25
25
 
26
26
  def get_auth(ctx: typer.Context | LkrCtxObj) -> Union["SqlLiteAuth", "ApiKeyAuth"]:
@@ -33,7 +33,7 @@ def get_auth(ctx: typer.Context | LkrCtxObj) -> Union["SqlLiteAuth", "ApiKeyAuth
33
33
  raise typer.Exit(1)
34
34
  if lkr_ctx.use_sdk == "api_key" and lkr_ctx.api_key:
35
35
  logger.info("Using API key authentication")
36
- return ApiKeyAuth(lkr_ctx.api_key)
36
+ return ApiKeyAuth(lkr_ctx.api_key, use_production=lkr_ctx.use_production)
37
37
  else:
38
38
  return SqlLiteAuth(lkr_ctx)
39
39
 
@@ -70,6 +70,36 @@ class OAuthApiSettings(ApiSettings):
70
70
  )
71
71
 
72
72
 
73
+ class ApiKeyAuthSession(AuthSession):
74
+ def __init__(self, *args, use_production: bool, **kwargs):
75
+ super().__init__(*args, **kwargs)
76
+ self.use_production = use_production
77
+
78
+ def _login(self, *args, **kwargs):
79
+ super()._login(*args, **kwargs)
80
+ if not self.use_production:
81
+ self._switch_to_dev_mode()
82
+
83
+ def _switch_to_dev_mode(self):
84
+ logger.debug("Switching to dev mode")
85
+ config = self.settings.read_config()
86
+ if "base_url" in config:
87
+ url = f"{config['base_url']}/api/{LOOKER_API_VERSION}/session"
88
+ return self.transport.request(
89
+ method=HttpMethod.PATCH,
90
+ path=url,
91
+ body=json.dumps({"workspace_id": "dev"}).encode("utf-8"),
92
+ transport_options={
93
+ "headers": {
94
+ "Content-Type": "application/json",
95
+ "Authorization": f"Bearer {self.token.access_token}",
96
+ }
97
+ },
98
+ )
99
+ else:
100
+ raise ValueError("Base URL not found in settings")
101
+
102
+
73
103
  class DbOAuthSession(OAuthSession):
74
104
  def __init__(
75
105
  self,
@@ -137,18 +167,19 @@ def get_auth_session(
137
167
  return auth
138
168
 
139
169
 
140
- def init_api_key_sdk(api_key: LookerApiKey) -> Looker40SDK:
170
+ def init_api_key_sdk(api_key: LookerApiKey, use_production: bool) -> Looker40SDK:
141
171
  from looker_sdk.rtl import serialize
142
172
 
143
173
  settings = ApiKeyApiSettings(api_key)
144
174
  settings.is_configured()
145
175
  transport = RequestsTransport.configure(settings)
146
176
  return Looker40SDK(
147
- auth=AuthSession(
177
+ auth=ApiKeyAuthSession(
148
178
  settings,
149
179
  transport,
150
180
  serialize.deserialize40, # type: ignore
151
181
  LOOKER_API_VERSION,
182
+ use_production=use_production,
152
183
  ),
153
184
  deserialize=serialize.deserialize40, # type: ignore
154
185
  serialize=serialize.serialize40, # type: ignore
@@ -395,9 +426,7 @@ class SqlLiteAuth:
395
426
  return current_auth.instance_name
396
427
  return None
397
428
 
398
- def get_current_sdk(
399
- self, prompt_refresh_invalid_token: bool = False
400
- ) -> Looker40SDK:
429
+ def get_current_sdk(self, prompt_refresh_invalid_token: bool = True) -> Looker40SDK:
401
430
  current_auth = self._get_current_auth()
402
431
  if current_auth:
403
432
  if not current_auth.valid_refresh_token:
@@ -480,8 +509,9 @@ class SqlLiteAuth:
480
509
 
481
510
 
482
511
  class ApiKeyAuth:
483
- def __init__(self, api_key: LookerApiKey):
512
+ def __init__(self, api_key: LookerApiKey, use_production: bool):
484
513
  self.api_key = api_key
514
+ self.use_production = use_production
485
515
 
486
516
  def __enter__(self):
487
517
  return self
@@ -518,7 +548,7 @@ class ApiKeyAuth:
518
548
  )
519
549
 
520
550
  def get_current_sdk(self, **kwargs) -> Looker40SDK:
521
- return init_api_key_sdk(self.api_key)
551
+ return init_api_key_sdk(self.api_key, self.use_production)
522
552
 
523
553
  def get_current_instance(self) -> str | None:
524
554
  raise NotImplementedError(
lkr/classes.py CHANGED
@@ -13,24 +13,25 @@ class LookerApiKey(BaseModel):
13
13
  def from_env(cls):
14
14
  try:
15
15
  return cls(
16
- client_id=os.environ.get("LOOKERSDK_CLIENT_ID"), # type: ignore
17
- client_secret=os.environ.get("LOOKERSDK_CLIENT_SECRET"), # type: ignore
18
- base_url=os.environ.get("LOOKERSDK_BASE_URL"), # type: ignore
16
+ client_id=os.environ.get("LOOKERSDK_CLIENT_ID"), # type: ignore
17
+ client_secret=os.environ.get("LOOKERSDK_CLIENT_SECRET"), # type: ignore
18
+ base_url=os.environ.get("LOOKERSDK_BASE_URL"), # type: ignore
19
19
  )
20
20
  except Exception:
21
21
  return None
22
22
 
23
-
23
+
24
24
  class LkrCtxObj(BaseModel):
25
25
  api_key: LookerApiKey | None
26
26
  force_oauth: bool = False
27
-
27
+ use_production: bool = True
28
+
28
29
  @property
29
30
  def use_sdk(self) -> Literal["oauth", "api_key"]:
30
31
  if self.force_oauth:
31
32
  return "oauth"
32
33
  return "api_key" if self.api_key else "oauth"
33
-
34
+
34
35
  def __init__(self, api_key: LookerApiKey | None = None, *args, **kwargs):
35
36
  super().__init__(api_key=api_key, *args, **kwargs)
36
37
  if not self.api_key:
lkr/main.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import os
2
- from typing import Annotated
2
+ from typing import Annotated, Optional
3
3
 
4
4
  import typer
5
5
 
@@ -30,6 +30,7 @@ def callback(
30
30
  log_level: Annotated[LogLevel | None, typer.Option(envvar="LOG_LEVEL")] = None,
31
31
  quiet: Annotated[bool, typer.Option("--quiet")] = False,
32
32
  force_oauth: Annotated[bool, typer.Option("--force-oauth")] = False,
33
+ dev: Annotated[Optional[bool], typer.Option("--dev")] = None,
33
34
  ):
34
35
  if client_id:
35
36
  os.environ["LOOKERSDK_CLIENT_ID"] = client_id
@@ -43,7 +44,16 @@ def callback(
43
44
  # Initialize ctx.obj as a dictionary if it's None
44
45
  if ctx.obj is None:
45
46
  ctx.obj = {}
46
- ctx.obj["ctx_lkr"] = LkrCtxObj(force_oauth=force_oauth)
47
+
48
+ ctx_obj = LkrCtxObj(
49
+ force_oauth=force_oauth,
50
+ use_production=not dev if dev is not None else True,
51
+ )
52
+ ctx.obj["ctx_lkr"] = ctx_obj
53
+ # if the user passes --dev, but lkrCtxObj.use_sdk is oauth, then we need to log a warning saying we're ignoring the --dev flag
54
+ if dev and ctx_obj.use_sdk == "oauth":
55
+ logger.warning("Ignoring --dev flag because OAuth token tracks dev/prod mode.")
56
+
47
57
  if log_level:
48
58
  from lkr.logging import set_log_level
49
59
 
lkr/mcp/main.py CHANGED
@@ -101,7 +101,7 @@ class SpectaclesRequest(BaseModel):
101
101
 
102
102
 
103
103
  def get_mcp_sdk(ctx: LkrCtxObj | typer.Context):
104
- sdk = get_auth(ctx).get_current_sdk()
104
+ sdk = get_auth(ctx).get_current_sdk(prompt_refresh_invalid_token=False)
105
105
  sdk.auth.settings.agent_tag += "-mcp"
106
106
  return sdk
107
107
 
@@ -32,10 +32,12 @@
32
32
  const urlParams = new URLSearchParams(window.location.search);
33
33
  const iframeUrl = urlParams.get('iframe_url');
34
34
  const origin = new URL(iframeUrl).origin;
35
- console.log(origin)
36
- console.log(iframeUrl)
37
35
  const sessionId = urlParams.get('session_id');
36
+ const debug = urlParams.get('debug');
38
37
  // Set the iframe source
38
+ if (debug) {
39
+ console.log({debug, iframeUrl, origin, sessionId})
40
+ }
39
41
  document.getElementById('looker-iframe').src = iframeUrl;
40
42
 
41
43
  // Track which events we've received
@@ -55,7 +57,7 @@
55
57
  return;
56
58
  }
57
59
  const {type, ...data} = JSON.parse(event.data)
58
- if (!trackedEvents.has(type)) {
60
+ if (!trackedEvents.has(type) && !debug) {
59
61
  return;
60
62
  }
61
63
  if (type) {
@@ -65,6 +67,9 @@
65
67
  event_data: data,
66
68
  timestamp: now.toISOString(),
67
69
  };
70
+ if (debug) {
71
+ console.log(eventData)
72
+ }
68
73
  // Send event data to the server
69
74
  fetch(`/log_event?session_id=${sessionId}`, {
70
75
  method: 'POST',
lkr/observability/main.py CHANGED
@@ -6,7 +6,7 @@ from uuid import uuid4
6
6
 
7
7
  import typer
8
8
  import uvicorn
9
- from fastapi import Depends, FastAPI, HTTPException, Query
9
+ from fastapi import Depends, FastAPI, HTTPException, Query, Request
10
10
  from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
11
11
  from pydash import get
12
12
  from selenium import webdriver
@@ -17,6 +17,7 @@ from selenium.webdriver.remote.webdriver import WebDriver
17
17
  from selenium.webdriver.support import expected_conditions as EC
18
18
  from selenium.webdriver.support.ui import WebDriverWait
19
19
 
20
+ from lkr.logging import structured_logger
20
21
  from lkr.observability.classes import (
21
22
  EmbedSDKObj,
22
23
  IframeRequestEvent,
@@ -52,7 +53,17 @@ def get_embed_sdk_obj(
52
53
  user_attributes: str = Query(default="{}"),
53
54
  secret_id: str = Query(default=None),
54
55
  ):
55
- user_attributes_dict = json.loads(user_attributes)
56
+ try:
57
+ user_attributes_dict = json.loads(user_attributes)
58
+ except json.JSONDecodeError as e:
59
+ structured_logger.error(
60
+ "JSONDecodeError: Invalid user attributes",
61
+ error=str(e),
62
+ user_attributes=user_attributes,
63
+ )
64
+ return None
65
+ except Exception:
66
+ return None
56
67
  return EmbedSDKObj(
57
68
  dashboard_id=dashboard_id,
58
69
  external_user_id=external_user_id,
@@ -122,13 +133,19 @@ def settings():
122
133
 
123
134
  @app.get("/health")
124
135
  def health_check(
125
- params: EmbedSDKObj = Depends(get_embed_sdk_obj),
136
+ request: Request,
137
+ params: EmbedSDKObj | None = Depends(get_embed_sdk_obj),
126
138
  open: bool = Query(default=False),
127
139
  ):
128
140
  """
129
141
  Launch a headless browser, open the embed container, and wait for the completion indicator.
130
142
  Returns health status and timing info.
131
143
  """
144
+ if not params:
145
+ raise HTTPException(
146
+ status_code=400,
147
+ detail=f"Invalid parameters: {str(request.query_params)}",
148
+ )
132
149
  session_id = str(uuid4())
133
150
  redirect = False
134
151
  observability_ctx.external_user_id = params.external_user_id
@@ -141,14 +158,30 @@ def health_check(
141
158
  params.model_dump(mode="json"), "health_check_start", session_id
142
159
  )
143
160
  chrome_options = Options()
161
+ chrome_options.set_capability("goog:loggingPrefs", {"browser": "ALL"})
144
162
  chrome_options.add_argument("--headless=new")
145
163
  chrome_options.add_argument("--no-sandbox")
164
+ chrome_options.add_argument("--disable-dev-shm-usage")
165
+ chrome_options.add_argument("--disable-gpu")
166
+ chrome_options.add_argument("--enable-logging")
167
+ chrome_options.add_argument("--v=1")
168
+
169
+ chrome_options.add_experimental_option(
170
+ "prefs",
171
+ {
172
+ "profile.default_content_settings.cookies": 1,
173
+ "profile.cookie_controls_mode": 0,
174
+ },
175
+ )
146
176
  driver = webdriver.Chrome(options=chrome_options)
147
177
  url = observability_ctx.sdk.create_sso_embed_url(
148
178
  body=params.to_embed_sso_params(
149
179
  observability_ctx.origin, observability_ctx.base_url or ""
150
180
  )
151
181
  )
182
+ observability_ctx.log_event(
183
+ {"sso_url": url.url}, "create_sso_embed_url", session_id
184
+ )
152
185
 
153
186
  if not (url and url.url):
154
187
  raise HTTPException(status_code=500, detail="No URL found")
@@ -158,11 +191,16 @@ def health_check(
158
191
  else:
159
192
  quoted_url = quote(url.url, safe="")
160
193
  embed_url = f"{observability_ctx.origin}/?iframe_url={quoted_url}&session_id={session_id}"
161
- if True:
162
- driver.get(embed_url)
163
- WebDriverWait(driver, observability_ctx.timeout).until(
164
- EC.presence_of_element_located((By.ID, "completion-indicator"))
165
- )
194
+ driver.get(embed_url)
195
+ observability_ctx.log_event(
196
+ {"url": embed_url}, "chromium_driver_get", session_id
197
+ )
198
+ WebDriverWait(driver, observability_ctx.timeout).until(
199
+ EC.presence_of_element_located((By.ID, "completion-indicator"))
200
+ )
201
+ observability_ctx.log_event(
202
+ {"session_id": session_id}, "chromium_driver_get_complete", session_id
203
+ )
166
204
 
167
205
  except TimeoutException:
168
206
  observability_ctx.log_event(
@@ -192,6 +230,9 @@ def health_check(
192
230
  session_id,
193
231
  )
194
232
  finally:
233
+ observability_ctx.log_event(
234
+ {"session_id": session_id}, "health_check_complete", session_id
235
+ )
195
236
  if driver:
196
237
  driver.quit()
197
238
  if not redirect:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lkr-dev-cli
3
- Version: 0.0.21
3
+ Version: 0.0.23
4
4
  Summary: lkr: a command line interface for looker
5
5
  Author: bwebs
6
6
  License-Expression: MIT
@@ -0,0 +1,21 @@
1
+ lkr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ lkr/auth_service.py,sha256=gwKbNXa2v6oSc01h7Vlhrld12uQgrFd5NkbxYnxjGS0,19140
3
+ lkr/classes.py,sha256=f2TJOXFta0s8LJLEXOqPdWPLg-EIIntUSDS6gDOon7M,1163
4
+ lkr/constants.py,sha256=DdCfsV6q8wgs2iHpIQeb6oDP_2XejusEHyPvCbaM3yY,108
5
+ lkr/exceptions.py,sha256=M_aR4YaCZtY4wyxhcoqJCVkxVu9z3Wwo5KgSDyOoEnI,210
6
+ lkr/logging.py,sha256=bBGdxkVrUidRTJAvqGHyQ5KS6IJGYDCoool5tTB_JxM,1822
7
+ lkr/main.py,sha256=R3WSyj1AklinWE7wntuV9JSO_a6SsPhE3iOJE1nUn30,2371
8
+ lkr/types.py,sha256=feJ-W2U61PJTiotMLuZJqxrotA53er95kO1O30mooy4,323
9
+ lkr/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ lkr/auth/main.py,sha256=ebGp-NdgULodHaDrLKspnGSFf_sOkV2Vanil1NbOJKY,7382
11
+ lkr/auth/oauth.py,sha256=THynLg8ejAPl4RJ7q4PugEsLq4FFB0wKCHhDeNO9NDo,6106
12
+ lkr/mcp/main.py,sha256=91LQ8Ny6VTOBRRcDI58Z1c8na9TyfgJfZ8nPjmt1n6w,22887
13
+ lkr/observability/classes.py,sha256=5kQnHxa3pgUartrbccuG0yMClfoFqYCXY8iCTJTZvgk,6025
14
+ lkr/observability/embed_container.html,sha256=IcDG-QVsYYNGQGrkDrx9OMZ2Pmo4C8oAjRHddFQ7Tlw,2939
15
+ lkr/observability/main.py,sha256=1KCmJQLb6ht2-l2TXlN8Y8CCfpIP_E5TcMTy2VMaboA,9545
16
+ lkr/observability/utils.py,sha256=Hv3g60cI03cQwyEe8QV7bUMssE6pyrZKnDyl9rxm5b8,2915
17
+ lkr_dev_cli-0.0.23.dist-info/METADATA,sha256=M-UniLnNT-vHWfPc5xC4h09X5WzmSmjkwh5BQZrfr2o,10663
18
+ lkr_dev_cli-0.0.23.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
+ lkr_dev_cli-0.0.23.dist-info/entry_points.txt,sha256=nn2sFMGDpwUVE61ZUpbDPnQZkW7Gc08nV-tyLGo8q34,37
20
+ lkr_dev_cli-0.0.23.dist-info/licenses/LICENSE,sha256=hKnCOORW1JRE_M2vStz8dblS5u1iR-2VpqS9xagKNa0,1063
21
+ lkr_dev_cli-0.0.23.dist-info/RECORD,,
lkr/utils.py DELETED
File without changes
@@ -1,22 +0,0 @@
1
- lkr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- lkr/auth_service.py,sha256=_enIsYxpL1IILtBfNG4YAA_H9cqwnwcvrGMyfmzgH7U,17815
3
- lkr/classes.py,sha256=0NKttc5kAhW_omuxwnN9Jy6oQnRKgI7b2c7HZUfI0lc,1144
4
- lkr/constants.py,sha256=DdCfsV6q8wgs2iHpIQeb6oDP_2XejusEHyPvCbaM3yY,108
5
- lkr/exceptions.py,sha256=M_aR4YaCZtY4wyxhcoqJCVkxVu9z3Wwo5KgSDyOoEnI,210
6
- lkr/logging.py,sha256=bBGdxkVrUidRTJAvqGHyQ5KS6IJGYDCoool5tTB_JxM,1822
7
- lkr/main.py,sha256=5m036LAS4PTLIzpWW5ohxIs2FGYtVf-OwYnTmtrpnxU,1933
8
- lkr/types.py,sha256=feJ-W2U61PJTiotMLuZJqxrotA53er95kO1O30mooy4,323
9
- lkr/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- lkr/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- lkr/auth/main.py,sha256=ebGp-NdgULodHaDrLKspnGSFf_sOkV2Vanil1NbOJKY,7382
12
- lkr/auth/oauth.py,sha256=-QCb7YGIqmuTiy6SZcUTbVZrDo7itOpUUOK1VuvfMqM,5987
13
- lkr/embed/observability/utils.py,sha256=Hv3g60cI03cQwyEe8QV7bUMssE6pyrZKnDyl9rxm5b8,2915
14
- lkr/mcp/main.py,sha256=39VO0_bdscrCW7BC3kdlgjfIWaNigpT38HZ74_Drm-A,22853
15
- lkr/observability/classes.py,sha256=5kQnHxa3pgUartrbccuG0yMClfoFqYCXY8iCTJTZvgk,6025
16
- lkr/observability/embed_container.html,sha256=BMzV_jfBhcussUExf0KccOmOTAO3UEV7SuZ4lznQ0no,2758
17
- lkr/observability/main.py,sha256=Oo9ro6jCm_qSG4Fv377pS2BWW-SIjtbhGLGGFMrlRCA,8036
18
- lkr_dev_cli-0.0.21.dist-info/METADATA,sha256=7lD040SjtJdLv8JGASaFxtBbu4NcA8maWEo2XZGv3TM,10663
19
- lkr_dev_cli-0.0.21.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
20
- lkr_dev_cli-0.0.21.dist-info/entry_points.txt,sha256=nn2sFMGDpwUVE61ZUpbDPnQZkW7Gc08nV-tyLGo8q34,37
21
- lkr_dev_cli-0.0.21.dist-info/licenses/LICENSE,sha256=hKnCOORW1JRE_M2vStz8dblS5u1iR-2VpqS9xagKNa0,1063
22
- lkr_dev_cli-0.0.21.dist-info/RECORD,,
File without changes