onex-cli 1.16.2__tar.gz → 1.16.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. {onex_cli-1.16.2/onex_cli.egg-info → onex_cli-1.16.4}/PKG-INFO +1 -1
  2. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/__init__.py +1 -1
  3. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/mcp/tools/rocket_tools.py +147 -13
  4. {onex_cli-1.16.2 → onex_cli-1.16.4/onex_cli.egg-info}/PKG-INFO +1 -1
  5. {onex_cli-1.16.2 → onex_cli-1.16.4}/CHANGELOG.md +0 -0
  6. {onex_cli-1.16.2 → onex_cli-1.16.4}/LICENSE +0 -0
  7. {onex_cli-1.16.2 → onex_cli-1.16.4}/MANIFEST.in +0 -0
  8. {onex_cli-1.16.2 → onex_cli-1.16.4}/README.md +0 -0
  9. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/__main__.py +0 -0
  10. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/__init__.py +0 -0
  11. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/create.py +0 -0
  12. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/create_e2e.py +0 -0
  13. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/debug.py +0 -0
  14. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/deploy.py +0 -0
  15. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/dev.py +0 -0
  16. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/env.py +0 -0
  17. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/es.py +0 -0
  18. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/init.py +0 -0
  19. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/invoke.py +0 -0
  20. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/login.py +0 -0
  21. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/logout.py +0 -0
  22. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/logs.py +0 -0
  23. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/mcp.py +0 -0
  24. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/platform.py +0 -0
  25. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/provision.py +0 -0
  26. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/reload.py +0 -0
  27. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/replay.py +0 -0
  28. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/s3.py +0 -0
  29. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/status.py +0 -0
  30. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/switch.py +0 -0
  31. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/test.py +0 -0
  32. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/trace.py +0 -0
  33. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/undeploy.py +0 -0
  34. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/validate.py +0 -0
  35. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/commands/vpn.py +0 -0
  36. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/config.py +0 -0
  37. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/mcp/__init__.py +0 -0
  38. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/mcp/server.py +0 -0
  39. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/mcp/tools/__init__.py +0 -0
  40. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/runtime/__init__.py +0 -0
  41. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/runtime/local_runtime.py +0 -0
  42. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/schema/__init__.py +0 -0
  43. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/schema/service_descriptor.py +0 -0
  44. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/schema/validator.py +0 -0
  45. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/crud-service/README.md.j2 +0 -0
  46. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/crud-service/__init__.py.j2 +0 -0
  47. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/crud-service/service.yml.j2 +0 -0
  48. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/crud-service/src/__init__.py.j2 +0 -0
  49. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/crud-service/src/apis/__init__.py.j2 +0 -0
  50. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/crud-service/src/models/__init__.py.j2 +0 -0
  51. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/crud-service/src/models/schemas.py.j2 +0 -0
  52. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/crud-service/src/repositories/__init__.py.j2 +0 -0
  53. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/crud-service/src/services/__init__.py.j2 +0 -0
  54. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/e2e/data_service.yml.j2 +0 -0
  55. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/e2e/test_service_e2e.py.j2 +0 -0
  56. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/event-driven/README.md.j2 +0 -0
  57. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/event-driven/__init__.py.j2 +0 -0
  58. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/event-driven/service.yml.j2 +0 -0
  59. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/event-driven/src/__init__.py.j2 +0 -0
  60. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/event-driven/src/triggers/__init__.py.j2 +0 -0
  61. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/event-driven/src/triggers/events.py.j2 +0 -0
  62. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/event-driven/src/triggers/schedules.py.j2 +0 -0
  63. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/go-minimal/README.md.j2 +0 -0
  64. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/go-minimal/go.mod.j2 +0 -0
  65. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/go-minimal/main.go.j2 +0 -0
  66. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/go-minimal/service.yml.j2 +0 -0
  67. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/go-rest-api/README.md.j2 +0 -0
  68. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/go-rest-api/go.mod.j2 +0 -0
  69. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/go-rest-api/handlers/items.go.j2 +0 -0
  70. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/go-rest-api/main.go.j2 +0 -0
  71. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/go-rest-api/service.yml.j2 +0 -0
  72. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/minimal/README.md.j2 +0 -0
  73. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/minimal/__init__.py.j2 +0 -0
  74. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/minimal/service.yml.j2 +0 -0
  75. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/minimal/src/__init__.py.j2 +0 -0
  76. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/minimal/src/apis/__init__.py.j2 +0 -0
  77. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/minimal/src/apis/hello.py.j2 +0 -0
  78. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/rest-api/README.md.j2 +0 -0
  79. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/rest-api/__init__.py.j2 +0 -0
  80. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/rest-api/service.yml.j2 +0 -0
  81. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/rest-api/src/__init__.py.j2 +0 -0
  82. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/rest-api/src/apis/__init__.py.j2 +0 -0
  83. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/templates/rest-api/src/apis/handlers.py.j2 +0 -0
  84. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/utils/__init__.py +0 -0
  85. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/utils/auth.py +0 -0
  86. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/utils/crypto.py +0 -0
  87. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/utils/email.py +0 -0
  88. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/utils/helpers.py +0 -0
  89. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/vpn/__init__.py +0 -0
  90. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/vpn/platform_detector.py +0 -0
  91. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/vpn/setup_vpn.py +0 -0
  92. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex/vpn/wireguard_manager.py +0 -0
  93. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex_cli.egg-info/SOURCES.txt +0 -0
  94. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex_cli.egg-info/dependency_links.txt +0 -0
  95. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex_cli.egg-info/entry_points.txt +0 -0
  96. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex_cli.egg-info/requires.txt +0 -0
  97. {onex_cli-1.16.2 → onex_cli-1.16.4}/onex_cli.egg-info/top_level.txt +0 -0
  98. {onex_cli-1.16.2 → onex_cli-1.16.4}/setup.cfg +0 -0
  99. {onex_cli-1.16.2 → onex_cli-1.16.4}/setup.py +0 -0
  100. {onex_cli-1.16.2 → onex_cli-1.16.4}/tests/test_mcp_logs_e2e.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onex-cli
