emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51) - #1049

Merged
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react
Aug 27, 2026
Merged

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51)#1049
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The GUI upgrade notification ("new version installed — restart to apply" banner) was silently broken since the React migration (Batch 5, #1024): the renderer's event bridge dropped upgrade frames. This PR restores the full chain.

Root cause

main.js heartbeat detects installed_version ≠ current_version and sends a dedicated upgrade event every 15s; preload.js forwards it; but renderer/src/lib/daemonBridge.tshandleFrame() had no upgrade case → the frame fell into the default "unknown event" branch and was silently dropped. No UI component referenced the upgrade i18n keys either.

Changes

  1. daemonBridge.ts — add UpgradeData frame type, upgradeBanner: {current, installed} | null store field, and an upgrade case (dedupe per installed version — the 15s heartbeat re-sends the same version, and after dismiss the banner must not reappear).
  2. Shell.tsx — render the #upgrade-banner overlay (CSS already survived in renderer/css/layout.css, theme-token based): from→to message (falls back to plain message), restart button, dismiss button. Restart failure surfaces as a system message via app.upgradeRestartFailed.
  3. main.js — new emrg:relaunchGui IPC: app.relaunch() + app.exit(0)GUI process only. The existing emrg:restartDaemon channel stops the daemon (emrg._stop_all --skip-gui) which is forbidden for this purpose: the daemon is EMRG's living core (MANIFESTO 最高原则) and must not be killed by an upgrade-banner click. After relaunch the new GUI process reuses the running daemon; if the daemon itself needs new code, the heartbeat keeps driving the banner.
  4. preload.js — expose relaunchGui.
  5. preload-api.test.js — frozen API contract updated 52 → 53 invoke methods.
  6. Tests — daemonBridge upgrade routing + dedupe test; Shell banner render/restart/dismiss test; DialogHost mock state updated for the new store field.

Verification

  • Renderer vitest: 447/447 (was 445; +2 new)
  • GUI node tests: 85 pass / 8 skipped (incl. the 54-member preload contract)
  • tsc --noEmit clean; vite build OK
  • Python: pytest 1126 passed + 1 skipped, import + CLI green

Closes rant 2026-08-27T21:54:51 (GUI upgrade notification broken after React migration).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-230933

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-232221 (2/3). Head bae227c unchanged since cyc20260827-230933 LGTM, CI test + test-windows green (33085725605), MERGEABLE/CLEAN. relaunchGui verified GUI-only (app.relaunch + app.exit, no daemon-stop path).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-233730 (3/3). Head bae227c unchanged since cyc20260827-232221 LGTM (2/3), CI test + test-windows green (33085725605), MERGEABLE/CLEAN. No ❌ in review history — 3 consecutive ✅ from distinct cycles (230933, 232221, 233730). Merging.

@argszero
argszero merged commit 2b402a0 into masterAug 27, 2026
2 checks passed
argszero added a commit that referenced this pull request Aug 27, 2026
…derer count against reality (#1052)
* emrg: test — fix Agent.md renderer count drift (445->448) + guard renderer count against reality
R2254: #1049/#1050 added renderer tests (daemonBridge/Shell/SettingsPanel/
WorkspaceView) without bumping Agent.md — the renderer count drifted
445 -> 448 silently. The doc-count guard only validates each "(N: ...)"
line's internal sum (parts == headline), not reality, and the pytest CI
job has no node_modules to run vitest.
FIX: Agent.md renderer line corrected to 448 with per-file counts aligned
to vitest's executed numbers (workspaceView 29->27, WorkspaceView 8->10,
daemonBridge 14->15, Shell 24->25, SettingsPanel 19->20).
GUARD: test_doc_counts.py::test_renderer_count_matches_docs — a static
count of test-case definitions (^\s*(it|test)\( per file under
renderer/src) equals vitest's executed total exactly (verified for all 44
files), so it runs in plain pytest and turns any future renderer-count
drift red immediately.
Python tests 1127 -> 1128 (new guard), Agent.md synced.
* test: escape regex in docstring (fix SyntaxWarning in renderer count guard)
---------
Co-authored-by: argszero <argszero@gmail.com>
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 28, 2026
… theme persistence + integrity guard, renderer count guard, llm-cost-report, vision-aware token estimate, auto-title) (#1058)
Co-authored-by: argszero <argszero@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@argszero
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51) - #1049

