@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.
- package/LICENSE +21 -0
- package/README.md +114 -0
- package/dist/backoffice/index.d.ts +2 -0
- package/dist/backoffice/index.d.ts.map +1 -0
- package/dist/backoffice/index.js +47 -0
- package/dist/backoffice/index.js.map +1 -0
- package/dist/backoffice/server.d.ts +45 -0
- package/dist/backoffice/server.d.ts.map +1 -0
- package/dist/backoffice/server.js +610 -0
- package/dist/backoffice/server.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +525 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/config-manager.d.ts +80 -0
- package/dist/core/config-manager.d.ts.map +1 -0
- package/dist/core/config-manager.js +218 -0
- package/dist/core/config-manager.js.map +1 -0
- package/dist/core/enhanced-history-manager.d.ts +84 -0
- package/dist/core/enhanced-history-manager.d.ts.map +1 -0
- package/dist/core/enhanced-history-manager.js +319 -0
- package/dist/core/enhanced-history-manager.js.map +1 -0
- package/dist/core/file-manager.d.ts +79 -0
- package/dist/core/file-manager.d.ts.map +1 -0
- package/dist/core/file-manager.js +338 -0
- package/dist/core/file-manager.js.map +1 -0
- package/dist/core/file-storage-subscriber.d.ts +38 -0
- package/dist/core/file-storage-subscriber.d.ts.map +1 -0
- package/dist/core/file-storage-subscriber.js +132 -0
- package/dist/core/file-storage-subscriber.js.map +1 -0
- package/dist/core/monitoring-manager.d.ts +32 -0
- package/dist/core/monitoring-manager.d.ts.map +1 -0
- package/dist/core/monitoring-manager.js +296 -0
- package/dist/core/monitoring-manager.js.map +1 -0
- package/dist/core/process-manager.d.ts +105 -0
- package/dist/core/process-manager.d.ts.map +1 -0
- package/dist/core/process-manager.js +1374 -0
- package/dist/core/process-manager.js.map +1 -0
- package/dist/core/realtime-stream-subscriber.d.ts +93 -0
- package/dist/core/realtime-stream-subscriber.d.ts.map +1 -0
- package/dist/core/realtime-stream-subscriber.js +200 -0
- package/dist/core/realtime-stream-subscriber.js.map +1 -0
- package/dist/core/remote-http-client.d.ts +15 -0
- package/dist/core/remote-http-client.d.ts.map +1 -0
- package/dist/core/remote-http-client.js +60 -0
- package/dist/core/remote-http-client.js.map +1 -0
- package/dist/core/remote-process-service.d.ts +50 -0
- package/dist/core/remote-process-service.d.ts.map +1 -0
- package/dist/core/remote-process-service.js +20 -0
- package/dist/core/remote-process-service.js.map +1 -0
- package/dist/core/server-manager.d.ts +71 -0
- package/dist/core/server-manager.d.ts.map +1 -0
- package/dist/core/server-manager.js +680 -0
- package/dist/core/server-manager.js.map +1 -0
- package/dist/core/stream-publisher.d.ts +75 -0
- package/dist/core/stream-publisher.d.ts.map +1 -0
- package/dist/core/stream-publisher.js +127 -0
- package/dist/core/stream-publisher.js.map +1 -0
- package/dist/core/streaming-pipeline-reader.d.ts +67 -0
- package/dist/core/streaming-pipeline-reader.d.ts.map +1 -0
- package/dist/core/streaming-pipeline-reader.js +191 -0
- package/dist/core/streaming-pipeline-reader.js.map +1 -0
- package/dist/core/terminal-manager.d.ts +96 -0
- package/dist/core/terminal-manager.d.ts.map +1 -0
- package/dist/core/terminal-manager.js +515 -0
- package/dist/core/terminal-manager.js.map +1 -0
- package/dist/daemon/server.d.ts +8 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +416 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/uds-transport.d.ts +31 -0
- package/dist/daemon/uds-transport.d.ts.map +1 -0
- package/dist/daemon/uds-transport.js +149 -0
- package/dist/daemon/uds-transport.js.map +1 -0
- package/dist/executor/server.d.ts +20 -0
- package/dist/executor/server.d.ts.map +1 -0
- package/dist/executor/server.js +375 -0
- package/dist/executor/server.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/daemon-runtime.d.ts +4 -0
- package/dist/runtime/daemon-runtime.d.ts.map +1 -0
- package/dist/runtime/daemon-runtime.js +4 -0
- package/dist/runtime/daemon-runtime.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/tool-runtime.d.ts +52 -0
- package/dist/runtime/tool-runtime.d.ts.map +1 -0
- package/dist/runtime/tool-runtime.js +161 -0
- package/dist/runtime/tool-runtime.js.map +1 -0
- package/dist/security/chat-completion-adapter.d.ts +443 -0
- package/dist/security/chat-completion-adapter.d.ts.map +1 -0
- package/dist/security/chat-completion-adapter.js +475 -0
- package/dist/security/chat-completion-adapter.js.map +1 -0
- package/dist/security/enhanced-evaluator.d.ts +139 -0
- package/dist/security/enhanced-evaluator.d.ts.map +1 -0
- package/dist/security/enhanced-evaluator.js +1208 -0
- package/dist/security/enhanced-evaluator.js.map +1 -0
- package/dist/security/evaluator-types.d.ts +614 -0
- package/dist/security/evaluator-types.d.ts.map +1 -0
- package/dist/security/evaluator-types.js +124 -0
- package/dist/security/evaluator-types.js.map +1 -0
- package/dist/security/manager.d.ts +76 -0
- package/dist/security/manager.d.ts.map +1 -0
- package/dist/security/manager.js +445 -0
- package/dist/security/manager.js.map +1 -0
- package/dist/security/security-llm-prompt-generator.d.ts +105 -0
- package/dist/security/security-llm-prompt-generator.d.ts.map +1 -0
- package/dist/security/security-llm-prompt-generator.js +323 -0
- package/dist/security/security-llm-prompt-generator.js.map +1 -0
- package/dist/security/security-tools.d.ts +174 -0
- package/dist/security/security-tools.d.ts.map +1 -0
- package/dist/security/security-tools.js +159 -0
- package/dist/security/security-tools.js.map +1 -0
- package/dist/security/validator-criteria-manager.d.ts +47 -0
- package/dist/security/validator-criteria-manager.d.ts.map +1 -0
- package/dist/security/validator-criteria-manager.js +169 -0
- package/dist/security/validator-criteria-manager.js.map +1 -0
- package/dist/tools/shell-tools.d.ts +474 -0
- package/dist/tools/shell-tools.d.ts.map +1 -0
- package/dist/tools/shell-tools.js +861 -0
- package/dist/tools/shell-tools.js.map +1 -0
- package/dist/types/enhanced-security.d.ts +529 -0
- package/dist/types/enhanced-security.d.ts.map +1 -0
- package/dist/types/enhanced-security.js +286 -0
- package/dist/types/enhanced-security.js.map +1 -0
- package/dist/types/index.d.ts +282 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +158 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/quick-schemas.d.ts +177 -0
- package/dist/types/quick-schemas.d.ts.map +1 -0
- package/dist/types/quick-schemas.js +113 -0
- package/dist/types/quick-schemas.js.map +1 -0
- package/dist/types/response-schemas.d.ts +41 -0
- package/dist/types/response-schemas.d.ts.map +1 -0
- package/dist/types/response-schemas.js +41 -0
- package/dist/types/response-schemas.js.map +1 -0
- package/dist/types/schemas.d.ts +578 -0
- package/dist/types/schemas.d.ts.map +1 -0
- package/dist/types/schemas.js +498 -0
- package/dist/types/schemas.js.map +1 -0
- package/dist/utils/criteria-manager.d.ts +47 -0
- package/dist/utils/criteria-manager.d.ts.map +1 -0
- package/dist/utils/criteria-manager.js +228 -0
- package/dist/utils/criteria-manager.js.map +1 -0
- package/dist/utils/errors.d.ts +27 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +67 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/helpers.d.ts +85 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +400 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/json-repair.d.ts +23 -0
- package/dist/utils/json-repair.d.ts.map +1 -0
- package/dist/utils/json-repair.js +208 -0
- package/dist/utils/json-repair.js.map +1 -0
- package/dist/utils/process-utils.d.ts +31 -0
- package/dist/utils/process-utils.d.ts.map +1 -0
- package/dist/utils/process-utils.js +217 -0
- package/dist/utils/process-utils.js.map +1 -0
- package/dist/utils/server-helpers.d.ts +4 -0
- package/dist/utils/server-helpers.d.ts.map +1 -0
- package/dist/utils/server-helpers.js +10 -0
- package/dist/utils/server-helpers.js.map +1 -0
- package/dist/utils/sse.d.ts +2 -0
- package/dist/utils/sse.d.ts.map +1 -0
- package/dist/utils/sse.js +6 -0
- package/dist/utils/sse.js.map +1 -0
- 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
|