3
- Version: 1.16.2
3
+ Version: 1.16.4
4
4
  Summary: Official CLI for deploying and managing services on OneXEOS Platform (Windows, macOS, Linux)
5
5
  Home-page: https://github.com/onexeos/onex-cli
6
6
  Author: OneXEOS Platform Team
@@ -1,2 +1,2 @@
1
1
  # OneXEOS Services CLI
2
- __version__ = "1.16.2"
2
+ __version__ = "1.16.4"
@@ -130,11 +130,25 @@ def _detect_git_repo() -> Optional[dict]:
130
130
 
131
131
  def register_rocket_tools(mcp, api_url: Optional[str] = None):
132
132
  """Register all onex-rocket tools on an existing FastMCP server."""
133
+ import time as _time
134
+
133
135
  base_url = _resolve_rocket_url(api_url)
134
136
  client = httpx.Client(base_url=base_url, timeout=10.0)
135
137
  _indexed_repos: set = set() # track repos already indexed this session
136
138
  _indexing_in_progress: set = set() # repos currently being indexed
137
139
 
140
+ # Session tracking for savings estimation
141
+ _session_start = _time.time()
142
+ _call_counts: dict = {} # tool_name -> count
143
+ _total_response_tokens = 0 # approximate tokens from MCP responses
144
+
145
+ def _track_call(tool_name: str, response_len: int):
146
+ """Track a tool call for session savings estimation."""
147
+ nonlocal _total_response_tokens
148
+ _call_counts[tool_name] = _call_counts.get(tool_name, 0) + 1
149
+ # Rough estimate: 1 token ≈ 4 chars
150
+ _total_response_tokens += response_len // 4
151
+
138
152
  def _check_index_status() -> Optional[dict]:
139
153
  """Check server-side indexing status for repos in progress.
140
154
  Returns status dict if indexing, None if all done."""
@@ -167,6 +181,7 @@ def register_rocket_tools(mcp, api_url: Optional[str] = None):
167
181
  resp = client.get(f"/api/v1/{path}", params=params or {})
168
182
  resp.raise_for_status()
169
183
  result = resp.text
184
+ _track_call(path.split("/")[0], len(result))
170
185
  if result in ("null", "[]", "{}"):
171
186
  active = _check_index_status()
172
187
  if active:
@@ -183,7 +198,9 @@ def register_rocket_tools(mcp, api_url: Optional[str] = None):
183
198
  try:
184
199
  resp = client.post(f"/api/v1/{path}", json=data)
185
200
  resp.raise_for_status()
186
- return resp.text
201
+ result = resp.text
202
+ _track_call(path, len(result))
203
+ return result
187
204
  except httpx.HTTPError as e:
188
205
  return f'{{"error": "{str(e)}"}}'
189
206
 
@@ -254,6 +271,75 @@ def register_rocket_tools(mcp, api_url: Optional[str] = None):
254
271
  return None
255
272
  return repo_info["graph_name"]
256
273
 
274
+ # GitHub org used to construct clone URLs for auto-indexing
275
+ GITHUB_ORG = "OneXApis"
276
+
277
+ # Map of known repo folder names to GitHub repo names
278
+ KNOWN_REPOS = {
279
+ "onexerp-platform": "onex-platform",
280
+ "onexerp-services": "onex-services",
281
+ "onexeos-graph": "onex-rocket",
282
+ }
283
+
284
+ def _ensure_repo_by_name(repo_name: str):
285
+ """Auto-index a repo by name if not already in the graph.
286
+
287
+ Constructs the GitHub URL from the known org and triggers
288
+ async indexing on the server. Non-blocking.
289
+ """
290
+ if not repo_name or repo_name in _indexed_repos or repo_name in _indexing_in_progress:
291
+ return
292
+
293
+ # Check if already in graph via index/status
294
+ try:
295
+ resp = client.get(f"/api/v1/index/status/{repo_name}", timeout=3)
296
+ if resp.status_code == 200:
297
+ status = resp.json()
298
+ if status.get("status") == "done":
299
+ _indexed_repos.add(repo_name)
300
+ return
301
+ if status.get("status") == "indexing":
302
+ _indexing_in_progress.add(repo_name)
303
+ return
304
+ except Exception:
305
+ pass
306
+
307
+ # Check graph stats as fallback
308
+ try:
309
+ resp = client.get("/api/v1/stats", timeout=3)
310
+ if resp.status_code == 200:
311
+ by_repo = resp.json().get("by_repo", {})
312
+ if repo_name in by_repo:
313
+ _indexed_repos.add(repo_name)
314
+ return
315
+ except Exception:
316
+ return
317
+
318
+ # Not in graph — construct URL and trigger async index
319
+ # Extract branch from name: "repo@branch" -> branch, "repo" -> "main"
320
+ if "@" in repo_name:
321
+ base_name = repo_name.split("@")[0]
322
+ branch = repo_name.split("@")[1]
323
+ else:
324
+ base_name = repo_name
325
+ branch = "main"
326
+
327
+ # Resolve GitHub repo name
328
+ github_name = KNOWN_REPOS.get(base_name, base_name)
329
+ url = f"https://github.com/{GITHUB_ORG}/{github_name}.git"
330
+
331
+ try:
332
+ resp = client.post("/api/v1/index", json={
333
+ "url": url,
334
+ "name": repo_name,
335
+ "branch": branch,
336
+ "async": True,
337
+ }, timeout=5)
338
+ if resp.status_code == 200:
339
+ _indexing_in_progress.add(repo_name)
340
+ except Exception:
341
+ pass
342
+
257
343
  # ================================================================