Merged
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react
Aug 27, 2026
Merged

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51)#1049
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The GUI upgrade notification ("new version installed — restart to apply" banner) was silently broken since the React migration (Batch 5, #1024): the renderer's event bridge dropped upgrade frames. This PR restores the full chain.

Root cause

main.js heartbeat detects installed_version ≠ current_version and sends a dedicated upgrade event every 15s; preload.js forwards it; but renderer/src/lib/daemonBridge.tshandleFrame() had no upgrade case → the frame fell into the default "unknown event" branch and was silently dropped. No UI component referenced the upgrade i18n keys either.

Changes

  1. daemonBridge.ts — add UpgradeData frame type, upgradeBanner: {current, installed} | null store field, and an upgrade case (dedupe per installed version — the 15s heartbeat re-sends the same version, and after dismiss the banner must not reappear).
  2. Shell.tsx — render the #upgrade-banner overlay (CSS already survived in renderer/css/layout.css, theme-token based): from→to message (falls back to plain message), restart button, dismiss button. Restart failure surfaces as a system message via app.upgradeRestartFailed.
  3. main.js — new emrg:relaunchGui IPC: app.relaunch() + app.exit(0)GUI process only. The existing emrg:restartDaemon channel stops the daemon (emrg._stop_all --skip-gui) which is forbidden for this purpose: the daemon is EMRG's living core (MANIFESTO 最高原则) and must not be killed by an upgrade-banner click. After relaunch the new GUI process reuses the running daemon; if the daemon itself needs new code, the heartbeat keeps driving the banner.
  4. preload.js — expose relaunchGui.
  5. preload-api.test.js — frozen API contract updated 52 → 53 invoke methods.
  6. Tests — daemonBridge upgrade routing + dedupe test; Shell banner render/restart/dismiss test; DialogHost mock state updated for the new store field.

Verification

  • Renderer vitest: 447/447 (was 445; +2 new)
  • GUI node tests: 85 pass / 8 skipped (incl. the 54-member preload contract)
  • tsc --noEmit clean; vite build OK
  • Python: pytest 1126 passed + 1 skipped, import + CLI green

Closes rant 2026-08-27T21:54:51 (GUI upgrade notification broken after React migration).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-230933

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-232221 (2/3). Head bae227c unchanged since cyc20260827-230933 LGTM, CI test + test-windows green (33085725605), MERGEABLE/CLEAN. relaunchGui verified GUI-only (app.relaunch + app.exit, no daemon-stop path).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-233730 (3/3). Head bae227c unchanged since cyc20260827-232221 LGTM (2/3), CI test + test-windows green (33085725605), MERGEABLE/CLEAN. No ❌ in review history — 3 consecutive ✅ from distinct cycles (230933, 232221, 233730). Merging.

@argszero
argszero merged commit 2b402a0 into masterAug 27, 2026
2 checks passed
argszero added a commit that referenced this pull request Aug 27, 2026
…derer count against reality (#1052)
* emrg: test — fix Agent.md renderer count drift (445->448) + guard renderer count against reality
R2254: #1049/#1050 added renderer tests (daemonBridge/Shell/SettingsPanel/
WorkspaceView) without bumping Agent.md — the renderer count drifted
445 -> 448 silently. The doc-count guard only validates each "(N: ...)"
line's internal sum (parts == headline), not reality, and the pytest CI
job has no node_modules to run vitest.
FIX: Agent.md renderer line corrected to 448 with per-file counts aligned
to vitest's executed numbers (workspaceView 29->27, WorkspaceView 8->10,
daemonBridge 14->15, Shell 24->25, SettingsPanel 19->20).
GUARD: test_doc_counts.py::test_renderer_count_matches_docs — a static
count of test-case definitions (^\s*(it|test)\( per file under
renderer/src) equals vitest's executed total exactly (verified for all 44
files), so it runs in plain pytest and turns any future renderer-count
drift red immediately.
Python tests 1127 -> 1128 (new guard), Agent.md synced.
* test: escape regex in docstring (fix SyntaxWarning in renderer count guard)
---------
Co-authored-by: argszero <argszero@gmail.com>
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 28, 2026
… theme persistence + integrity guard, renderer count guard, llm-cost-report, vision-aware token estimate, auto-title) (#1058)
Co-authored-by: argszero <argszero@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@argszero
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51) - #1049

