Skip to content

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks - #1207

Merged
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake
Jul 18, 2026
Merged

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks#1207
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake

Conversation

@jackwener

Copy link
Copy Markdown
Member

User-requested: the 定时任务 page lacked the keep-system-awake notice + toggle + capability (a 即将支持 placeholder was removed earlier for placeholder honesty — this ships the real thing).

End-to-end

  • Setting: system.keepSystemAwake on AppSettings (default false), modeled on notifications.runComplete — merge/patch/fail-closed coercion + core tests.
  • Capability: keep-system-awake.ts wraps Electron powerSaveBlocker with prevent-app-suspension (system stays awake, display may sleep — the right mode for background scheduled work). Double-start guard, re-acquire after out-of-band release; 7 unit tests with mocked electron.
  • Wiring: rides the existing settings:update channel (zero new IPC). Toggle applies instantly; re-held at launch when enabled; reconciles external settings.json edits.
  • UI: neutral passive row above the plan list — Info icon + 定时任务仅在电脑保持唤醒时运行 + right-aligned 保持系统唤醒 SettingsSwitch. House style (no saturated banner; status-color restraint). Optimistic flip with revert-on-error + Chinese toast, useMountedRef + pending guard, row hides when the bridge is absent.

Verification

Live CDP: click → aria-checked true → stayed true (full path exercised: optimistic → settings:update → powerSaveBlocker.start). Light+dark captures both states, accepted by maintainer. plan-reminder-panel contract extended (new pins for duplicate-guard/revert/unmount-release), nothing deleted.

