@mako10k/shell-server 0.1.0

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 (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -0
  3. package/dist/backoffice/index.d.ts +2 -0
  4. package/dist/backoffice/index.d.ts.map +1 -0
  5. package/dist/backoffice/index.js +47 -0
  6. package/dist/backoffice/index.js.map +1 -0
  7. package/dist/backoffice/server.d.ts +45 -0
  8. package/dist/backoffice/server.d.ts.map +1 -0
  9. package/dist/backoffice/server.js +610 -0
  10. package/dist/backoffice/server.js.map +1 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +525 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/core/config-manager.d.ts +80 -0
  16. package/dist/core/config-manager.d.ts.map +1 -0
  17. package/dist/core/config-manager.js +218 -0
  18. package/dist/core/config-manager.js.map +1 -0
  19. package/dist/core/enhanced-history-manager.d.ts +84 -0
  20. package/dist/core/enhanced-history-manager.d.ts.map +1 -0
  21. package/dist/core/enhanced-history-manager.js +319 -0
  22. package/dist/core/enhanced-history-manager.js.map +1 -0
  23. package/dist/core/file-manager.d.ts +79 -0
  24. package/dist/core/file-manager.d.ts.map +1 -0
  25. package/dist/core/file-manager.js +338 -0
  26. package/dist/core/file-manager.js.map +1 -0
  27. package/dist/core/file-storage-subscriber.d.ts +38 -0
  28. package/dist/core/file-storage-subscriber.d.ts.map +1 -0
  29. package/dist/core/file-storage-subscriber.js +132 -0
  30. package/dist/core/file-storage-subscriber.js.map +1 -0
  31. package/dist/core/monitoring-manager.d.ts +32 -0
  32. package/dist/core/monitoring-manager.d.ts.map +1 -0
  33. package/dist/core/monitoring-manager.js +296 -0
  34. package/dist/core/monitoring-manager.js.map +1 -0
  35. package/dist/core/process-manager.d.ts +105 -0
  36. package/dist/core/process-manager.d.ts.map +1 -0
  37. package/dist/core/process-manager.js +1374 -0
  38. package/dist/core/process-manager.js.map +1 -0
  39. package/dist/core/realtime-stream-subscriber.d.ts +93 -0
  40. package/dist/core/realtime-stream-subscriber.d.ts.map +1 -0
  41. package/dist/core/realtime-stream-subscriber.js +200 -0
  42. package/dist/core/realtime-stream-subscriber.js.map +1 -0
  43. package/dist/core/remote-http-client.d.ts +15 -0
  44. package/dist/core/remote-http-client.d.ts.map +1 -0
  45. package/dist/core/remote-http-client.js +60 -0
  46. package/dist/core/remote-http-client.js.map +1 -0
  47. package/dist/core/remote-process-service.d.ts +50 -0
  48. package/dist/core/remote-process-service.d.ts.map +1 -0
  49. package/dist/core/remote-process-service.js +20 -0
  50. package/dist/core/remote-process-service.js.map +1 -0
  51. package/dist/core/server-manager.d.ts +71 -0
  52. package/dist/core/server-manager.d.ts.map +1 -0
  53. package/dist/core/server-manager.js +680 -0
  54. package/dist/core/server-manager.js.map +1 -0
  55. package/dist/core/stream-publisher.d.ts +75 -0
  56. package/dist/core/stream-publisher.d.ts.map +1 -0
  57. package/dist/core/stream-publisher.js +127 -0
  58. package/dist/core/stream-publisher.js.map +1 -0
  59. package/dist/core/streaming-pipeline-reader.d.ts +67 -0
  60. package/dist/core/streaming-pipeline-reader.d.ts.map +1 -0
  61. package/dist/core/streaming-pipeline-reader.js +191 -0
  62. package/dist/core/streaming-pipeline-reader.js.map +1 -0
  63. package/dist/core/terminal-manager.d.ts +96 -0
  64. package/dist/core/terminal-manager.d.ts.map +1 -0
  65. package/dist/core/terminal-manager.js +515 -0
  66. package/dist/core/terminal-manager.js.map +1 -0
  67. package/dist/daemon/server.d.ts +8 -0
  68. package/dist/daemon/server.d.ts.map +1 -0
  69. package/dist/daemon/server.js +416 -0
  70. package/dist/daemon/server.js.map +1 -0
  71. package/dist/daemon/uds-transport.d.ts +31 -0
  72. package/dist/daemon/uds-transport.d.ts.map +1 -0
  73. package/dist/daemon/uds-transport.js +149 -0
  74. package/dist/daemon/uds-transport.js.map +1 -0
  75. package/dist/executor/server.d.ts +20 -0
  76. package/dist/executor/server.d.ts.map +1 -0
  77. package/dist/executor/server.js +375 -0
  78. package/dist/executor/server.js.map +1 -0
  79. package/dist/index.d.ts +2 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +73 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/runtime/daemon-runtime.d.ts +4 -0
  84. package/dist/runtime/daemon-runtime.d.ts.map +1 -0
  85. package/dist/runtime/daemon-runtime.js +4 -0
  86. package/dist/runtime/daemon-runtime.js.map +1 -0
  87. package/dist/runtime/index.d.ts +3 -0
  88. package/dist/runtime/index.d.ts.map +1 -0
  89. package/dist/runtime/index.js +3 -0
  90. package/dist/runtime/index.js.map +1 -0
  91. package/dist/runtime/tool-runtime.d.ts +52 -0
  92. package/dist/runtime/tool-runtime.d.ts.map +1 -0
  93. package/dist/runtime/tool-runtime.js +161 -0
  94. package/dist/runtime/tool-runtime.js.map +1 -0
  95. package/dist/security/chat-completion-adapter.d.ts +443 -0
  96. package/dist/security/chat-completion-adapter.d.ts.map +1 -0
  97. package/dist/security/chat-completion-adapter.js +475 -0
  98. package/dist/security/chat-completion-adapter.js.map +1 -0
  99. package/dist/security/enhanced-evaluator.d.ts +139 -0
  100. package/dist/security/enhanced-evaluator.d.ts.map +1 -0
  101. package/dist/security/enhanced-evaluator.js +1208 -0
  102. package/dist/security/enhanced-evaluator.js.map +1 -0
  103. package/dist/security/evaluator-types.d.ts +614 -0
  104. package/dist/security/evaluator-types.d.ts.map +1 -0
  105. package/dist/security/evaluator-types.js +124 -0
  106. package/dist/security/evaluator-types.js.map +1 -0
  107. package/dist/security/manager.d.ts +76 -0
  108. package/dist/security/manager.d.ts.map +1 -0
  109. package/dist/security/manager.js +445 -0
  110. package/dist/security/manager.js.map +1 -0
  111. package/dist/security/security-llm-prompt-generator.d.ts +105 -0
  112. package/dist/security/security-llm-prompt-generator.d.ts.map +1 -0
  113. package/dist/security/security-llm-prompt-generator.js +323 -0
  114. package/dist/security/security-llm-prompt-generator.js.map +1 -0
  115. package/dist/security/security-tools.d.ts +174 -0
  116. package/dist/security/security-tools.d.ts.map +1 -0
  117. package/dist/security/security-tools.js +159 -0
  118. package/dist/security/security-tools.js.map +1 -0
  119. package/dist/security/validator-criteria-manager.d.ts +47 -0
  120. package/dist/security/validator-criteria-manager.d.ts.map +1 -0
  121. package/dist/security/validator-criteria-manager.js +169 -0
  122. package/dist/security/validator-criteria-manager.js.map +1 -0
  123. package/dist/tools/shell-tools.d.ts +474 -0
  124. package/dist/tools/shell-tools.d.ts.map +1 -0
  125. package/dist/tools/shell-tools.js +861 -0
  126. package/dist/tools/shell-tools.js.map +1 -0
  127. package/dist/types/enhanced-security.d.ts +529 -0
  128. package/dist/types/enhanced-security.d.ts.map +1 -0
  129. package/dist/types/enhanced-security.js +286 -0
  130. package/dist/types/enhanced-security.js.map +1 -0
  131. package/dist/types/index.d.ts +282 -0
  132. package/dist/types/index.d.ts.map +1 -0
  133. package/dist/types/index.js +158 -0
  134. package/dist/types/index.js.map +1 -0
  135. package/dist/types/quick-schemas.d.ts +177 -0
  136. package/dist/types/quick-schemas.d.ts.map +1 -0
  137. package/dist/types/quick-schemas.js +113 -0
  138. package/dist/types/quick-schemas.js.map +1 -0
  139. package/dist/types/response-schemas.d.ts +41 -0
  140. package/dist/types/response-schemas.d.ts.map +1 -0
  141. package/dist/types/response-schemas.js +41 -0
  142. package/dist/types/response-schemas.js.map +1 -0
  143. package/dist/types/schemas.d.ts +578 -0
  144. package/dist/types/schemas.d.ts.map +1 -0
  145. package/dist/types/schemas.js +498 -0
  146. package/dist/types/schemas.js.map +1 -0
  147. package/dist/utils/criteria-manager.d.ts +47 -0
  148. package/dist/utils/criteria-manager.d.ts.map +1 -0
  149. package/dist/utils/criteria-manager.js +228 -0
  150. package/dist/utils/criteria-manager.js.map +1 -0
  151. package/dist/utils/errors.d.ts +27 -0
  152. package/dist/utils/errors.d.ts.map +1 -0
  153. package/dist/utils/errors.js +67 -0
  154. package/dist/utils/errors.js.map +1 -0
  155. package/dist/utils/helpers.d.ts +85 -0
  156. package/dist/utils/helpers.d.ts.map +1 -0
  157. package/dist/utils/helpers.js +400 -0
  158. package/dist/utils/helpers.js.map +1 -0
  159. package/dist/utils/json-repair.d.ts +23 -0
  160. package/dist/utils/json-repair.d.ts.map +1 -0
  161. package/dist/utils/json-repair.js +208 -0
  162. package/dist/utils/json-repair.js.map +1 -0
  163. package/dist/utils/process-utils.d.ts +31 -0
  164. package/dist/utils/process-utils.d.ts.map +1 -0
  165. package/dist/utils/process-utils.js +217 -0
  166. package/dist/utils/process-utils.js.map +1 -0
  167. package/dist/utils/server-helpers.d.ts +4 -0
  168. package/dist/utils/server-helpers.d.ts.map +1 -0
  169. package/dist/utils/server-helpers.js +10 -0
  170. package/dist/utils/server-helpers.js.map +1 -0
  171. package/dist/utils/sse.d.ts +2 -0
  172. package/dist/utils/sse.d.ts.map +1 -0
  173. package/dist/utils/sse.js +6 -0
  174. package/dist/utils/sse.js.map +1 -0
  175. package/package.json +47 -0
@@ -0,0 +1,861 @@
1
+ import { ShellExecuteParamsSchema, ShellGetExecutionParamsSchema, ShellSetDefaultWorkdirParamsSchema, FileListParamsSchema, FileReadParamsSchema, FileDeleteParamsSchema, TerminalListParamsSchema, TerminalGetParamsSchema, TerminalCloseParamsSchema, CleanupSuggestionsParamsSchema, AutoCleanupParamsSchema, CommandHistoryQueryParamsSchema, } from '../types/schemas.js';
2
+ import { TerminalOperateParamsSchema } from '../types/quick-schemas.js';
3
+ import { RemoteProcessService } from '../core/remote-process-service.js';
4
+ import { MCPShellError } from '../utils/errors.js';
5
+ import { saveCriteria as _saveCriteria, getCriteriaStatus as _getCriteriaStatus } from '../utils/criteria-manager.js'; // Disabled MCP tool functions
6
+ // ...existing code...
7
+ export class ShellTools {
8
+ processManager;
9
+ terminalManager;
10
+ fileManager;
11
+ monitoringManager;
12
+ securityManager;
13
+ historyManager;
14
+ constructor(processManager, terminalManager, fileManager, monitoringManager, securityManager, historyManager) {
15
+ this.processManager = processManager;
16
+ this.terminalManager = terminalManager;
17
+ this.fileManager = fileManager;
18
+ this.monitoringManager = monitoringManager;
19
+ this.securityManager = securityManager;
20
+ this.historyManager = historyManager;
21
+ }
22
+ // Simple backend switch: local (default) or remote
23
+ isRemoteBackend() {
24
+ return (process.env['EXECUTION_BACKEND'] || '').toLowerCase() === 'remote';
25
+ }
26
+ // Shell Operations
27
+ async executeShellValidated(rawParams) {
28
+ const params = ShellExecuteParamsSchema.parse(rawParams);
29
+ return this.executeShell(params);
30
+ }
31
+ async getExecutionValidated(rawParams) {
32
+ const params = ShellGetExecutionParamsSchema.parse(rawParams);
33
+ return this.getExecution(params);
34
+ }
35
+ async executeShell(params) {
36
+ try {
37
+ // Enhanced security evaluation (if enabled)
38
+ const workingDir = params.working_directory || this.processManager.getDefaultWorkingDirectory();
39
+ let safetyEvaluation = null;
40
+ if (this.securityManager.isEnhancedModeEnabled()) {
41
+ // Evaluate command safety with enhanced evaluator
42
+ safetyEvaluation = await this.securityManager.evaluateCommandSafetyByEnhancedEvaluator(params.command, workingDir, params.comment, params.force_user_confirm);
43
+ // Handle evaluation results with strict safety guards
44
+ if (safetyEvaluation?.getEvaluationResult() === 'deny') {
45
+ const toolResponse = safetyEvaluation.generateToolResponse();
46
+ throw new Error(`Command denied: ${toolResponse.reasoning}`);
47
+ }
48
+ // For NEED_ASSISTANT_CONFIRM, return evaluation info without executing
49
+ // Assistant must provide additional context
50
+ if (safetyEvaluation?.getEvaluationResult() === 'ai_assistant_confirm') {
51
+ return {
52
+ status: 'need_assistant_confirm',
53
+ command: params.command,
54
+ working_directory: workingDir,
55
+ safety_evaluation: safetyEvaluation.generateToolResponse(),
56
+ message: 'Command requires assistant confirmation before execution. Assistant should provide more context.',
57
+ };
58
+ }
59
+ // CRITICAL SAFETY GUARD: Only execute if explicitly ALLOWED
60
+ if (safetyEvaluation && safetyEvaluation.getEvaluationResult() !== 'allow') {
61
+ const toolResponse = safetyEvaluation.generateToolResponse();
62
+ throw new Error(`Command execution blocked: evaluation result '${safetyEvaluation.getEvaluationResult()}' is not ALLOW. Reasoning: ${toolResponse.reasoning}`);
63
+ }
64
+ }
65
+ // Traditional security checks (still performed)
66
+ this.securityManager.auditCommand(params.command, params.working_directory);
67
+ this.securityManager.validateExecutionTime(params.timeout_seconds);
68
+ // foreground_timeout_secondsの最大値チェック
69
+ if (params.execution_mode === 'foreground' &&
70
+ typeof params.foreground_timeout_seconds === 'number' &&
71
+ params.foreground_timeout_seconds > 300) {
72
+ throw new MCPShellError('TIMEOUT_LIMIT_EXCEEDED', `foreground_timeout_seconds (${params.foreground_timeout_seconds}) exceeds the maximum allowed (300 seconds). For timeouts above 300 seconds, use execution_mode 'background' or 'adaptive'.`, 'PARAM');
73
+ }
74
+ const executionOptions = {
75
+ command: params.command,
76
+ executionMode: params.execution_mode,
77
+ timeoutSeconds: params.timeout_seconds,
78
+ foregroundTimeoutSeconds: params.foreground_timeout_seconds,
79
+ maxOutputSize: params.max_output_size,
80
+ captureStderr: params.capture_stderr,
81
+ returnPartialOnTimeout: params.return_partial_on_timeout,
82
+ };
83
+ // オプショナルなプロパティを追加(undefinedでない場合のみ)
84
+ if (params.working_directory !== undefined) {
85
+ executionOptions.workingDirectory = params.working_directory;
86
+ }
87
+ if (params.environment_variables !== undefined) {
88
+ executionOptions.environmentVariables = params.environment_variables;
89
+ }
90
+ if (params.input_data !== undefined) {
91
+ executionOptions.inputData = params.input_data;
92
+ }
93
+ if (params.input_output_id !== undefined) {
94
+ executionOptions.inputOutputId = params.input_output_id;
95
+ }
96
+ if (params.session_id !== undefined) {
97
+ executionOptions.sessionId = params.session_id;
98
+ }
99
+ if (params.create_terminal !== undefined) {
100
+ executionOptions.createTerminal = params.create_terminal;
101
+ }
102
+ if (params.terminal_shell !== undefined) {
103
+ executionOptions.terminalShell = params.terminal_shell;
104
+ }
105
+ if (params.terminal_dimensions !== undefined) {
106
+ executionOptions.terminalDimensions = params.terminal_dimensions;
107
+ }
108
+ let executionInfo;
109
+ if (this.isRemoteBackend()) {
110
+ // Minimal remote start: map subset of fields
111
+ const remote = new RemoteProcessService();
112
+ const req = {
113
+ command: executionOptions.command,
114
+ timeout_seconds: executionOptions.timeoutSeconds,
115
+ capture_stderr: executionOptions.captureStderr,
116
+ max_output_size: executionOptions.maxOutputSize,
117
+ };
118
+ if (executionOptions.workingDirectory !== undefined) {
119
+ req.working_directory = executionOptions.workingDirectory;
120
+ }
121
+ if (safetyEvaluation) {
122
+ req.safety_evaluation = safetyEvaluation.generateToolResponse();
123
+ }
124
+ const startRes = await remote.start(req);
125
+ executionInfo = {
126
+ execution_id: startRes.execution_id,
127
+ command: executionOptions.command,
128
+ status: startRes.status,
129
+ working_directory: executionOptions.workingDirectory || this.processManager.getDefaultWorkingDirectory(),
130
+ created_at: new Date().toISOString(),
131
+ started_at: new Date().toISOString(),
132
+ };
133
+ }
134
+ else {
135
+ executionInfo = await this.processManager.executeCommand(executionOptions);
136
+ }
137
+ // Add command to history
138
+ try {
139
+ const safetyClassification = this.securityManager.analyzeCommandSafety(params.command);
140
+ const baseWorkingDir = params.working_directory || this.processManager.getDefaultWorkingDirectory();
141
+ const outputSize = (executionInfo.stdout?.length || 0) + (executionInfo.stderr?.length || 0);
142
+ const durationMs = executionInfo.execution_time_ms ?? 0;
143
+ const exitCode = executionInfo.exit_code ?? 0;
144
+ await this.historyManager.addHistoryEntry({
145
+ command: params.command,
146
+ working_directory: baseWorkingDir,
147
+ was_executed: true,
148
+ resubmission_count: 0,
149
+ safety_classification: safetyClassification.classification,
150
+ execution_status: executionInfo.status,
151
+ output_summary: `Exit code: ${exitCode}, Duration: ${durationMs}ms, Output size: ${outputSize} bytes`,
152
+ });
153
+ }
154
+ catch (historyError) {
155
+ console.warn('Failed to add command to history:', historyError);
156
+ }
157
+ // Include safety evaluation in response if available
158
+ const response = { ...executionInfo };
159
+ if (safetyEvaluation) {
160
+ response['safety_evaluation'] = safetyEvaluation.generateToolResponse();
161
+ }
162
+ return response;
163
+ }
164
+ catch (error) {
165
+ throw MCPShellError.fromError(error);
166
+ }
167
+ }
168
+ async getExecution(params) {
169
+ try {
170
+ if (this.isRemoteBackend()) {
171
+ const remote = new RemoteProcessService();
172
+ return await remote.get(params.execution_id);
173
+ }
174
+ else {
175
+ const executionInfo = this.processManager.getExecution(params.execution_id);
176
+ if (!executionInfo) {
177
+ throw new MCPShellError('RESOURCE_001', `Execution with ID ${params.execution_id} not found`, 'RESOURCE');
178
+ }
179
+ return executionInfo;
180
+ }
181
+ }
182
+ catch (error) {
183
+ throw MCPShellError.fromError(error);
184
+ }
185
+ }
186
+ // Process Management
187
+ async listProcesses(params) {
188
+ try {
189
+ // Convert status filter - handle different enum values
190
+ let statusFilter = params.status_filter;
191
+ if (statusFilter === 'all') {
192
+ statusFilter = undefined;
193
+ }
194
+ const listOptions = {
195
+ limit: params.limit,
196
+ offset: params.offset,
197
+ };
198
+ if (statusFilter !== undefined) {
199
+ listOptions['status'] = statusFilter;
200
+ }
201
+ if (params.command_pattern !== undefined) {
202
+ listOptions['commandPattern'] = params.command_pattern;
203
+ }
204
+ if (params.session_id !== undefined) {
205
+ listOptions['sessionId'] = params.session_id;
206
+ }
207
+ const result = this.processManager.listExecutions(listOptions);
208
+ return {
209
+ processes: result.executions,
210
+ total_count: result.total,
211
+ filtered_count: result.executions.length,
212
+ };
213
+ }
214
+ catch (error) {
215
+ throw MCPShellError.fromError(error);
216
+ }
217
+ }
218
+ async killProcess(params) {
219
+ try {
220
+ const result = await this.processManager.killProcess(params.process_id, params.signal, params.force);
221
+ return {
222
+ success: result.success,
223
+ process_id: params.process_id,
224
+ signal_sent: result.signal_sent,
225
+ exit_code: result.exit_code,
226
+ message: result.message,
227
+ };
228
+ }
229
+ catch (error) {
230
+ throw MCPShellError.fromError(error);
231
+ }
232
+ }
233
+ async monitorProcess(params) {
234
+ try {
235
+ const monitorInfo = this.monitoringManager.startProcessMonitor(params.process_id, params.monitor_interval_ms, params.include_metrics);
236
+ return monitorInfo;
237
+ }
238
+ catch (error) {
239
+ throw MCPShellError.fromError(error);
240
+ }
241
+ }
242
+ // File Operations
243
+ async listFilesValidated(rawParams) {
244
+ const params = FileListParamsSchema.parse(rawParams ?? {});
245
+ return this.listFiles(params);
246
+ }
247
+ async readFileValidated(rawParams) {
248
+ const params = FileReadParamsSchema.parse(rawParams);
249
+ return this.readFile(params);
250
+ }
251
+ async deleteFilesValidated(rawParams) {
252
+ const params = FileDeleteParamsSchema.parse(rawParams);
253
+ return this.deleteFiles(params);
254
+ }
255
+ async listFiles(params) {
256
+ try {
257
+ const listOptions = {
258
+ limit: params.limit,
259
+ };
260
+ if (params.output_type !== undefined) {
261
+ listOptions['outputType'] = params.output_type;
262
+ }
263
+ if (params.execution_id !== undefined) {
264
+ listOptions['executionId'] = params.execution_id;
265
+ }
266
+ if (params.name_pattern !== undefined) {
267
+ listOptions['namePattern'] = params.name_pattern;
268
+ }
269
+ const result = this.fileManager.listFiles(listOptions);
270
+ return result;
271
+ }
272
+ catch (error) {
273
+ throw MCPShellError.fromError(error);
274
+ }
275
+ }
276
+ async readFile(params) {
277
+ try {
278
+ const result = await this.fileManager.readFile(params.output_id, params.offset, params.size, params.encoding);
279
+ return result;
280
+ }
281
+ catch (error) {
282
+ throw MCPShellError.fromError(error);
283
+ }
284
+ }
285
+ async deleteFiles(params) {
286
+ try {
287
+ const result = await this.fileManager.deleteFiles(params.output_ids, params.confirm);
288
+ return result;
289
+ }
290
+ catch (error) {
291
+ throw MCPShellError.fromError(error);
292
+ }
293
+ }
294
+ // Terminal Management
295
+ async terminalOperateValidated(rawParams) {
296
+ const params = TerminalOperateParamsSchema.parse(rawParams ?? {});
297
+ return this.terminalOperate(params);
298
+ }
299
+ async listTerminalsValidated(rawParams) {
300
+ const params = TerminalListParamsSchema.parse(rawParams ?? {});
301
+ return this.listTerminals(params);
302
+ }
303
+ async getTerminalValidated(rawParams) {
304
+ const params = TerminalGetParamsSchema.parse(rawParams);
305
+ return this.getTerminal(params);
306
+ }
307
+ async closeTerminalValidated(rawParams) {
308
+ const params = TerminalCloseParamsSchema.parse(rawParams);
309
+ return this.closeTerminal(params);
310
+ }
311
+ // ...existing code...
312
+ async createTerminal(params) {
313
+ try {
314
+ const terminalOptions = {
315
+ shellType: params.shell_type,
316
+ dimensions: params.dimensions,
317
+ autoSaveHistory: params.auto_save_history ?? false,
318
+ sessionName: params.session_name ?? '',
319
+ workingDirectory: params.working_directory,
320
+ environmentVariables: params.environment_variables,
321
+ };
322
+ const terminalInfo = await this.terminalManager.createTerminal(terminalOptions);
323
+ return terminalInfo;
324
+ }
325
+ catch (error) {
326
+ throw MCPShellError.fromError(error);
327
+ }
328
+ }
329
+ async listTerminals(params) {
330
+ try {
331
+ const listOptions = {};
332
+ if (params.limit !== undefined) {
333
+ listOptions.limit = params.limit;
334
+ }
335
+ if (params.session_name_pattern !== undefined) {
336
+ listOptions.sessionNamePattern = params.session_name_pattern;
337
+ }
338
+ if (params.status_filter !== undefined) {
339
+ listOptions.statusFilter = params.status_filter;
340
+ }
341
+ const result = this.terminalManager.listTerminals(listOptions);
342
+ return result;
343
+ }
344
+ catch (error) {
345
+ throw MCPShellError.fromError(error);
346
+ }
347
+ }
348
+ async getTerminal(params) {
349
+ try {
350
+ const terminalInfo = await this.terminalManager.getTerminal(params.terminal_id);
351
+ return terminalInfo;
352
+ }
353
+ catch (error) {
354
+ throw MCPShellError.fromError(error);
355
+ }
356
+ }
357
+ async sendTerminalInput(params) {
358
+ try {
359
+ const result = await this.terminalManager.sendInput(params.terminal_id, params.input, params.execute, params.control_codes, params.raw_bytes, params.send_to);
360
+ return {
361
+ success: result.success,
362
+ input_sent: params.input,
363
+ control_codes_enabled: params.control_codes || false,
364
+ raw_bytes_mode: params.raw_bytes || false,
365
+ program_guard: result.guard_check,
366
+ timestamp: result.timestamp,
367
+ };
368
+ }
369
+ catch (error) {
370
+ throw MCPShellError.fromError(error);
371
+ }
372
+ }
373
+ async getTerminalOutput(params) {
374
+ try {
375
+ const result = await this.terminalManager.getOutput(params.terminal_id, params.start_line, params.line_count, params.include_ansi, params.include_foreground_process);
376
+ const response = {
377
+ terminal_id: params.terminal_id,
378
+ output: result.output,
379
+ line_count: result.line_count,
380
+ total_lines: result.total_lines,
381
+ has_more: result.has_more,
382
+ start_line: result.start_line,
383
+ next_start_line: result.next_start_line,
384
+ };
385
+ if (params.include_foreground_process) {
386
+ response.foreground_process = result.foreground_process;
387
+ }
388
+ return response;
389
+ }
390
+ catch (error) {
391
+ throw MCPShellError.fromError(error);
392
+ }
393
+ }
394
+ async resizeTerminal(params) {
395
+ try {
396
+ const result = this.terminalManager.resizeTerminal(params.terminal_id, params.dimensions);
397
+ return {
398
+ success: result.success,
399
+ terminal_id: params.terminal_id,
400
+ dimensions: params.dimensions,
401
+ updated_at: result.updated_at,
402
+ };
403
+ }
404
+ catch (error) {
405
+ throw MCPShellError.fromError(error);
406
+ }
407
+ }
408
+ async closeTerminal(params) {
409
+ try {
410
+ const result = this.terminalManager.closeTerminal(params.terminal_id, params.save_history);
411
+ return result;
412
+ }
413
+ catch (error) {
414
+ throw MCPShellError.fromError(error);
415
+ }
416
+ }
417
+ // Security & Monitoring
418
+ async setSecurityRestrictions(params) {
419
+ try {
420
+ const restrictionParams = {
421
+ enable_network: params.enable_network,
422
+ };
423
+ if (params.allowed_commands !== undefined) {
424
+ restrictionParams['allowed_commands'] = params.allowed_commands;
425
+ }
426
+ if (params.blocked_commands !== undefined) {
427
+ restrictionParams['blocked_commands'] = params.blocked_commands;
428
+ }
429
+ if (params.allowed_directories !== undefined) {
430
+ restrictionParams['allowed_directories'] = params.allowed_directories;
431
+ }
432
+ if (params.max_execution_time !== undefined) {
433
+ restrictionParams['max_execution_time'] = params.max_execution_time;
434
+ }
435
+ if (params.max_memory_mb !== undefined) {
436
+ restrictionParams['max_memory_mb'] = params.max_memory_mb;
437
+ }
438
+ const restrictions = this.securityManager.setRestrictions(restrictionParams);
439
+ return {
440
+ restriction_id: restrictions.restriction_id,
441
+ active: restrictions.active,
442
+ configured_at: restrictions.configured_at,
443
+ };
444
+ }
445
+ catch (error) {
446
+ throw MCPShellError.fromError(error);
447
+ }
448
+ }
449
+ async getMonitoringStats(params) {
450
+ try {
451
+ let stats = this.monitoringManager.getSystemStats(params.time_range_minutes);
452
+ // 要求されたメトリクスのみを含める
453
+ if (params.include_metrics) {
454
+ const filteredStats = {
455
+ collected_at: stats.collected_at,
456
+ };
457
+ for (const metric of params.include_metrics) {
458
+ switch (metric) {
459
+ case 'processes':
460
+ filteredStats['active_processes'] = stats.active_processes;
461
+ break;
462
+ case 'terminals':
463
+ filteredStats['active_terminals'] = stats.active_terminals;
464
+ break;
465
+ case 'files':
466
+ filteredStats['total_files'] = stats.total_files;
467
+ break;
468
+ case 'system':
469
+ filteredStats['system_load'] = stats.system_load;
470
+ filteredStats['memory_usage'] = stats.memory_usage;
471
+ filteredStats['uptime_seconds'] = stats.uptime_seconds;
472
+ break;
473
+ }
474
+ }
475
+ return filteredStats;
476
+ }
477
+ return stats;
478
+ }
479
+ catch (error) {
480
+ throw MCPShellError.fromError(error);
481
+ }
482
+ }
483
+ async setDefaultWorkingDirectoryValidated(rawParams) {
484
+ const params = ShellSetDefaultWorkdirParamsSchema.parse(rawParams);
485
+ return this.setDefaultWorkingDirectory(params);
486
+ }
487
+ async setDefaultWorkingDirectory(params) {
488
+ try {
489
+ const result = this.processManager.setDefaultWorkingDirectory(params.working_directory);
490
+ return {
491
+ success: result.success,
492
+ previous_working_directory: result.previous_working_directory,
493
+ new_working_directory: result.new_working_directory,
494
+ working_directory_changed: result.working_directory_changed,
495
+ default_working_directory: this.processManager.getDefaultWorkingDirectory(),
496
+ allowed_working_directories: this.processManager.getAllowedWorkingDirectories(),
497
+ };
498
+ }
499
+ catch (error) {
500
+ throw MCPShellError.fromError(error);
501
+ }
502
+ }
503
+ // Issue #15: クリーンアップ提案機能
504
+ async getCleanupSuggestions(params) {
505
+ try {
506
+ const options = {};
507
+ if (params?.max_size_mb !== undefined)
508
+ options.maxSizeMB = params.max_size_mb;
509
+ if (params?.max_age_hours !== undefined)
510
+ options.maxAgeHours = params.max_age_hours;
511
+ if (params?.include_warnings !== undefined)
512
+ options.includeWarnings = params.include_warnings;
513
+ const result = await this.fileManager.getCleanupSuggestions(options);
514
+ return result;
515
+ }
516
+ catch (error) {
517
+ throw MCPShellError.fromError(error);
518
+ }
519
+ }
520
+ // Issue #15: 自動クリーンアップ実行機能
521
+ async performAutoCleanup(params) {
522
+ try {
523
+ const options = {};
524
+ if (params?.max_age_hours !== undefined)
525
+ options.maxAgeHours = params.max_age_hours;
526
+ if (params?.dry_run !== undefined)
527
+ options.dryRun = params.dry_run;
528
+ if (params?.preserve_recent !== undefined)
529
+ options.preserveRecent = params.preserve_recent;
530
+ const result = await this.fileManager.performAutoCleanup(options);
531
+ return result;
532
+ }
533
+ catch (error) {
534
+ throw MCPShellError.fromError(error);
535
+ }
536
+ }
537
+ // 統合ターミナル操作 (create + send_input + get_output を統合)
538
+ async terminalOperate(params) {
539
+ try {
540
+ let terminalId = params.terminal_id;
541
+ let terminalInfo = null;
542
+ let inputRejected = false;
543
+ let rejectionReason = '';
544
+ let unreadOutput = null;
545
+ // 1. ターミナルの準備 (新規作成 or 既存利用)
546
+ if (!terminalId) {
547
+ if (!params.command) {
548
+ throw new Error('Either terminal_id or command must be provided');
549
+ }
550
+ // 新規ターミナル作成
551
+ const createOptions = {
552
+ shellType: params.shell_type || 'bash',
553
+ dimensions: params.dimensions || { width: 120, height: 30 },
554
+ autoSaveHistory: true,
555
+ sessionName: params.session_name ?? undefined,
556
+ workingDirectory: params.working_directory ?? undefined,
557
+ environmentVariables: params.environment_variables ?? undefined,
558
+ };
559
+ terminalInfo = await this.terminalManager.createTerminal(createOptions);
560
+ terminalId = terminalInfo.terminal_id;
561
+ // 作成後にコマンドを自動実行
562
+ if (params.command) {
563
+ await this.terminalManager.sendInput(terminalId, params.command, true, // execute
564
+ params.control_codes || false, false, // raw_bytes
565
+ params.send_to // program guard
566
+ );
567
+ }
568
+ }
569
+ else {
570
+ // 既存ターミナル使用
571
+ terminalInfo = await this.terminalManager.getTerminal(terminalId);
572
+ // dimensionsが指定されている場合、現在のサイズと比較してリサイズ
573
+ if (params.dimensions) {
574
+ const currentDimensions = terminalInfo.dimensions;
575
+ const newDimensions = params.dimensions;
576
+ if (currentDimensions.width !== newDimensions.width ||
577
+ currentDimensions.height !== newDimensions.height) {
578
+ // サイズが異なる場合はリサイズ実行
579
+ await this.terminalManager.resizeTerminal(terminalId, newDimensions);
580
+ // 最新のターミナル情報を再取得
581
+ terminalInfo = await this.terminalManager.getTerminal(terminalId);
582
+ }
583
+ }
584
+ // inputまたはcommandが指定されていれば送信(未読出力チェック付き)
585
+ const inputToSend = params.input || params.command;
586
+ if (typeof inputToSend === 'string' && inputToSend.length > 0) {
587
+ // 制御コード送信時は自動的にforce_inputをtrueにする(Ctrl+C等の緊急操作のため)
588
+ const effectiveForceInput = params.force_input || params.control_codes;
589
+ // 未読出力チェック(force_inputまたはcontrol_codesがfalseの場合のみ)
590
+ if (!effectiveForceInput) {
591
+ const unreadCheck = await this.terminalManager.getOutput(terminalId, undefined, // start_lineはデフォルト(連続読み取り)
592
+ 1000, // 大きめの値で未読データを全取得
593
+ params.include_ansi || false, false // include_foreground_process
594
+ );
595
+ if (unreadCheck.output && unreadCheck.output.trim().length > 0) {
596
+ inputRejected = true;
597
+ rejectionReason =
598
+ 'Unread output exists. Read output first or use force_input=true to override.';
599
+ unreadOutput = unreadCheck;
600
+ }
601
+ }
602
+ // 制約に引っかからなかった場合のみ入力送信
603
+ if (!inputRejected) {
604
+ await this.terminalManager.sendInput(terminalId, inputToSend, params.execute !== false, // デフォルトtrue
605
+ params.control_codes || false, false, // raw_bytes
606
+ params.send_to // program guard
607
+ );
608
+ }
609
+ }
610
+ }
611
+ // 2. 遅延処理(コマンド完了待ち)
612
+ if (params.output_delay_ms > 0) {
613
+ await new Promise((resolve) => setTimeout(resolve, params.output_delay_ms));
614
+ }
615
+ // 3. 出力取得
616
+ let output = null;
617
+ if (params.get_output !== false) {
618
+ const outputResult = await this.terminalManager.getOutput(terminalId, undefined, // start_lineはデフォルト(連続読み取り)
619
+ params.output_lines || 20, params.include_ansi || false, false // include_foreground_process
620
+ );
621
+ output = outputResult;
622
+ }
623
+ // 4. レスポンス構築
624
+ const response = {
625
+ terminal_id: terminalId,
626
+ success: !inputRejected, // 入力が拒否された場合はfalse
627
+ };
628
+ // 入力拒否情報を追加
629
+ if (inputRejected) {
630
+ response['input_rejected'] = true;
631
+ response['reason'] = rejectionReason;
632
+ if (unreadOutput) {
633
+ response['unread_output'] = unreadOutput.output;
634
+ response['unread_output_info'] = {
635
+ line_count: unreadOutput.line_count,
636
+ total_lines: unreadOutput.total_lines,
637
+ has_more: unreadOutput.has_more,
638
+ start_line: unreadOutput.start_line,
639
+ next_start_line: unreadOutput.next_start_line,
640
+ };
641
+ }
642
+ }
643
+ if (params.return_terminal_info !== false && terminalInfo) {
644
+ response['terminal_info'] = terminalInfo;
645
+ }
646
+ if (output) {
647
+ response['output'] = output.output;
648
+ response['output_info'] = {
649
+ line_count: output.line_count,
650
+ total_lines: output.total_lines,
651
+ has_more: output.has_more,
652
+ start_line: output.start_line,
653
+ next_start_line: output.next_start_line,
654
+ };
655
+ }
656
+ // 応答レベルに応じて情報を調整
657
+ if (params.response_level === 'minimal') {
658
+ return {
659
+ terminal_id: terminalId,
660
+ success: true,
661
+ output: output?.output || null,
662
+ };
663
+ }
664
+ else if (params.response_level === 'full') {
665
+ // フル情報を含める(すでにresponseに含まれている)
666
+ }
667
+ return response;
668
+ }
669
+ catch (error) {
670
+ throw MCPShellError.fromError(error);
671
+ }
672
+ }
673
+ // Command History Management
674
+ async queryCommandHistory(params) {
675
+ try {
676
+ // Handle individual entry reference
677
+ if (params.entry_id) {
678
+ const entries = this.historyManager.searchHistory({
679
+ limit: 1000, // Get all entries to search for the specific ID
680
+ });
681
+ const entry = entries.find((e) => e.execution_id === params.entry_id);
682
+ if (!entry) {
683
+ return {
684
+ success: false,
685
+ error: `Entry with ID ${params.entry_id} not found`,
686
+ };
687
+ }
688
+ return {
689
+ success: true,
690
+ entry: params.include_full_details
691
+ ? entry
692
+ : {
693
+ execution_id: entry.execution_id,
694
+ command: entry.command,
695
+ timestamp: entry.timestamp,
696
+ working_directory: entry.working_directory,
697
+ safety_classification: entry.safety_classification,
698
+ was_executed: entry.was_executed,
699
+ output_summary: entry.output_summary,
700
+ },
701
+ };
702
+ }
703
+ // Handle analytics
704
+ if (params.analytics_type) {
705
+ const stats = this.historyManager.getHistoryStats();
706
+ switch (params.analytics_type) {
707
+ case 'stats':
708
+ return {
709
+ success: true,
710
+ analytics: {
711
+ type: 'stats',
712
+ total_entries: stats.totalEntries,
713
+ entries_with_evaluation: stats.entriesWithEvaluation,
714
+ entries_with_confirmation: stats.entriesWithConfirmation,
715
+ },
716
+ };
717
+ case 'patterns':
718
+ return {
719
+ success: true,
720
+ analytics: {
721
+ type: 'patterns',
722
+ confirmation_patterns: stats.confirmationPatterns,
723
+ },
724
+ };
725
+ case 'top_commands':
726
+ return {
727
+ success: true,
728
+ analytics: {
729
+ type: 'top_commands',
730
+ top_commands: stats.topCommands,
731
+ },
732
+ };
733
+ }
734
+ }
735
+ // Handle search and pagination
736
+ const searchQuery = {};
737
+ if (params.command_pattern || params.query) {
738
+ searchQuery['command'] = params.command_pattern || params.query;
739
+ }
740
+ if (params.working_directory) {
741
+ searchQuery['working_directory'] = params.working_directory;
742
+ }
743
+ if (params.was_executed !== undefined) {
744
+ searchQuery['was_executed'] = params.was_executed;
745
+ }
746
+ if (params.safety_classification) {
747
+ searchQuery['safety_classification'] = params.safety_classification;
748
+ }
749
+ // Calculate pagination
750
+ const offset = (params.page - 1) * params.page_size;
751
+ searchQuery['limit'] = params.page_size + offset; // Get more to handle offset
752
+ let results = this.historyManager.searchHistory(searchQuery);
753
+ // Apply date filtering if specified
754
+ if (params.date_from || params.date_to) {
755
+ const fromDate = params.date_from ? new Date(params.date_from) : new Date(0);
756
+ const toDate = params.date_to ? new Date(params.date_to) : new Date();
757
+ results = results.filter((entry) => {
758
+ const entryDate = new Date(entry.timestamp);
759
+ return entryDate >= fromDate && entryDate <= toDate;
760
+ });
761
+ }
762
+ // Apply pagination
763
+ const totalEntries = results.length;
764
+ const paginatedResults = results.slice(offset, offset + params.page_size);
765
+ // Format results
766
+ const entries = paginatedResults.map((entry) => {
767
+ if (params.include_full_details) {
768
+ return entry;
769
+ }
770
+ else {
771
+ // Return metadata with IDs for external tool integration
772
+ return {
773
+ execution_id: entry.execution_id,
774
+ command: entry.command,
775
+ timestamp: entry.timestamp,
776
+ working_directory: entry.working_directory,
777
+ safety_classification: entry.safety_classification,
778
+ llm_evaluation_result: entry.llm_evaluation_result,
779
+ was_executed: entry.was_executed,
780
+ resubmission_count: entry.resubmission_count,
781
+ output_summary: entry.output_summary,
782
+ // IDs for external tool integration
783
+ ...(entry.was_executed && {
784
+ // These can be used with process_get_execution and read_execution_output
785
+ reference_note: 'Use process_get_execution with execution_id for detailed execution info, or read_execution_output for full output',
786
+ }),
787
+ };
788
+ }
789
+ });
790
+ return {
791
+ success: true,
792
+ entries,
793
+ pagination: {
794
+ page: params.page,
795
+ page_size: params.page_size,
796
+ total_entries: totalEntries,
797
+ total_pages: Math.ceil(totalEntries / params.page_size),
798
+ has_next: offset + params.page_size < totalEntries,
799
+ has_previous: params.page > 1,
800
+ },
801
+ };
802
+ }
803
+ catch (error) {
804
+ throw MCPShellError.fromError(error);
805
+ }
806
+ }
807
+ async getCleanupSuggestionsValidated(rawParams) {
808
+ const params = CleanupSuggestionsParamsSchema.parse(rawParams ?? {});
809
+ return this.getCleanupSuggestions(params);
810
+ }
811
+ async performAutoCleanupValidated(rawParams) {
812
+ const params = AutoCleanupParamsSchema.parse(rawParams ?? {});
813
+ return this.performAutoCleanup(params);
814
+ }
815
+ async queryCommandHistoryValidated(rawParams) {
816
+ const params = CommandHistoryQueryParamsSchema.parse(rawParams ?? {});
817
+ return this.queryCommandHistory(params);
818
+ }
819
+ // Dynamic Security Criteria Adjustment
820
+ // NOTE: MCP-side adjust_criteria method is disabled (security concern)
821
+ async _adjustCriteria(params) {
822
+ try {
823
+ // Validate criteria text
824
+ if (!params.criteria_text || params.criteria_text.trim().length === 0) {
825
+ return {
826
+ success: false,
827
+ error: 'Criteria text cannot be empty',
828
+ };
829
+ }
830
+ // Get current status before modification
831
+ const statusBefore = await _getCriteriaStatus();
832
+ // Save criteria with backup option
833
+ const result = await _saveCriteria(params.criteria_text, params.append_mode || false, params.backup_existing !== false // Default to true
834
+ );
835
+ // Get status after modification
836
+ const statusAfter = await _getCriteriaStatus();
837
+ return {
838
+ success: true,
839
+ message: `Security criteria ${params.append_mode ? 'appended to' : 'updated at'} ${result.criteriaPath}`,
840
+ details: {
841
+ criteria_path: result.criteriaPath,
842
+ backup_path: result.backupPath,
843
+ append_mode: params.append_mode || false,
844
+ backup_created: result.backupPath !== null,
845
+ status_before: statusBefore,
846
+ status_after: statusAfter,
847
+ },
848
+ };
849
+ }
850
+ catch (error) {
851
+ return {
852
+ success: false,
853
+ error: `Failed to adjust criteria: ${error instanceof Error ? error.message : String(error)}`,
854
+ details: {
855
+ error_type: error instanceof Error ? error.constructor.name : 'Unknown',
856
+ },
857
+ };
858
+ }
859
+ }
860
+ }
861
+ //# sourceMappingURL=shell-tools.js.map