Merged
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react
Aug 27, 2026
Merged

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51)#1049
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The GUI upgrade notification ("new version installed — restart to apply" banner) was silently broken since the React migration (Batch 5, #1024): the renderer's event bridge dropped upgrade frames. This PR restores the full chain.

Root cause

main.js heartbeat detects installed_version ≠ current_version and sends a dedicated upgrade event every 15s; preload.js forwards it; but renderer/src/lib/daemonBridge.tshandleFrame() had no upgrade case → the frame fell into the default "unknown event" branch and was silently dropped. No UI component referenced the upgrade i18n keys either.

Changes

  1. daemonBridge.ts — add UpgradeData frame type, upgradeBanner: {current, installed} | null store field, and an upgrade case (dedupe per installed version — the 15s heartbeat re-sends the same version, and after dismiss the banner must not reappear).
  2. Shell.tsx — render the #upgrade-banner overlay (CSS already survived in renderer/css/layout.css, theme-token based): from→to message (falls back to plain message), restart button, dismiss button. Restart failure surfaces as a system message via app.upgradeRestartFailed.
  3. main.js — new emrg:relaunchGui IPC: app.relaunch() + app.exit(0)GUI process only. The existing emrg:restartDaemon channel stops the daemon (emrg._stop_all --skip-gui) which is forbidden for this purpose: the daemon is EMRG's living core (MANIFESTO 最高原则) and must not be killed by an upgrade-banner click. After relaunch the new GUI process reuses the running daemon; if the daemon itself needs new code, the heartbeat keeps driving the banner.
  4. preload.js — expose relaunchGui.
  5. preload-api.test.js — frozen API contract updated 52 → 53 invoke methods.
  6. Tests — daemonBridge upgrade routing + dedupe test; Shell banner render/restart/dismiss test; DialogHost mock state updated for the new store field.

Verification

  • Renderer vitest: 447/447 (was 445; +2 new)
  • GUI node tests: 85 pass / 8 skipped (incl. the 54-member preload contract)
  • tsc --noEmit clean; vite build OK
  • Python: pytest 1126 passed + 1 skipped, import + CLI green

Closes rant 2026-08-27T21:54:51 (GUI upgrade notification broken after React migration).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-230933

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-232221 (2/3). Head bae227c unchanged since cyc20260827-230933 LGTM, CI test + test-windows green (33085725605), MERGEABLE/CLEAN. relaunchGui verified GUI-only (app.relaunch + app.exit, no daemon-stop path).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-233730 (3/3). Head bae227c unchanged since cyc20260827-232221 LGTM (2/3), CI test + test-windows green (33085725605), MERGEABLE/CLEAN. No ❌ in review history — 3 consecutive ✅ from distinct cycles (230933, 232221, 233730). Merging.

@argszero
argszero merged commit 2b402a0 into masterAug 27, 2026
2 checks passed
argszero added a commit that referenced this pull request Aug 27, 2026
…derer count against reality (#1052)
* emrg: test — fix Agent.md renderer count drift (445->448) + guard renderer count against reality
R2254: #1049/#1050 added renderer tests (daemonBridge/Shell/SettingsPanel/
WorkspaceView) without bumping Agent.md — the renderer count drifted
445 -> 448 silently. The doc-count guard only validates each "(N: ...)"
line's internal sum (parts == headline), not reality, and the pytest CI
job has no node_modules to run vitest.
FIX: Agent.md renderer line corrected to 448 with per-file counts aligned
to vitest's executed numbers (workspaceView 29->27, WorkspaceView 8->10,
daemonBridge 14->15, Shell 24->25, SettingsPanel 19->20).
GUARD: test_doc_counts.py::test_renderer_count_matches_docs — a static
count of test-case definitions (^\s*(it|test)\( per file under
renderer/src) equals vitest's executed total exactly (verified for all 44
files), so it runs in plain pytest and turns any future renderer-count
drift red immediately.
Python tests 1127 -> 1128 (new guard), Agent.md synced.
* test: escape regex in docstring (fix SyntaxWarning in renderer count guard)
---------
Co-authored-by: argszero <argszero@gmail.com>
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 28, 2026
… theme persistence + integrity guard, renderer count guard, llm-cost-report, vision-aware token estimate, auto-title) (#1058)
Co-authored-by: argszero <argszero@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@argszero
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51) - #1049