258
344
  # IMPORTANT: Graph context for AI agents
259
345
  # The code graph indexes the MAIN branch only. Results do not reflect
@@ -294,36 +380,40 @@ def register_rocket_tools(mcp, api_url: Optional[str] = None):
294
380
  def rocket_find_dead_code(repo: str = "") -> str:
295
381
  """Find functions/methods never called anywhere in the codebase.
296
382
  BEST FOR: "what code can I safely delete?". Grep can't do this — only a graph can determine zero callers.
297
- If repo is omitted, auto-detects from current git repo and branch."""
298
- _ensure_repo_indexed()
383
+ If repo is omitted, auto-detects from current git repo and branch.
384
+ Auto-indexes the repo if not already in the graph."""
299
385
  repo = repo or _get_current_graph_name() or "unknown"
386
+ _ensure_repo_by_name(repo)
300
387
  return _get(f"repo/{repo}/dead-code")
301
388
 
302
389
  @mcp.tool()
303
390
  def rocket_find_hotspots(repo: str = "", limit: int = 20) -> str:
304
391
  """Find the most depended-on symbols, ranked by caller count.
305
392
  BEST FOR: "what are the riskiest parts?", "what should we test most?".
306
- If repo is omitted, auto-detects from current git repo and branch."""
307
- _ensure_repo_indexed()
393
+ If repo is omitted, auto-detects from current git repo and branch.
394
+ Auto-indexes the repo if not already in the graph."""
308
395
  repo = repo or _get_current_graph_name() or "unknown"
396
+ _ensure_repo_by_name(repo)
309
397
  return _get(f"repo/{repo}/hotspots", {"limit": limit})
310
398
 
311
399
  @mcp.tool()
312
400
  def rocket_find_cycles(repo: str = "") -> str:
313
401
  """Find circular dependencies in the codebase.
314
402
  BEST FOR: "are there any import cycles?", architectural analysis.
315
- If repo is omitted, auto-detects from current git repo and branch."""
316
- _ensure_repo_indexed()
403
+ If repo is omitted, auto-detects from current git repo and branch.
404
+ Auto-indexes the repo if not already in the graph."""
317
405
  repo = repo or _get_current_graph_name() or "unknown"
406
+ _ensure_repo_by_name(repo)
318
407
  return _get(f"repo/{repo}/cycles")
319
408
 
320
409
  @mcp.tool()
321
410
  def rocket_get_repo_map(repo: str = "") -> str:
322
411
  """Get a bird's-eye view of the entire repo: all files with their key symbols.
323
412
  BEST FOR: understanding project structure, onboarding. Much faster than reading files one by one.
324
- If repo is omitted, auto-detects from current git repo and branch."""
325
- _ensure_repo_indexed()
413
+ If repo is omitted, auto-detects from current git repo and branch.
414
+ Auto-indexes the repo if not already in the graph."""
326
415
  repo = repo or _get_current_graph_name() or "unknown"
416
+ _ensure_repo_by_name(repo)
327
417
  return _get(f"repo/{repo}/map")
328
418
 
329
419
  @mcp.tool()
@@ -396,16 +486,17 @@ def register_rocket_tools(mcp, api_url: Optional[str] = None):
396
486
  @mcp.tool()
397
487
  def rocket_get_file_churn(repo: str = "", limit: int = 20) -> str:
398
488
  """Get files ranked by change frequency. BEST FOR: identifying unstable/buggy code.
399
- If repo is omitted, auto-detects from current git repo and branch."""
400
- _ensure_repo_indexed()
489
+ If repo is omitted, auto-detects from current git repo and branch.
490
+ Auto-indexes the repo if not already in the graph."""
401
491
  repo = repo or _get_current_graph_name() or "unknown"
492
+ _ensure_repo_by_name(repo)
402
493
  return _get(f"repo/{repo}/churn", {"limit": limit})
403
494
 
404
495
  @mcp.tool()
405
496
  def rocket_stats() -> str:
406
497
  """Get graph statistics: total nodes/edges, breakdown by kind and repo.
