ryugyosoft commited on
Commit
a538ce1
·
verified ·
1 Parent(s): 97ca32a

onw 0.8.5: after an update the onw window reopens on the new version

Browse files
Files changed (8) hide show
  1. CHANGELOG.md +4 -0
  2. CHANGELOG_en.md +4 -0
  3. onw/__init__.py +1 -1
  4. onw/__main__.py +2 -1
  5. onw/app.py +19 -4
  6. onw/relaunch.py +4 -3
  7. onw/tray.py +7 -4
  8. pyproject.toml +1 -1
CHANGELOG.md CHANGED
@@ -5,6 +5,10 @@
5
  日付は日本時間です。各版は Hugging Face の `ryugyosoft/onw` にタグ(`v0.4.2` 以降)付きで残っています。
6
  onw ウィンドウは、新しい版があるとこのファイルから変更点を表示します(`## v…` の見出しで区切っています)。
7
 
 
 
 
 
8
  ## v0.8.4 (2026-09-27)
9
  - 画面を英語・中国語(簡体字)にも対応。OS の言語に合わせて自動で選び、「設定」の「言語」で切り替えられます
10
  (onw ウィンドウ、トレイのメニューと通知、チャット画面、検証ページ)。
 
5
  日付は日本時間です。各版は Hugging Face の `ryugyosoft/onw` にタグ(`v0.4.2` 以降)付きで残っています。
6
  onw ウィンドウは、新しい版があるとこのファイルから変更点を表示します(`## v…` の見出しで区切っています)。
7
 
8
+ ## v0.8.5 (2026-09-27)
9
+ - 更新後、開いていた onw ウィンドウも新しい版で開き直すように(これまではページだけ読み直していたため、タイトルの版表示や
10
+ アイコンが古いままでした)。開いていたタブはそのまま。更新で再起動したトレイも、新しい版のウィンドウを開きます。
11
+
12
  ## v0.8.4 (2026-09-27)
13
  - 画面を英語・中国語(簡体字)にも対応。OS の言語に合わせて自動で選び、「設定」の「言語」で切り替えられます
14
  (onw ウィンドウ、トレイのメニューと通知、チャット画面、検証ページ)。
CHANGELOG_en.md CHANGED
@@ -4,6 +4,10 @@
4
 
5
  Dates are JST. Every version is on Hugging Face `ryugyosoft/onw`, tagged from `v0.4.2` on.
6
 
 
 
 
 
7
  ## v0.8.4 (2026-09-27)
8
  - The UI speaks English and Simplified Chinese too: it follows the OS language, Settings → Language switches it
9
  (onw window, tray menu and notifications, chat page, check page).
 
4
 
5
  Dates are JST. Every version is on Hugging Face `ryugyosoft/onw`, tagged from `v0.4.2` on.
6
 
7
+ ## v0.8.5 (2026-09-27)
8
+ - After an update an open onw window reopens on the new version too (it used to reload only the page, so its title and
9
+ icon stayed old), on the same tab. The tray restarted by an update opens a window on the new version as well.
10
+
11
  ## v0.8.4 (2026-09-27)
12
  - The UI speaks English and Simplified Chinese too: it follows the OS language, Settings → Language switches it
13
  (onw window, tray menu and notifications, chat page, check page).
onw/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
 
3
  A small engine that runs LLMs entirely on the Intel NPU: static segment graphs + host-managed state.
4
  """
5
- __version__ = "0.8.4"
 
2
 
3
  A small engine that runs LLMs entirely on the Intel NPU: static segment graphs + host-managed state.
4
  """
5
+ __version__ = "0.8.5"
onw/__main__.py CHANGED
@@ -63,7 +63,8 @@ def main():
63
  convert(argv)
64
  elif cmd == "window":
65
  from onw.app import window
66
- window(argv[argv.index("--tab") + 1] if "--tab" in argv else "server")
 
67
  elif cmd == "tray":
68
  from onw.tray import main as tray
69
  tray(argv)
 
63
  convert(argv)
64
  elif cmd == "window":
65
  from onw.app import window