Merged
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react
Aug 27, 2026
Merged

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51)#1049
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The GUI upgrade notification ("new version installed — restart to apply" banner) was silently broken since the React migration (Batch 5, #1024): the renderer's event bridge dropped upgrade frames. This PR restores the full chain.

Root cause

main.js heartbeat detects installed_version ≠ current_version and sends a dedicated upgrade event every 15s; preload.js forwards it; but renderer/src/lib/daemonBridge.tshandleFrame() had no upgrade case → the frame fell into the default "unknown event" branch and was silently dropped. No UI component referenced the upgrade i18n keys either.

Changes

  1. daemonBridge.ts — add UpgradeData frame type, upgradeBanner: {current, installed} | null store field, and an upgrade case (dedupe per installed version — the 15s heartbeat re-sends the same version, and after dismiss the banner must not reappear).
  2. Shell.tsx — render the #upgrade-banner overlay (CSS already survived in renderer/css/layout.css, theme-token based): from→to message (falls back to plain message), restart button, dismiss button. Restart failure surfaces as a system message via app.upgradeRestartFailed.
  3. main.js — new emrg:relaunchGui IPC: app.relaunch() + app.exit(0)GUI process only. The existing emrg:restartDaemon channel stops the daemon (emrg._stop_all --skip-gui) which is forbidden for this purpose: the daemon is EMRG's living core (MANIFESTO 最高原则) and must not be killed by an upgrade-banner click. After relaunch the new GUI process reuses the running daemon; if the daemon itself needs new code, the heartbeat keeps driving the banner.
  4. preload.js — expose relaunchGui.
  5. preload-api.test.js — frozen API contract updated 52 → 53 invoke methods.
  6. Tests — daemonBridge upgrade routing + dedupe test; Shell banner render/restart/dismiss test; DialogHost mock state updated for the new store field.

Verification

  • Renderer vitest: 447/447 (was 445; +2 new)
  • GUI node tests: 85 pass / 8 skipped (incl. the 54-member preload contract)
  • tsc --noEmit clean; vite build OK
  • Python: pytest 1126 passed + 1 skipped, import + CLI green

Closes rant 2026-08-27T21:54:51 (GUI upgrade notification broken after React migration).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-230933

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-232221 (2/3). Head bae227c unchanged since cyc20260827-230933 LGTM, CI test + test-windows green (33085725605), MERGEABLE/CLEAN. relaunchGui verified GUI-only (app.relaunch + app.exit, no daemon-stop path).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-233730 (3/3). Head bae227c unchanged since cyc20260827-232221 LGTM (2/3), CI test + test-windows green (33085725605), MERGEABLE/CLEAN. No ❌ in review history — 3 consecutive ✅ from distinct cycles (230933, 232221, 233730). Merging.

@argszero
argszero merged commit 2b402a0 into masterAug 27, 2026
2 checks passed
argszero added a commit that referenced this pull request Aug 27, 2026
…derer count against reality (#1052)
* emrg: test — fix Agent.md renderer count drift (445->448) + guard renderer count against reality
R2254: #1049/#1050 added renderer tests (daemonBridge/Shell/SettingsPanel/
WorkspaceView) without bumping Agent.md — the renderer count drifted
445 -> 448 silently. The doc-count guard only validates each "(N: ...)"
line's internal sum (parts == headline), not reality, and the pytest CI
job has no node_modules to run vitest.
FIX: Agent.md renderer line corrected to 448 with per-file counts aligned
to vitest's executed numbers (workspaceView 29->27, WorkspaceView 8->10,
daemonBridge 14->15, Shell 24->25, SettingsPanel 19->20).
GUARD: test_doc_counts.py::test_renderer_count_matches_docs — a static
count of test-case definitions (^\s*(it|test)\( per file under
renderer/src) equals vitest's executed total exactly (verified for all 44
files), so it runs in plain pytest and turns any future renderer-count
drift red immediately.
Python tests 1127 -> 1128 (new guard), Agent.md synced.
* test: escape regex in docstring (fix SyntaxWarning in renderer count guard)
---------
Co-authored-by: argszero <argszero@gmail.com>
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 28, 2026
… theme persistence + integrity guard, renderer count guard, llm-cost-report, vision-aware token estimate, auto-title) (#1058)
Co-authored-by: argszero <argszero@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@argszero
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51) - #1049

