diff --git a/README.md b/README.md
index 2a60eb7..5206019 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
+
+
+
+
diff --git a/electron/main-process/bounded-output-buffer.js b/electron/main-process/bounded-output-buffer.js
new file mode 100644
index 0000000..ab98de2
--- /dev/null
+++ b/electron/main-process/bounded-output-buffer.js
@@ -0,0 +1,22 @@
+const DEFAULT_MAX_OUTPUT_CHARS = 256 * 1024;
+
+function appendBoundedOutput(currentOutput, nextChunk, maxChars = DEFAULT_MAX_OUTPUT_CHARS) {
+ if (!Number.isFinite(maxChars) || maxChars <= 0) {
+ return '';
+ }
+
+ const current = typeof currentOutput === 'string' ? currentOutput : '';
+ const next = Buffer.isBuffer(nextChunk) ? nextChunk.toString() : String(nextChunk ?? '');
+ const combined = current + next;
+
+ if (combined.length <= maxChars) {
+ return combined;
+ }
+
+ return combined.slice(-maxChars);
+}
+
+module.exports = {
+ DEFAULT_MAX_OUTPUT_CHARS,
+ appendBoundedOutput,
+};
diff --git a/electron/main-process/mihomo-service.js b/electron/main-process/mihomo-service.js
index 41bdf75..133b06d 100644
--- a/electron/main-process/mihomo-service.js
+++ b/electron/main-process/mihomo-service.js
@@ -17,6 +17,7 @@ module.exports = function initMihomoService(context) {
const { applyOverrides } = require('../ipc-handlers/overrides');
const { getMihomoControllerParam, cleanupSocketFile } = require('../utils/socket-path');
const { RunningMode, setRunningMode, getRunningMode, isServiceMode, getSocketPath, getServiceSocketPath, getSidecarSocketPath } = require('../utils/running-mode');
+ const { appendBoundedOutput } = require('./bounded-output-buffer');
console.log('[mihomo-service] applyOverrides函数已导入:', typeof applyOverrides);
async function waitForProcessExit(proc, timeoutMs = 5000) {
@@ -1200,7 +1201,7 @@ module.exports = function initMihomoService(context) {
spawnedProcess.stdout.on('data', (data) => {
const logContent = data.toString();
- stdoutOutput += logContent; // 收集 stdout 输出
+ stdoutOutput = appendBoundedOutput(stdoutOutput, logContent); // 收集最近的 stdout 输出
console.log(`mihomo stdout: ${logContent}`);
// 检测 TUN 启动失败
@@ -1258,7 +1259,7 @@ module.exports = function initMihomoService(context) {
spawnedProcess.stderr.on('data', (data) => {
const errorText = data.toString();
- stderrOutput += errorText; // 收集 stderr 输出
+ stderrOutput = appendBoundedOutput(stderrOutput, errorText); // 收集最近的 stderr 输出
console.error(`mihomo stderr: ${errorText}`);
safeSend('mihomo-error', errorText);
process.stderr.write(data);
diff --git a/package.json b/package.json
index 4301bb5..694776d 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"build": "next build",
"start": "next start",
"lint": "next lint",
+ "test": "node --test",
"rebuild:native": "electron-rebuild -f -w better-sqlite3",
"postinstall": "electron-builder install-app-deps",
"prepare": "node scripts/prepare.mjs",
diff --git a/test/bounded-output-buffer.test.js b/test/bounded-output-buffer.test.js
new file mode 100644
index 0000000..7511ab6
--- /dev/null
+++ b/test/bounded-output-buffer.test.js
@@ -0,0 +1,30 @@
+const assert = require('node:assert/strict');
+const test = require('node:test');
+
+const {
+ DEFAULT_MAX_OUTPUT_CHARS,
+ appendBoundedOutput,
+} = require('../electron/main-process/bounded-output-buffer');
+
+test('appendBoundedOutput keeps short output unchanged', () => {
+ const output = appendBoundedOutput('hello', '\nworld', 32);
+
+ assert.equal(output, 'hello\nworld');
+});
+
+test('appendBoundedOutput caps retained output and keeps newest content', () => {
+ let output = '';
+
+ output = appendBoundedOutput(output, '12345', 10);
+ output = appendBoundedOutput(output, '67890', 10);
+ output = appendBoundedOutput(output, 'abcde', 10);
+
+ assert.equal(output, '67890abcde');
+ assert.equal(output.length, 10);
+});
+
+test('appendBoundedOutput truncates a single large chunk to the configured limit', () => {
+ const output = appendBoundedOutput('', 'x'.repeat(DEFAULT_MAX_OUTPUT_CHARS + 5), 16);
+
+ assert.equal(output, 'x'.repeat(16));
+});