utim-cli 1.48.2__tar.gz → 1.48.3__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 (90) hide show
  1. {utim_cli-1.48.2 → utim_cli-1.48.3}/CHANGELOG.md +7 -1
  2. {utim_cli-1.48.2/utim_cli.egg-info → utim_cli-1.48.3}/PKG-INFO +1 -1
  3. {utim_cli-1.48.2 → utim_cli-1.48.3}/pyproject.toml +1 -1
  4. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/__init__.py +1 -1
  5. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/_version.py +1 -1
  6. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/blender_agent.py +1 -1
  7. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/client_utils.py +5 -2
  8. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/orchestrator.py +24 -4
  9. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/auth.py +5 -0
  10. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/db.py +3 -0
  11. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/completion_routes.py +404 -129
  12. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/quota_share_routes.py +2 -1
  13. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tools.py +354 -3
  14. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/quota_redeem_dialog.py +20 -3
  15. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/quota_share_dialog.py +22 -4
  16. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/tools_dialog.py +5 -26
  17. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/utim.py +34 -3
  18. {utim_cli-1.48.2 → utim_cli-1.48.3/utim_cli.egg-info}/PKG-INFO +1 -1
  19. {utim_cli-1.48.2 → utim_cli-1.48.3}/LICENSE +0 -0
  20. {utim_cli-1.48.2 → utim_cli-1.48.3}/MANIFEST.in +0 -0
  21. {utim_cli-1.48.2 → utim_cli-1.48.3}/README.md +0 -0
  22. {utim_cli-1.48.2 → utim_cli-1.48.3}/setup.cfg +0 -0
  23. {utim_cli-1.48.2 → utim_cli-1.48.3}/setup.py +0 -0
  24. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/agent.py +0 -0
  25. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/auth.py +0 -0
  26. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/backup.py +0 -0
  27. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/bootstrap.py +0 -0
  28. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/config.py +0 -0
  29. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/constants.py +0 -0
  30. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/context_pruner.py +0 -0
  31. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/doctor.py +0 -0
  32. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/knowledge_graph.py +0 -0
  33. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/local_db.py +0 -0
  34. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/logger.py +0 -0
  35. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/mcp_clean_wrapper.py +0 -0
  36. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/mcp_client.py +0 -0
  37. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/mcp_registry.json +0 -0
  38. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/reflection.py +0 -0
  39. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/report.py +0 -0
  40. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/scrapy_search.py +0 -0
  41. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/__init__.py +0 -0
  42. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/about.md +0 -0
  43. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/changelog.md +0 -0
  44. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/docs.md +0 -0
  45. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/features.md +0 -0
  46. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/license.md +0 -0
  47. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/pricing.md +0 -0
  48. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/privacy.md +0 -0
  49. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/refund.md +0 -0
  50. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/support.md +0 -0
  51. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/docs_md/terms.md +0 -0
  52. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/email_utils.py +0 -0
  53. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/exchange_rate.py +0 -0
  54. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/firebase.py +0 -0
  55. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/history.py +0 -0
  56. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/logging_config.py +0 -0
  57. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/models.py +0 -0
  58. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/pricing_updater.py +0 -0
  59. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/rate_limit.py +0 -0
  60. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/router.py +0 -0
  61. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/__init__.py +0 -0
  62. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/auth_routes.py +0 -0
  63. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/credit_routes.py +0 -0
  64. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/feedback_routes.py +0 -0
  65. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/quota_routes.py +0 -0
  66. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/referral_routes.py +0 -0
  67. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/session_routes.py +0 -0
  68. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/routes/share_routes.py +0 -0
  69. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/server/server.py +0 -0
  70. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/share.py +0 -0
  71. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/share_tui.py +0 -0
  72. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/situational_scoring.py +0 -0
  73. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/state.py +0 -0
  74. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/__init__.py +0 -0
  75. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/feedback_dialog.py +0 -0
  76. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/history_dialog.py +0 -0
  77. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/mcp_dialog.py +0 -0
  78. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/model_dialog.py +0 -0
  79. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/quota_dialog.py +0 -0
  80. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/resume_dialog.py +0 -0
  81. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/skills_dialog.py +0 -0
  82. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/tui/update_dialog.py +0 -0
  83. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/utilities.py +0 -0
  84. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/vector_memory.py +0 -0
  85. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli/workspace.py +0 -0
  86. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli.egg-info/SOURCES.txt +0 -0
  87. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli.egg-info/dependency_links.txt +0 -0
  88. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli.egg-info/entry_points.txt +0 -0
  89. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli.egg-info/requires.txt +0 -0
  90. {utim_cli-1.48.2 → utim_cli-1.48.3}/utim_cli.egg-info/top_level.txt +0 -0
@@ -1,8 +1,14 @@
1
1
  # Changelog
2
2
 
3
- ## [1.48.2] - 2026-07-23
3
+ ## [1.48.3] - 2026-07-24
4
4
 
5
5
  ### Fixed