Merged
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react
Aug 27, 2026
Merged

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51)#1049
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The GUI upgrade notification ("new version installed — restart to apply" banner) was silently broken since the React migration (Batch 5, #1024): the renderer's event bridge dropped upgrade frames. This PR restores the full chain.

Root cause

main.js heartbeat detects installed_version ≠ current_version and sends a dedicated upgrade event every 15s; preload.js forwards it; but renderer/src/lib/daemonBridge.tshandleFrame() had no upgrade case → the frame fell into the default "unknown event" branch and was silently dropped. No UI component referenced the upgrade i18n keys either.

Changes

  1. daemonBridge.ts — add UpgradeData frame type, upgradeBanner: {current, installed} | null store field, and an upgrade case (dedupe per installed version — the 15s heartbeat re-sends the same version, and after dismiss the banner must not reappear).
  2. Shell.tsx — render the #upgrade-banner overlay (CSS already survived in renderer/css/layout.css, theme-token based): from→to message (falls back to plain message), restart button, dismiss button. Restart failure surfaces as a system message via app.upgradeRestartFailed.
  3. main.js — new emrg:relaunchGui IPC: app.relaunch() + app.exit(0)GUI process only. The existing emrg:restartDaemon channel stops the daemon (emrg._stop_all --skip-gui) which is forbidden for this purpose: the daemon is EMRG's living core (MANIFESTO 最高原则) and must not be killed by an upgrade-banner click. After relaunch the new GUI process reuses the running daemon; if the daemon itself needs new code, the heartbeat keeps driving the banner.
  4. preload.js — expose relaunchGui.
  5. preload-api.test.js — frozen API contract updated 52 → 53 invoke methods.
  6. Tests — daemonBridge upgrade routing + dedupe test; Shell banner render/restart/dismiss test; DialogHost mock state updated for the new store field.

Verification

  • Renderer vitest: 447/447 (was 445; +2 new)
  • GUI node tests: 85 pass / 8 skipped (incl. the 54-member preload contract)
  • tsc --noEmit clean; vite build OK
  • Python: pytest 1126 passed + 1 skipped, import + CLI green

Closes rant 2026-08-27T21:54:51 (GUI upgrade notification broken after React migration).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-230933

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-232221 (2/3). Head bae227c unchanged since cyc20260827-230933 LGTM, CI test + test-windows green (33085725605), MERGEABLE/CLEAN. relaunchGui verified GUI-only (app.relaunch + app.exit, no daemon-stop path).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-233730 (3/3). Head bae227c unchanged since cyc20260827-232221 LGTM (2/3), CI test + test-windows green (33085725605), MERGEABLE/CLEAN. No ❌ in review history — 3 consecutive ✅ from distinct cycles (230933, 232221, 233730). Merging.

@argszero
argszero merged commit 2b402a0 into masterAug 27, 2026
2 checks passed
argszero added a commit that referenced this pull request Aug 27, 2026
…derer count against reality (#1052)
* emrg: test — fix Agent.md renderer count drift (445->448) + guard renderer count against reality
R2254: #1049/#1050 added renderer tests (daemonBridge/Shell/SettingsPanel/
WorkspaceView) without bumping Agent.md — the renderer count drifted
445 -> 448 silently. The doc-count guard only validates each "(N: ...)"
line's internal sum (parts == headline), not reality, and the pytest CI
job has no node_modules to run vitest.
FIX: Agent.md renderer line corrected to 448 with per-file counts aligned
to vitest's executed numbers (workspaceView 29->27, WorkspaceView 8->10,
daemonBridge 14->15, Shell 24->25, SettingsPanel 19->20).
GUARD: test_doc_counts.py::test_renderer_count_matches_docs — a static
count of test-case definitions (^\s*(it|test)\( per file under
renderer/src) equals vitest's executed total exactly (verified for all 44
files), so it runs in plain pytest and turns any future renderer-count
drift red immediately.
Python tests 1127 -> 1128 (new guard), Agent.md synced.
* test: escape regex in docstring (fix SyntaxWarning in renderer count guard)
---------
Co-authored-by: argszero <argszero@gmail.com>
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 28, 2026
… theme persistence + integrity guard, renderer count guard, llm-cost-report, vision-aware token estimate, auto-title) (#1058)
Co-authored-by: argszero <argszero@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@argszero
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51) - #1049