66
+ window(argv[argv.index("--tab") + 1] if "--tab" in argv else "server",
67
+ argv[argv.index("--updated") + 1] if "--updated" in argv else None)
68
  elif cmd == "tray":
69
  from onw.tray import main as tray
70
  tray(argv)
onw/app.py CHANGED
@@ -365,9 +365,10 @@ def open_path(p):
365
 
366
  # ------------------------------------------------------------------ window
367
 
368
- def window(tab="server"):
369
  """The onw window: onw/web/manage.html in a small native web view (pywebview), talking to the manager (the tray
370
- process; started here when no tray is running). Without pywebview the same page opens in the browser."""
 
371
  if not single_instance("window"):
372
  raise_window()
373
  return
@@ -377,6 +378,8 @@ def window(tab="server"):
377
  if own:
378
  info = mgr.serve()
379
  url = mgr.page_url(info, tab)
 
 
380
  try:
381
  import webview
382
  except ImportError:
@@ -398,7 +401,8 @@ def window(tab="server"):
398
  win = webview.create_window(TITLE, url, js_api=Api(), width=780, height=460, min_size=(420, 320))
399
 
400
  def follow():
401
- """The tray restarts after an update with a new manager (new port and token): load the page from it."""
 
402
  cur = info
403
  while True:
404
  time.sleep(2)
@@ -410,7 +414,18 @@ def window(tab="server"):
410
  timeout=5).read())["version"]
411
  except Exception:
412
  v = ""
413
- win.load_url(mgr.page_url(m, "server").replace("?token=", f"?updated={v}&token="))
 
 
 
 
 
 
 
 
 
 
 
414
  if not own:
415
  threading.Thread(target=follow, daemon=True).start()
416
  webview.start(icon=icon_path())
 
365
 
366
  # ------------------------------------------------------------------ window
367
 
368
+ def window(tab="server", updated=None):
369
  """The onw window: onw/web/manage.html in a small native web view (pywebview), talking to the manager (the tray
370
+ process; started here when no tray is running). Without pywebview the same page opens in the browser.
371
+ `updated`: the version just installed (the page says so once)."""
372
  if not single_instance("window"):
373
  raise_window()
374
  return
 
378
  if own:
379
  info = mgr.serve()
380
  url = mgr.page_url(info, tab)
381
+ if updated:
382
+ url = url.replace("?token=", f"?updated={updated}&token=")
383
  try:
384
  import webview
385
  except ImportError:
 
401
  win = webview.create_window(TITLE, url, js_api=Api(), width=780, height=460, min_size=(420, 320))
402
 
403
  def follow():
404
+ """The tray restarted (new manager: new port and token). After an update this window's own code is old too:
405
+ close it and open a fresh window on the new code; otherwise just load the page from the new manager."""
406
  cur = info
407
  while True:
408
  time.sleep(2)
 
414
  timeout=5).read())["version"]
415
  except Exception:
416
  v = ""
417
+ if v and v != __version__:
418
+ try:
419
+ page = win.evaluate_js("location.hash.slice(1)") or "server"
420
+ except Exception:
421
+ page = "server"
422
+ subprocess.Popen([sys.executable, "-m", "onw.relaunch", str(os.getpid()), "window", "--tab", page,
423
+ "--updated", v], cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
424
+ **({"creationflags": subprocess.CREATE_NO_WINDOW | subprocess.DETACHED_PROCESS}
425
+ if os.name == "nt" else {"start_new_session": True}))
426
+ win.destroy() # the new window takes the single-instance lock once we exit
427
+ return
428
+ win.load_url(mgr.page_url(m, tab))
429
  if not own:
430
  threading.Thread(target=follow, daemon=True).start()
431
  webview.start(icon=icon_path())
onw/relaunch.py CHANGED
@@ -1,10 +1,11 @@
1
- """Start a fresh tray once the old one has exited (used after an update).
2
- usage (internal): python -m onw.relaunch OLD_PID"""
3
  import os, subprocess, sys, time
4
 
5
 
6
  def main():
7
  pid = int(sys.argv[1])
 
8
  try:
9
  import psutil
10
  deadline = time.time() + 60
@@ -17,7 +18,7 @@ def main():
17
  exe = exe[:-10] + "pythonw.exe"
