@mako10k/shell-server 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +35 -10
  2. package/dist/backoffice/server.js +9 -9
  3. package/dist/backoffice/server.js.map +1 -1
  4. package/dist/core/file-manager.d.ts +3 -3
  5. package/dist/core/file-manager.js +27 -27
  6. package/dist/core/file-manager.js.map +1 -1
  7. package/dist/core/file-storage-subscriber.d.ts +7 -7
  8. package/dist/core/file-storage-subscriber.js +19 -19
  9. package/dist/core/file-storage-subscriber.js.map +1 -1
  10. package/dist/core/monitoring-manager.d.ts +1 -1
  11. package/dist/core/monitoring-manager.js +31 -31
  12. package/dist/core/monitoring-manager.js.map +1 -1
  13. package/dist/core/process-manager.d.ts +4 -4
  14. package/dist/core/process-manager.js +151 -151
  15. package/dist/core/process-manager.js.map +1 -1
  16. package/dist/core/realtime-stream-subscriber.d.ts +18 -18
  17. package/dist/core/realtime-stream-subscriber.d.ts.map +1 -1
  18. package/dist/core/realtime-stream-subscriber.js +23 -23
  19. package/dist/core/realtime-stream-subscriber.js.map +1 -1
  20. package/dist/core/stream-publisher.d.ts +20 -20
  21. package/dist/core/stream-publisher.d.ts.map +1 -1
  22. package/dist/core/stream-publisher.js +15 -15
  23. package/dist/core/stream-publisher.js.map +1 -1
  24. package/dist/core/streaming-pipeline-reader.d.ts +12 -16
  25. package/dist/core/streaming-pipeline-reader.d.ts.map +1 -1
  26. package/dist/core/streaming-pipeline-reader.js +28 -28
  27. package/dist/core/streaming-pipeline-reader.js.map +1 -1
  28. package/dist/core/terminal-manager.d.ts +3 -3
  29. package/dist/core/terminal-manager.js +61 -61
  30. package/dist/core/terminal-manager.js.map +1 -1
  31. package/dist/executor/server.js +3 -3
  32. package/dist/executor/server.js.map +1 -1
  33. package/dist/security/chat-completion-adapter.d.ts.map +1 -1
  34. package/dist/security/chat-completion-adapter.js +23 -4
  35. package/dist/security/chat-completion-adapter.js.map +1 -1
  36. package/dist/security/enhanced-evaluator.js +3 -3
  37. package/dist/security/enhanced-evaluator.js.map +1 -1
  38. package/dist/security/manager.js +2 -2
  39. package/dist/security/manager.js.map +1 -1
  40. package/dist/security/security-llm-prompt-generator.d.ts +2 -2
  41. package/dist/security/security-llm-prompt-generator.js +4 -4
  42. package/dist/security/security-llm-prompt-generator.js.map +1 -1
  43. package/dist/tools/shell-tools.d.ts.map +1 -1
  44. package/dist/tools/shell-tools.js +28 -28
  45. package/dist/tools/shell-tools.js.map +1 -1
  46. package/dist/types/enhanced-security.js +29 -29
  47. package/dist/types/enhanced-security.js.map +1 -1
  48. package/dist/types/index.js +21 -21
  49. package/dist/types/index.js.map +1 -1
  50. package/dist/types/quick-schemas.js +5 -5
  51. package/dist/types/quick-schemas.js.map +1 -1
  52. package/dist/types/response-schemas.js +4 -4
  53. package/dist/types/response-schemas.js.map +1 -1
  54. package/dist/types/schemas.js +3 -3
  55. package/dist/types/schemas.js.map +1 -1
  56. package/dist/utils/errors.js +1 -1
  57. package/dist/utils/errors.js.map +1 -1
  58. package/dist/utils/helpers.js +51 -51
  59. package/dist/utils/helpers.js.map +1 -1
  60. package/dist/utils/process-utils.d.ts +6 -6
  61. package/dist/utils/process-utils.js +29 -29
  62. package/dist/utils/process-utils.js.map +1 -1
  63. package/package.json +2 -2