Merged
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react
Aug 27, 2026
Merged

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51)#1049
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The GUI upgrade notification ("new version installed — restart to apply" banner) was silently broken since the React migration (Batch 5, #1024): the renderer's event bridge dropped upgrade frames. This PR restores the full chain.

Root cause

main.js heartbeat detects installed_version ≠ current_version and sends a dedicated upgrade event every 15s; preload.js forwards it; but renderer/src/lib/daemonBridge.tshandleFrame() had no upgrade case → the frame fell into the default "unknown event" branch and was silently dropped. No UI component referenced the upgrade i18n keys either.

Changes

  1. daemonBridge.ts — add UpgradeData frame type, upgradeBanner: {current, installed} | null store field, and an upgrade case (dedupe per installed version — the 15s heartbeat re-sends the same version, and after dismiss the banner must not reappear).
  2. Shell.tsx — render the #upgrade-banner overlay (CSS already survived in renderer/css/layout.css, theme-token based): from→to message (falls back to plain message), restart button, dismiss button. Restart failure surfaces as a system message via app.upgradeRestartFailed.
  3. main.js — new emrg:relaunchGui IPC: app.relaunch() + app.exit(0)GUI process only. The existing emrg:restartDaemon channel stops the daemon (emrg._stop_all --skip-gui) which is forbidden for this purpose: the daemon is EMRG's living core (MANIFESTO 最高原则) and must not be killed by an upgrade-banner click. After relaunch the new GUI process reuses the running daemon; if the daemon itself needs new code, the heartbeat keeps driving the banner.
  4. preload.js — expose relaunchGui.
  5. preload-api.test.js — frozen API contract updated 52 → 53 invoke methods.
  6. Tests — daemonBridge upgrade routing + dedupe test; Shell banner render/restart/dismiss test; DialogHost mock state updated for the new store field.

Verification

  • Renderer vitest: 447/447 (was 445; +2 new)
  • GUI node tests: 85 pass / 8 skipped (incl. the 54-member preload contract)
  • tsc --noEmit clean; vite build OK
  • Python: pytest 1126 passed + 1 skipped, import + CLI green

Closes rant 2026-08-27T21:54:51 (GUI upgrade notification broken after React migration).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-230933

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-232221 (2/3). Head bae227c unchanged since cyc20260827-230933 LGTM, CI test + test-windows green (33085725605), MERGEABLE/CLEAN. relaunchGui verified GUI-only (app.relaunch + app.exit, no daemon-stop path).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-233730 (3/3). Head bae227c unchanged since cyc20260827-232221 LGTM (2/3), CI test + test-windows green (33085725605), MERGEABLE/CLEAN. No ❌ in review history — 3 consecutive ✅ from distinct cycles (230933, 232221, 233730). Merging.

@argszero
argszero merged commit 2b402a0 into masterAug 27, 2026
2 checks passed
argszero added a commit that referenced this pull request Aug 27, 2026
…derer count against reality (#1052)
* emrg: test — fix Agent.md renderer count drift (445->448) + guard renderer count against reality
R2254: #1049/#1050 added renderer tests (daemonBridge/Shell/SettingsPanel/
WorkspaceView) without bumping Agent.md — the renderer count drifted
445 -> 448 silently. The doc-count guard only validates each "(N: ...)"
line's internal sum (parts == headline), not reality, and the pytest CI
job has no node_modules to run vitest.
FIX: Agent.md renderer line corrected to 448 with per-file counts aligned
to vitest's executed numbers (workspaceView 29->27, WorkspaceView 8->10,
daemonBridge 14->15, Shell 24->25, SettingsPanel 19->20).
GUARD: test_doc_counts.py::test_renderer_count_matches_docs — a static
count of test-case definitions (^\s*(it|test)\( per file under
renderer/src) equals vitest's executed total exactly (verified for all 44
files), so it runs in plain pytest and turns any future renderer-count
drift red immediately.
Python tests 1127 -> 1128 (new guard), Agent.md synced.
* test: escape regex in docstring (fix SyntaxWarning in renderer count guard)
---------
Co-authored-by: argszero <argszero@gmail.com>
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 28, 2026
… theme persistence + integrity guard, renderer count guard, llm-cost-report, vision-aware token estimate, auto-title) (#1058)
Co-authored-by: argszero <argszero@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@argszero
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51) - #1049