6
+ - **Blender 3D Tools**: Fully restored normal functionality and re-enabled the local Blender asset generation workflow and agent scripts.
7
+ - **Windows Shell Sanitization**: Resolved issues with Unix commands like `mkdir -p` and `rm -rf` failing on native Windows PowerShell by introducing automatic translation to `New-Item` and `Remove-Item`.
8
+ - **Command Redirection Safeguards**: Automatically blocks Bash-style here-docs (`<<`) on Windows with a helpful prompt to guide models to use proper file-write tools.
9
+ - **UI Abort and Confirmation Fixes**: Removed the 30-second background timeout on confirmation dialogs to prevent thread synchronization freeze states. Fixed signal-handling bugs so pressing Ctrl+C or Esc immediately cancels active HTTP streams and releases the CLI layout.
10
+
11
+ ## [1.48.2] - 2026-07-23
6
12
  - **Minor Bug Fixes**: Under-the-hood optimization and resolution of minor dependency issues.
7
13
 
8
14
  ## [1.48.1] - 2026-07-23
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: utim-cli
3
- Version: 1.48.2
3
+ Version: 1.48.3
4
4
  Summary: UTIM – Universal Terminal Intelligence Manager. A powerful agentic AI coding assistant for your terminal.
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://utim.dev
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "utim-cli"
7
- version = "1.48.2"
7
+ version = "1.48.3"
8
8
  description = "UTIM – Universal Terminal Intelligence Manager. A powerful agentic AI coding assistant for your terminal."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -5,7 +5,7 @@ try:
5
5
  from utim_cli._version import VERSION as __version__
6
6
  except ImportError:
7
7
  # Fallback during first-install / editable-install edge cases
8
- __version__ = "1.48.2"
8
+ __version__ = "1.48.3"
9
9
 
10
10
  import builtins, os, pathlib, urllib.parse, re
11
11
 
@@ -11,4 +11,4 @@
11
11
  # from here so every surface stays in sync automatically.
12
12
  # ─────────────────────────────────────────────────────────────────────────────
13
13
 
14
- VERSION = "1.48.2"
14
+ VERSION = "1.48.3"
@@ -1110,7 +1110,7 @@ def blender_agent_create_from_image(
1110
1110
  A human-readable progress log including the path to the exported
1111
1111
  file, or an error description.
1112
1112
  """
1113
- return "Error: The Blender 3D tool is currently Under Maintenance."
1113
+
1114
1114
 
1115
1115
  output_dir = output_path or os.path.join(os.getcwd(), ".utim_tmp", "blender_assets")
1116
1116
  assets_dir = pathlib.Path(output_dir).absolute()
@@ -258,7 +258,7 @@ def parse_xml_tool_calls(content: str) -> tuple[str | None, list[dict]]:
258
258
 
259
259
  args = {}
260
260
  # Pattern 1: <arg_key>key</arg_key>\s*<arg_value>value</arg_value>
261
- arg_pattern = re.compile(r'<arg_key>([^<]+)</arg_key>\s*<arg_value>([^<]*)</arg_value>')
261
+ arg_pattern = re.compile(r'<arg_key>([^<]+)</arg_key>\s*<arg_value>([\s\S]*?)</arg_value>')
262
262
  for arg_match in arg_pattern.finditer(block):
263
263
  args[arg_match.group(1).strip()] = arg_match.group(2).strip()
264
264
 
@@ -269,9 +269,12 @@ def parse_xml_tool_calls(content: str) -> tuple[str | None, list[dict]]:
269
269
 
270
270
  # Standardize argument name for run_command
271
271
  if tool_name == "run_command":
272
- for wrong_key in ["CommandLine", "cmd", "shell", "script"]:
272
+ for wrong_key in ["CommandLine", "commandLine", "command_line", "cmd_line", "cmd", "shell", "script"]:
273
273
  if wrong_key in args and "command" not in args:
274
274
  args["command"] = args.pop(wrong_key)
275
+ for path_key in ["cwd", "directory", "folder", "path"]:
276
+ if path_key in args and "dir_path" not in args:
277
+ args["dir_path"] = args.pop(path_key)
275
278
  for bg_key in ["background", "is_background", "bg"]:
276
279
  if bg_key in args:
277
280
  val = args.pop(bg_key)
@@ -2040,6 +2040,15 @@ class Orchestrator:
2040
2040
  finally:
2041
2041
  self.active_response = None
2042
2042
 
2043
+ if self.cancel_event.is_set():
2044
+ return {
2045
+ "role": "assistant",
2046
+ "content": "[Aborted by user]",
2047
+ "tool_calls": None,
2048
+ "was_cut_off": True,
2049
+ "aborted": True,
2050
+ }, False
2051
+
2043
2052
  # Flush any remaining text in _line_buf and table_buf
2044
2053
  flush_table()
2045
2054
  if _line_buf and not silent:
@@ -3084,10 +3093,21 @@ class Orchestrator:
3084
3093
  ("edit_file", "path"): "filepath",
3085
3094
  ("edit_file", "file"): "filepath",
3086
3095
  ("edit_file", "filename"): "filepath",
3087
- # run_command: model sometimes uses 'cmd'
3088
- ("run_command", "cmd"): "command",
3089
- ("run_command", "shell"): "command",
3090
- ("run_command", "script"): "command",
3096
+ # run_command: model sometimes uses 'cmd' or 'CommandLine'
3097
+ ("run_command", "cmd"): "command",
3098
+ ("run_command", "shell"): "command",
3099
+ ("run_command", "script"): "command",
3100
+ ("run_command", "CommandLine"): "command",
3101
+ ("run_command", "commandLine"): "command",
3102
+ ("run_command", "command_line"): "command",
3103
+ ("run_command", "cmd_line"): "command",
3104
+ ("run_command", "cwd"): "dir_path",
3105
+ ("run_command", "directory"): "dir_path",
3106
+ ("run_command", "folder"): "dir_path",
3107
+ ("run_command", "path"): "dir_path",
3108
+ ("run_command", "background"): "is_background",
3109
+ ("run_command", "bg"): "is_background",
3110
+ ("run_command", "run_in_background"):"is_background",
3091
3111
  # web_search: model sometimes uses 'prompt'
3092
3112
  ("web_search", "prompt"): "query",
3093
3113
  ("web_search", "text"): "query",
@@ -163,6 +163,11 @@ def process_user_refills(db: Session, user_id: str) -> None:
163
163
  unused_credits = max(0.0, cycle_allowance - current_cycle_used)
164
164
  if due > 1:
165
165
  unused_credits += cycle_allowance * (due - 1)
166
+
167
+ # Cap refills to remaining monthly plan credits after direct deductions
168
+ unallocated_deducted = getattr(sub, "unallocated_deducted", 0.0) or 0.0
169
+ remaining_pool = max(0.0, plan.credits_per_month - (sub.refills_processed * cycle_allowance) - unallocated_deducted)
170
+ unused_credits = min(unused_credits, remaining_pool)
166
171
 
167
172
  credit = db.query(Credit).filter(Credit.user_id == user_id).first()
168
173
  if not credit:
@@ -118,6 +118,7 @@ class UserSubscription(Base):
118
118
  last_refill_at = Column(DateTime, nullable=True)
119
119
  # Overrides the default per-cycle credit allocation after a quota-share deduction
120
120
  refill_rate_override = Column(Float, nullable=True)
121
+ unallocated_deducted = Column(Float, default=0.0, nullable=False)
121
122
  created_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)
122
123
  updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow, nullable=False)
123
124
 
@@ -630,12 +631,14 @@ def init_db(silent: bool = True) -> None:
630
631
  _run_migration("users", "referral_code", "ALTER TABLE users ADD COLUMN IF NOT EXISTS referral_code VARCHAR(50)", "postgres add referral_code")
631
632
  _run_migration("feedbacks", "chat_history", "ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS chat_history TEXT", "postgres add chat_history")
632
633
  _run_migration("user_subscriptions", "refill_rate_override", "ALTER TABLE user_subscriptions ADD COLUMN IF NOT EXISTS refill_rate_override FLOAT", "postgres add refill_rate_override")
634
+ _run_migration("user_subscriptions", "unallocated_deducted", "ALTER TABLE user_subscriptions ADD COLUMN IF NOT EXISTS unallocated_deducted FLOAT DEFAULT 0.0 NOT NULL", "postgres add unallocated_deducted")
633
635
  else:
634
636
  # SQLite: no IF NOT EXISTS on ADD COLUMN, swallow duplicate errors
635
637
  _run_migration("user_subscriptions", "refills_processed", "ALTER TABLE user_subscriptions ADD COLUMN refills_processed INTEGER DEFAULT 0 NOT NULL", "sqlite add refills_processed")
636
638
  _run_migration("user_subscriptions", "last_refill_at", "ALTER TABLE user_subscriptions ADD COLUMN last_refill_at TIMESTAMP", "sqlite add last_refill_at")
637
639
  _run_migration("user_subscriptions", "current_cycle_used", "ALTER TABLE user_subscriptions ADD COLUMN current_cycle_used FLOAT DEFAULT 0.0 NOT NULL", "sqlite add current_cycle_used")
638
640
  _run_migration("user_subscriptions", "refill_rate_override", "ALTER TABLE user_subscriptions ADD COLUMN refill_rate_override FLOAT", "sqlite add refill_rate_override")
641
+ _run_migration("user_subscriptions", "unallocated_deducted", "ALTER TABLE user_subscriptions ADD COLUMN unallocated_deducted FLOAT DEFAULT 0.0 NOT NULL", "sqlite add unallocated_deducted")
639
642
  _run_migration("credits", "bonus_balance", "ALTER TABLE credits ADD COLUMN bonus_balance FLOAT DEFAULT 0.0 NOT NULL", "sqlite add bonus_balance")
640
643
  _run_migration("credits", "bonus_limit", "ALTER TABLE credits ADD COLUMN bonus_limit FLOAT DEFAULT 0.0 NOT NULL", "sqlite add bonus_limit")
641
644
  _run_migration("credits", "free_monthly_used", "ALTER TABLE credits ADD COLUMN free_monthly_used FLOAT DEFAULT 0.0 NOT NULL", "sqlite add free_monthly_used")