cometapi-cli 0.3.0__py3-none-any.whl → 0.3.2__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.
cometapi_cli/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """CometAPI CLI — professional terminal interface for CometAPI."""
2
2
 
3
- __version__ = "0.3.0"
3
+ __version__ = "0.3.2"
cometapi_cli/client.py CHANGED
@@ -9,6 +9,8 @@ import openai
9
9
 
10
10
  COMETAPI_BASE_URL = "https://api.cometapi.com/v1"
11
11
  COMETAPI_DASHBOARD_BASE = "https://api.cometapi.com"
12
+ ACCOUNT_REQUEST_TIMEOUT = 30.0
13
+ ACCOUNT_EXPORT_TIMEOUT = 120.0
12
14
 
13
15
 
14
16
  class CometClient(openai.OpenAI):
@@ -44,7 +46,14 @@ class CometClient(openai.OpenAI):
44
46
 
45
47
  # -- Account management (access-token auth) --------------------------------
46
48
 
47
- def _account_request(self, method: str, path: str, *, params: dict | None = None) -> dict:
49
+ def _account_request(
50
+ self,
51
+ method: str,
52
+ path: str,
53
+ *,
54
+ params: dict | None = None,
55
+ timeout: float = ACCOUNT_REQUEST_TIMEOUT,
56
+ ) -> dict:
48
57
  """Make an authenticated request to a CometAPI account endpoint."""
49
58
  if not self._access_token:
50
59
  raise openai.OpenAIError(
@@ -56,6 +65,7 @@ class CometClient(openai.OpenAI):
56
65
  f"{COMETAPI_DASHBOARD_BASE}{path}",
57
66
  headers={"Authorization": f"Bearer {self._access_token}"},
58
67
  params=params,
68
+ timeout=timeout,
59
69
  )
60
70
  response.raise_for_status()
61
71
  return response.json()
@@ -151,6 +161,7 @@ class CometClient(openai.OpenAI):
151
161
  start_timestamp: int | None = None,
152
162
  end_timestamp: int | None = None,
153
163
  group: str | None = None,
164
+ request_id: str | None = None,
154
165
  ) -> dict:
155
166
  """List the user's usage logs (requires access token)."""
156
167
  params: dict[str, Any] = {"p": page, "page_size": page_size}
@@ -166,6 +177,8 @@ class CometClient(openai.OpenAI):
166
177
  params["end_timestamp"] = end_timestamp
167
178
  if group:
168
179
  params["group"] = group
180
+ if request_id:
181
+ params["request_id"] = request_id
169
182
  return self._account_request("GET", "/api/log/self", params=params)
170
183
 
171
184
  def search_logs(self, keyword: str) -> dict:
@@ -235,6 +248,7 @@ class CometClient(openai.OpenAI):
235
248
  f"{COMETAPI_DASHBOARD_BASE}/api/log/self/export",
236
249
  headers={"Authorization": f"Bearer {self._access_token}"},
237
250
  params=params,
251
+ timeout=ACCOUNT_EXPORT_TIMEOUT,
238
252
  )
239
253
  response.raise_for_status()
240
254
  return response.content
@@ -4,12 +4,20 @@ from __future__ import annotations
4
4
 
5
5
  import json as _json
6
6
  import sys
7
+ from datetime import datetime, time, timedelta, timezone
7
8
  from typing import Annotated
8
9
 
9
10
  import typer
10
11
 
11
12
  from ..config import get_client
12
- from ..constants import extract_items, format_ts, parse_date, quota_to_usd
13
+ from ..constants import (
14
+ QUOTA_PER_UNIT,
15
+ extract_items,
16
+ format_iso,
17
+ format_ts,
18
+ parse_date,
19
+ quota_to_usd,
20
+ )
13
21
  from ..errors import handle_errors
14
22
  from ..formatters import OutputFormat, output, resolve_format
15
23
 
@@ -24,6 +32,9 @@ LOG_TYPE_MAP = {
24
32
  }
25
33
 
26
34
  _LOG_TYPE_NAMES = {v: k for k, v in LOG_TYPE_MAP.items()}