Merged
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react
Aug 27, 2026
Merged

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51)#1049
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The GUI upgrade notification ("new version installed — restart to apply" banner) was silently broken since the React migration (Batch 5, #1024): the renderer's event bridge dropped upgrade frames. This PR restores the full chain.

Root cause

main.js heartbeat detects installed_version ≠ current_version and sends a dedicated upgrade event every 15s; preload.js forwards it; but renderer/src/lib/daemonBridge.tshandleFrame() had no upgrade case → the frame fell into the default "unknown event" branch and was silently dropped. No UI component referenced the upgrade i18n keys either.

Changes

  1. daemonBridge.ts — add UpgradeData frame type, upgradeBanner: {current, installed} | null store field, and an upgrade case (dedupe per installed version — the 15s heartbeat re-sends the same version, and after dismiss the banner must not reappear).
  2. Shell.tsx — render the #upgrade-banner overlay (CSS already survived in renderer/css/layout.css, theme-token based): from→to message (falls back to plain message), restart button, dismiss button. Restart failure surfaces as a system message via app.upgradeRestartFailed.
  3. main.js — new emrg:relaunchGui IPC: app.relaunch() + app.exit(0)GUI process only. The existing emrg:restartDaemon channel stops the daemon (emrg._stop_all --skip-gui) which is forbidden for this purpose: the daemon is EMRG's living core (MANIFESTO 最高原则) and must not be killed by an upgrade-banner click. After relaunch the new GUI process reuses the running daemon; if the daemon itself needs new code, the heartbeat keeps driving the banner.
  4. preload.js — expose relaunchGui.
  5. preload-api.test.js — frozen API contract updated 52 → 53 invoke methods.
  6. Tests — daemonBridge upgrade routing + dedupe test; Shell banner render/restart/dismiss test; DialogHost mock state updated for the new store field.

Verification

  • Renderer vitest: 447/447 (was 445; +2 new)
  • GUI node tests: 85 pass / 8 skipped (incl. the 54-member preload contract)
  • tsc --noEmit clean; vite build OK
  • Python: pytest 1126 passed + 1 skipped, import + CLI green

Closes rant 2026-08-27T21:54:51 (GUI upgrade notification broken after React migration).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-230933

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-232221 (2/3). Head bae227c unchanged since cyc20260827-230933 LGTM, CI test + test-windows green (33085725605), MERGEABLE/CLEAN. relaunchGui verified GUI-only (app.relaunch + app.exit, no daemon-stop path).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-233730 (3/3). Head bae227c unchanged since cyc20260827-232221 LGTM (2/3), CI test + test-windows green (33085725605), MERGEABLE/CLEAN. No ❌ in review history — 3 consecutive ✅ from distinct cycles (230933, 232221, 233730). Merging.

@argszero
argszero merged commit 2b402a0 into masterAug 27, 2026
2 checks passed
argszero added a commit that referenced this pull request Aug 27, 2026
…derer count against reality (#1052)
* emrg: test — fix Agent.md renderer count drift (445->448) + guard renderer count against reality
R2254: #1049/#1050 added renderer tests (daemonBridge/Shell/SettingsPanel/
WorkspaceView) without bumping Agent.md — the renderer count drifted
445 -> 448 silently. The doc-count guard only validates each "(N: ...)"
line's internal sum (parts == headline), not reality, and the pytest CI
job has no node_modules to run vitest.
FIX: Agent.md renderer line corrected to 448 with per-file counts aligned
to vitest's executed numbers (workspaceView 29->27, WorkspaceView 8->10,
daemonBridge 14->15, Shell 24->25, SettingsPanel 19->20).
GUARD: test_doc_counts.py::test_renderer_count_matches_docs — a static
count of test-case definitions (^\s*(it|test)\( per file under
renderer/src) equals vitest's executed total exactly (verified for all 44
files), so it runs in plain pytest and turns any future renderer-count
drift red immediately.
Python tests 1127 -> 1128 (new guard), Agent.md synced.
* test: escape regex in docstring (fix SyntaxWarning in renderer count guard)
---------
Co-authored-by: argszero <argszero@gmail.com>
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 28, 2026
… theme persistence + integrity guard, renderer count guard, llm-cost-report, vision-aware token estimate, auto-title) (#1058)
Co-authored-by: argszero <argszero@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@argszero
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51) - #1049

Merged
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react
Aug 27, 2026
Merged

emrg: gui — restore upgrade banner in React shell (fix rant 2026-08-27T21:54:51)#1049
argszero merged 1 commit into
masterfrom
feature/gui-upgrade-banner-react

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

