@allansantos-dev/smart-tool 0.9.46 → 0.9.47

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.47 - beta
4
+
5
+ - The update window names the browser check ("Checking the browsers…") while the installer verifies Camoufox and
6
+ Chromium, the longest step of an update; before, it kept saying "Preparing Python…" until the end.
7
+ - Update notifications carry a button. "Smart Tool updated from X to Y" opens what changed (the product page); a failed
8
+ update, on the update window's toast and on the tray's notice at the next start, opens the update log. Both are
9
+ fixed actions of `notice_action.py` (`open-changes`, `open-update-log`), never a link taken from the toast.
10
+
3
11
  ## 0.9.46 - beta
4
12
 
5
13
  - The interface speaks Portuguese and English. It follows the Windows display language (any Portuguese shows Brazilian
package/README.md CHANGED
@@ -17,7 +17,7 @@ registered as the `playwright` server where this machine lets a browser be drive
17
17
  An optional hook routes the agent's native Grep/Glob/Read/Bash/WebSearch/WebFetch calls to these tools when they
18
18
  are cheaper, or just tells the agent what Smart Tool would do.
19
19
 
20
- **Status:** 0.9.46 beta. Windows only. What changed in each version: [CHANGELOG.md](CHANGELOG.md).
20
+ **Status:** 0.9.47 beta. Windows only. What changed in each version: [CHANGELOG.md](CHANGELOG.md).
21
21
 
22
22
  ## How it works
23
23
 
@@ -881,7 +881,10 @@
881
881
  "({0} sites)": "({0} sites)",
882
882
  "{0} skills": "{0} skills",
883
883
  ", {0} new": ", {0} novos",
884
- "{0} {1} (~{2} tokens)": "{0} {1} (~{2} tokens)"
884
+ "{0} {1} (~{2} tokens)": "{0} {1} (~{2} tokens)",
885
+ "Checking the browsers…": "Verificando os navegadores…",
886
+ "View log": "Ver o log",
887
+ "What changed": "O que mudou"
885
888
  },
886
889
  "ignore": [
887
890
  "saved msg",
@@ -920,4 +923,4 @@
920
923
  "{0} KiB",
921
924
  "- **{0}** [{1}] {2}: {3} ([source]({4}))"
922
925
  ]
923
- }
926
+ }
package/notice_action.py CHANGED
@@ -33,6 +33,14 @@ def run(uri):
33
33
  import daemon_launcher
34
34
  webbrowser.open(daemon_launcher.ensure_daemon_running().rstrip("/") + "/setup#" + params.get("section", "models"))
35
35
  return "setup opened"
36
+ if action == "open-update-log":
37
+ import update_check
38
+ os.startfile(update_check.UPDATE_LOG)
39
+ return "update log opened"
40
+ if action == "open-changes":
41
+ import update_check
42
+ webbrowser.open(update_check.SITE_URL)
43
+ return "changes opened"
36
44
  if action == "mute-model":
37
45
  import model_health
38
46
  return model_health.mute(params.get("model", ""))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allansantos-dev/smart-tool",
3
- "version": "0.9.46",
3
+ "version": "0.9.47",
4
4
  "description": "Local MCP server that gives coding agents (Claude Code, Codex) cheaper, sharper tools than their built-in search. Windows.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Allan Santos",
package/tray.py CHANGED
@@ -82,13 +82,13 @@ def _set_state(health, icon=None):
82
82
  icon.title = i18n.t(_TITLES[health])
83
83
 
84
84
 
85
- def _notify(icon, text, **values):
86
- """Windows notification, translated (text is an English catalog key). A toast under Smart Tool's own app id,
87
- since the tray balloon is shown as "Python"; when Windows refuses the toast, the balloon carries the text and the
88
- refusal."""
85
+ def _notify(icon, text, buttons=(), **values):
86
+ """Windows notification, translated (text is an English catalog key; buttons are (catalog key, protocol link)). A
87
+ toast under Smart Tool's own app id, since the tray balloon is shown as "Python"; when Windows refuses the toast,
88
+ the balloon carries the text and the refusal."""
89
89
  message = i18n.t(text, **values)
90
90
  try:
91
- toast_notice.show("Smart Tool", [message], [])
91
+ toast_notice.show("Smart Tool", [message], [(i18n.t(label), uri) for label, uri in buttons])
92
92
  except Exception as exc:
93
93
  icon.notify(f"{message} ({exc})", "Smart Tool")
94
94
 
@@ -187,11 +187,13 @@ def _announce_start(icon):
187
187
  """Tells the user, once per start, that Smart Tool was just updated or that the last automatic update failed."""
188
188
  updated = update_check.update_for_tray()
189
189
  if updated:
190
- _notify(icon, "Smart Tool updated from {old} to {new}.", old=updated["from"], new=updated["to"])
190
+ changes = (i18n.N_("What changed"), toast_notice.action_uri("open-changes"))
191
+ _notify(icon, "Smart Tool updated from {old} to {new}.", [changes], old=updated["from"], new=updated["to"])
191
192
  failed = update_check.failed_update()
192
193
  if failed:
194
+ log = (i18n.N_("View log"), toast_notice.action_uri("open-update-log"))
193
195
  _notify(icon, "The update to {target} failed; Smart Tool {version} is still installed. It is tried again in "
194
- "24 h, or now from this menu.", target=failed, version=version.VERSION)
196
+ "24 h, or now from this menu.", [log], target=failed, version=version.VERSION)
195
197
 
196
198
 
197
199
  def _update_loop(icon):
package/update_check.py CHANGED
@@ -23,6 +23,7 @@ REGISTRY_URL = "https://registry.npmjs.org/@allansantos-dev%2Fsmart-tool/latest"
23
23
  UPDATE_COMMAND = f"npx --yes {PACKAGE}@latest install"
24
24
  SITE_URL = "https://allansantos-dv.github.io/smart-tool/"
25
25
  STATE_PATH = os.path.join(paths.DATA_DIR, "update-state.json")
26
+ UPDATE_LOG = os.path.join(paths.DATA_DIR, "update.log")
26
27
  ENV_OPT_OUT = "SMART_TOOL_AUTO_UPDATE"
27
28
  RETRY_AFTER_S = 24 * 3600
28
29
  UPDATED_NOTICE_S = 24 * 3600
package/update_splash.py CHANGED
@@ -3,7 +3,7 @@ the interface language, then the result. Started by the tray (update_check.run_u
3
3
  <version>`; it outlives the tray, which the installer stops and starts again.
4
4
 
5
5
  The install command runs with CREATE_NO_WINDOW, so it and every console program it starts (node, the installer,
6
- pip, PowerShell, schtasks) share one hidden console. Its output goes to UPDATE_LOG; a failure shows the last line,
6
+ pip, PowerShell, schtasks) share one hidden console. Its output goes to update_check.UPDATE_LOG; a failure shows the last line,
7
7
  the log path and a Windows notification, and the installer has already restored the previous version."""
8
8
  import os
9
9
  import queue
@@ -15,12 +15,10 @@ import time
15
15
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
16
16
  import i18n
17
17
  import node_locator
18
- import paths
19
18
  import toast_notice
20
19
  import update_check
21
20
  import version
22
21
 
23
- UPDATE_LOG = os.path.join(paths.DATA_DIR, "update.log")
24
22
  TIMEOUT_S = 20 * 60
25
23
  SUCCESS_CLOSE_MS = 4000
26
24
  FAILURE_CLOSE_MS = 15000
@@ -30,6 +28,8 @@ STEPS = (
30
28
  ("Downloading uv", i18n.N_("Downloading components…")),
31
29
  ("Preparing Python", i18n.N_("Preparing Python…")),
32
30
  ("TLS inspection", i18n.N_("Preparing Python…")),
31
+ ("Camoufox browser", i18n.N_("Checking the browsers…")),
32
+ ("Chromium browser", i18n.N_("Checking the browsers…")),
33
33
  ("Older Smart Tool installation found", i18n.N_("Removing an older installation…")),
34
34
  ("Updating Smart Tool at", i18n.N_("Copying the new files…")),
35
35
  ("Installing Smart Tool at", i18n.N_("Copying the new files…")),
@@ -56,12 +56,12 @@ def install_command():
56
56
 
57
57
 
58
58
  def run_install(lines):
59
- """Runs the install command hidden, puts each output line on `lines`, writes them to UPDATE_LOG and returns
59
+ """Runs the install command hidden, puts each output line on `lines`, writes them to update_check.UPDATE_LOG and returns
60
60
  (exit code, last non-empty line). Kills the whole process tree after TIMEOUT_S."""
61
61
  command, npx = install_command()
62
- os.makedirs(os.path.dirname(UPDATE_LOG), exist_ok=True)
62
+ os.makedirs(os.path.dirname(update_check.UPDATE_LOG), exist_ok=True)
63
63
  last = ""
64
- with open(UPDATE_LOG, "w", encoding="utf-8") as log:
64
+ with open(update_check.UPDATE_LOG, "w", encoding="utf-8") as log:
65
65
  log.write(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {' '.join(command)}\n")
66
66
  with subprocess.Popen(command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
67
67
  text=True, encoding="utf-8", errors="replace", creationflags=NO_WINDOW,
@@ -179,11 +179,11 @@ def main(argv):
179
179
  i18n.t("This window closes by itself."))
180
180
  return
181
181
  detail = i18n.t("The update did not finish; version {version} is still installed.", version=version.VERSION)
182
- splash.finish(False, i18n.t("Update not finished"), f"{detail}\n{outcome['last'][:180]}",
183
- i18n.t("Details in {path}", path=UPDATE_LOG))
182
+ where = i18n.t("Details in {path}", path=update_check.UPDATE_LOG)
183
+ splash.finish(False, i18n.t("Update not finished"), f"{detail}\n{outcome['last'][:180]}", where)
184
184
  try:
185
- toast_notice.show(i18n.t("Smart Tool update not finished"), [detail, i18n.t("Details in {path}", path=UPDATE_LOG)],
186
- [], tag="update-failed")
185
+ toast_notice.show(i18n.t("Smart Tool update not finished"), [detail, where],
186
+ [(i18n.t("View log"), toast_notice.action_uri("open-update-log"))], tag="update-failed")
187
187
  except Exception as exc:
188
188
  splash.note.config(text=f"{splash.note.cget('text')}\n{exc}")
189
189
 
package/version.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Single source of the Smart Tool version and of the User-Agent sent to public APIs."""
2
2
  import re
3
3
 
4
- VERSION = "0.9.46"
4
+ VERSION = "0.9.47"
5
5
  _CONTACT_RE = re.compile(r"^(?:[^\s@()<>;]+@[^\s@()<>;]+\.[^\s@()<>;]+|https?://[^\s()<>;]+)$")
6
6
 
7
7