@@ -12,12 +12,12 @@ export class ProcessManager {
12
12
  processes = new Map();
13
13
  maxConcurrentProcesses;
14
14
  outputDir;
15
- terminalManager; // TerminalManager への参照
16
- fileManager; // FileManager への参照
15
+ terminalManager; // Reference to TerminalManager
16
+ fileManager; // Reference to FileManager
17
17
  defaultWorkingDirectory;
18
18
  allowedWorkingDirectories;
19
- backgroundProcessCallbacks = {}; // バックグラウンドプロセス終了コールバック
20
- // Issue #13: PUB/SUB統合 - Feature Flag付きで段階的統合
19
+ backgroundProcessCallbacks = {}; // Background process completion callbacks
20
+ // Issue #13: PUB/SUB integration - phased rollout with feature flag
21
21
  streamPublisher;
22
22
  fileStorageSubscriber;
23
23
  realtimeStreamSubscriber;
@@ -30,45 +30,45 @@ export class ProcessManager {
30
30
  this.allowedWorkingDirectories = process.env['SHELL_SERVER_ALLOWED_WORKDIRS']
31
31
  ? process.env['SHELL_SERVER_ALLOWED_WORKDIRS'].split(',').map((dir) => dir.trim())
32
32
  : [process.cwd()];
33
- // StreamPublisher初期化
33
+ // Initialize StreamPublisher
34
34
  this.streamPublisher = new StreamPublisher({
35
- enableRealtimeStreaming: false, // 初期状態は無効
35
+ enableRealtimeStreaming: false, // disabled by default
36
36
  bufferSize: 8192,
37
37
  notificationInterval: 100,
38
38
  });
39
- // 環境変数でStreaming機能を制御(段階的展開、デフォルト有効)
39
+ // Control streaming via environment variable (phased rollout, enabled by default)
40
40
  this.enableStreaming = process.env['SHELL_SERVER_ENABLE_STREAMING'] !== 'false';
41
41
  if (this.enableStreaming) {
42
42
  this.initializeStreamingComponents();
43
43
  }
44
44
  this.initializeOutputDirectory();
45
45
  }
46
- // TerminalManager への参照を設定
46
+ // Set TerminalManager reference
47
47
  setTerminalManager(terminalManager) {
48
48
  this.terminalManager = terminalManager;
49
49
  }
50
- // FileManager への参照を設定
50
+ // Set FileManager reference
51
51
  setFileManager(fileManager) {
52
52
  this.fileManager = fileManager;
53
- // FileManagerが設定された時にStreaming機能を再初期化
53
+ // Reinitialize streaming when FileManager is set
54
54
  if (this.enableStreaming) {
55
55
  this.initializeStreamingComponents();
56
56
  }
57
57
  }
58
- // バックグラウンドプロセス終了時のコールバックを設定
58
+ // Set callbacks for background process completion
59
59
  setBackgroundProcessCallbacks(callbacks) {
60
60
  this.backgroundProcessCallbacks = callbacks;
61
61
  }
62
- // Issue #13: Streaming コンポーネントの初期化
62
+ // Issue #13: Initialize streaming components
63
63
  initializeStreamingComponents() {
64
64
  if (!this.fileManager) {
65
65
  console.error('ProcessManager: FileManager is required for streaming components');
66
66
  return;
67
67
  }
68
- // FileStorageSubscriber初期化(既存FileManager機能を代替)
68
+ // Initialize FileStorageSubscriber (replacing part of existing FileManager handling)
69
69
  this.fileStorageSubscriber = new FileStorageSubscriber(this.fileManager, this.outputDir);
70
70
  this.streamPublisher.subscribe(this.fileStorageSubscriber);
71
- // RealtimeStreamSubscriber初期化
71
+ // Initialize RealtimeStreamSubscriber
72
72
  this.realtimeStreamSubscriber = new RealtimeStreamSubscriber({
73
73
  bufferSize: 8192,
74
74
  notificationInterval: 100,
@@ -78,14 +78,14 @@ export class ProcessManager {
78
78
  this.streamPublisher.subscribe(this.realtimeStreamSubscriber);
79
79
  console.error('ProcessManager: Streaming components initialized');
80
80
  }
81
- // Issue #13: Streaming機能の有効/無効切り替え
81
+ // Issue #13: Enable/disable streaming
82
82
  enableStreamingFeature(enable = true) {
83
83
  this.enableStreaming = enable;
84
84
  if (enable && this.fileManager) {
85
85
  this.initializeStreamingComponents();
86
86
  }
87
87
  else if (!enable) {
88
- // Streaming無効化時のクリーンアップ
88
+ // Cleanup when streaming is disabled
89
89
  if (this.realtimeStreamSubscriber) {
90
90
  this.streamPublisher.unsubscribe(this.realtimeStreamSubscriber.id);
91
91
  this.realtimeStreamSubscriber.destroy();
@@ -97,12 +97,12 @@ export class ProcessManager {
97
97
  }
98
98
  }
99
99
  }
100
- // Issue #13: RealtimeStreamSubscriber への参照を取得(新しいMCPツール用)
100
+ // Issue #13: Get RealtimeStreamSubscriber reference (for new MCP tools)
101
101
  getRealtimeStreamSubscriber() {
102
102
  return this.realtimeStreamSubscriber;
103
103
  }
104
104
  /**
105
- * Issue #13: output_idから実行IDを取得
105
+ * Issue #13: Get execution ID from output_id
106
106
  */
107
107
  findExecutionIdByOutputId(outputId) {
108
108
  return this.fileManager?.getExecutionIdByOutputId(outputId);
@@ -111,12 +111,12 @@ export class ProcessManager {
111
111
  await ensureDirectory(this.outputDir);
112
112
  }
113
113
  async executeCommand(options) {
114
- // 同時実行数のチェック
114
+ // Check concurrent execution limit
115
115
  const runningProcesses = Array.from(this.executions.values()).filter((exec) => exec.status === 'running').length;
116
116
  if (runningProcesses >= this.maxConcurrentProcesses) {
117
117
  throw new ResourceLimitError('concurrent processes', this.maxConcurrentProcesses);
118
118
  }
119
- // 入力データの準備 - input_output_idが指定された場合の処理
119
+ // Prepare input data when input_output_id is specified
120
120
  let resolvedInputData = options.inputData;
121
121
  let inputStream = undefined;
122
122
  if (options.inputOutputId) {
@@ -125,21 +125,21 @@ export class ProcessManager {
125
125
  inputOutputId: options.inputOutputId,
126
126
  });
127
127
  }
128
- // output_idから実行IDを特定
128
+ // Identify execution ID from output_id
129
129
  const sourceExecutionId = this.findExecutionIdByOutputId(options.inputOutputId);
130
130
  if (sourceExecutionId && this.realtimeStreamSubscriber) {
131
- // 実行中プロセスの場合: StreamingPipelineReaderを使用
131
+ // For active processes: use StreamingPipelineReader
132
132
  const streamState = this.realtimeStreamSubscriber.getStreamState(sourceExecutionId);
133
133
  if (streamState && streamState.isActive) {
134
134
  console.error(`ProcessManager: Using streaming pipeline for active process ${sourceExecutionId}`);
135
135
  inputStream = new StreamingPipelineReader(this.fileManager, this.realtimeStreamSubscriber, options.inputOutputId, sourceExecutionId);
136
136
  }
137
137
  }
138
- // 実行中プロセスでない場合、または失敗した場合: 従来のファイル読み取り
138
+ // If not active (or on failure), fall back to traditional file read
139
139
  if (!inputStream) {
140
140
  try {
141
141
  console.error(`ProcessManager: Using traditional file read for ${options.inputOutputId}`);
142
- const result = await this.fileManager.readFile(options.inputOutputId, 0, 100 * 1024 * 1024, // 100MB まで読み取り
142
+ const result = await this.fileManager.readFile(options.inputOutputId, 0, 100 * 1024 * 1024, // read up to 100MB
143
143
  'utf-8');
144
144
  resolvedInputData = result.content;
145
145
  }
@@ -153,7 +153,7 @@ export class ProcessManager {
153
153
  }
154
154
  const executionId = generateId();
155
155
  const startTime = getCurrentTimestamp();
156
- // 実行情報の初期化
156
+ // Initialize execution info
157
157
  const resolvedWorkingDirectory = this.resolveWorkingDirectory(options.workingDirectory);
158
158
  const executionInfo = {
159
159
  execution_id: executionId,
@@ -169,7 +169,7 @@ export class ProcessManager {
169
169
  executionInfo.environment_variables = options.environmentVariables;
170
170
  }
171
171
  this.executions.set(executionId, executionInfo);
172
- // 新規ターミナル作成オプションがある場合
172
+ // If new terminal creation is requested
173
173
  if (options.createTerminal && this.terminalManager) {
174
174
  try {
175
175
  const terminalOptions = {
@@ -186,9 +186,9 @@ export class ProcessManager {
186
186
  }
187
187
  const terminalInfo = await this.terminalManager.createTerminal(terminalOptions);
188
188
  executionInfo.terminal_id = terminalInfo.terminal_id;
189
- // ターミナルにコマンドを送信
189
+ // Send command to terminal
190
190
  this.terminalManager.sendInput(terminalInfo.terminal_id, options.command, true);
191
- // 実行情報を更新
191
+ // Update execution info
192
192
  executionInfo.status = 'completed';
193
193
  executionInfo.completed_at = getCurrentTimestamp();
194
194
  this.executions.set(executionId, executionInfo);
@@ -204,13 +204,13 @@ export class ProcessManager {
204
204
  }
205
205
  }
206
206
  try {
207
- // 実行オプションを準備
207
+ // Prepare execution options
208
208
  const { inputOutputId: _inputOutputId, ...baseOptions } = options;
209
209
  const updatedOptions = {
210
210
  ...baseOptions,
211
211
  ...(resolvedInputData !== undefined && { inputData: resolvedInputData }),
212
212
  };
213
- // StreamingPipelineReaderがある場合は特別処理
213
+ // Special handling when StreamingPipelineReader exists
214
214
  if (inputStream) {
215
215
  return await this.executeCommandWithInputStream(executionId, updatedOptions, inputStream);
216
216
  }
@@ -228,7 +228,7 @@ export class ProcessManager {
228
228
  }
229
229
  }
230
230
  catch (error) {
231
- // エラー時の実行情報更新
231
+ // Update execution info on error
232
232
  const updatedInfo = this.executions.get(executionId);
233
233
  if (updatedInfo) {
234
234
  updatedInfo.status = 'failed';
@@ -239,7 +239,7 @@ export class ProcessManager {
239
239
  }
240
240
  }
241
241
  /**
242
- * Issue #13: StreamingPipelineReaderを使用したコマンド実行
242
+ * Issue #13: Execute command using StreamingPipelineReader
243
243
  */
244
244
  async executeCommandWithInputStream(executionId, options, inputStream) {
245
245
  console.error(`ProcessManager: Executing command with input stream for ${executionId}`);
@@ -248,15 +248,15 @@ export class ProcessManager {
248
248
  let stdout = '';
249
249
  let stderr = '';
250
250
  let outputTruncated = false;
251
- // 環境変数の準備
251
+ // Prepare environment variables
252
252
  const env = getSafeEnvironment(process.env, options.environmentVariables);
253
- // プロセスの起動
253
+ // Start process
254
254
  const child = spawn('sh', ['-c', options.command], {
255
255
  cwd: this.resolveWorkingDirectory(options.workingDirectory),
256
256
  env,
257
257
  stdio: ['pipe', 'pipe', 'pipe'],
258
258
  });
259
- // StreamingPipelineReaderSTDINに接続
259
+ // Connect StreamingPipelineReader to STDIN
260
260
  if (child.stdin) {
261
261
  inputStream.pipe(child.stdin);
262
262
  }
@@ -264,11 +264,11 @@ export class ProcessManager {
264
264
  console.error(`StreamingPipelineReader error for ${executionId}: ${error.message}`);
265
265
  child.kill('SIGTERM');
266
266
  });
267
- // StreamPublisher通知
267
+ // Notify StreamPublisher
268
268
  if (this.streamPublisher) {
269
269
  this.streamPublisher.notifyProcessStart(executionId, options.command);
270
270
  }
271
- // STDOUT処理
271
+ // Handle STDOUT
272
272
  if (child.stdout) {
273
273
  child.stdout.on('data', (data) => {
274
274
  const chunk = data.toString();
@@ -278,13 +278,13 @@ export class ProcessManager {
278
278
  else {
279
279
  outputTruncated = true;
280
280
  }
281
- // StreamPublisher通知
281
+ // Notify StreamPublisher
282
282
  if (this.streamPublisher) {
283
283
  this.streamPublisher.notifyOutputData(executionId, chunk, false);
284
284
  }
285
285
  });
286
286
  }
287
- // STDERR処理
287
+ // Handle STDERR
288
288
  if (options.captureStderr && child.stderr) {
289
289
  child.stderr.on('data', (data) => {
290
290
  const chunk = data.toString();
@@ -294,29 +294,29 @@ export class ProcessManager {
294
294
  else {
295
295
  outputTruncated = true;
296
296
  }
297
- // StreamPublisher通知
297
+ // Notify StreamPublisher
298
298
  if (this.streamPublisher) {
299
299
  this.streamPublisher.notifyOutputData(executionId, chunk, true);
300
300
  }
301
301
  });
302
302
  }
303
- // プロセス終了処理
303
+ // Handle process completion
304
304
  child.on('close', async (code) => {
305
305
  const executionInfo = this.executions.get(executionId);
306
306
  if (!executionInfo) {
307
307
  reject(new ExecutionError('Execution info not found', { executionId }));
308
308
  return;
309
309
  }
310
- // 実行時間の計算
310
+ // Calculate execution time
311
311
  const executionTime = Date.now() - startTime;
312
- // 実行情報の更新
312
+ // Update execution info
313
313
  executionInfo.status = code === 0 ? 'completed' : 'failed';
314
314
  executionInfo.completed_at = getCurrentTimestamp();
315
315
  if (code !== null) {
316
316
  executionInfo.exit_code = code;
317
317
  }
318
318
  executionInfo.execution_time_ms = executionTime;
319
- // 出力の保存
319
+ // Save output
320
320
  if (this.fileManager) {
321
321
  try {
322
322
  const combinedOutput = stdout + (options.captureStderr ? stderr : '');
@@ -331,7 +331,7 @@ export class ProcessManager {
331
331
  }
332
332
  }
333
333
  this.executions.set(executionId, executionInfo);
334
- // StreamPublisher通知
334
+ // Notify StreamPublisher
335
335
  if (this.streamPublisher) {
336
336
  this.streamPublisher.notifyProcessEnd(executionId, code);
337
337
  }
@@ -340,13 +340,13 @@ export class ProcessManager {
340
340
  });
341
341
  child.on('error', (error) => {
342
342
  console.error(`Process error for ${executionId}: ${error.message}`);
343
- // StreamPublisher通知
343
+ // Notify StreamPublisher
344
344
  if (this.streamPublisher) {
345
345
  this.streamPublisher.notifyError(executionId, error);
346
346
  }
347
347
  reject(new ExecutionError(`Process error: ${error.message}`, { originalError: String(error) }));
348
348
  });
349
- // タイムアウト処理
349
+ // Timeout handling
350
350
  const timeout = setTimeout(() => {
351
351
  console.error(`Process timeout for ${executionId}`);
352
352
  child.kill('SIGTERM');
@@ -367,9 +367,9 @@ export class ProcessManager {
367
367
  let stdout = '';
368
368
  let stderr = '';
369
369
  let outputTruncated = false;
370
- // 環境変数の準備
370
+ // Prepare environment variables
371
371
  const env = getSafeEnvironment(process.env, options.environmentVariables);
372
- // プロセスの起動
372
+ // Start process
373
373
  const childProcess = spawn('/bin/bash', ['-c', options.command], {
374
374
  cwd: this.resolveWorkingDirectory(options.workingDirectory),
375
375
  env,
@@ -378,7 +378,7 @@ export class ProcessManager {
378
378
  if (childProcess.pid) {
379
379
  this.processes.set(childProcess.pid, childProcess);
380
380
  }
381
- // タイムアウトの設定
381
+ // Set timeout
382
382
  const timeout = setTimeout(async () => {
383
383
  childProcess.kill('SIGTERM');
384
384
  setTimeout(() => {
@@ -397,21 +397,21 @@ export class ProcessManager {
397
397
  if (childProcess.pid !== undefined) {
398
398
  executionInfo.process_id = childProcess.pid;
399
399
  }
400
- // 出力をFileManagerに保存(サイズに関係なく)
400
+ // Save output to FileManager (regardless of size)
401
401
  let outputFileId;
402
402
  try {
403
403
  outputFileId = await this.saveOutputToFile(executionId, stdout, stderr);
404
404
  executionInfo.output_id = outputFileId;
405
405
  }
406
406
  catch (error) {
407
- // ファイル保存失敗は重要なエラーとしてログに記録し、実行情報に含める
407
+ // Record file-save failures as critical errors and include them in execution info
408
408
  console.error(`[CRITICAL] Failed to save output file for execution ${executionId}:`, error);
409
409
  executionInfo.message = `Output file save failed: ${error instanceof Error ? error.message : String(error)}`;
410
410
  }
411
- // 出力状態の詳細情報を設定
411
+ // Set detailed output status
412
412
  this.setOutputStatus(executionInfo, outputTruncated, 'timeout', outputFileId);
413
413
  this.executions.set(executionId, executionInfo);
414
- // return_partial_on_timeout true の場合は部分結果を返す
414
+ // Return partial result when return_partial_on_timeout is true
415
415
  if (options.returnPartialOnTimeout) {
416
416
  resolve(executionInfo);
417
417
  return;
@@ -419,7 +419,7 @@ export class ProcessManager {
419
419
  }
420
420
  reject(new TimeoutError(options.timeoutSeconds));
421
421
  }, options.timeoutSeconds * 1000);
422
- // 標準入力の送信
422
+ // Send stdin
423
423
  if (options.inputData) {
424
424
  childProcess.stdin?.write(options.inputData);
425
425
  childProcess.stdin?.end();
@@ -427,7 +427,7 @@ export class ProcessManager {
427
427
  else {
428
428
  childProcess.stdin?.end();
429
429
  }
430
- // 標準出力の処理
430
+ // Handle stdout
431
431
  childProcess.stdout?.on('data', (data) => {
432
432
  const output = data.toString();
433
433
  if (stdout.length + output.length <= options.maxOutputSize) {
@@ -438,7 +438,7 @@ export class ProcessManager {
438
438
  outputTruncated = true;
439
439
  }
440
440
  });
441
- // 標準エラー出力の処理
441
+ // Handle stderr
442
442
  if (options.captureStderr) {
443
443
  childProcess.stderr?.on('data', (data) => {
444
444
  const output = data.toString();
@@ -451,7 +451,7 @@ export class ProcessManager {
451
451
  }
452
452
  });
453
453
  }
454
- // プロセス終了時の処理
454
+ // Handle process close
455
455
  childProcess.on('close', async (code) => {
456
456
  clearTimeout(timeout);
457
457
  if (childProcess.pid) {
@@ -469,30 +469,30 @@ export class ProcessManager {
469
469
  executionInfo.process_id = childProcess.pid;
470
470
  }
471
471
  executionInfo.completed_at = getCurrentTimestamp();
472
- // 出力をFileManagerに保存(サイズに関係なく)
472
+ // Save output to FileManager (regardless of size)
473
473
  let outputFileId;
474
474
  try {
475
475
  outputFileId = await this.saveOutputToFile(executionId, stdout, stderr);
476
476
  executionInfo.output_id = outputFileId;
477
477
  }
478
478
  catch (error) {
479
- // ファイル保存失敗は重要なエラーとしてログに記録し、実行情報に含める
479
+ // Record file-save failures as critical errors and include them in execution info
480
480
  console.error(`[CRITICAL] Failed to save output file for execution ${executionId}:`, error);
481
481
  executionInfo.message = `Output file save failed: ${error instanceof Error ? error.message : String(error)}`;
482
482
  }
483
- // 出力状態の詳細情報を設定
483
+ // Set detailed output status
484
484
  if (outputTruncated) {
485
485
  this.setOutputStatus(executionInfo, true, 'size_limit', outputFileId);
486
486
  }
487
487
  else {
488
- // 通常完了時 - actuallyTruncated=false, 適当なreasonで完了時ガイダンスを表示
488
+ // Normal completion: actuallyTruncated=false, use a valid reason to show completion guidance
489
489
  this.setOutputStatus(executionInfo, false, 'size_limit', outputFileId);
490
490
  }
491
491
  this.executions.set(executionId, executionInfo);
492
492
  resolve(executionInfo);
493
493
  }
494
494
  });
495
- // エラー処理
495
+ // Error handling
496
496
  childProcess.on('error', (error) => {
497
497
  clearTimeout(timeout);
498
498
  if (childProcess.pid) {
@@ -512,9 +512,9 @@ export class ProcessManager {
512
512
  });
513
513
  }
514
514
  async executeAdaptiveCommand(executionId, options) {
515
- // adaptiveモード: 1つのプロセスを起動し、以下の条件でバックグラウンドに移行
516
- // 1. フォアグラウンドタイムアウトに達した場合
517
- // 2. 出力サイズ制限に達した場合
515
+ // Adaptive mode: start one process and transition to background when:
516
+ // 1. Foreground timeout is reached
517
+ // 2. Output size limit is reached
518
518
  const returnPartialOnTimeout = options.returnPartialOnTimeout ?? true;
519
519
  const foregroundTimeout = options.foregroundTimeoutSeconds ?? 10;
520
520
  return new Promise((resolve, reject) => {
@@ -523,9 +523,9 @@ export class ProcessManager {
523
523
  let stderr = '';
524
524
  let outputTruncated = false;
525
525
  let backgroundTransitionReason = null;
526
- // 環境変数の準備
526
+ // Prepare environment variables
527
527
  const env = getSafeEnvironment(process.env, options.environmentVariables);
528
- // プロセスの起動(バックグラウンド対応)
528
+ // Start process (supports background transition)
529
529
  const childProcess = spawn('/bin/bash', ['-c', options.command], {
530
530
  cwd: this.resolveWorkingDirectory(options.workingDirectory),
531
531
  env,
@@ -534,14 +534,14 @@ export class ProcessManager {
534
534
  if (childProcess.pid) {
535
535
  this.processes.set(childProcess.pid, childProcess);
536
536
  }
537
- // フォアグラウンドタイムアウトの設定
537
+ // Set foreground timeout
538
538
  const foregroundTimeoutHandle = setTimeout(() => {
539
539
  if (!backgroundTransitionReason) {
540
540
  backgroundTransitionReason = 'timeout';
541
541
  transitionToBackground();
542
542
  }
543
543
  }, foregroundTimeout * 1000);
544
- // 最終タイムアウトの設定
544
+ // Set final timeout
545
545
  const finalTimeoutHandle = setTimeout(async () => {
546
546
  childProcess.kill('SIGTERM');
547
547
  setTimeout(() => {
@@ -557,13 +557,13 @@ export class ProcessManager {
557
557
  executionInfo.output_truncated = outputTruncated;
558
558
  executionInfo.completed_at = getCurrentTimestamp();
559
559
  executionInfo.execution_time_ms = Date.now() - startTime;
560
- // 出力をFileManagerに保存
560
+ // Save output to FileManager
561
561
  try {
562
562
  const outputFileId = await this.saveOutputToFile(executionId, stdout, stderr);
563
563
  executionInfo.output_id = outputFileId;
564
564
  }
565
565
  catch (error) {
566
- // ファイル保存失敗は重要なエラーとしてログに記録し、実行情報に含める
566
+ // Record file-save failures as critical errors and include them in execution info
567
567
  console.error(`[CRITICAL] Failed to save output file for execution ${executionId}:`, error);
568
568
  executionInfo.message = `Output file save failed: ${error instanceof Error ? error.message : String(error)}`;
569
569
  }
@@ -575,7 +575,7 @@ export class ProcessManager {
575
575
  }
576
576
  reject(new TimeoutError(options.timeoutSeconds));
577
577
  }, options.timeoutSeconds * 1000);
578
- // バックグラウンドに移行する関数
578
+ // Function to transition to background mode
579
579
  const transitionToBackground = async () => {
580
580
  clearTimeout(foregroundTimeoutHandle);
581
581
  const executionInfo = this.executions.get(executionId);
@@ -583,7 +583,7 @@ export class ProcessManager {
583
583
  executionInfo.status = 'running';
584
584
  executionInfo.stdout = sanitizeString(stdout);
585
585
  executionInfo.stderr = sanitizeString(stderr);
586
- // 移行理由を記録
586
+ // Record transition reason
587
587
  if (backgroundTransitionReason === 'timeout') {
588
588
  executionInfo.transition_reason = 'foreground_timeout';
589
589
  }
@@ -593,21 +593,21 @@ export class ProcessManager {
593
593
  if (childProcess.pid !== undefined) {
594
594
  executionInfo.process_id = childProcess.pid;
595
595
  }
596
- // 出力をFileManagerに保存
596
+ // Save output to FileManager
597
597
  let outputFileId;
598
598
  try {
599
599
  outputFileId = await this.saveOutputToFile(executionId, stdout, stderr);
600
600
  executionInfo.output_id = outputFileId;
601
601
  }
602
602
  catch (error) {
603
- // ファイル保存失敗は重要なエラーとしてログに記録し、実行情報に含める
603
+ // Record file-save failures as critical errors and include them in execution info
604
604
  console.error(`[CRITICAL] Failed to save output file for execution ${executionId}:`, error);
605
605
  executionInfo.message = `Output file save failed: ${error instanceof Error ? error.message : String(error)}`;
606
606
  }
607
- // 出力状態の詳細情報を設定(バックグラウンド移行)
607
+ // Set detailed output status (background transition)
608
608
  this.setOutputStatus(executionInfo, outputTruncated, 'background_transition', outputFileId);
609
609
  this.executions.set(executionId, executionInfo);
610
- // バックグラウンド処理の継続設定(adaptive mode専用)
610
+ // Configure continued background handling (adaptive mode only)
611
611
  this.handleAdaptiveBackgroundTransition(executionId, childProcess, {
612
612
  ...options,
613
613
  timeoutSeconds: Math.max(1, options.timeoutSeconds - Math.floor((Date.now() - startTime) / 1000)),
@@ -615,7 +615,7 @@ export class ProcessManager {
615
615
  resolve(executionInfo);
616
616
  }
617
617
  };
618
- // 標準入力の送信
618
+ // Send stdin
619
619
  if (options.inputData) {
620
620
  childProcess.stdin?.write(options.inputData);
621
621
  childProcess.stdin?.end();
@@ -623,7 +623,7 @@ export class ProcessManager {
623
623
  else {
624
624
  childProcess.stdin?.end();
625
625
  }
626
- // 標準出力の処理
626
+ // Handle stdout
627
627
  childProcess.stdout?.on('data', (data) => {
628
628
  const output = data.toString();
629
629
  if (stdout.length + output.length <= options.maxOutputSize) {
@@ -632,14 +632,14 @@ export class ProcessManager {
632
632
  else {
633
633
  stdout += output.substring(0, options.maxOutputSize - stdout.length);
634
634
  outputTruncated = true;
635
- // 出力サイズ制限に達した場合、バックグラウンドに移行
635
+ // Transition to background when output size limit is reached
636
636
  if (!backgroundTransitionReason) {
637
637
  backgroundTransitionReason = 'output_size_limit';
638
638
  transitionToBackground();
639
639
  }
640
640
  }
641
641
  });
642
- // 標準エラー出力の処理
642
+ // Handle stderr
643
643
  if (options.captureStderr) {
644
644
  childProcess.stderr?.on('data', (data) => {
645
645
  const output = data.toString();
@@ -649,7 +649,7 @@ export class ProcessManager {
649
649
  else {
650
650
  stderr += output.substring(0, options.maxOutputSize - stderr.length);
651
651
  outputTruncated = true;
652
- // 出力サイズ制限に達した場合、バックグラウンドに移行
652
+ // Transition to background when output size limit is reached
653
653
  if (!backgroundTransitionReason) {
654
654
  backgroundTransitionReason = 'output_size_limit';
655
655
  transitionToBackground();
@@ -657,14 +657,14 @@ export class ProcessManager {
657
657
  }
658
658
  });
659
659
  }
660
- // プロセス終了時の処理
660
+ // Handle process close
661
661
  childProcess.on('close', async (code) => {
662
662
  clearTimeout(foregroundTimeoutHandle);
663
663
  clearTimeout(finalTimeoutHandle);
664
664
  if (childProcess.pid) {
665
665
  this.processes.delete(childProcess.pid);
666
666
  }
667
- // バックグラウンドに移行していない場合のみ処理
667
+ // Handle only when no background transition occurred
668
668
  if (!backgroundTransitionReason) {
669
669
  const executionTime = Date.now() - startTime;
670
670
  const executionInfo = this.executions.get(executionId);
@@ -679,13 +679,13 @@ export class ProcessManager {
679
679
  executionInfo.process_id = childProcess.pid;
680
680
  }
681
681
  executionInfo.completed_at = getCurrentTimestamp();
682
- // 出力をFileManagerに保存
682
+ // Save output to FileManager
683
683
  try {
684
684
  const outputFileId = await this.saveOutputToFile(executionId, stdout, stderr);
685
685
  executionInfo.output_id = outputFileId;
686
686
  }
687
687
  catch (error) {
688
- // ファイル保存失敗は重要なエラーとしてログに記録し、実行情報に含める
688
+ // Record file-save failures as critical errors and include them in execution info
689
689
  console.error(`[CRITICAL] Failed to save output file for execution ${executionId}:`, error);
690
690
  executionInfo.message = `Output file save failed: ${error instanceof Error ? error.message : String(error)}`;
691
691
  }
@@ -694,7 +694,7 @@ export class ProcessManager {
694
694
  }
695
695
  }
696
696
  });
697
- // エラー処理
697
+ // Error handling
698
698
  childProcess.on('error', (error) => {
699
699
  clearTimeout(foregroundTimeoutHandle);
700
700
  clearTimeout(finalTimeoutHandle);
@@ -732,7 +732,7 @@ export class ProcessManager {
732
732
  executionInfo.process_id = childProcess.pid;
733
733
  this.executions.set(executionId, executionInfo);
734
734
  }
735
- // バックグラウンドプロセスの場合、出力を非同期で処理
735
+ // For background processes, handle output asynchronously
736
736
  if (options.executionMode === 'background') {
737
737
  this.handleBackgroundProcess(executionId, childProcess, options);
738
738
  }
@@ -746,7 +746,7 @@ export class ProcessManager {
746
746
  const startTime = Date.now();
747
747
  let stdout = '';
748
748
  let stderr = '';
749
- // タイムアウトの設定(backgroundプロセス用)
749
+ // Set timeout (for background processes)
750
750
  const timeout = setTimeout(async () => {
751
751
  childProcess.kill('SIGTERM');
752
752
  setTimeout(() => {
@@ -762,18 +762,18 @@ export class ProcessManager {
762
762
  executionInfo.output_truncated = true;
763
763
  executionInfo.completed_at = getCurrentTimestamp();
764
764
  executionInfo.execution_time_ms = Date.now() - startTime;
765
- // 出力をFileManagerに保存
765
+ // Save output to FileManager
766
766
  try {
767
767
  const outputFileId = await this.saveOutputToFile(executionId, stdout, stderr);
768
768
  executionInfo.output_id = outputFileId;
769
769
  }
770
770
  catch (error) {
771
- // ファイル保存失敗は重要なエラーとしてログに記録し、実行情報に含める
771
+ // Record file-save failures as critical errors and include them in execution info
772
772
  console.error(`[CRITICAL] Failed to save output file for execution ${executionId}:`, error);
773
773
  executionInfo.message = `Output file save failed: ${error instanceof Error ? error.message : String(error)}`;
774
774
  }
775
775
  this.executions.set(executionId, executionInfo);
776
- // バックグラウンドプロセスタイムアウトのコールバック呼び出し
776
+ // Invoke timeout callback for background process
777
777
  if (this.backgroundProcessCallbacks.onTimeout) {
778
778
  setImmediate(async () => {
779
779
  try {
@@ -786,14 +786,14 @@ export class ProcessManager {
786
786
  }
787
787
  }
788
788
  catch (callbackError) {
789
- // コールバックエラーは内部ログに記録のみ
789
+ // Record callback errors in internal logs only
790
790
  // console.error('Background process timeout callback error:', callbackError);
791
791
  }
792
792
  });
793
793
  }
794
794
  }
795
795
  }, options.timeoutSeconds * 1000);
796
- // 出力の収集
796
+ // Collect output
797
797
  childProcess.stdout?.on('data', (data) => {
798
798
  stdout += data.toString();
799
799
  });
@@ -802,7 +802,7 @@ export class ProcessManager {
802
802
  stderr += data.toString();
803
803
  });
804
804
  }
805
- // プロセス終了時の処理
805
+ // Handle process close
806
806
  childProcess.on('close', async (code) => {
807
807
  clearTimeout(timeout);
808
808
  if (childProcess.pid) {
@@ -814,18 +814,18 @@ export class ProcessManager {
814
814
  executionInfo.exit_code = code || 0;
815
815
  executionInfo.execution_time_ms = Date.now() - startTime;
816
816
  executionInfo.completed_at = getCurrentTimestamp();
817
- // 出力をファイルに保存
817
+ // Save output to file
818
818
  try {
819
819
  const outputFileId = await this.saveOutputToFile(executionId, stdout, stderr);
820
820
  executionInfo.output_id = outputFileId;
821
821
  }
822
822
  catch (error) {
823
- // ファイル保存失敗は重要なエラーとしてログに記録し、実行情報に含める
823
+ // Record file-save failures as critical errors and include them in execution info
824
824
  console.error(`[CRITICAL] Failed to save output file for execution ${executionId}:`, error);
825
825
  executionInfo.message = `Output file save failed: ${error instanceof Error ? error.message : String(error)}`;
826
826
  }
827
827
  this.executions.set(executionId, executionInfo);
828
- // バックグラウンドプロセス正常終了のコールバック呼び出し
828
+ // Invoke completion callback for background process
829
829
  if (this.backgroundProcessCallbacks.onComplete) {
830
830
  setImmediate(async () => {
831
831
  try {
@@ -838,7 +838,7 @@ export class ProcessManager {
838
838
  }
839
839
  }
840
840
  catch (callbackError) {
841
- // コールバックエラーは内部ログに記録のみ
841
+ // Record callback errors in internal logs only
842
842
  // console.error('Background process completion callback error:', callbackError);
843
843
  }
844
844
  });
@@ -856,7 +856,7 @@ export class ProcessManager {
856
856
  executionInfo.execution_time_ms = Date.now() - startTime;
857
857
  executionInfo.completed_at = getCurrentTimestamp();
858
858
  this.executions.set(executionId, executionInfo);
859
- // バックグラウンドプロセスエラーのコールバック呼び出し
859
+ // Invoke error callback for background process
860
860
  if (this.backgroundProcessCallbacks.onError) {
861
861
  setImmediate(async () => {
862
862
  try {
@@ -869,7 +869,7 @@ export class ProcessManager {
869
869
  }
870
870
  }
871
871
  catch (callbackError) {
872
- // コールバックエラーは内部ログに記録のみ
872
+ // Record callback errors in internal logs only
873
873
  // console.error('Background process error callback error:', callbackError);
874
874
  }
875
875
  });
@@ -877,9 +877,9 @@ export class ProcessManager {
877
877
  }
878
878
  });
879
879
  }
880
- // adaptive modeでバックグラウンドに移行したプロセスの処理
880
+ // Handle processes transitioned to background in adaptive mode
881
881
  handleAdaptiveBackgroundTransition(executionId, childProcess, options) {
882
- // タイムアウトの設定(最終タイムアウト)
882
+ // Set timeout (final timeout)
883
883
  const timeout = setTimeout(async () => {
884
884
  childProcess.kill('SIGTERM');
885
885
  setTimeout(() => {
@@ -891,11 +891,11 @@ export class ProcessManager {
891
891
  if (executionInfo) {
892
892
  executionInfo.status = 'timeout';
893
893
  executionInfo.completed_at = getCurrentTimestamp();
894
- // 既存の出力は保持(adaptive modeで既にキャプチャ済み)
894
+ // Keep existing output (already captured in adaptive mode)
895
895
  this.executions.set(executionId, executionInfo);
896
896
  }
897
897
  }, options.timeoutSeconds * 1000);
898
- // プロセス終了時の処理
898
+ // Handle process close
899
899
  childProcess.on('close', async (code) => {
900
900
  clearTimeout(timeout);
901
901
  if (childProcess.pid) {
@@ -906,13 +906,13 @@ export class ProcessManager {
906
906
  executionInfo.status = 'completed';
907
907
  executionInfo.exit_code = code || 0;
908
908
  executionInfo.completed_at = getCurrentTimestamp();
909
- // 実行時間は全体(フォアグラウンド + バックグラウンド)で計算
909
+ // Calculate total execution time (foreground + background)
910
910
  if (executionInfo.started_at) {
911
911
  const startTime = new Date(executionInfo.started_at).getTime();
912
912
  executionInfo.execution_time_ms = Date.now() - startTime;
913
913
  }
914
914
  this.executions.set(executionId, executionInfo);
915
- // adaptive modeバックグラウンドプロセス正常終了のコールバック呼び出し
915
+ // Invoke completion callback for adaptive-mode background process
916
916
  if (this.backgroundProcessCallbacks.onComplete) {
917
917
  setImmediate(async () => {
918
918
  try {
@@ -925,7 +925,7 @@ export class ProcessManager {
925
925
  }
926
926
  }
927
927
  catch (callbackError) {
928
- // コールバックエラーは内部ログに記録のみ
928
+ // Record callback errors in internal logs only
929
929
  // console.error('Adaptive background process completion callback error:', callbackError);
930
930
  }
931
931
  });
@@ -946,7 +946,7 @@ export class ProcessManager {
946
946
  executionInfo.execution_time_ms = Date.now() - startTime;
947
947
  }
948
948
  this.executions.set(executionId, executionInfo);
949
- // adaptive modeバックグラウンドプロセスエラーのコールバック呼び出し
949
+ // Invoke error callback for adaptive-mode background process
950
950
  if (this.backgroundProcessCallbacks.onError) {
951
951
  setImmediate(async () => {
952
952
  try {
@@ -959,7 +959,7 @@ export class ProcessManager {
959
959
  }
960
960
  }
961
961
  catch (callbackError) {
962
- // コールバックエラーは内部ログに記録のみ
962
+ // Record callback errors in internal logs only
963
963
  // console.error('Adaptive background process error callback error:', callbackError);
964
964
  }
965
965
  });
@@ -968,23 +968,23 @@ export class ProcessManager {
968
968
  });
969
969
  }
970
970
  async executeDetachedCommand(executionId, options) {
971
- // detachedモード: 完全にバックグラウンドで実行し、親プロセスとの接続を切断
971
+ // Detached mode: run fully in background and detach from parent process
972
972
  const env = getSafeEnvironment(process.env, options.environmentVariables);
973
973
  const childProcess = spawn('/bin/bash', ['-c', options.command], {
974
974
  cwd: this.resolveWorkingDirectory(options.workingDirectory),
975
975
  env,
976
- stdio: ['ignore', 'pipe', 'pipe'], // stdin は無視
977
- detached: true, // 完全にデタッチ
976
+ stdio: ['ignore', 'pipe', 'pipe'], // ignore stdin
977
+ detached: true, // fully detached
978
978
  });
979
- // デタッチされたプロセスのPIDは記録するが、プロセス管理からは除外
979
+ // Record detached process PID but exclude it from process management
980
980
  const executionInfo = this.executions.get(executionId);
981
981
  if (executionInfo && childProcess.pid !== undefined) {
982
982
  executionInfo.process_id = childProcess.pid;
983
983
  executionInfo.status = 'running';
984
984
  this.executions.set(executionId, executionInfo);
985
985
  }
986
- // デタッチされたプロセスは親プロセスの終了後も継続実行されるため、
987
- // 出力の収集は限定的
986
+ // Detached processes continue after parent exits,
987
+ // so output collection is limited
988
988
  const startTime = Date.now();
989
989
  let stdout = '';
990
990
  let stderr = '';
@@ -998,7 +998,7 @@ export class ProcessManager {
998
998
  stderr += data.toString();
999
999
  });
1000
1000
  }
1001
- // プロセスの終了を監視(デタッチされているため必ずしも捕捉されない)
1001
+ // Monitor process exit (not always capturable when detached)
1002
1002
  childProcess.on('close', async (code) => {
1003
1003
  const executionInfo = this.executions.get(executionId);
1004
1004
  if (executionInfo) {
@@ -1011,12 +1011,12 @@ export class ProcessManager {
1011
1011
  executionInfo.output_id = outputFileId;
1012
1012
  }
1013
1013
  catch (error) {
1014
- // ファイル保存失敗は重要なエラーとしてログに記録し、実行情報に含める
1014
+ // Record file-save failures as critical errors and include them in execution info
1015
1015
  console.error(`[CRITICAL] Failed to save output file for execution ${executionId}:`, error);
1016
1016
  executionInfo.message = `Output file save failed: ${error instanceof Error ? error.message : String(error)}`;
1017
1017
  }
1018
1018
  this.executions.set(executionId, executionInfo);
1019
- // detachedプロセス正常終了のコールバック呼び出し
1019
+ // Invoke completion callback for detached process
1020
1020
  if (this.backgroundProcessCallbacks.onComplete) {
1021
1021
  setImmediate(async () => {
1022
1022
  try {
@@ -1029,7 +1029,7 @@ export class ProcessManager {
1029
1029
  }
1030
1030
  }
1031
1031
  catch (callbackError) {
1032
- // コールバックエラーは内部ログに記録のみ
1032
+ // Record callback errors in internal logs only
1033
1033
  // console.error('Detached process completion callback error:', callbackError);
1034
1034
  }
1035
1035
  });
@@ -1043,7 +1043,7 @@ export class ProcessManager {
1043
1043
  executionInfo.execution_time_ms = Date.now() - startTime;
1044
1044
  executionInfo.completed_at = getCurrentTimestamp();
1045
1045
  this.executions.set(executionId, executionInfo);
1046
- // detachedプロセスエラーのコールバック呼び出し
1046
+ // Invoke error callback for detached process
1047
1047
  if (this.backgroundProcessCallbacks.onError) {
1048
1048
  setImmediate(async () => {
1049
1049
  try {
@@ -1056,14 +1056,14 @@ export class ProcessManager {
1056
1056
  }
1057
1057
  }
1058
1058
  catch (callbackError) {
1059
- // コールバックエラーは内部ログに記録のみ
1059
+ // Record callback errors in internal logs only
1060
1060
  // console.error('Detached process error callback error:', callbackError);
1061
1061
  }
1062
1062
  });
1063
1063
  }
1064
1064
  }
1065
1065
  });
1066
- // プロセスをデタッチ
1066
+ // Detach process
1067
1067
  childProcess.unref();
1068
1068
  const resultExecutionInfo = this.executions.get(executionId);
1069
1069
  if (!resultExecutionInfo) {
@@ -1073,7 +1073,7 @@ export class ProcessManager {
1073
1073
  }
1074
1074
  async saveOutputToFile(executionId, stdout, stderr) {
1075
1075
  if (!this.fileManager) {
1076
- // FileManagerが利用できない場合は、従来の方法でファイルを保存
1076
+ // If FileManager is unavailable, save file using legacy method
1077
1077
  const outputFileId = generateId();
1078
1078
  const filePath = path.join(this.outputDir, `${outputFileId}.json`);
1079
1079
  const outputData = {
@@ -1085,27 +1085,27 @@ export class ProcessManager {
1085
1085
  await fs.writeFile(filePath, JSON.stringify(outputData, null, 2), 'utf-8');
1086
1086
  return outputFileId;
1087
1087
  }
1088
- // FileManagerを使用して出力ファイルを作成
1088
+ // Create output file using FileManager
1089
1089
  const combinedOutput = stdout + (stderr ? '\n--- STDERR ---\n' + stderr : '');
1090
1090
  return await this.fileManager.createOutputFile(combinedOutput, executionId);
1091
1091
  }
1092
1092
  /**
1093
- * 出力状態の詳細情報を設定するヘルパー関数
1093
+ * Helper to set detailed output status information
1094
1094
  * Issue #14: Enhanced guidance messages for adaptive mode transitions
1095
- * 改善: outputTruncated の代わりに reason ベースで状態を判定
1095
+ * Improvement: determine status by reason instead of outputTruncated
1096
1096
  */
1097
- setOutputStatus(executionInfo, actuallyTruncated, // 実際に出力が切り捨てられたか
1097
+ setOutputStatus(executionInfo, actuallyTruncated, // whether output was actually truncated
1098
1098
  reason, outputId) {
1099
- // reasonに基づいて出力状態を設定
1100
- const needsGuidance = !!outputId; // output_idがあれば常にガイダンスを提供
1101
- // 後方互換性のため outputTruncated を設定
1099
+ // Set output status based on reason
1100
+ const needsGuidance = !!outputId; // always provide guidance when output_id exists
1101
+ // Set outputTruncated for backward compatibility
1102
1102
  executionInfo.output_truncated =
1103
1103
  actuallyTruncated || reason === 'timeout' || reason === 'background_transition';
1104
- // Issue #14: バックグラウンド移行とタイムアウトは特別扱い
1104
+ // Issue #14: Handle background transitions and timeouts specially
1105
1105
  if (reason === 'background_transition') {
1106
1106
  executionInfo.truncation_reason = reason;
1107
1107
  executionInfo.output_status = {
1108
- complete: false, // バックグラウンド実行中は未完了
1108
+ complete: false, // incomplete while running in background
1109
1109
  reason: reason,
1110
1110
  available_via_output_id: !!outputId,
1111
1111
  recommended_action: outputId ? 'use_read_execution_output' : undefined,
@@ -1136,7 +1136,7 @@ export class ProcessManager {
1136
1136
  if (reason === 'timeout') {
1137
1137
  executionInfo.truncation_reason = reason;
1138
1138
  executionInfo.output_status = {
1139
- complete: false, // タイムアウトは未完了
1139
+ complete: false, // timeout means incomplete
1140
1140
  reason: reason,
1141
1141
  available_via_output_id: !!outputId,
1142
1142
  recommended_action: outputId ? 'use_read_execution_output' : undefined,
@@ -1158,7 +1158,7 @@ export class ProcessManager {
1158
1158
  }
1159
1159
  return;
1160
1160
  }
1161
- // 実際に出力が切り捨てられた場合
1161
+ // When output was actually truncated
1162
1162
  if (actuallyTruncated) {
1163
1163
  executionInfo.truncation_reason = reason;
1164
1164
  executionInfo.output_status = {
@@ -1167,7 +1167,7 @@ export class ProcessManager {
1167
1167
  available_via_output_id: !!outputId,
1168
1168
  recommended_action: outputId ? 'use_read_execution_output' : undefined,
1169
1169
  };
1170
- // 状況に応じたメッセージとアクションの設定
1170
+ // Set message and actions based on situation
1171
1171
  switch (reason) {
1172
1172
  case 'size_limit':
1173
1173
  executionInfo.message = `Output exceeded size limit. ${outputId ? 'Complete output available via output_id.' : 'Output was truncated.'}`;
@@ -1205,7 +1205,7 @@ export class ProcessManager {
1205
1205
  }
1206
1206
  }
1207
1207
  else {
1208
- // 完了した場合(切り捨てなし)
1208
+ // Completed case (no truncation)
1209
1209
  executionInfo.output_status = {
1210
1210
  complete: true,
1211
1211
  available_via_output_id: !!outputId,
@@ -1228,7 +1228,7 @@ export class ProcessManager {
1228
1228
  }
1229
1229
  listExecutions(filter) {
1230
1230
  let executions = Array.from(this.executions.values());
1231
- // フィルタリング
1231
+ // Filtering
1232
1232
  if (filter) {
1233
1233
  if (filter.status) {
1234
1234
  executions = executions.filter((exec) => exec.status === filter.status);
@@ -1238,11 +1238,11 @@ export class ProcessManager {
1238
1238
  executions = executions.filter((exec) => pattern.test(exec.command));
1239
1239
  }
1240
1240
  if (filter.sessionId) {
1241
- // セッション管理は今後実装
1241
+ // Session management will be implemented later
1242
1242
  }
1243
1243
  }
1244
1244
  const total = executions.length;
1245
- // ページネーション
1245
+ // Pagination
1246
1246
  if (filter?.offset || filter?.limit) {
1247
1247
  const offset = filter.offset || 0;
1248
1248
  const limit = filter.limit || 50;
@@ -1256,17 +1256,17 @@ export class ProcessManager {
1256
1256
  throw new ResourceNotFoundError('process', processId.toString());
1257
1257
  }
1258
1258
  try {
1259
- // プロセスを終了
1259
+ // Terminate process
1260
1260
  const signalName = signal === 'KILL' ? 'SIGKILL' : `SIG${signal}`;
1261
1261
  const killed = childProcess.kill(signalName);
1262
1262
  if (!killed && force && signal !== 'KILL') {
1263
- // 強制終了
1263
+ // Force kill
1264
1264
  childProcess.kill('SIGKILL');
1265
1265
  }
1266
- // プロセスが終了するまで待機
1266
+ // Wait until process exits
1267
1267
  await new Promise((resolve) => {
1268
1268
  childProcess.on('close', () => resolve());
1269
- setTimeout(() => resolve(), 5000); // 5秒でタイムアウト
1269
+ setTimeout(() => resolve(), 5000); // timeout after 5 seconds
1270
1270
  });
1271
1271
  this.processes.delete(processId);
1272
1272
  return {
@@ -1287,7 +1287,7 @@ export class ProcessManager {
1287
1287
  listProcesses() {
1288
1288
  const processes = [];
1289
1289
  for (const [pid] of this.processes) {
1290
- // 対応する実行情報を検索
1290
+ // Find corresponding execution info
1291
1291
  const execution = Array.from(this.executions.values()).find((exec) => exec.process_id === pid);
1292
1292
  if (execution) {
1293
1293
  const processInfo = {
@@ -1315,7 +1315,7 @@ export class ProcessManager {
1315
1315
  return processes;
1316
1316
  }
1317
1317
  cleanup() {
1318
- // 実行中のプロセスを全て終了
1318
+ // Terminate all running processes
1319
1319
  for (const [, childProcess] of this.processes) {
1320
1320
  try {
1321
1321
  childProcess.kill('SIGTERM');
@@ -1326,17 +1326,17 @@ export class ProcessManager {
1326
1326
  }, 5000);
1327
1327
  }
1328
1328
  catch (error) {
1329
- // エラーログを内部ログに記録(標準出力を避ける)
1329
+ // Record error in internal log (avoid stdout)
1330
1330
  // console.error(`Failed to cleanup process ${pid}:`, error);
1331
1331
  }
1332
1332
  }
1333
1333
  this.processes.clear();
1334
1334
  this.executions.clear();
1335
1335
  }
1336
- // ワーキングディレクトリ管理
1336
+ // Working directory management
1337
1337
  setDefaultWorkingDirectory(workingDirectory) {
1338
1338
  const previousWorkdir = this.defaultWorkingDirectory;
1339
- // ディレクトリの検証
1339
+ // Validate directory
1340
1340
  if (!this.isAllowedWorkingDirectory(workingDirectory)) {
1341
1341
  throw new Error(`Working directory not allowed: ${workingDirectory}`);
1342
1342
  }
@@ -1355,7 +1355,7 @@ export class ProcessManager {
1355
1355
  return [...this.allowedWorkingDirectories];
1356
1356
  }
1357
1357
  isAllowedWorkingDirectory(workingDirectory) {
1358
- // パスの正規化を行って比較
1358
+ // Compare using normalized paths
1359
1359
  const normalizedPath = path.resolve(workingDirectory);
1360
1360
  return this.allowedWorkingDirectories.some((allowedDir) => {
1361
1361
  const normalizedAllowed = path.resolve(allowedDir);