Gates (merged tree with main incl. #1205)

desktop 2709/2709 · ui 183/183 · core green · typecheck · check-dead-css · knip no new debt · alignment auditor all fixtures clean. Implemented by an opus worktree agent.

Scheduled reminders run off an in-process timer that freezes when the
machine sleeps, so tasks silently never fire. Add a keepSystemAwake
setting that holds an Electron powerSaveBlocker to keep background
scheduled work running.
- core: add SystemSettings { keepSystemAwake } to AppSettings, mirroring
notifications.runComplete end to end (default, merge, patch surface,
fail-closed boolean coercion in normalizeSettings) + contract tests.
- main: keep-system-awake controller wraps powerSaveBlocker with
'prevent-app-suspension' (system stays awake WITHOUT forcing the
display on) — Electron-free + injected blocker so it unit-tests under
node --test, with a double-start guard on the blocker id.
- wiring: apply on launch if enabled, start/stop the instant the toggle
flips via applySettingsRuntimeEffects (rides the existing settings
channel), and reconcile on external settings.json edits.
Replace the placeholder-honesty gap (designer audit P1-5) with the real
control: an informational row above the plan list — Info icon + 定时任务
仅在电脑保持唤醒时运行 copy, right-aligned 保持系统唤醒 label + switch.
- Status-color restraint: neutral passive surface (settingsNotice passive
recipe: --foreground-5 / --muted-foreground, hairline border,
radius-surface), NOT the reference's saturated blue banner. Replaces
the old maka-plan-system-alert accent recipe.
- Switch reflects reality: optimistic local state initialized from the
persisted snapshot, revert-on-error + Chinese toast, useMountedRef +
pending-ref guard so a slow IPC write can't double-fire or set state
after unmount.
- Fail-soft: the row hides entirely unless the host wires both the value
and the setter (bridge present).
- Re-pin the panel async-action contract with the new toggle invariants.
- use-keep-system-awake hook reads/writes settings.system.keepSystemAwake
over the existing settings:get/update bridge (no new IPC channel),
gating on runtime bridge presence for fail-soft on older mains.
- app-shell threads the value + setter into AutomationsPage; the panel
hides the row when the capability is unavailable.
- AutomationsPage forwards the keepSystemAwake props to PlanReminderPanel.
@jackwener
jackwener merged commit 7abe8de into mainJul 18, 2026
3 checks passed
jackwener added a commit that referenced this pull request Jul 19, 2026
…ain.ts (arch R5) (#1248)
* chore(main): extract settings-runtime-effects from main.ts (arch R5)
Pure move of main.ts's settings runtime-effects cluster into
settings-runtime-effects.ts, exporting createSettingsRuntimeEffects(deps)
→ { normalizeSettingsPatch, applySettingsRuntimeEffects,
handleExternalSettingsChange } (syncDefaultPermissionModeToSessions stays
internal). Follows the R4 tool-assembly / tool-artifact-persistence DI
precedent: settingsStore / botRegistry / openGateway / keepSystemAwake /
runtime / safeSendToRenderer / emitSessionsChanged are injected, bodies
byte-identical. keep-awake runtime-effect (#1207) rides
applySettingsRuntimeEffects unchanged.
Contract mechanics: add settings-runtime-effects.ts to the
main-process-contract-source-helpers aggregator; allowlist the moved
[config-watcher] console.error at its new path in check-console.mjs. No
source-pin test targeted these functions in main.ts directly.
* chore(main): extract session-stream core from main.ts (arch R5)
Pure move of main.ts's session-stream cluster into session-stream.ts:
- createAiSdkBackendFactory(deps): BackendFactory — the whole
backends.register('ai-sdk', …) closure plus the internal modelSupportsVision.
Two seams resolved after the registration point are injected as accessors:
getRuntime (SessionManager built later) and getLookupPricing (mutable pricing
lookup, read live per recordLlmCall / snapshotted once for the lookupPricing
field — matching the original module-let closure semantics exactly).
- createSessionStreamer(deps): StreamEvents — streamEvents + its two
event-classifier helpers and the StreamEventsOptions/Result types.
main.ts keeps the module-scoped seams it owns (backends.register call site,
sessionActivities, lookupPricing let, runtime, the fake/e2e backend registers)
and every streamEvents call site.
Contract re-pins (maintainer-authorized): add session-stream.ts to the
main-process-contract-source-helpers aggregator; switch three direct-main.ts
readers to the combined source keeping every assertion —
attachment-frontend-contract (modelSupportsVision + supportsVision vision pin),
ipc-surface-contract (memoryPromptSnapshot + buildBackendSystemPrompt),
web-search-telemetry-scrub-contract (argsSummary scrub). registerIpc /
main-process-wiring-contract untouched.
main.ts 1656 → 1372 (−284 across both R5 clusters).
* docs(arch): mark R5 shipped (main.ts −284, settings-runtime-effects + session-stream)
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

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks by jackwener · Pull Request #1207 · apache/maka · GitHub
Skip to content

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks - #1207

Merged
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake
Jul 18, 2026
Merged

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks#1207
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake

Conversation

@jackwener

Copy link
Copy Markdown
Member

User-requested: the 定时任务 page lacked the keep-system-awake notice + toggle + capability (a 即将支持 placeholder was removed earlier for placeholder honesty — this ships the real thing).

End-to-end

  • Setting: system.keepSystemAwake on AppSettings (default false), modeled on notifications.runComplete — merge/patch/fail-closed coercion + core tests.
  • Capability: keep-system-awake.ts wraps Electron powerSaveBlocker with prevent-app-suspension (system stays awake, display may sleep — the right mode for background scheduled work). Double-start guard, re-acquire after out-of-band release; 7 unit tests with mocked electron.
  • Wiring: rides the existing settings:update channel (zero new IPC). Toggle applies instantly; re-held at launch when enabled; reconciles external settings.json edits.
  • UI: neutral passive row above the plan list — Info icon + 定时任务仅在电脑保持唤醒时运行 + right-aligned 保持系统唤醒 SettingsSwitch. House style (no saturated banner; status-color restraint). Optimistic flip with revert-on-error + Chinese toast, useMountedRef + pending guard, row hides when the bridge is absent.

Verification

Live CDP: click → aria-checked true → stayed true (full path exercised: optimistic → settings:update → powerSaveBlocker.start). Light+dark captures both states, accepted by maintainer. plan-reminder-panel contract extended (new pins for duplicate-guard/revert/unmount-release), nothing deleted.

Gates (merged tree with main incl. #1205)

desktop 2709/2709 · ui 183/183 · core green · typecheck · check-dead-css · knip no new debt · alignment auditor all fixtures clean. Implemented by an opus worktree agent.

Scheduled reminders run off an in-process timer that freezes when the
machine sleeps, so tasks silently never fire. Add a keepSystemAwake
setting that holds an Electron powerSaveBlocker to keep background
scheduled work running.
- core: add SystemSettings { keepSystemAwake } to AppSettings, mirroring
notifications.runComplete end to end (default, merge, patch surface,
fail-closed boolean coercion in normalizeSettings) + contract tests.
- main: keep-system-awake controller wraps powerSaveBlocker with
'prevent-app-suspension' (system stays awake WITHOUT forcing the
display on) — Electron-free + injected blocker so it unit-tests under
node --test, with a double-start guard on the blocker id.
- wiring: apply on launch if enabled, start/stop the instant the toggle
flips via applySettingsRuntimeEffects (rides the existing settings
channel), and reconcile on external settings.json edits.
Replace the placeholder-honesty gap (designer audit P1-5) with the real
control: an informational row above the plan list — Info icon + 定时任务
仅在电脑保持唤醒时运行 copy, right-aligned 保持系统唤醒 label + switch.
- Status-color restraint: neutral passive surface (settingsNotice passive
recipe: --foreground-5 / --muted-foreground, hairline border,
radius-surface), NOT the reference's saturated blue banner. Replaces
the old maka-plan-system-alert accent recipe.
- Switch reflects reality: optimistic local state initialized from the
persisted snapshot, revert-on-error + Chinese toast, useMountedRef +
pending-ref guard so a slow IPC write can't double-fire or set state
after unmount.
- Fail-soft: the row hides entirely unless the host wires both the value
and the setter (bridge present).
- Re-pin the panel async-action contract with the new toggle invariants.
- use-keep-system-awake hook reads/writes settings.system.keepSystemAwake
over the existing settings:get/update bridge (no new IPC channel),
gating on runtime bridge presence for fail-soft on older mains.
- app-shell threads the value + setter into AutomationsPage; the panel
hides the row when the capability is unavailable.
- AutomationsPage forwards the keepSystemAwake props to PlanReminderPanel.
@jackwener
jackwener merged commit 7abe8de into mainJul 18, 2026
3 checks passed
jackwener added a commit that referenced this pull request Jul 19, 2026
…ain.ts (arch R5) (#1248)
* chore(main): extract settings-runtime-effects from main.ts (arch R5)
Pure move of main.ts's settings runtime-effects cluster into
settings-runtime-effects.ts, exporting createSettingsRuntimeEffects(deps)
→ { normalizeSettingsPatch, applySettingsRuntimeEffects,
handleExternalSettingsChange } (syncDefaultPermissionModeToSessions stays
internal). Follows the R4 tool-assembly / tool-artifact-persistence DI
precedent: settingsStore / botRegistry / openGateway / keepSystemAwake /
runtime / safeSendToRenderer / emitSessionsChanged are injected, bodies
byte-identical. keep-awake runtime-effect (#1207) rides
applySettingsRuntimeEffects unchanged.
Contract mechanics: add settings-runtime-effects.ts to the
main-process-contract-source-helpers aggregator; allowlist the moved
[config-watcher] console.error at its new path in check-console.mjs. No
source-pin test targeted these functions in main.ts directly.
* chore(main): extract session-stream core from main.ts (arch R5)
Pure move of main.ts's session-stream cluster into session-stream.ts:
- createAiSdkBackendFactory(deps): BackendFactory — the whole
backends.register('ai-sdk', …) closure plus the internal modelSupportsVision.
Two seams resolved after the registration point are injected as accessors:
getRuntime (SessionManager built later) and getLookupPricing (mutable pricing
lookup, read live per recordLlmCall / snapshotted once for the lookupPricing
field — matching the original module-let closure semantics exactly).
- createSessionStreamer(deps): StreamEvents — streamEvents + its two
event-classifier helpers and the StreamEventsOptions/Result types.
main.ts keeps the module-scoped seams it owns (backends.register call site,
sessionActivities, lookupPricing let, runtime, the fake/e2e backend registers)
and every streamEvents call site.
Contract re-pins (maintainer-authorized): add session-stream.ts to the
main-process-contract-source-helpers aggregator; switch three direct-main.ts
readers to the combined source keeping every assertion —
attachment-frontend-contract (modelSupportsVision + supportsVision vision pin),
ipc-surface-contract (memoryPromptSnapshot + buildBackendSystemPrompt),
web-search-telemetry-scrub-contract (argsSummary scrub). registerIpc /
main-process-wiring-contract untouched.
main.ts 1656 → 1372 (−284 across both R5 clusters).
* docs(arch): mark R5 shipped (main.ts −284, settings-runtime-effects + session-stream)
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

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks by jackwener · Pull Request #1207 · apache/maka · GitHub
Skip to content

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks - #1207

Merged
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake
Jul 18, 2026
Merged

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks#1207
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake

Conversation

@jackwener

Copy link
Copy Markdown
Member

User-requested: the 定时任务 page lacked the keep-system-awake notice + toggle + capability (a 即将支持 placeholder was removed earlier for placeholder honesty — this ships the real thing).

End-to-end

  • Setting: system.keepSystemAwake on AppSettings (default false), modeled on notifications.runComplete — merge/patch/fail-closed coercion + core tests.
  • Capability: keep-system-awake.ts wraps Electron powerSaveBlocker with prevent-app-suspension (system stays awake, display may sleep — the right mode for background scheduled work). Double-start guard, re-acquire after out-of-band release; 7 unit tests with mocked electron.
  • Wiring: rides the existing settings:update channel (zero new IPC). Toggle applies instantly; re-held at launch when enabled; reconciles external settings.json edits.
  • UI: neutral passive row above the plan list — Info icon + 定时任务仅在电脑保持唤醒时运行 + right-aligned 保持系统唤醒 SettingsSwitch. House style (no saturated banner; status-color restraint). Optimistic flip with revert-on-error + Chinese toast, useMountedRef + pending guard, row hides when the bridge is absent.

Verification

Live CDP: click → aria-checked true → stayed true (full path exercised: optimistic → settings:update → powerSaveBlocker.start). Light+dark captures both states, accepted by maintainer. plan-reminder-panel contract extended (new pins for duplicate-guard/revert/unmount-release), nothing deleted.

Gates (merged tree with main incl. #1205)

desktop 2709/2709 · ui 183/183 · core green · typecheck · check-dead-css · knip no new debt · alignment auditor all fixtures clean. Implemented by an opus worktree agent.

Scheduled reminders run off an in-process timer that freezes when the
machine sleeps, so tasks silently never fire. Add a keepSystemAwake
setting that holds an Electron powerSaveBlocker to keep background
scheduled work running.
- core: add SystemSettings { keepSystemAwake } to AppSettings, mirroring
notifications.runComplete end to end (default, merge, patch surface,
fail-closed boolean coercion in normalizeSettings) + contract tests.
- main: keep-system-awake controller wraps powerSaveBlocker with
'prevent-app-suspension' (system stays awake WITHOUT forcing the
display on) — Electron-free + injected blocker so it unit-tests under
node --test, with a double-start guard on the blocker id.
- wiring: apply on launch if enabled, start/stop the instant the toggle
flips via applySettingsRuntimeEffects (rides the existing settings
channel), and reconcile on external settings.json edits.
Replace the placeholder-honesty gap (designer audit P1-5) with the real
control: an informational row above the plan list — Info icon + 定时任务
仅在电脑保持唤醒时运行 copy, right-aligned 保持系统唤醒 label + switch.
- Status-color restraint: neutral passive surface (settingsNotice passive
recipe: --foreground-5 / --muted-foreground, hairline border,
radius-surface), NOT the reference's saturated blue banner. Replaces
the old maka-plan-system-alert accent recipe.
- Switch reflects reality: optimistic local state initialized from the
persisted snapshot, revert-on-error + Chinese toast, useMountedRef +
pending-ref guard so a slow IPC write can't double-fire or set state
after unmount.
- Fail-soft: the row hides entirely unless the host wires both the value
and the setter (bridge present).
- Re-pin the panel async-action contract with the new toggle invariants.
- use-keep-system-awake hook reads/writes settings.system.keepSystemAwake
over the existing settings:get/update bridge (no new IPC channel),
gating on runtime bridge presence for fail-soft on older mains.
- app-shell threads the value + setter into AutomationsPage; the panel
hides the row when the capability is unavailable.
- AutomationsPage forwards the keepSystemAwake props to PlanReminderPanel.
@jackwener
jackwener merged commit 7abe8de into mainJul 18, 2026
3 checks passed
jackwener added a commit that referenced this pull request Jul 19, 2026
…ain.ts (arch R5) (#1248)
* chore(main): extract settings-runtime-effects from main.ts (arch R5)
Pure move of main.ts's settings runtime-effects cluster into
settings-runtime-effects.ts, exporting createSettingsRuntimeEffects(deps)
→ { normalizeSettingsPatch, applySettingsRuntimeEffects,
handleExternalSettingsChange } (syncDefaultPermissionModeToSessions stays
internal). Follows the R4 tool-assembly / tool-artifact-persistence DI
precedent: settingsStore / botRegistry / openGateway / keepSystemAwake /
runtime / safeSendToRenderer / emitSessionsChanged are injected, bodies
byte-identical. keep-awake runtime-effect (#1207) rides
applySettingsRuntimeEffects unchanged.
Contract mechanics: add settings-runtime-effects.ts to the
main-process-contract-source-helpers aggregator; allowlist the moved
[config-watcher] console.error at its new path in check-console.mjs. No
source-pin test targeted these functions in main.ts directly.
* chore(main): extract session-stream core from main.ts (arch R5)
Pure move of main.ts's session-stream cluster into session-stream.ts:
- createAiSdkBackendFactory(deps): BackendFactory — the whole
backends.register('ai-sdk', …) closure plus the internal modelSupportsVision.
Two seams resolved after the registration point are injected as accessors:
getRuntime (SessionManager built later) and getLookupPricing (mutable pricing
lookup, read live per recordLlmCall / snapshotted once for the lookupPricing
field — matching the original module-let closure semantics exactly).
- createSessionStreamer(deps): StreamEvents — streamEvents + its two
event-classifier helpers and the StreamEventsOptions/Result types.
main.ts keeps the module-scoped seams it owns (backends.register call site,
sessionActivities, lookupPricing let, runtime, the fake/e2e backend registers)
and every streamEvents call site.
Contract re-pins (maintainer-authorized): add session-stream.ts to the
main-process-contract-source-helpers aggregator; switch three direct-main.ts
readers to the combined source keeping every assertion —
attachment-frontend-contract (modelSupportsVision + supportsVision vision pin),
ipc-surface-contract (memoryPromptSnapshot + buildBackendSystemPrompt),
web-search-telemetry-scrub-contract (argsSummary scrub). registerIpc /
main-process-wiring-contract untouched.
main.ts 1656 → 1372 (−284 across both R5 clusters).
* docs(arch): mark R5 shipped (main.ts −284, settings-runtime-effects + session-stream)
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

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

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks - #1207

Merged
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake
Jul 18, 2026
Merged

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks#1207
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake

Conversation

@jackwener

Copy link
Copy Markdown
Member

User-requested: the 定时任务 page lacked the keep-system-awake notice + toggle + capability (a 即将支持 placeholder was removed earlier for placeholder honesty — this ships the real thing).

End-to-end

  • Setting: system.keepSystemAwake on AppSettings (default false), modeled on notifications.runComplete — merge/patch/fail-closed coercion + core tests.
  • Capability: keep-system-awake.ts wraps Electron powerSaveBlocker with prevent-app-suspension (system stays awake, display may sleep — the right mode for background scheduled work). Double-start guard, re-acquire after out-of-band release; 7 unit tests with mocked electron.
  • Wiring: rides the existing settings:update channel (zero new IPC). Toggle applies instantly; re-held at launch when enabled; reconciles external settings.json edits.
  • UI: neutral passive row above the plan list — Info icon + 定时任务仅在电脑保持唤醒时运行 + right-aligned 保持系统唤醒 SettingsSwitch. House style (no saturated banner; status-color restraint). Optimistic flip with revert-on-error + Chinese toast, useMountedRef + pending guard, row hides when the bridge is absent.

Verification

Live CDP: click → aria-checked true → stayed true (full path exercised: optimistic → settings:update → powerSaveBlocker.start). Light+dark captures both states, accepted by maintainer. plan-reminder-panel contract extended (new pins for duplicate-guard/revert/unmount-release), nothing deleted.

Gates (merged tree with main incl. #1205)

desktop 2709/2709 · ui 183/183 · core green · typecheck · check-dead-css · knip no new debt · alignment auditor all fixtures clean. Implemented by an opus worktree agent.

Scheduled reminders run off an in-process timer that freezes when the
machine sleeps, so tasks silently never fire. Add a keepSystemAwake
setting that holds an Electron powerSaveBlocker to keep background
scheduled work running.
- core: add SystemSettings { keepSystemAwake } to AppSettings, mirroring
notifications.runComplete end to end (default, merge, patch surface,
fail-closed boolean coercion in normalizeSettings) + contract tests.
- main: keep-system-awake controller wraps powerSaveBlocker with
'prevent-app-suspension' (system stays awake WITHOUT forcing the
display on) — Electron-free + injected blocker so it unit-tests under
node --test, with a double-start guard on the blocker id.
- wiring: apply on launch if enabled, start/stop the instant the toggle
flips via applySettingsRuntimeEffects (rides the existing settings
channel), and reconcile on external settings.json edits.
Replace the placeholder-honesty gap (designer audit P1-5) with the real
control: an informational row above the plan list — Info icon + 定时任务
仅在电脑保持唤醒时运行 copy, right-aligned 保持系统唤醒 label + switch.
- Status-color restraint: neutral passive surface (settingsNotice passive
recipe: --foreground-5 / --muted-foreground, hairline border,
radius-surface), NOT the reference's saturated blue banner. Replaces
the old maka-plan-system-alert accent recipe.
- Switch reflects reality: optimistic local state initialized from the
persisted snapshot, revert-on-error + Chinese toast, useMountedRef +
pending-ref guard so a slow IPC write can't double-fire or set state
after unmount.
- Fail-soft: the row hides entirely unless the host wires both the value
and the setter (bridge present).
- Re-pin the panel async-action contract with the new toggle invariants.
- use-keep-system-awake hook reads/writes settings.system.keepSystemAwake
over the existing settings:get/update bridge (no new IPC channel),
gating on runtime bridge presence for fail-soft on older mains.
- app-shell threads the value + setter into AutomationsPage; the panel
hides the row when the capability is unavailable.
- AutomationsPage forwards the keepSystemAwake props to PlanReminderPanel.
@jackwener
jackwener merged commit 7abe8de into mainJul 18, 2026
3 checks passed
jackwener added a commit that referenced this pull request Jul 19, 2026
…ain.ts (arch R5) (#1248)
* chore(main): extract settings-runtime-effects from main.ts (arch R5)
Pure move of main.ts's settings runtime-effects cluster into
settings-runtime-effects.ts, exporting createSettingsRuntimeEffects(deps)
→ { normalizeSettingsPatch, applySettingsRuntimeEffects,
handleExternalSettingsChange } (syncDefaultPermissionModeToSessions stays
internal). Follows the R4 tool-assembly / tool-artifact-persistence DI
precedent: settingsStore / botRegistry / openGateway / keepSystemAwake /
runtime / safeSendToRenderer / emitSessionsChanged are injected, bodies
byte-identical. keep-awake runtime-effect (#1207) rides
applySettingsRuntimeEffects unchanged.
Contract mechanics: add settings-runtime-effects.ts to the
main-process-contract-source-helpers aggregator; allowlist the moved
[config-watcher] console.error at its new path in check-console.mjs. No
source-pin test targeted these functions in main.ts directly.
* chore(main): extract session-stream core from main.ts (arch R5)
Pure move of main.ts's session-stream cluster into session-stream.ts:
- createAiSdkBackendFactory(deps): BackendFactory — the whole
backends.register('ai-sdk', …) closure plus the internal modelSupportsVision.
Two seams resolved after the registration point are injected as accessors:
getRuntime (SessionManager built later) and getLookupPricing (mutable pricing
lookup, read live per recordLlmCall / snapshotted once for the lookupPricing
field — matching the original module-let closure semantics exactly).
- createSessionStreamer(deps): StreamEvents — streamEvents + its two
event-classifier helpers and the StreamEventsOptions/Result types.
main.ts keeps the module-scoped seams it owns (backends.register call site,
sessionActivities, lookupPricing let, runtime, the fake/e2e backend registers)
and every streamEvents call site.
Contract re-pins (maintainer-authorized): add session-stream.ts to the
main-process-contract-source-helpers aggregator; switch three direct-main.ts
readers to the combined source keeping every assertion —
attachment-frontend-contract (modelSupportsVision + supportsVision vision pin),
ipc-surface-contract (memoryPromptSnapshot + buildBackendSystemPrompt),
web-search-telemetry-scrub-contract (argsSummary scrub). registerIpc /
main-process-wiring-contract untouched.
main.ts 1656 → 1372 (−284 across both R5 clusters).
* docs(arch): mark R5 shipped (main.ts −284, settings-runtime-effects + session-stream)
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

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks by jackwener · Pull Request #1207 · apache/maka · GitHub
Skip to content

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks - #1207

Merged
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake
Jul 18, 2026
Merged

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks#1207
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake

Conversation

@jackwener

Copy link
Copy Markdown
Member

User-requested: the 定时任务 page lacked the keep-system-awake notice + toggle + capability (a 即将支持 placeholder was removed earlier for placeholder honesty — this ships the real thing).

End-to-end

  • Setting: system.keepSystemAwake on AppSettings (default false), modeled on notifications.runComplete — merge/patch/fail-closed coercion + core tests.
  • Capability: keep-system-awake.ts wraps Electron powerSaveBlocker with prevent-app-suspension (system stays awake, display may sleep — the right mode for background scheduled work). Double-start guard, re-acquire after out-of-band release; 7 unit tests with mocked electron.
  • Wiring: rides the existing settings:update channel (zero new IPC). Toggle applies instantly; re-held at launch when enabled; reconciles external settings.json edits.
  • UI: neutral passive row above the plan list — Info icon + 定时任务仅在电脑保持唤醒时运行 + right-aligned 保持系统唤醒 SettingsSwitch. House style (no saturated banner; status-color restraint). Optimistic flip with revert-on-error + Chinese toast, useMountedRef + pending guard, row hides when the bridge is absent.

Verification

Live CDP: click → aria-checked true → stayed true (full path exercised: optimistic → settings:update → powerSaveBlocker.start). Light+dark captures both states, accepted by maintainer. plan-reminder-panel contract extended (new pins for duplicate-guard/revert/unmount-release), nothing deleted.

Gates (merged tree with main incl. #1205)

desktop 2709/2709 · ui 183/183 · core green · typecheck · check-dead-css · knip no new debt · alignment auditor all fixtures clean. Implemented by an opus worktree agent.

Scheduled reminders run off an in-process timer that freezes when the
machine sleeps, so tasks silently never fire. Add a keepSystemAwake
setting that holds an Electron powerSaveBlocker to keep background
scheduled work running.
- core: add SystemSettings { keepSystemAwake } to AppSettings, mirroring
notifications.runComplete end to end (default, merge, patch surface,
fail-closed boolean coercion in normalizeSettings) + contract tests.
- main: keep-system-awake controller wraps powerSaveBlocker with
'prevent-app-suspension' (system stays awake WITHOUT forcing the
display on) — Electron-free + injected blocker so it unit-tests under
node --test, with a double-start guard on the blocker id.
- wiring: apply on launch if enabled, start/stop the instant the toggle
flips via applySettingsRuntimeEffects (rides the existing settings
channel), and reconcile on external settings.json edits.
Replace the placeholder-honesty gap (designer audit P1-5) with the real
control: an informational row above the plan list — Info icon + 定时任务
仅在电脑保持唤醒时运行 copy, right-aligned 保持系统唤醒 label + switch.
- Status-color restraint: neutral passive surface (settingsNotice passive
recipe: --foreground-5 / --muted-foreground, hairline border,
radius-surface), NOT the reference's saturated blue banner. Replaces
the old maka-plan-system-alert accent recipe.
- Switch reflects reality: optimistic local state initialized from the
persisted snapshot, revert-on-error + Chinese toast, useMountedRef +
pending-ref guard so a slow IPC write can't double-fire or set state
after unmount.
- Fail-soft: the row hides entirely unless the host wires both the value
and the setter (bridge present).
- Re-pin the panel async-action contract with the new toggle invariants.
- use-keep-system-awake hook reads/writes settings.system.keepSystemAwake
over the existing settings:get/update bridge (no new IPC channel),
gating on runtime bridge presence for fail-soft on older mains.
- app-shell threads the value + setter into AutomationsPage; the panel
hides the row when the capability is unavailable.
- AutomationsPage forwards the keepSystemAwake props to PlanReminderPanel.
@jackwener
jackwener merged commit 7abe8de into mainJul 18, 2026
3 checks passed
jackwener added a commit that referenced this pull request Jul 19, 2026
…ain.ts (arch R5) (#1248)
* chore(main): extract settings-runtime-effects from main.ts (arch R5)
Pure move of main.ts's settings runtime-effects cluster into
settings-runtime-effects.ts, exporting createSettingsRuntimeEffects(deps)
→ { normalizeSettingsPatch, applySettingsRuntimeEffects,
handleExternalSettingsChange } (syncDefaultPermissionModeToSessions stays
internal). Follows the R4 tool-assembly / tool-artifact-persistence DI
precedent: settingsStore / botRegistry / openGateway / keepSystemAwake /
runtime / safeSendToRenderer / emitSessionsChanged are injected, bodies
byte-identical. keep-awake runtime-effect (#1207) rides
applySettingsRuntimeEffects unchanged.
Contract mechanics: add settings-runtime-effects.ts to the
main-process-contract-source-helpers aggregator; allowlist the moved
[config-watcher] console.error at its new path in check-console.mjs. No
source-pin test targeted these functions in main.ts directly.
* chore(main): extract session-stream core from main.ts (arch R5)
Pure move of main.ts's session-stream cluster into session-stream.ts:
- createAiSdkBackendFactory(deps): BackendFactory — the whole
backends.register('ai-sdk', …) closure plus the internal modelSupportsVision.
Two seams resolved after the registration point are injected as accessors:
getRuntime (SessionManager built later) and getLookupPricing (mutable pricing
lookup, read live per recordLlmCall / snapshotted once for the lookupPricing
field — matching the original module-let closure semantics exactly).
- createSessionStreamer(deps): StreamEvents — streamEvents + its two
event-classifier helpers and the StreamEventsOptions/Result types.
main.ts keeps the module-scoped seams it owns (backends.register call site,
sessionActivities, lookupPricing let, runtime, the fake/e2e backend registers)
and every streamEvents call site.
Contract re-pins (maintainer-authorized): add session-stream.ts to the
main-process-contract-source-helpers aggregator; switch three direct-main.ts
readers to the combined source keeping every assertion —
attachment-frontend-contract (modelSupportsVision + supportsVision vision pin),
ipc-surface-contract (memoryPromptSnapshot + buildBackendSystemPrompt),
web-search-telemetry-scrub-contract (argsSummary scrub). registerIpc /
main-process-wiring-contract untouched.
main.ts 1656 → 1372 (−284 across both R5 clusters).
* docs(arch): mark R5 shipped (main.ts −284, settings-runtime-effects + session-stream)
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

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks by jackwener · Pull Request #1207 · apache/maka · GitHub
Skip to content

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks - #1207

Merged
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake
Jul 18, 2026
Merged

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks#1207
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake

Conversation

@jackwener

Copy link
Copy Markdown
Member

User-requested: the 定时任务 page lacked the keep-system-awake notice + toggle + capability (a 即将支持 placeholder was removed earlier for placeholder honesty — this ships the real thing).

End-to-end

  • Setting: system.keepSystemAwake on AppSettings (default false), modeled on notifications.runComplete — merge/patch/fail-closed coercion + core tests.
  • Capability: keep-system-awake.ts wraps Electron powerSaveBlocker with prevent-app-suspension (system stays awake, display may sleep — the right mode for background scheduled work). Double-start guard, re-acquire after out-of-band release; 7 unit tests with mocked electron.
  • Wiring: rides the existing settings:update channel (zero new IPC). Toggle applies instantly; re-held at launch when enabled; reconciles external settings.json edits.
  • UI: neutral passive row above the plan list — Info icon + 定时任务仅在电脑保持唤醒时运行 + right-aligned 保持系统唤醒 SettingsSwitch. House style (no saturated banner; status-color restraint). Optimistic flip with revert-on-error + Chinese toast, useMountedRef + pending guard, row hides when the bridge is absent.

Verification

Live CDP: click → aria-checked true → stayed true (full path exercised: optimistic → settings:update → powerSaveBlocker.start). Light+dark captures both states, accepted by maintainer. plan-reminder-panel contract extended (new pins for duplicate-guard/revert/unmount-release), nothing deleted.

Gates (merged tree with main incl. #1205)

desktop 2709/2709 · ui 183/183 · core green · typecheck · check-dead-css · knip no new debt · alignment auditor all fixtures clean. Implemented by an opus worktree agent.

Scheduled reminders run off an in-process timer that freezes when the
machine sleeps, so tasks silently never fire. Add a keepSystemAwake
setting that holds an Electron powerSaveBlocker to keep background
scheduled work running.
- core: add SystemSettings { keepSystemAwake } to AppSettings, mirroring
notifications.runComplete end to end (default, merge, patch surface,
fail-closed boolean coercion in normalizeSettings) + contract tests.
- main: keep-system-awake controller wraps powerSaveBlocker with
'prevent-app-suspension' (system stays awake WITHOUT forcing the
display on) — Electron-free + injected blocker so it unit-tests under
node --test, with a double-start guard on the blocker id.
- wiring: apply on launch if enabled, start/stop the instant the toggle
flips via applySettingsRuntimeEffects (rides the existing settings
channel), and reconcile on external settings.json edits.
Replace the placeholder-honesty gap (designer audit P1-5) with the real
control: an informational row above the plan list — Info icon + 定时任务
仅在电脑保持唤醒时运行 copy, right-aligned 保持系统唤醒 label + switch.
- Status-color restraint: neutral passive surface (settingsNotice passive
recipe: --foreground-5 / --muted-foreground, hairline border,
radius-surface), NOT the reference's saturated blue banner. Replaces
the old maka-plan-system-alert accent recipe.
- Switch reflects reality: optimistic local state initialized from the
persisted snapshot, revert-on-error + Chinese toast, useMountedRef +
pending-ref guard so a slow IPC write can't double-fire or set state
after unmount.
- Fail-soft: the row hides entirely unless the host wires both the value
and the setter (bridge present).
- Re-pin the panel async-action contract with the new toggle invariants.
- use-keep-system-awake hook reads/writes settings.system.keepSystemAwake
over the existing settings:get/update bridge (no new IPC channel),
gating on runtime bridge presence for fail-soft on older mains.
- app-shell threads the value + setter into AutomationsPage; the panel
hides the row when the capability is unavailable.
- AutomationsPage forwards the keepSystemAwake props to PlanReminderPanel.
@jackwener
jackwener merged commit 7abe8de into mainJul 18, 2026
3 checks passed
jackwener added a commit that referenced this pull request Jul 19, 2026
…ain.ts (arch R5) (#1248)
* chore(main): extract settings-runtime-effects from main.ts (arch R5)
Pure move of main.ts's settings runtime-effects cluster into
settings-runtime-effects.ts, exporting createSettingsRuntimeEffects(deps)
→ { normalizeSettingsPatch, applySettingsRuntimeEffects,
handleExternalSettingsChange } (syncDefaultPermissionModeToSessions stays
internal). Follows the R4 tool-assembly / tool-artifact-persistence DI
precedent: settingsStore / botRegistry / openGateway / keepSystemAwake /
runtime / safeSendToRenderer / emitSessionsChanged are injected, bodies
byte-identical. keep-awake runtime-effect (#1207) rides
applySettingsRuntimeEffects unchanged.
Contract mechanics: add settings-runtime-effects.ts to the
main-process-contract-source-helpers aggregator; allowlist the moved
[config-watcher] console.error at its new path in check-console.mjs. No
source-pin test targeted these functions in main.ts directly.
* chore(main): extract session-stream core from main.ts (arch R5)
Pure move of main.ts's session-stream cluster into session-stream.ts:
- createAiSdkBackendFactory(deps): BackendFactory — the whole
backends.register('ai-sdk', …) closure plus the internal modelSupportsVision.
Two seams resolved after the registration point are injected as accessors:
getRuntime (SessionManager built later) and getLookupPricing (mutable pricing
lookup, read live per recordLlmCall / snapshotted once for the lookupPricing
field — matching the original module-let closure semantics exactly).
- createSessionStreamer(deps): StreamEvents — streamEvents + its two
event-classifier helpers and the StreamEventsOptions/Result types.
main.ts keeps the module-scoped seams it owns (backends.register call site,
sessionActivities, lookupPricing let, runtime, the fake/e2e backend registers)
and every streamEvents call site.
Contract re-pins (maintainer-authorized): add session-stream.ts to the
main-process-contract-source-helpers aggregator; switch three direct-main.ts
readers to the combined source keeping every assertion —
attachment-frontend-contract (modelSupportsVision + supportsVision vision pin),
ipc-surface-contract (memoryPromptSnapshot + buildBackendSystemPrompt),
web-search-telemetry-scrub-contract (argsSummary scrub). registerIpc /
main-process-wiring-contract untouched.
main.ts 1656 → 1372 (−284 across both R5 clusters).
* docs(arch): mark R5 shipped (main.ts −284, settings-runtime-effects + session-stream)
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

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks by jackwener · Pull Request #1207 · apache/maka · GitHub
Skip to content

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks - #1207

Merged
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake
Jul 18, 2026
Merged

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks#1207
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake

Conversation

@jackwener

Copy link
Copy Markdown
Member

User-requested: the 定时任务 page lacked the keep-system-awake notice + toggle + capability (a 即将支持 placeholder was removed earlier for placeholder honesty — this ships the real thing).

End-to-end

  • Setting: system.keepSystemAwake on AppSettings (default false), modeled on notifications.runComplete — merge/patch/fail-closed coercion + core tests.
  • Capability: keep-system-awake.ts wraps Electron powerSaveBlocker with prevent-app-suspension (system stays awake, display may sleep — the right mode for background scheduled work). Double-start guard, re-acquire after out-of-band release; 7 unit tests with mocked electron.
  • Wiring: rides the existing settings:update channel (zero new IPC). Toggle applies instantly; re-held at launch when enabled; reconciles external settings.json edits.
  • UI: neutral passive row above the plan list — Info icon + 定时任务仅在电脑保持唤醒时运行 + right-aligned 保持系统唤醒 SettingsSwitch. House style (no saturated banner; status-color restraint). Optimistic flip with revert-on-error + Chinese toast, useMountedRef + pending guard, row hides when the bridge is absent.

Verification

Live CDP: click → aria-checked true → stayed true (full path exercised: optimistic → settings:update → powerSaveBlocker.start). Light+dark captures both states, accepted by maintainer. plan-reminder-panel contract extended (new pins for duplicate-guard/revert/unmount-release), nothing deleted.

Gates (merged tree with main incl. #1205)

desktop 2709/2709 · ui 183/183 · core green · typecheck · check-dead-css · knip no new debt · alignment auditor all fixtures clean. Implemented by an opus worktree agent.

Scheduled reminders run off an in-process timer that freezes when the
machine sleeps, so tasks silently never fire. Add a keepSystemAwake
setting that holds an Electron powerSaveBlocker to keep background
scheduled work running.
- core: add SystemSettings { keepSystemAwake } to AppSettings, mirroring
notifications.runComplete end to end (default, merge, patch surface,
fail-closed boolean coercion in normalizeSettings) + contract tests.
- main: keep-system-awake controller wraps powerSaveBlocker with
'prevent-app-suspension' (system stays awake WITHOUT forcing the
display on) — Electron-free + injected blocker so it unit-tests under
node --test, with a double-start guard on the blocker id.
- wiring: apply on launch if enabled, start/stop the instant the toggle
flips via applySettingsRuntimeEffects (rides the existing settings
channel), and reconcile on external settings.json edits.
Replace the placeholder-honesty gap (designer audit P1-5) with the real
control: an informational row above the plan list — Info icon + 定时任务
仅在电脑保持唤醒时运行 copy, right-aligned 保持系统唤醒 label + switch.
- Status-color restraint: neutral passive surface (settingsNotice passive
recipe: --foreground-5 / --muted-foreground, hairline border,
radius-surface), NOT the reference's saturated blue banner. Replaces
the old maka-plan-system-alert accent recipe.
- Switch reflects reality: optimistic local state initialized from the
persisted snapshot, revert-on-error + Chinese toast, useMountedRef +
pending-ref guard so a slow IPC write can't double-fire or set state
after unmount.
- Fail-soft: the row hides entirely unless the host wires both the value
and the setter (bridge present).
- Re-pin the panel async-action contract with the new toggle invariants.
- use-keep-system-awake hook reads/writes settings.system.keepSystemAwake
over the existing settings:get/update bridge (no new IPC channel),
gating on runtime bridge presence for fail-soft on older mains.
- app-shell threads the value + setter into AutomationsPage; the panel
hides the row when the capability is unavailable.
- AutomationsPage forwards the keepSystemAwake props to PlanReminderPanel.
@jackwener
jackwener merged commit 7abe8de into mainJul 18, 2026
3 checks passed
jackwener added a commit that referenced this pull request Jul 19, 2026
…ain.ts (arch R5) (#1248)
* chore(main): extract settings-runtime-effects from main.ts (arch R5)
Pure move of main.ts's settings runtime-effects cluster into
settings-runtime-effects.ts, exporting createSettingsRuntimeEffects(deps)
→ { normalizeSettingsPatch, applySettingsRuntimeEffects,
handleExternalSettingsChange } (syncDefaultPermissionModeToSessions stays
internal). Follows the R4 tool-assembly / tool-artifact-persistence DI
precedent: settingsStore / botRegistry / openGateway / keepSystemAwake /
runtime / safeSendToRenderer / emitSessionsChanged are injected, bodies
byte-identical. keep-awake runtime-effect (#1207) rides
applySettingsRuntimeEffects unchanged.
Contract mechanics: add settings-runtime-effects.ts to the
main-process-contract-source-helpers aggregator; allowlist the moved
[config-watcher] console.error at its new path in check-console.mjs. No
source-pin test targeted these functions in main.ts directly.
* chore(main): extract session-stream core from main.ts (arch R5)
Pure move of main.ts's session-stream cluster into session-stream.ts:
- createAiSdkBackendFactory(deps): BackendFactory — the whole
backends.register('ai-sdk', …) closure plus the internal modelSupportsVision.
Two seams resolved after the registration point are injected as accessors:
getRuntime (SessionManager built later) and getLookupPricing (mutable pricing
lookup, read live per recordLlmCall / snapshotted once for the lookupPricing
field — matching the original module-let closure semantics exactly).
- createSessionStreamer(deps): StreamEvents — streamEvents + its two
event-classifier helpers and the StreamEventsOptions/Result types.
main.ts keeps the module-scoped seams it owns (backends.register call site,
sessionActivities, lookupPricing let, runtime, the fake/e2e backend registers)
and every streamEvents call site.
Contract re-pins (maintainer-authorized): add session-stream.ts to the
main-process-contract-source-helpers aggregator; switch three direct-main.ts
readers to the combined source keeping every assertion —
attachment-frontend-contract (modelSupportsVision + supportsVision vision pin),
ipc-surface-contract (memoryPromptSnapshot + buildBackendSystemPrompt),
web-search-telemetry-scrub-contract (argsSummary scrub). registerIpc /
main-process-wiring-contract untouched.
main.ts 1656 → 1372 (−284 across both R5 clusters).
* docs(arch): mark R5 shipped (main.ts −284, settings-runtime-effects + session-stream)
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

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

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks - #1207

Merged
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake
Jul 18, 2026
Merged

feat(plans): 保持系统唤醒 — real powerSaveBlocker capability for scheduled tasks#1207
jackwener merged 4 commits into
mainfrom
feat/keep-system-awake

Conversation

@jackwener

Copy link
Copy Markdown
Member

User-requested: the 定时任务 page lacked the keep-system-awake notice + toggle + capability (a 即将支持 placeholder was removed earlier for placeholder honesty — this ships the real thing).

End-to-end

  • Setting: system.keepSystemAwake on AppSettings (default false), modeled on notifications.runComplete — merge/patch/fail-closed coercion + core tests.
  • Capability: keep-system-awake.ts wraps Electron powerSaveBlocker with prevent-app-suspension (system stays awake, display may sleep — the right mode for background scheduled work). Double-start guard, re-acquire after out-of-band release; 7 unit tests with mocked electron.
  • Wiring: rides the existing settings:update channel (zero new IPC). Toggle applies instantly; re-held at launch when enabled; reconciles external settings.json edits.
  • UI: neutral passive row above the plan list — Info icon + 定时任务仅在电脑保持唤醒时运行 + right-aligned 保持系统唤醒 SettingsSwitch. House style (no saturated banner; status-color restraint). Optimistic flip with revert-on-error + Chinese toast, useMountedRef + pending guard, row hides when the bridge is absent.

Verification

Live CDP: click → aria-checked true → stayed true (full path exercised: optimistic → settings:update → powerSaveBlocker.start). Light+dark captures both states, accepted by maintainer. plan-reminder-panel contract extended (new pins for duplicate-guard/revert/unmount-release), nothing deleted.

Gates (merged tree with main incl. #1205)

desktop 2709/2709 · ui 183/183 · core green · typecheck · check-dead-css · knip no new debt · alignment auditor all fixtures clean. Implemented by an opus worktree agent.

Scheduled reminders run off an in-process timer that freezes when the
machine sleeps, so tasks silently never fire. Add a keepSystemAwake
setting that holds an Electron powerSaveBlocker to keep background
scheduled work running.
- core: add SystemSettings { keepSystemAwake } to AppSettings, mirroring
notifications.runComplete end to end (default, merge, patch surface,
fail-closed boolean coercion in normalizeSettings) + contract tests.
- main: keep-system-awake controller wraps powerSaveBlocker with
'prevent-app-suspension' (system stays awake WITHOUT forcing the
display on) — Electron-free + injected blocker so it unit-tests under
node --test, with a double-start guard on the blocker id.
- wiring: apply on launch if enabled, start/stop the instant the toggle
flips via applySettingsRuntimeEffects (rides the existing settings
channel), and reconcile on external settings.json edits.
Replace the placeholder-honesty gap (designer audit P1-5) with the real
control: an informational row above the plan list — Info icon + 定时任务
仅在电脑保持唤醒时运行 copy, right-aligned 保持系统唤醒 label + switch.
- Status-color restraint: neutral passive surface (settingsNotice passive
recipe: --foreground-5 / --muted-foreground, hairline border,
radius-surface), NOT the reference's saturated blue banner. Replaces
the old maka-plan-system-alert accent recipe.
- Switch reflects reality: optimistic local state initialized from the
persisted snapshot, revert-on-error + Chinese toast, useMountedRef +
pending-ref guard so a slow IPC write can't double-fire or set state
after unmount.
- Fail-soft: the row hides entirely unless the host wires both the value
and the setter (bridge present).
- Re-pin the panel async-action contract with the new toggle invariants.
- use-keep-system-awake hook reads/writes settings.system.keepSystemAwake
over the existing settings:get/update bridge (no new IPC channel),
gating on runtime bridge presence for fail-soft on older mains.
- app-shell threads the value + setter into AutomationsPage; the panel
hides the row when the capability is unavailable.
- AutomationsPage forwards the keepSystemAwake props to PlanReminderPanel.
@jackwener
jackwener merged commit 7abe8de into mainJul 18, 2026
3 checks passed
jackwener added a commit that referenced this pull request Jul 19, 2026
…ain.ts (arch R5) (#1248)
* chore(main): extract settings-runtime-effects from main.ts (arch R5)
Pure move of main.ts's settings runtime-effects cluster into
settings-runtime-effects.ts, exporting createSettingsRuntimeEffects(deps)
→ { normalizeSettingsPatch, applySettingsRuntimeEffects,
handleExternalSettingsChange } (syncDefaultPermissionModeToSessions stays
internal). Follows the R4 tool-assembly / tool-artifact-persistence DI
precedent: settingsStore / botRegistry / openGateway / keepSystemAwake /
runtime / safeSendToRenderer / emitSessionsChanged are injected, bodies
byte-identical. keep-awake runtime-effect (#1207) rides
applySettingsRuntimeEffects unchanged.
Contract mechanics: add settings-runtime-effects.ts to the
main-process-contract-source-helpers aggregator; allowlist the moved
[config-watcher] console.error at its new path in check-console.mjs. No
source-pin test targeted these functions in main.ts directly.
* chore(main): extract session-stream core from main.ts (arch R5)
Pure move of main.ts's session-stream cluster into session-stream.ts:
- createAiSdkBackendFactory(deps): BackendFactory — the whole
backends.register('ai-sdk', …) closure plus the internal modelSupportsVision.
Two seams resolved after the registration point are injected as accessors:
getRuntime (SessionManager built later) and getLookupPricing (mutable pricing
lookup, read live per recordLlmCall / snapshotted once for the lookupPricing
field — matching the original module-let closure semantics exactly).
- createSessionStreamer(deps): StreamEvents — streamEvents + its two
event-classifier helpers and the StreamEventsOptions/Result types.
main.ts keeps the module-scoped seams it owns (backends.register call site,
sessionActivities, lookupPricing let, runtime, the fake/e2e backend registers)
and every streamEvents call site.
Contract re-pins (maintainer-authorized): add session-stream.ts to the
main-process-contract-source-helpers aggregator; switch three direct-main.ts
readers to the combined source keeping every assertion —
attachment-frontend-contract (modelSupportsVision + supportsVision vision pin),
ipc-surface-contract (memoryPromptSnapshot + buildBackendSystemPrompt),
web-search-telemetry-scrub-contract (argsSummary scrub). registerIpc /
main-process-wiring-contract untouched.
main.ts 1656 → 1372 (−284 across both R5 clusters).
* docs(arch): mark R5 shipped (main.ts −284, settings-runtime-effects + session-stream)
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

@jackwener