Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,9 @@ describe("DesktopBackendConfiguration", () => {
assert.equal(first.cwd, environment.backendCwd);
assert.equal(first.captureOutput, true);
assert.equal(first.env.ELECTRON_RUN_AS_NODE, "1");
// Heap headroom for the primary backend (issue #21). extendEnv:true means
// this config value wins over an inherited process.env NODE_OPTIONS.
assert.include(first.env.NODE_OPTIONS ?? "", "--max-old-space-size=4096");
assert.isUndefined(first.env.T3CODE_PORT);
assert.isUndefined(first.env.T3CODE_MODE);
assert.isUndefined(first.env.T3CODE_DESKTOP_LAN_HOST);
Expand All@@ -152,6 +155,43 @@ describe("DesktopBackendConfiguration", () => {
),
);

it.effect("resolvePrimary sets a bare heap flag when NODE_OPTIONS is unset", () => {
const previous = process.env.NODE_OPTIONS;
delete process.env.NODE_OPTIONS;
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary appends heap headroom to an existing NODE_OPTIONS", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--enable-source-maps";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--enable-source-maps --max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary preserves an explicit NODE_OPTIONS heap setting", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--max-old-space-size=1024";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
// An operator override wins; we do not append a second, conflicting flag.
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=1024");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolveWsl reuses the primary's bootstrap token", () =>
withHarness(
Effect.gen(function* () {
Expand DownExpand Up@@ -279,6 +319,8 @@ describe("DesktopBackendConfiguration", () => {
"env",
"PATH=/home/test user's/.nvm/versions/node/v22.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin",
nodePath,
// Heap headroom, passed as a V8 execArg before the entry script (issue #21).
"--max-old-space-size=4096",
linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
29 changes: 29 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,6 +94,30 @@ const WSL_FORWARDED_ENV_NAMES = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] as const

const WSL_SERVER_SYSTEM_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

// Give the backend a predictable V8 old-space ceiling instead of inheriting the
// default. This is headroom for transient heap spikes (large diffs, big file
// reads) so a memory-constrained host is less likely to push the backend into a
// GC-thrash / stall while it is busy — part of the robustness work for issue
// #21. It is a ceiling, not a reservation, so it does not raise steady-state
// memory use (the backend's normal RSS is well under this).
const DESKTOP_BACKEND_MAX_OLD_SPACE_MB = 4096;
const DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG = `--max-old-space-size=${DESKTOP_BACKEND_MAX_OLD_SPACE_MB}`;

// Append our heap-headroom flag to any NODE_OPTIONS already exported (by the
// user or the dev-runner) rather than replacing it. If an explicit
// --max-old-space-size is already present we leave it untouched so an operator
// can override the ceiling. Electron-run-as-node honours the NODE_OPTIONS
// safelist, which includes --max-old-space-size.
const backendNodeOptions = (existing: string | undefined): string => {
const trimmed = existing?.trim() ?? "";
if (trimmed.includes("--max-old-space-size")) {
return trimmed;
}
return trimmed.length > 0
? `${trimmed} ${DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG}`
: DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG;
};

const backendChildEnvPatch = (): Record<string, string | undefined> =>
Object.fromEntries(DESKTOP_BACKEND_ENV_NAMES.map((name) => [name, undefined]));

Expand DownExpand Up@@ -356,6 +380,7 @@ const resolvePrimaryStartConfig = Effect.fn("desktop.backendConfiguration.resolv
env: {
...backendChildEnvPatch(),
ELECTRON_RUN_AS_NODE: "1",
NODE_OPTIONS: backendNodeOptions(process.env.NODE_OPTIONS),
},
// Primary wants process.env (PATH, dev-runner's T3CODE_HOME, etc.).
extendEnv: true,
Expand DownExpand Up@@ -546,6 +571,10 @@ const resolveWslStartConfig = Effect.fn("desktop.backendConfiguration.resolveWsl
"env",
`PATH=${launchPath}`,
preflight.nodePath,
// Match the primary backend's heap headroom. WSL runs plain node, so the
// flag is passed as a V8 execArg (before the entry script) rather than via
// NODE_OPTIONS.
DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG,
preflight.linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
Loading
Loading
, '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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,9 @@ describe("DesktopBackendConfiguration", () => {
assert.equal(first.cwd, environment.backendCwd);
assert.equal(first.captureOutput, true);
assert.equal(first.env.ELECTRON_RUN_AS_NODE, "1");
// Heap headroom for the primary backend (issue #21). extendEnv:true means
// this config value wins over an inherited process.env NODE_OPTIONS.
assert.include(first.env.NODE_OPTIONS ?? "", "--max-old-space-size=4096");
assert.isUndefined(first.env.T3CODE_PORT);
assert.isUndefined(first.env.T3CODE_MODE);
assert.isUndefined(first.env.T3CODE_DESKTOP_LAN_HOST);
Expand All@@ -152,6 +155,43 @@ describe("DesktopBackendConfiguration", () => {
),
);

it.effect("resolvePrimary sets a bare heap flag when NODE_OPTIONS is unset", () => {
const previous = process.env.NODE_OPTIONS;
delete process.env.NODE_OPTIONS;
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary appends heap headroom to an existing NODE_OPTIONS", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--enable-source-maps";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--enable-source-maps --max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary preserves an explicit NODE_OPTIONS heap setting", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--max-old-space-size=1024";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
// An operator override wins; we do not append a second, conflicting flag.
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=1024");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolveWsl reuses the primary's bootstrap token", () =>
withHarness(
Effect.gen(function* () {
Expand DownExpand Up@@ -279,6 +319,8 @@ describe("DesktopBackendConfiguration", () => {
"env",
"PATH=/home/test user's/.nvm/versions/node/v22.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin",
nodePath,
// Heap headroom, passed as a V8 execArg before the entry script (issue #21).
"--max-old-space-size=4096",
linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
29 changes: 29 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,6 +94,30 @@ const WSL_FORWARDED_ENV_NAMES = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] as const

const WSL_SERVER_SYSTEM_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

// Give the backend a predictable V8 old-space ceiling instead of inheriting the
// default. This is headroom for transient heap spikes (large diffs, big file
// reads) so a memory-constrained host is less likely to push the backend into a
// GC-thrash / stall while it is busy — part of the robustness work for issue
// #21. It is a ceiling, not a reservation, so it does not raise steady-state
// memory use (the backend's normal RSS is well under this).
const DESKTOP_BACKEND_MAX_OLD_SPACE_MB = 4096;
const DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG = `--max-old-space-size=${DESKTOP_BACKEND_MAX_OLD_SPACE_MB}`;

// Append our heap-headroom flag to any NODE_OPTIONS already exported (by the
// user or the dev-runner) rather than replacing it. If an explicit
// --max-old-space-size is already present we leave it untouched so an operator
// can override the ceiling. Electron-run-as-node honours the NODE_OPTIONS
// safelist, which includes --max-old-space-size.
const backendNodeOptions = (existing: string | undefined): string => {
const trimmed = existing?.trim() ?? "";
if (trimmed.includes("--max-old-space-size")) {
return trimmed;
}
return trimmed.length > 0
? `${trimmed} ${DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG}`
: DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG;
};

const backendChildEnvPatch = (): Record<string, string | undefined> =>
Object.fromEntries(DESKTOP_BACKEND_ENV_NAMES.map((name) => [name, undefined]));

Expand DownExpand Up@@ -356,6 +380,7 @@ const resolvePrimaryStartConfig = Effect.fn("desktop.backendConfiguration.resolv
env: {
...backendChildEnvPatch(),
ELECTRON_RUN_AS_NODE: "1",
NODE_OPTIONS: backendNodeOptions(process.env.NODE_OPTIONS),
},
// Primary wants process.env (PATH, dev-runner's T3CODE_HOME, etc.).
extendEnv: true,
Expand DownExpand Up@@ -546,6 +571,10 @@ const resolveWslStartConfig = Effect.fn("desktop.backendConfiguration.resolveWsl
"env",
`PATH=${launchPath}`,
preflight.nodePath,
// Match the primary backend's heap headroom. WSL runs plain node, so the
// flag is passed as a V8 execArg (before the entry script) rather than via
// NODE_OPTIONS.
DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG,
preflight.linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
Loading
Loading
, '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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,9 @@ describe("DesktopBackendConfiguration", () => {
assert.equal(first.cwd, environment.backendCwd);
assert.equal(first.captureOutput, true);
assert.equal(first.env.ELECTRON_RUN_AS_NODE, "1");
// Heap headroom for the primary backend (issue #21). extendEnv:true means
// this config value wins over an inherited process.env NODE_OPTIONS.
assert.include(first.env.NODE_OPTIONS ?? "", "--max-old-space-size=4096");
assert.isUndefined(first.env.T3CODE_PORT);
assert.isUndefined(first.env.T3CODE_MODE);
assert.isUndefined(first.env.T3CODE_DESKTOP_LAN_HOST);
Expand All@@ -152,6 +155,43 @@ describe("DesktopBackendConfiguration", () => {
),
);

it.effect("resolvePrimary sets a bare heap flag when NODE_OPTIONS is unset", () => {
const previous = process.env.NODE_OPTIONS;
delete process.env.NODE_OPTIONS;
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary appends heap headroom to an existing NODE_OPTIONS", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--enable-source-maps";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--enable-source-maps --max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary preserves an explicit NODE_OPTIONS heap setting", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--max-old-space-size=1024";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
// An operator override wins; we do not append a second, conflicting flag.
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=1024");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolveWsl reuses the primary's bootstrap token", () =>
withHarness(
Effect.gen(function* () {
Expand DownExpand Up@@ -279,6 +319,8 @@ describe("DesktopBackendConfiguration", () => {
"env",
"PATH=/home/test user's/.nvm/versions/node/v22.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin",
nodePath,
// Heap headroom, passed as a V8 execArg before the entry script (issue #21).
"--max-old-space-size=4096",
linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
29 changes: 29 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,6 +94,30 @@ const WSL_FORWARDED_ENV_NAMES = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] as const

const WSL_SERVER_SYSTEM_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

// Give the backend a predictable V8 old-space ceiling instead of inheriting the
// default. This is headroom for transient heap spikes (large diffs, big file
// reads) so a memory-constrained host is less likely to push the backend into a
// GC-thrash / stall while it is busy — part of the robustness work for issue
// #21. It is a ceiling, not a reservation, so it does not raise steady-state
// memory use (the backend's normal RSS is well under this).
const DESKTOP_BACKEND_MAX_OLD_SPACE_MB = 4096;
const DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG = `--max-old-space-size=${DESKTOP_BACKEND_MAX_OLD_SPACE_MB}`;

// Append our heap-headroom flag to any NODE_OPTIONS already exported (by the
// user or the dev-runner) rather than replacing it. If an explicit
// --max-old-space-size is already present we leave it untouched so an operator
// can override the ceiling. Electron-run-as-node honours the NODE_OPTIONS
// safelist, which includes --max-old-space-size.
const backendNodeOptions = (existing: string | undefined): string => {
const trimmed = existing?.trim() ?? "";
if (trimmed.includes("--max-old-space-size")) {
return trimmed;
}
return trimmed.length > 0
? `${trimmed} ${DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG}`
: DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG;
};

const backendChildEnvPatch = (): Record<string, string | undefined> =>
Object.fromEntries(DESKTOP_BACKEND_ENV_NAMES.map((name) => [name, undefined]));

Expand DownExpand Up@@ -356,6 +380,7 @@ const resolvePrimaryStartConfig = Effect.fn("desktop.backendConfiguration.resolv
env: {
...backendChildEnvPatch(),
ELECTRON_RUN_AS_NODE: "1",
NODE_OPTIONS: backendNodeOptions(process.env.NODE_OPTIONS),
},
// Primary wants process.env (PATH, dev-runner's T3CODE_HOME, etc.).
extendEnv: true,
Expand DownExpand Up@@ -546,6 +571,10 @@ const resolveWslStartConfig = Effect.fn("desktop.backendConfiguration.resolveWsl
"env",
`PATH=${launchPath}`,
preflight.nodePath,
// Match the primary backend's heap headroom. WSL runs plain node, so the
// flag is passed as a V8 execArg (before the entry script) rather than via
// NODE_OPTIONS.
DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG,
preflight.linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
Loading
Loading
, '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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,9 @@ describe("DesktopBackendConfiguration", () => {
assert.equal(first.cwd, environment.backendCwd);
assert.equal(first.captureOutput, true);
assert.equal(first.env.ELECTRON_RUN_AS_NODE, "1");
// Heap headroom for the primary backend (issue #21). extendEnv:true means
// this config value wins over an inherited process.env NODE_OPTIONS.
assert.include(first.env.NODE_OPTIONS ?? "", "--max-old-space-size=4096");
assert.isUndefined(first.env.T3CODE_PORT);
assert.isUndefined(first.env.T3CODE_MODE);
assert.isUndefined(first.env.T3CODE_DESKTOP_LAN_HOST);
Expand All@@ -152,6 +155,43 @@ describe("DesktopBackendConfiguration", () => {
),
);

it.effect("resolvePrimary sets a bare heap flag when NODE_OPTIONS is unset", () => {
const previous = process.env.NODE_OPTIONS;
delete process.env.NODE_OPTIONS;
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary appends heap headroom to an existing NODE_OPTIONS", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--enable-source-maps";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--enable-source-maps --max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary preserves an explicit NODE_OPTIONS heap setting", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--max-old-space-size=1024";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
// An operator override wins; we do not append a second, conflicting flag.
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=1024");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolveWsl reuses the primary's bootstrap token", () =>
withHarness(
Effect.gen(function* () {
Expand DownExpand Up@@ -279,6 +319,8 @@ describe("DesktopBackendConfiguration", () => {
"env",
"PATH=/home/test user's/.nvm/versions/node/v22.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin",
nodePath,
// Heap headroom, passed as a V8 execArg before the entry script (issue #21).
"--max-old-space-size=4096",
linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
29 changes: 29 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,6 +94,30 @@ const WSL_FORWARDED_ENV_NAMES = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] as const

const WSL_SERVER_SYSTEM_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

// Give the backend a predictable V8 old-space ceiling instead of inheriting the
// default. This is headroom for transient heap spikes (large diffs, big file
// reads) so a memory-constrained host is less likely to push the backend into a
// GC-thrash / stall while it is busy — part of the robustness work for issue
// #21. It is a ceiling, not a reservation, so it does not raise steady-state
// memory use (the backend's normal RSS is well under this).
const DESKTOP_BACKEND_MAX_OLD_SPACE_MB = 4096;
const DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG = `--max-old-space-size=${DESKTOP_BACKEND_MAX_OLD_SPACE_MB}`;

// Append our heap-headroom flag to any NODE_OPTIONS already exported (by the
// user or the dev-runner) rather than replacing it. If an explicit
// --max-old-space-size is already present we leave it untouched so an operator
// can override the ceiling. Electron-run-as-node honours the NODE_OPTIONS
// safelist, which includes --max-old-space-size.
const backendNodeOptions = (existing: string | undefined): string => {
const trimmed = existing?.trim() ?? "";
if (trimmed.includes("--max-old-space-size")) {
return trimmed;
}
return trimmed.length > 0
? `${trimmed} ${DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG}`
: DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG;
};

const backendChildEnvPatch = (): Record<string, string | undefined> =>
Object.fromEntries(DESKTOP_BACKEND_ENV_NAMES.map((name) => [name, undefined]));

Expand DownExpand Up@@ -356,6 +380,7 @@ const resolvePrimaryStartConfig = Effect.fn("desktop.backendConfiguration.resolv
env: {
...backendChildEnvPatch(),
ELECTRON_RUN_AS_NODE: "1",
NODE_OPTIONS: backendNodeOptions(process.env.NODE_OPTIONS),
},
// Primary wants process.env (PATH, dev-runner's T3CODE_HOME, etc.).
extendEnv: true,
Expand DownExpand Up@@ -546,6 +571,10 @@ const resolveWslStartConfig = Effect.fn("desktop.backendConfiguration.resolveWsl
"env",
`PATH=${launchPath}`,
preflight.nodePath,
// Match the primary backend's heap headroom. WSL runs plain node, so the
// flag is passed as a V8 execArg (before the entry script) rather than via
// NODE_OPTIONS.
DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG,
preflight.linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
Loading
Loading
, '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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,9 @@ describe("DesktopBackendConfiguration", () => {
assert.equal(first.cwd, environment.backendCwd);
assert.equal(first.captureOutput, true);
assert.equal(first.env.ELECTRON_RUN_AS_NODE, "1");
// Heap headroom for the primary backend (issue #21). extendEnv:true means
// this config value wins over an inherited process.env NODE_OPTIONS.
assert.include(first.env.NODE_OPTIONS ?? "", "--max-old-space-size=4096");
assert.isUndefined(first.env.T3CODE_PORT);
assert.isUndefined(first.env.T3CODE_MODE);
assert.isUndefined(first.env.T3CODE_DESKTOP_LAN_HOST);
Expand All@@ -152,6 +155,43 @@ describe("DesktopBackendConfiguration", () => {
),
);

it.effect("resolvePrimary sets a bare heap flag when NODE_OPTIONS is unset", () => {
const previous = process.env.NODE_OPTIONS;
delete process.env.NODE_OPTIONS;
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary appends heap headroom to an existing NODE_OPTIONS", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--enable-source-maps";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--enable-source-maps --max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary preserves an explicit NODE_OPTIONS heap setting", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--max-old-space-size=1024";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
// An operator override wins; we do not append a second, conflicting flag.
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=1024");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolveWsl reuses the primary's bootstrap token", () =>
withHarness(
Effect.gen(function* () {
Expand DownExpand Up@@ -279,6 +319,8 @@ describe("DesktopBackendConfiguration", () => {
"env",
"PATH=/home/test user's/.nvm/versions/node/v22.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin",
nodePath,
// Heap headroom, passed as a V8 execArg before the entry script (issue #21).
"--max-old-space-size=4096",
linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
29 changes: 29 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,6 +94,30 @@ const WSL_FORWARDED_ENV_NAMES = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] as const

const WSL_SERVER_SYSTEM_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

// Give the backend a predictable V8 old-space ceiling instead of inheriting the
// default. This is headroom for transient heap spikes (large diffs, big file
// reads) so a memory-constrained host is less likely to push the backend into a
// GC-thrash / stall while it is busy — part of the robustness work for issue
// #21. It is a ceiling, not a reservation, so it does not raise steady-state
// memory use (the backend's normal RSS is well under this).
const DESKTOP_BACKEND_MAX_OLD_SPACE_MB = 4096;
const DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG = `--max-old-space-size=${DESKTOP_BACKEND_MAX_OLD_SPACE_MB}`;

// Append our heap-headroom flag to any NODE_OPTIONS already exported (by the
// user or the dev-runner) rather than replacing it. If an explicit
// --max-old-space-size is already present we leave it untouched so an operator
// can override the ceiling. Electron-run-as-node honours the NODE_OPTIONS
// safelist, which includes --max-old-space-size.
const backendNodeOptions = (existing: string | undefined): string => {
const trimmed = existing?.trim() ?? "";
if (trimmed.includes("--max-old-space-size")) {
return trimmed;
}
return trimmed.length > 0
? `${trimmed} ${DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG}`
: DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG;
};

const backendChildEnvPatch = (): Record<string, string | undefined> =>
Object.fromEntries(DESKTOP_BACKEND_ENV_NAMES.map((name) => [name, undefined]));

Expand DownExpand Up@@ -356,6 +380,7 @@ const resolvePrimaryStartConfig = Effect.fn("desktop.backendConfiguration.resolv
env: {
...backendChildEnvPatch(),
ELECTRON_RUN_AS_NODE: "1",
NODE_OPTIONS: backendNodeOptions(process.env.NODE_OPTIONS),
},
// Primary wants process.env (PATH, dev-runner's T3CODE_HOME, etc.).
extendEnv: true,
Expand DownExpand Up@@ -546,6 +571,10 @@ const resolveWslStartConfig = Effect.fn("desktop.backendConfiguration.resolveWsl
"env",
`PATH=${launchPath}`,
preflight.nodePath,
// Match the primary backend's heap headroom. WSL runs plain node, so the
// flag is passed as a V8 execArg (before the entry script) rather than via
// NODE_OPTIONS.
DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG,
preflight.linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
Loading
Loading
, '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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,9 @@ describe("DesktopBackendConfiguration", () => {
assert.equal(first.cwd, environment.backendCwd);
assert.equal(first.captureOutput, true);
assert.equal(first.env.ELECTRON_RUN_AS_NODE, "1");
// Heap headroom for the primary backend (issue #21). extendEnv:true means
// this config value wins over an inherited process.env NODE_OPTIONS.
assert.include(first.env.NODE_OPTIONS ?? "", "--max-old-space-size=4096");
assert.isUndefined(first.env.T3CODE_PORT);
assert.isUndefined(first.env.T3CODE_MODE);
assert.isUndefined(first.env.T3CODE_DESKTOP_LAN_HOST);
Expand All@@ -152,6 +155,43 @@ describe("DesktopBackendConfiguration", () => {
),
);

it.effect("resolvePrimary sets a bare heap flag when NODE_OPTIONS is unset", () => {
const previous = process.env.NODE_OPTIONS;
delete process.env.NODE_OPTIONS;
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary appends heap headroom to an existing NODE_OPTIONS", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--enable-source-maps";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--enable-source-maps --max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary preserves an explicit NODE_OPTIONS heap setting", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--max-old-space-size=1024";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
// An operator override wins; we do not append a second, conflicting flag.
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=1024");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolveWsl reuses the primary's bootstrap token", () =>
withHarness(
Effect.gen(function* () {
Expand DownExpand Up@@ -279,6 +319,8 @@ describe("DesktopBackendConfiguration", () => {
"env",
"PATH=/home/test user's/.nvm/versions/node/v22.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin",
nodePath,
// Heap headroom, passed as a V8 execArg before the entry script (issue #21).
"--max-old-space-size=4096",
linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
29 changes: 29 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,6 +94,30 @@ const WSL_FORWARDED_ENV_NAMES = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] as const

const WSL_SERVER_SYSTEM_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

// Give the backend a predictable V8 old-space ceiling instead of inheriting the
// default. This is headroom for transient heap spikes (large diffs, big file
// reads) so a memory-constrained host is less likely to push the backend into a
// GC-thrash / stall while it is busy — part of the robustness work for issue
// #21. It is a ceiling, not a reservation, so it does not raise steady-state
// memory use (the backend's normal RSS is well under this).
const DESKTOP_BACKEND_MAX_OLD_SPACE_MB = 4096;
const DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG = `--max-old-space-size=${DESKTOP_BACKEND_MAX_OLD_SPACE_MB}`;

// Append our heap-headroom flag to any NODE_OPTIONS already exported (by the
// user or the dev-runner) rather than replacing it. If an explicit
// --max-old-space-size is already present we leave it untouched so an operator
// can override the ceiling. Electron-run-as-node honours the NODE_OPTIONS
// safelist, which includes --max-old-space-size.
const backendNodeOptions = (existing: string | undefined): string => {
const trimmed = existing?.trim() ?? "";
if (trimmed.includes("--max-old-space-size")) {
return trimmed;
}
return trimmed.length > 0
? `${trimmed} ${DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG}`
: DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG;
};

const backendChildEnvPatch = (): Record<string, string | undefined> =>
Object.fromEntries(DESKTOP_BACKEND_ENV_NAMES.map((name) => [name, undefined]));

Expand DownExpand Up@@ -356,6 +380,7 @@ const resolvePrimaryStartConfig = Effect.fn("desktop.backendConfiguration.resolv
env: {
...backendChildEnvPatch(),
ELECTRON_RUN_AS_NODE: "1",
NODE_OPTIONS: backendNodeOptions(process.env.NODE_OPTIONS),
},
// Primary wants process.env (PATH, dev-runner's T3CODE_HOME, etc.).
extendEnv: true,
Expand DownExpand Up@@ -546,6 +571,10 @@ const resolveWslStartConfig = Effect.fn("desktop.backendConfiguration.resolveWsl
"env",
`PATH=${launchPath}`,
preflight.nodePath,
// Match the primary backend's heap headroom. WSL runs plain node, so the
// flag is passed as a V8 execArg (before the entry script) rather than via
// NODE_OPTIONS.
DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG,
preflight.linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
Loading
Loading
, '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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,9 @@ describe("DesktopBackendConfiguration", () => {
assert.equal(first.cwd, environment.backendCwd);
assert.equal(first.captureOutput, true);
assert.equal(first.env.ELECTRON_RUN_AS_NODE, "1");
// Heap headroom for the primary backend (issue #21). extendEnv:true means
// this config value wins over an inherited process.env NODE_OPTIONS.
assert.include(first.env.NODE_OPTIONS ?? "", "--max-old-space-size=4096");
assert.isUndefined(first.env.T3CODE_PORT);
assert.isUndefined(first.env.T3CODE_MODE);
assert.isUndefined(first.env.T3CODE_DESKTOP_LAN_HOST);
Expand All@@ -152,6 +155,43 @@ describe("DesktopBackendConfiguration", () => {
),
);

it.effect("resolvePrimary sets a bare heap flag when NODE_OPTIONS is unset", () => {
const previous = process.env.NODE_OPTIONS;
delete process.env.NODE_OPTIONS;
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary appends heap headroom to an existing NODE_OPTIONS", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--enable-source-maps";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--enable-source-maps --max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary preserves an explicit NODE_OPTIONS heap setting", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--max-old-space-size=1024";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
// An operator override wins; we do not append a second, conflicting flag.
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=1024");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolveWsl reuses the primary's bootstrap token", () =>
withHarness(
Effect.gen(function* () {
Expand DownExpand Up@@ -279,6 +319,8 @@ describe("DesktopBackendConfiguration", () => {
"env",
"PATH=/home/test user's/.nvm/versions/node/v22.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin",
nodePath,
// Heap headroom, passed as a V8 execArg before the entry script (issue #21).
"--max-old-space-size=4096",
linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
29 changes: 29 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,6 +94,30 @@ const WSL_FORWARDED_ENV_NAMES = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] as const

const WSL_SERVER_SYSTEM_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

// Give the backend a predictable V8 old-space ceiling instead of inheriting the
// default. This is headroom for transient heap spikes (large diffs, big file
// reads) so a memory-constrained host is less likely to push the backend into a
// GC-thrash / stall while it is busy — part of the robustness work for issue
// #21. It is a ceiling, not a reservation, so it does not raise steady-state
// memory use (the backend's normal RSS is well under this).
const DESKTOP_BACKEND_MAX_OLD_SPACE_MB = 4096;
const DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG = `--max-old-space-size=${DESKTOP_BACKEND_MAX_OLD_SPACE_MB}`;

// Append our heap-headroom flag to any NODE_OPTIONS already exported (by the
// user or the dev-runner) rather than replacing it. If an explicit
// --max-old-space-size is already present we leave it untouched so an operator
// can override the ceiling. Electron-run-as-node honours the NODE_OPTIONS
// safelist, which includes --max-old-space-size.
const backendNodeOptions = (existing: string | undefined): string => {
const trimmed = existing?.trim() ?? "";
if (trimmed.includes("--max-old-space-size")) {
return trimmed;
}
return trimmed.length > 0
? `${trimmed} ${DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG}`
: DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG;
};

const backendChildEnvPatch = (): Record<string, string | undefined> =>
Object.fromEntries(DESKTOP_BACKEND_ENV_NAMES.map((name) => [name, undefined]));

Expand DownExpand Up@@ -356,6 +380,7 @@ const resolvePrimaryStartConfig = Effect.fn("desktop.backendConfiguration.resolv
env: {
...backendChildEnvPatch(),
ELECTRON_RUN_AS_NODE: "1",
NODE_OPTIONS: backendNodeOptions(process.env.NODE_OPTIONS),
},
// Primary wants process.env (PATH, dev-runner's T3CODE_HOME, etc.).
extendEnv: true,
Expand DownExpand Up@@ -546,6 +571,10 @@ const resolveWslStartConfig = Effect.fn("desktop.backendConfiguration.resolveWsl
"env",
`PATH=${launchPath}`,
preflight.nodePath,
// Match the primary backend's heap headroom. WSL runs plain node, so the
// flag is passed as a V8 execArg (before the entry script) rather than via
// NODE_OPTIONS.
DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG,
preflight.linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
Loading
Loading
, '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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -135,6 +135,9 @@ describe("DesktopBackendConfiguration", () => {
assert.equal(first.cwd, environment.backendCwd);
assert.equal(first.captureOutput, true);
assert.equal(first.env.ELECTRON_RUN_AS_NODE, "1");
// Heap headroom for the primary backend (issue #21). extendEnv:true means
// this config value wins over an inherited process.env NODE_OPTIONS.
assert.include(first.env.NODE_OPTIONS ?? "", "--max-old-space-size=4096");
assert.isUndefined(first.env.T3CODE_PORT);
assert.isUndefined(first.env.T3CODE_MODE);
assert.isUndefined(first.env.T3CODE_DESKTOP_LAN_HOST);
Expand All@@ -152,6 +155,43 @@ describe("DesktopBackendConfiguration", () => {
),
);

it.effect("resolvePrimary sets a bare heap flag when NODE_OPTIONS is unset", () => {
const previous = process.env.NODE_OPTIONS;
delete process.env.NODE_OPTIONS;
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary appends heap headroom to an existing NODE_OPTIONS", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--enable-source-maps";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
assert.equal(config.env.NODE_OPTIONS, "--enable-source-maps --max-old-space-size=4096");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolvePrimary preserves an explicit NODE_OPTIONS heap setting", () => {
const previous = process.env.NODE_OPTIONS;
process.env.NODE_OPTIONS = "--max-old-space-size=1024";
return withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolvePrimary;
// An operator override wins; we do not append a second, conflicting flag.
assert.equal(config.env.NODE_OPTIONS, "--max-old-space-size=1024");
}),
).pipe(Effect.ensuring(Effect.sync(() => restoreEnv("NODE_OPTIONS", previous))));
});

it.effect("resolveWsl reuses the primary's bootstrap token", () =>
withHarness(
Effect.gen(function* () {
Expand DownExpand Up@@ -279,6 +319,8 @@ describe("DesktopBackendConfiguration", () => {
"env",
"PATH=/home/test user's/.nvm/versions/node/v22.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin",
nodePath,
// Heap headroom, passed as a V8 execArg before the entry script (issue #21).
"--max-old-space-size=4096",
linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
29 changes: 29 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,6 +94,30 @@ const WSL_FORWARDED_ENV_NAMES = ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"] as const

const WSL_SERVER_SYSTEM_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

// Give the backend a predictable V8 old-space ceiling instead of inheriting the
// default. This is headroom for transient heap spikes (large diffs, big file
// reads) so a memory-constrained host is less likely to push the backend into a
// GC-thrash / stall while it is busy — part of the robustness work for issue
// #21. It is a ceiling, not a reservation, so it does not raise steady-state
// memory use (the backend's normal RSS is well under this).
const DESKTOP_BACKEND_MAX_OLD_SPACE_MB = 4096;
const DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG = `--max-old-space-size=${DESKTOP_BACKEND_MAX_OLD_SPACE_MB}`;

// Append our heap-headroom flag to any NODE_OPTIONS already exported (by the
// user or the dev-runner) rather than replacing it. If an explicit
// --max-old-space-size is already present we leave it untouched so an operator
// can override the ceiling. Electron-run-as-node honours the NODE_OPTIONS
// safelist, which includes --max-old-space-size.
const backendNodeOptions = (existing: string | undefined): string => {
const trimmed = existing?.trim() ?? "";
if (trimmed.includes("--max-old-space-size")) {
return trimmed;
}
return trimmed.length > 0
? `${trimmed} ${DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG}`
: DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG;
};

const backendChildEnvPatch = (): Record<string, string | undefined> =>
Object.fromEntries(DESKTOP_BACKEND_ENV_NAMES.map((name) => [name, undefined]));

Expand DownExpand Up@@ -356,6 +380,7 @@ const resolvePrimaryStartConfig = Effect.fn("desktop.backendConfiguration.resolv
env: {
...backendChildEnvPatch(),
ELECTRON_RUN_AS_NODE: "1",
NODE_OPTIONS: backendNodeOptions(process.env.NODE_OPTIONS),
},
// Primary wants process.env (PATH, dev-runner's T3CODE_HOME, etc.).
extendEnv: true,
Expand DownExpand Up@@ -546,6 +571,10 @@ const resolveWslStartConfig = Effect.fn("desktop.backendConfiguration.resolveWsl
"env",
`PATH=${launchPath}`,
preflight.nodePath,
// Match the primary backend's heap headroom. WSL runs plain node, so the
// flag is passed as a V8 execArg (before the entry script) rather than via
// NODE_OPTIONS.
DESKTOP_BACKEND_MAX_OLD_SPACE_FLAG,
preflight.linuxEntryPath,
"--bootstrap-fd",
"0",
Expand Down
Loading
Loading