407
- Auto-indexes the current repo if not already in the graph (non-blocking)."""
408
- _ensure_repo_indexed()
498
+ Auto-indexes the current git repo if not already in the graph (non-blocking)."""
499
+ _ensure_repo_indexed() # index cwd repo if possible
409
500
  return _get("stats")
410
501
 
411
502
  @mcp.tool()
@@ -451,6 +542,7 @@ def register_rocket_tools(mcp, api_url: Optional[str] = None):
451
542
  data["name"] = name
452
543
  return _post("index", data)
453
544
 
545
+ @mcp.tool()
454
546
  @mcp.tool()
455
547
  def rocket_index_status(repo: str = "") -> str:
456
548
  """Check indexing status for a repo or all repos.
@@ -459,3 +551,45 @@ def register_rocket_tools(mcp, api_url: Optional[str] = None):
459
551
  if repo:
460
552
  return _get(f"index/status/{repo}")
461
553
  return _get("index/status")
554
+
555
+ @mcp.tool()
556
+ def rocket_session_savings() -> str:
557
+ """Show how many tokens and time the code graph saved in this session.
558
+ Call at the end of a conversation to report savings.
559
+ Returns: total calls, tokens used via MCP, estimated tokens without MCP, savings percentage."""
560
+ elapsed = _time.time() - _session_start
561
+ total_calls = sum(_call_counts.values())
562
+
563
+ # Estimation: without the graph, each query would require reading ~5 files
564
+ # averaging ~200 lines = ~1000 tokens per file = ~5000 tokens per query.
565
+ # The graph returns structured data at ~1/4 of that cost.
566
+ est_without_mcp = total_calls * 5000
567
+ est_with_mcp = _total_response_tokens
568
+ est_saved = max(0, est_without_mcp - est_with_mcp)
569
+ savings_pct = (est_saved / est_without_mcp * 100) if est_without_mcp > 0 else 0
570
+
571
+ # Cost estimates (Opus pricing: ~$15/M input, ~$75/M output)
572
+ cost_per_token = 15.0 / 1_000_000 # input token cost
573
+ est_cost_mcp = est_with_mcp * cost_per_token
574
+ est_cost_without = est_without_mcp * cost_per_token
575
+ est_cost_saved = est_cost_without - est_cost_mcp
576
+
577
+ # Time estimate: ~2s per file read avoided
578
+ est_time_saved_sec = total_calls * 5 * 2 # 5 files * 2s each
579
+
580
+ minutes = int(elapsed // 60)
581
+ seconds = int(elapsed % 60)
582
+
583
+ return json.dumps({
584
+ "session_duration": f"{minutes}m{seconds}s",
585
+ "total_calls": total_calls,
586
+ "calls_by_tool": _call_counts,
587
+ "mcp_tokens_used": est_with_mcp,
588
+ "est_without_mcp": est_without_mcp,
589
+ "est_tokens_saved": est_saved,
590
+ "est_savings_percent": round(savings_pct, 1),
591
+ "est_cost_mcp_usd": round(est_cost_mcp, 5),
592
+ "est_cost_without_usd": round(est_cost_without, 5),
593
+ "est_cost_saved_usd": round(est_cost_saved, 5),
594
+ "est_time_saved": f"{est_time_saved_sec // 60}m{est_time_saved_sec % 60}s" if est_time_saved_sec >= 60 else f"{est_time_saved_sec}s",
595
+ })
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onex-cli
3
- Version: 1.16.2
3
+ Version: 1.16.4
4
4
  Summary: Official CLI for deploying and managing services on OneXEOS Platform (Windows, macOS, Linux)
5
5
  Home-page: https://github.com/onexeos/onex-cli
6
6
  Author: OneXEOS Platform Team
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes