@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 +8 -0
- package/README.md +1 -1
- package/locales/pt-BR.json +5 -2
- package/notice_action.py +8 -0
- package/package.json +1 -1
- package/tray.py +9 -7
- package/update_check.py +1 -0
- package/update_splash.py +10 -10
- package/version.py +1 -1
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.
|
|
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
|
|
package/locales/pt-BR.json
CHANGED
|
@@ -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.
|
|
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
|
|
87
|
-
since the tray balloon is shown as "Python"; when Windows refuses the toast,
|
|
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
|
-
|
|
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
|
-
|
|
183
|
-
|
|
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,
|
|
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