The GUI upgrade notification ("new version installed — restart to apply" banner) was silently broken since the React migration (Batch 5, #1024): the renderer's event bridge dropped upgrade frames. This PR restores the full chain.

Root cause

main.js heartbeat detects installed_version ≠ current_version and sends a dedicated upgrade event every 15s; preload.js forwards it; but renderer/src/lib/daemonBridge.tshandleFrame() had no upgrade case → the frame fell into the default "unknown event" branch and was silently dropped. No UI component referenced the upgrade i18n keys either.

Changes

  1. daemonBridge.ts — add UpgradeData frame type, upgradeBanner: {current, installed} | null store field, and an upgrade case (dedupe per installed version — the 15s heartbeat re-sends the same version, and after dismiss the banner must not reappear).
  2. Shell.tsx — render the #upgrade-banner overlay (CSS already survived in renderer/css/layout.css, theme-token based): from→to message (falls back to plain message), restart button, dismiss button. Restart failure surfaces as a system message via app.upgradeRestartFailed.
  3. main.js — new emrg:relaunchGui IPC: app.relaunch() + app.exit(0)GUI process only. The existing emrg:restartDaemon channel stops the daemon (emrg._stop_all --skip-gui) which is forbidden for this purpose: the daemon is EMRG's living core (MANIFESTO 最高原则) and must not be killed by an upgrade-banner click. After relaunch the new GUI process reuses the running daemon; if the daemon itself needs new code, the heartbeat keeps driving the banner.
  4. preload.js — expose relaunchGui.
  5. preload-api.test.js — frozen API contract updated 52 → 53 invoke methods.
  6. Tests — daemonBridge upgrade routing + dedupe test; Shell banner render/restart/dismiss test; DialogHost mock state updated for the new store field.

Verification

  • Renderer vitest: 447/447 (was 445; +2 new)
  • GUI node tests: 85 pass / 8 skipped (incl. the 54-member preload contract)
  • tsc --noEmit clean; vite build OK
  • Python: pytest 1126 passed + 1 skipped, import + CLI green

Closes rant 2026-08-27T21:54:51 (GUI upgrade notification broken after React migration).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-230933

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-232221 (2/3). Head bae227c unchanged since cyc20260827-230933 LGTM, CI test + test-windows green (33085725605), MERGEABLE/CLEAN. relaunchGui verified GUI-only (app.relaunch + app.exit, no daemon-stop path).

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle cyc20260827-233730 (3/3). Head bae227c unchanged since cyc20260827-232221 LGTM (2/3), CI test + test-windows green (33085725605), MERGEABLE/CLEAN. No ❌ in review history — 3 consecutive ✅ from distinct cycles (230933, 232221, 233730). Merging.

@argszero
argszero merged commit 2b402a0 into masterAug 27, 2026
2 checks passed
argszero added a commit that referenced this pull request Aug 27, 2026
…derer count against reality (#1052)
* emrg: test — fix Agent.md renderer count drift (445->448) + guard renderer count against reality
R2254: #1049/#1050 added renderer tests (daemonBridge/Shell/SettingsPanel/
WorkspaceView) without bumping Agent.md — the renderer count drifted
445 -> 448 silently. The doc-count guard only validates each "(N: ...)"
line's internal sum (parts == headline), not reality, and the pytest CI
job has no node_modules to run vitest.
FIX: Agent.md renderer line corrected to 448 with per-file counts aligned
to vitest's executed numbers (workspaceView 29->27, WorkspaceView 8->10,
daemonBridge 14->15, Shell 24->25, SettingsPanel 19->20).
GUARD: test_doc_counts.py::test_renderer_count_matches_docs — a static
count of test-case definitions (^\s*(it|test)\( per file under
renderer/src) equals vitest's executed total exactly (verified for all 44
files), so it runs in plain pytest and turns any future renderer-count
drift red immediately.
Python tests 1127 -> 1128 (new guard), Agent.md synced.
* test: escape regex in docstring (fix SyntaxWarning in renderer count guard)
---------
Co-authored-by: argszero <argszero@gmail.com>
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
argszero added a commit that referenced this pull request Aug 28, 2026
… theme persistence + integrity guard, renderer count guard, llm-cost-report, vision-aware token estimate, auto-title) (#1058)
Co-authored-by: argszero <argszero@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@argszero