35
+ REQUEST_ID_PAGE_SIZE = 100
36
+ REQUEST_ID_DEFAULT_MAX_PAGES = 10
37
+ REQUEST_ID_LOCAL_TZ = timezone(timedelta(hours=8))
27
38
 
28
39
 
29
40
  def _parse_other(other_raw: str | None) -> dict:
@@ -37,7 +48,29 @@ def _parse_other(other_raw: str | None) -> dict:
37
48
  return {}
38
49
 
39
50
 
40
- def _find_log_by_id(
51
+ def _request_id_date_window(request_id: str) -> tuple[int, int] | None:
52
+ """Infer the local request day from a CometAPI request ID prefix."""
53
+ prefix = request_id[:14]
54
+ if len(prefix) != 14 or not prefix.isdigit():
55
+ return None
56
+ try:
57
+ local_dt = datetime.strptime(prefix, "%Y%m%d%H%M%S").replace(tzinfo=REQUEST_ID_LOCAL_TZ)
58
+ except ValueError:
59
+ return None
60
+
61
+ local_day_start = datetime.combine(local_dt.date(), time.min, tzinfo=REQUEST_ID_LOCAL_TZ)
62
+ local_day_end = local_day_start + timedelta(days=1) - timedelta(seconds=1)
63
+ return int(local_day_start.timestamp()), int(local_day_end.timestamp())
64
+
65
+
66
+ def _exact_request_id_match(items: list, request_id: str) -> dict | None:
67
+ for item in items:
68
+ if isinstance(item, dict) and item.get("request_id") == request_id:
69
+ return item
70
+ return None
71
+
72
+
73
+ def _lookup_log_by_id(
41
74
  client: object,
42
75
  *,
43
76
  request_id: str,
@@ -47,84 +80,166 @@ def _find_log_by_id(
47
80
  start_timestamp: int | None = None,
48
81
  end_timestamp: int | None = None,
49
82
  group: str | None = None,
50
- max_pages: int = 10,
51
- ) -> dict | None:
52
- """Search through paginated logs to find the entry matching a request ID."""
83
+ max_pages: int = REQUEST_ID_DEFAULT_MAX_PAGES,
84
+ ) -> tuple[dict | None, dict]:
85
+ """Look up a log entry by request ID, using server filtering before fallback scans."""
86
+ meta = {
87
+ "used_server_filter": False,
88
+ "used_inferred_window": False,
89
+ "scanned_pages": 0,
90
+ "max_pages": max_pages,
91
+ }
92
+
93
+ # Older backends may ignore request_id, so verify the returned item matches
94
+ # before trusting this direct lookup.
95
+ resp = client.list_logs( # type: ignore[union-attr]
96
+ page=1,
97
+ page_size=REQUEST_ID_PAGE_SIZE,
98
+ log_type=log_type,
99
+ model_name=model_name,
100
+ token_name=token_name,
101
+ start_timestamp=start_timestamp,
102
+ end_timestamp=end_timestamp,
103
+ group=group,
104
+ request_id=request_id,
105
+ )
106
+ meta["used_server_filter"] = True
107
+ if match := _exact_request_id_match(extract_items(resp), request_id):
108
+ return match, meta
109
+
110
+ scan_start = start_timestamp
111
+ scan_end = end_timestamp
112
+ if scan_start is None and scan_end is None:
113
+ inferred = _request_id_date_window(request_id)
114
+ if inferred:
115
+ scan_start, scan_end = inferred
116
+ meta["used_inferred_window"] = True
117
+
53
118
  for pg in range(1, max_pages + 1):
54
119
  resp = client.list_logs( # type: ignore[union-attr]
55
120
  page=pg,
56
- page_size=100,
121
+ page_size=REQUEST_ID_PAGE_SIZE,
57
122
  log_type=log_type,
58
123
  model_name=model_name,
59
124
  token_name=token_name,
60
- start_timestamp=start_timestamp,
61
- end_timestamp=end_timestamp,
125
+ start_timestamp=scan_start,
126
+ end_timestamp=scan_end,
62
127
  group=group,
63
128
  )
129
+ meta["scanned_pages"] = pg
64
130
  items = extract_items(resp)
65
131
  if not items:
66
132
  break
67
- for item in items:
68
- if item.get("request_id") == request_id:
69
- return item
70
- return None
133
+ if match := _exact_request_id_match(items, request_id):
134
+ return match, meta
135
+ return None, meta
136
+
71
137
 
138
+ def _build_log_record(log: dict) -> dict:
139
+ """Build the canonical, machine-friendly record for a single log entry.
72
140
 
73
- def _format_log_detail(log: dict) -> dict:
74
- """Build a rich key-value detail card from a single log entry."""
141
+ Returns a stable schema with raw, typed values (numbers, booleans, ISO 8601
142
+ time). The same field set drives every output format; human-facing formats
143
+ layer display formatting on top via :func:`_record_to_detail_display`.
144
+ Missing values are ``None`` so the schema stays consistent across entries.
145
+ """
75
146
  other = _parse_other(log.get("other"))
76
- prompt_tokens = log.get("prompt_tokens", 0)
77
- completion_tokens = log.get("completion_tokens", 0)
78
- quota = log.get("quota", 0)
147
+ quota = log.get("quota", 0) or 0
148
+
149
+ # model_price == -1 is the backend sentinel for "use ratio-based pricing"
150
+ # (i.e. no fixed per-call price); expose it as null in the canonical record.
151
+ raw_model_price = other.get("model_price")
152
+ model_price = None if raw_model_price == -1 else raw_model_price
153
+
154
+ # Prefer total_ms (true end-to-end latency) over use_time, which the backend
155
+ # records in seconds and is too coarse to be useful as a duration.
156
+ total_ms = other.get("total_ms")
157
+ use_time = log.get("use_time", 0) or 0
158
+ duration_ms = total_ms if total_ms else (use_time or None)
159
+
160
+ frt = other.get("frt")
161
+ user_id = log.get("user_id")
79
162
 
163
+ return {
164
+ "request_id": log.get("request_id") or None,
165
+ "response_id": log.get("response_id") or None,
166
+ "time": format_iso(log.get("created_at", 0)),
167
+ "type": _LOG_TYPE_NAMES.get(log.get("type", 0), "unknown"),
168
+ "model": log.get("model_name") or None,
169
+ "token_name": log.get("token_name") or None,
170
+ "username": log.get("username") or None,
171
+ "user_id": user_id if user_id else None,
172
+ "ip": log.get("ip") or None,
173
+ "stream": bool(log.get("is_stream")),
174
+ "prompt_tokens": log.get("prompt_tokens", 0) or 0,
175
+ "completion_tokens": log.get("completion_tokens", 0) or 0,
176
+ "cache_tokens": other.get("cache_tokens", 0) or 0,
177
+ "cost_usd": round(quota / QUOTA_PER_UNIT, 6),
178
+ "quota": quota,
179
+ "model_ratio": other.get("model_ratio"),
180
+ "completion_ratio": other.get("completion_ratio"),
181
+ "group_ratio": other.get("group_ratio"),
182
+ "model_price": model_price,
183
+ "cache_ratio": other.get("cache_ratio"),
184
+ "duration_ms": duration_ms,
185
+ "first_token_ms": frt if frt and frt > 0 else None,
186
+ "endpoint": other.get("request_path") or None,
187
+ }
188
+
189
+
190
+ def _record_to_detail_display(rec: dict) -> dict:
191
+ """Render a canonical log record as a formatted key-value detail card.
192
+
193
+ Mirrors the field set of :func:`_build_log_record` but uses human-friendly
194
+ labels and formatted strings (USD, ``Yes``/``No``, ``ms``). Optional fields
195
+ are omitted when absent to keep the card readable.
196
+ """
197
+ em_dash = "—"
80
198
  info: dict[str, str | int | float] = {}
81
- info["Request ID"] = log.get("request_id", "") or "—"
82
- info["Response ID"] = log.get("response_id", "") or "—"
83
- info["Time"] = format_ts(log.get("created_at", 0))
84
- info["Model"] = log.get("model_name", "") or "—"
85
- info["Token Name"] = log.get("token_name", "") or "—"
86
- info["Group"] = log.get("group", "") or "—"
87
- info["Stream"] = "Yes" if log.get("is_stream") else "No"
199
+ info["Request ID"] = rec["request_id"] or em_dash
200
+ info["Response ID"] = rec["response_id"] or em_dash
201
+ iso = rec["time"]
202
+ info["Time"] = iso[:19].replace("T", " ") if iso else em_dash
203
+ info["Model"] = rec["model"] or em_dash
204
+ info["Token Name"] = rec["token_name"] or em_dash
205
+ if rec["username"]:
206
+ info["Username"] = rec["username"]
207
+ if rec["user_id"] is not None:
208
+ info["User ID"] = rec["user_id"]
209
+ if rec["ip"]:
210
+ info["IP"] = rec["ip"]
211
+ info["Type"] = rec["type"]
212
+ info["Stream"] = "Yes" if rec["stream"] else "No"
88
213
 
89
214
  # Tokens
90
- info["Prompt Tokens"] = f"{prompt_tokens:,}"
91
- info["Completion Tokens"] = f"{completion_tokens:,}"
92
- cache_tokens = other.get("cache_tokens", 0)
93
- if cache_tokens:
94
- info["Cache Tokens"] = f"{cache_tokens:,}"
95
-
96
- # Cost
97
- info["Cost (USD)"] = quota_to_usd(quota)
98
- info["Quota (raw)"] = f"{quota:,}"
99
-
100
- # Pricing breakdown from 'other'
101
- model_ratio = other.get("model_ratio")
102
- if model_ratio is not None:
103
- info["Model Ratio"] = model_ratio
104
- completion_ratio = other.get("completion_ratio")
105
- if completion_ratio is not None:
106
- info["Completion Ratio"] = f"{completion_ratio}x"
107
- group_ratio = other.get("group_ratio")
108
- if group_ratio is not None:
109
- info["Group Ratio"] = group_ratio
110
- model_price = other.get("model_price")
111
- if model_price is not None:
112
- info["Model Price"] = "default" if model_price == -1 else model_price
113
- cache_ratio = other.get("cache_ratio")
114
- if cache_ratio is not None:
115
- info["Cache Ratio"] = cache_ratio
215
+ info["Prompt Tokens"] = f"{rec['prompt_tokens']:,}"
216
+ info["Completion Tokens"] = f"{rec['completion_tokens']:,}"
217
+ if rec["cache_tokens"]:
218
+ info["Cache Tokens"] = f"{rec['cache_tokens']:,}"
219
+
220
+ # Cost (6 decimals so sub-cent calls are not rounded away)
221
+ info["Cost (USD)"] = f"${rec['cost_usd']:,.6f}"
222
+ info["Quota (raw)"] = f"{rec['quota']:,}"
223
+
224
+ # Pricing breakdown
225
+ if rec["model_ratio"] is not None:
226
+ info["Model Ratio"] = rec["model_ratio"]
227
+ if rec["completion_ratio"] is not None:
228
+ info["Completion Ratio"] = f"{rec['completion_ratio']}x"
229
+ if rec["group_ratio"] is not None:
230
+ info["Group Ratio"] = rec["group_ratio"]
231
+ info["Model Price"] = "default" if rec["model_price"] is None else rec["model_price"]
232
+ if rec["cache_ratio"] is not None:
233
+ info["Cache Ratio"] = rec["cache_ratio"]
116
234
 
117
235
  # Timing
118
- use_time = log.get("use_time", 0)
119
- info["Duration"] = f"{use_time:,} ms" if use_time else "—"
120
- frt = other.get("frt")
121
- if frt and frt > 0:
122
- info["First Token"] = f"{frt:,} ms"
236
+ info["Duration"] = f"{rec['duration_ms']:,} ms" if rec["duration_ms"] else em_dash
237
+ if rec["first_token_ms"]:
238
+ info["First Token"] = f"{rec['first_token_ms']:,} ms"
123
239
 
124
240
  # Path
125
- request_path = other.get("request_path")
126
- if request_path:
127
- info["Endpoint"] = request_path
241
+ if rec["endpoint"]:
242
+ info["Endpoint"] = rec["endpoint"]
128
243
 
129
244
  return info
130
245
 
@@ -169,6 +284,14 @@ def logs(
169
284
  str | None,
170
285
  typer.Option("--request-id", help="Look up cost by request ID (X-Cometapi-Request-Id header)."),
171
286
  ] = None,
287
+ request_id_max_pages: Annotated[
288
+ int,
289
+ typer.Option(
290
+ "--request-id-max-pages",
291
+ min=1,
292
+ help="Fallback pages to scan when direct request-ID lookup is unavailable.",
293
+ ),
294
+ ] = REQUEST_ID_DEFAULT_MAX_PAGES,
172
295
  detail: Annotated[
173
296
  bool,
174
297
  typer.Option("--detail", help="Show extended columns (request ID, pricing ratios)."),
@@ -202,7 +325,7 @@ def logs(
202
325
  if log_type:
203
326
  type_int = LOG_TYPE_MAP.get(log_type.lower())
204
327
 
205
- log_entry = _find_log_by_id(
328
+ log_entry, lookup_meta = _lookup_log_by_id(
206
329
  client,
207
330
  request_id=request_id,
208
331
  log_type=type_int,
@@ -211,22 +334,32 @@ def logs(
211
334
  start_timestamp=start_ts,
212
335
  end_timestamp=end_ts,
213
336
  group=group,
337
+ max_pages=request_id_max_pages,
214
338
  )
215
339
 
216
340
  if log_entry is None:
341
+ if lookup_meta["used_inferred_window"]:
342
+ scan_note = (
343
+ f"Then scanned {lookup_meta['scanned_pages']} page(s) in the request ID's "
344
+ "inferred local date window."
345
+ )
346
+ else:
347
+ scan_note = f"Then scanned {lookup_meta['scanned_pages']} fallback page(s)."
217
348
  err_console.print(
218
349
  f"[red]No log found for request_id=[/]{request_id}\n"
219
- "[dim]The entry may be older than the search window. "
220
- "Try narrowing with --start/--end or --model.[/]"
350
+ "[dim]Tried direct request-id lookup first. "
351
+ f"{scan_note} Increase --request-id-max-pages or narrow with --start/--end "
352
+ "if the backend does not support direct request-id filtering.[/]"
221
353
  )
222
354
  raise typer.Exit(code=1)
223
355
 
224
- if fmt == OutputFormat.JSON:
225
- output(log_entry, fmt)
356
+ record = _build_log_record(log_entry)
357
+ # Machine formats get raw typed values; human formats get the formatted card.
358
+ if fmt in (OutputFormat.JSON, OutputFormat.YAML, OutputFormat.CSV):
359
+ output(record, fmt)
226
360
  return
227
361
 
228
- info = _format_log_detail(log_entry)
229
- output(info, fmt, title="Request Detail")
362
+ output(_record_to_detail_display(record), fmt, title="Request Detail")
230
363
  return
231
364
 
232
365
  # Server-side CSV export — write raw bytes to stdout and return early
@@ -266,12 +399,15 @@ def logs(
266
399
  start_timestamp=start_ts,
267
400
  end_timestamp=end_ts,
268
401
  group=group,
402
+ request_id=None,
269
403
  )
270
404
 
271
405
  data = extract_items(resp)
272
406
 
273
- if fmt == OutputFormat.JSON:
274
- output(data, fmt)
407
+ # Machine formats emit the full canonical record per entry (typed values,
408
+ # incl. cost_usd); table/markdown/csv keep the compact summary rows.
409
+ if fmt in (OutputFormat.JSON, OutputFormat.YAML):
410
+ output([_build_log_record(log) for log in data], fmt)
275
411
  return
276
412
 
277
413
  if not data:
cometapi_cli/constants.py CHANGED
@@ -24,6 +24,13 @@ def format_ts(ts: int, fmt: str = "%Y-%m-%d %H:%M:%S") -> str:
24
24
  return datetime.fromtimestamp(ts, tz=timezone.utc).strftime(fmt)
25
25
 
26
26
 
27
+ def format_iso(ts: int) -> str | None:
28
+ """Format a Unix timestamp as an ISO 8601 UTC string, or None when absent."""
29
+ if not ts:
30
+ return None
31
+ return datetime.fromtimestamp(ts, tz=timezone.utc).isoformat()
32
+
33
+
27
34
  def parse_date(value: str, label: str) -> int:
28
35
  """Parse a date string into a Unix timestamp (UTC).
29
36
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cometapi-cli
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: CometAPI CLI — official command-line interface for the CometAPI AI gateway
5
5
  Project-URL: Homepage, https://pypi.org/project/cometapi-cli/
6
6
  Project-URL: Documentation, https://apidoc.cometapi.com/libraries/cli/overview
@@ -21,6 +21,7 @@ Classifier: Topic :: Internet
21
21
  Classifier: Topic :: Software Development :: Libraries
22
22
  Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.10
24
+ Requires-Dist: click>=8.0
24
25
  Requires-Dist: openai>=1.0.0
25
26
  Requires-Dist: prompt-toolkit>=3.0
26
27
  Requires-Dist: pyyaml>=6.0
@@ -144,6 +145,21 @@ cometapi run -h
144
145
  | `repl` | Start an interactive command shell | Depends on command used |
145
146
  | `config` | Show, set, unset, or locate local configuration | None |
146
147
 
148
+ ## Logs
149
+
150
+ Use `cometapi logs` to inspect recent usage, export CSV, or look up one request by the
151
+ `X-Cometapi-Request-Id` response header.
152
+
153
+ ```bash
154
+ cometapi logs --limit 20
155
+ cometapi logs --type consume --start 2026-06-01 --json
156
+ cometapi logs --request-id 20260617165550885561292gJBlzjtp
157
+ ```
158
+
159
+ `logs --request-id` first asks the backend for that exact request ID. If the installed
160
+ backend does not support direct request-ID filtering yet, the CLI falls back to scanning
161
+ a bounded number of log pages. Use `--request-id-max-pages` to widen that fallback scan.
162
+
147
163
  ## Models
148
164
 
149
165
  `cometapi models` uses the public model catalog by default and displays richer metadata than `/v1/models`.
@@ -1,10 +1,10 @@
1
- cometapi_cli/__init__.py,sha256=QEpNqXBo4pYsnFqEmU3Twm9RJoOaTlwmkKDAb1xt7iA,92
1
+ cometapi_cli/__init__.py,sha256=I37ML-zws7ZAjDJSAw87LxYgHMsTcaVOz67of_juqiI,92
2
2
  cometapi_cli/app.py,sha256=d2IZJabWmdZtPtFNOB4YiuSJ1GYvO0hgIOkjm4gQjxA,2948
3
3
  cometapi_cli/catalog.py,sha256=Pc0XGoskMEKIzfbU2H_0Yi8zecLzKl1ss8fd2mV7778,4929
4
- cometapi_cli/client.py,sha256=4JkMSrjWwAQV8tmlwplZQ75gzt3zHno8ASKLgMCpYkU,9658
4
+ cometapi_cli/client.py,sha256=QBtQ1cvmwvwjpIYpzupC3BMNqxREhMoRnzgCZOeJnEE,9998
5
5
  cometapi_cli/config.py,sha256=oJXQidKCOsKNYPnE8OfLLoOfsv0MSZEDICB6VShJRSA,3307
6
6
  cometapi_cli/console.py,sha256=HFSU1gL9SDmwjBvgVgDraoaU50oTwCRpsAwYXYlVP9o,163
7
- cometapi_cli/constants.py,sha256=EV2i-ag4ss1xGrU1CLiF9iPz8ggzNm4-U3wpYCC2pys,1601
7
+ cometapi_cli/constants.py,sha256=UPfU36fnRTl4JdcyjySQ0UEVign3i_UTNH9mQ-Gb4ls,1826
8
8
  cometapi_cli/errors.py,sha256=MQ3VXefVhdIFa4uUmoLf_O5d1EFuu9PfGYrBGuq-mSA,3703
9
9
  cometapi_cli/formatters.py,sha256=PvIGp-O9UtSFuQWKJGp3OEeDnd9L6vbHL91V5VYrqLo,4559
10
10
  cometapi_cli/main.py,sha256=4NmO8MAAc_H30hahT6VNrdGdlaFlQ99AixKcRV5iDXE,168
@@ -16,7 +16,7 @@ cometapi_cli/commands/chat.py,sha256=xQgsjFQ33kVRfSnU5t3fbahjZE8nmVSa_w8qUTPeacE
16
16
  cometapi_cli/commands/chat_repl.py,sha256=b9lkYnbbaOb0AlSpRcq3wWHmnhtTXvaqeJiUImsMEBY,8176
17
17
  cometapi_cli/commands/config_cmd.py,sha256=OqR0TuAq6gQXw8nJIt5AAv_Fk4zdfbg-KhNLuUsrEsU,8619
18
18
  cometapi_cli/commands/doctor.py,sha256=s9XzRIkF9FIMAWSc7b3c6v3g8Px9kb0k6WDucOrdXY8,5360
19
- cometapi_cli/commands/logs.py,sha256=0mD9PviMitJl77gm3U9PJ2UYV8XKRkWqGGYY9aVUqvM,10333
19
+ cometapi_cli/commands/logs.py,sha256=__6Ft5TpBwVtRPTkFbmCjnriGfb1CBNGgGH_CWFmOeY,16082
20
20
  cometapi_cli/commands/model.py,sha256=YyMRt6enCAZfxW_dVcNvdNgYSl-J4iOqPlSsv14nfJs,2654
21
21
  cometapi_cli/commands/models.py,sha256=1TQC8LJ6JASErkLG5XtaZyRrq4vr4sVWH7eo426FeNs,8824
22
22
  cometapi_cli/commands/repl.py,sha256=b5z1jmEXOsCrb6fwEUyv-IKot929NIPQQAbA1uas1D4,4283
@@ -24,8 +24,8 @@ cometapi_cli/commands/run.py,sha256=JQQ1DFSyJoD4pByLmhMht1-XhDDZpV94F0hshXL7hKY,
24
24
  cometapi_cli/commands/stats.py,sha256=bEVywsom7bm8AGKGWlgAWTFjOp4NTJxDk6YEEvECM6U,1411
25
25
  cometapi_cli/commands/tasks.py,sha256=NBKOKrDow52sVjoM0ezwS9IhVRltlqYLmpamoEUbAWA,4718
26
26
  cometapi_cli/commands/tokens.py,sha256=U0AI8T690NJxAKFBwrWrsr3izXIiB_PZ9avmwpdgM9A,3042
27
- cometapi_cli-0.3.0.dist-info/METADATA,sha256=ychTHSOEc5NIaVi6QjBsTLWSie8f4p80ZgOZQfP5kds,10064
28
- cometapi_cli-0.3.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
29
- cometapi_cli-0.3.0.dist-info/entry_points.txt,sha256=xoiE2ZVNNWXTq0JRBtzC8hJ2JkdKuaBNz_fEd8OJpLs,50
30
- cometapi_cli-0.3.0.dist-info/licenses/LICENSE,sha256=-rBwHQzkmLbty07abmGvQvsRrvDeEQUkPDhNJfTcjdE,1065
31
- cometapi_cli-0.3.0.dist-info/RECORD,,
27
+ cometapi_cli-0.3.2.dist-info/METADATA,sha256=WJ4GHqBwefcOBQJ4A5jF3vLTcqotUOUmd4pAy0dld_s,10646
28
+ cometapi_cli-0.3.2.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
29
+ cometapi_cli-0.3.2.dist-info/entry_points.txt,sha256=xoiE2ZVNNWXTq0JRBtzC8hJ2JkdKuaBNz_fEd8OJpLs,50
30
+ cometapi_cli-0.3.2.dist-info/licenses/LICENSE,sha256=-rBwHQzkmLbty07abmGvQvsRrvDeEQUkPDhNJfTcjdE,1065
31
+ cometapi_cli-0.3.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.29.0
2
+ Generator: hatchling 1.30.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any