18
  kw = ({"creationflags": subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP} if os.name == "nt"
19
  else {"start_new_session": True})
20
- subprocess.Popen([exe, "-m", "onw", "tray"], cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
21
  stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kw)
22
 
23
 
 
1
+ """Start onw again once an old process has exited (after an update: the tray, or an open onw window).
2
+ usage (internal): python -m onw.relaunch OLD_PID [onw arguments, default: tray]"""
3
  import os, subprocess, sys, time
4
 
5
 
6
  def main():
7
  pid = int(sys.argv[1])
8
+ args = sys.argv[2:] or ["tray"]
9
  try:
10
  import psutil
11
  deadline = time.time() + 60
 
18
  exe = exe[:-10] + "pythonw.exe"
19
  kw = ({"creationflags": subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP} if os.name == "nt"
20
  else {"start_new_session": True})
21
+ subprocess.Popen([exe, "-m", "onw", *args], cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
22
  stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kw)
23
 
24
 
onw/tray.py CHANGED
@@ -9,14 +9,14 @@ going while the window is closed.
9
  """
10
  import json, os, subprocess, sys, threading, time, webbrowser
11
 
12
- from . import app
13
 
14
 
15
- def open_window(tab="server"):
16
  exe = sys.executable
17
  if os.name == "nt" and exe.lower().endswith("python.exe"):
18
  exe = exe[:-10] + "pythonw.exe"
19
- subprocess.Popen([exe, "-m", "onw", "window", "--tab", tab])
20
 
21
 
22
  def icon_image(state):
@@ -133,7 +133,8 @@ def main(argv=None):
133
  c = cfg()
134
  resume = os.path.join(app.config_dir(), "resume.json")
135
  resumed = None
136
- if os.path.exists(resume): # just restarted by an update: reload that model
 
137
  try:
138
  resumed = json.load(open(resume)).get("model")
139
  except (OSError, ValueError):
@@ -147,6 +148,8 @@ def main(argv=None):
147
  app.start_server(c)
148
  elif c["autostart_server"] and state["s"] == "stopped":
149
  start()
 
 
150
  threading.Thread(target=refresh, daemon=True).start()
151
  threading.Thread(target=app.refresh_shortcut, daemon=True).start()
152
  icon.run()
 
9
  """
10
  import json, os, subprocess, sys, threading, time, webbrowser
11
 
12
+ from . import app, __version__
13
 
14
 
15
+ def open_window(tab="server", updated=None):
16
  exe = sys.executable
17
  if os.name == "nt" and exe.lower().endswith("python.exe"):
18
  exe = exe[:-10] + "pythonw.exe"
19
+ subprocess.Popen([exe, "-m", "onw", "window", "--tab", tab] + (["--updated", updated] if updated else []))
20
 
21
 
22
  def icon_image(state):
 
133
  c = cfg()
134
  resume = os.path.join(app.config_dir(), "resume.json")
135
  resumed = None
136
+ after_update = os.path.exists(resume)
137
+ if after_update: # just restarted by an update: reload that model
138
  try:
139
  resumed = json.load(open(resume)).get("model")
140
  except (OSError, ValueError):
 
148
  app.start_server(c)
149
  elif c["autostart_server"] and state["s"] == "stopped":
150
  start()
151
+ if after_update and app.installed(c): # show the new version (an open window reopens itself
152
+ open_window("server", updated=__version__) # too; the single-instance lock keeps just one)
153
  threading.Thread(target=refresh, daemon=True).start()
154
  threading.Thread(target=app.refresh_shortcut, daemon=True).start()
155
  icon.run()
pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
 
5
  [project]
6
  name = "onw"
7
- version = "0.8.4"
8
  description = "Ore no NPU ga konna ni ugoku wake nai - LLMs entirely on the Intel NPU"
9
  readme = "README.md"
10
  license = {text = "Apache-2.0"}
 
4
 
5
  [project]
6
  name = "onw"
7
+ version = "0.8.5"
8
  description = "Ore no NPU ga konna ni ugoku wake nai - LLMs entirely on the Intel NPU"
9
  readme = "README.md"
10
  license = {text = "Apache-2.0"}