Passed
Pull Request — 1.x (#334)
by Akihito
02:30
created

semanticProfileAndAnalyze()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 74
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 3
Metric Value
cc 4
eloc 38
c 3
b 1
f 3
nc 4
nop 1
dl 0
loc 74
rs 9.312

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
#!/usr/bin/env php
2
<?php
3
4
/**
5
 * Semantic Profiler MCP Server
6
 *
7
 * AI-powered performance analysis through structured semantic profiling.
8
 * Fulfilling the vision of Semantic Web - machines understanding meaning.
9
 */
10
11
declare(strict_types=1);
12
13
$logDirectory = $argv[1] ?? null;
14
15
if (! $logDirectory) {
16
    fwrite(STDERR, "Usage: php server.php <log-directory>\n");
17
    exit(1);
18
}
19
20
if (! is_dir($logDirectory)) {
21
    fwrite(STDERR, "Directory not found: $logDirectory\n");
22
    exit(1);
23
}
24
25
// Find the latest semantic log file
26
$pattern = rtrim($logDirectory, '/') . '/semantic-dev-*.json';
27
$files = glob($pattern);
28
29
if (empty($files)) {
30
    fwrite(STDERR, "No semantic log files found in directory: $logDirectory\n");
31
    exit(1);
32
}
33
34
// Sort by modification time, get the latest
35
usort($files, static fn ($a, $b) => filemtime($b) <=> filemtime($a));
36
$logFile = $files[0];
37
38
fwrite(STDERR, "Using latest log file: $logFile\n");
39
40
// Make log directory available globally for runAndAnalyze function
41
$GLOBALS['logDirectory'] = $logDirectory;
42
43
// Handle JSON-RPC requests from STDIN
44
while ($line = fgets(STDIN)) {
45
    $request = json_decode(trim($line), true);
46
47
    if (! $request) {
48
        continue;
49
    }
50
51
    $response = match ($request['method'] ?? '') {
52
        'initialize' => [
53
            'jsonrpc' => '2.0',
54
            'id' => $request['id'],
55
            'result' => [
56
                'protocolVersion' => '2024-11-05',
57
                'serverInfo' => ['name' => 'semantic-profiler', 'version' => '1.0.0'],
58
                'capabilities' => [
59
                    'tools' => (object) [],
60
                ],
61
            ],
62
        ],
63
        'tools/list' => [
64
            'jsonrpc' => '2.0',
65
            'id' => $request['id'],
66
            'result' => [
67
                'tools' => [
68
                    [
69
                        'name' => 'getSemanticProfile',
70
                        'description' => 'Retrieve latest semantic performance profile - structured data designed for AI understanding and insight generation',
71
                        'inputSchema' => [
72
                            'type' => 'object',
73
                            'properties' => (object) [],
74
                        ],
75
                    ],
76
                    [
77
                        'name' => 'semanticProfileAndAnalyze',
78
                        'description' => 'Execute PHP script with semantic profiling enabled, then automatically generate AI-powered performance insights and recommendations',
79
                        'inputSchema' => [
80
                            'type' => 'object',
81
                            'properties' => [
82
                                'script' => [
83
                                    'type' => 'string',
84
                                    'description' => 'Path to PHP script to execute',
85
                                ],
86
                                'xdebug_mode' => [
87
                                    'type' => 'string',
88
                                    'description' => 'Xdebug mode (default: trace)',
89
                                    'default' => 'trace',
90
                                ],
91
                            ],
92
                            'required' => ['script'],
93
                        ],
94
                    ],
95
                ],
96
            ],
97
        ],
98
        'tools/call' => [
99
            'jsonrpc' => '2.0',
100
            'id' => $request['id'],
101
            'result' => handleToolCall($request['params'], $logFile),
102
        ],
103
        default => [
104
            'jsonrpc' => '2.0',
105
            'id' => $request['id'] ?? null,
106
            'error' => ['code' => -32601, 'message' => 'Method not found'],
107
        ]
108
    };
109
110
    fwrite(STDOUT, json_encode($response) . "\n");
111
}
112
113
function getLog(string $file): array
114
{
115
    $content = file_get_contents($file);
116
117
    return json_decode($content, true) ?: ['error' => 'Invalid log format'];
118
}
119
120
function handleToolCall(array $params, string $logFile): array
121
{
122
    $toolName = $params['name'] ?? '';
123
124
    if ($toolName === 'getSemanticProfile') {
125
        $logData = getLog($logFile);
126
        $analysisPrompt = getAnalysisPrompt();
127
128
        return [
129
            'content' => [
130
                [
131
                    'type' => 'text',
132
                    'text' => $analysisPrompt . "\n\n```json\n" . json_encode($logData, JSON_PRETTY_PRINT) . "\n```",
133
                ],
134
            ],
135
            'isError' => false,
136
        ];
137
    }
138
139
    if ($toolName === 'semanticProfileAndAnalyze') {
140
        return semanticProfileAndAnalyze($params['arguments'] ?? []);
141
    }
142
143
    return [
144
        'content' => [
145
            [
146
                'type' => 'text',
147
                'text' => 'Unknown tool: ' . $toolName,
148
            ],
149
        ],
150
        'isError' => true,
151
    ];
152
}
153
154
function semanticProfileAndAnalyze(array $args): array
155
{
156
    $script = $args['script'] ?? '';
157
    $xdebugMode = $args['xdebug_mode'] ?? 'trace';
158
159
    if (! $script) {
160
        return [
161
            'content' => [
162
                [
163
                    'type' => 'text',
164
                    'text' => 'Error: script parameter is required',
165
                ],
166
            ],
167
            'isError' => true,
168
        ];
169
    }
170
171
    if (! file_exists($script)) {
172
        return [
173
            'content' => [
174
                [
175
                    'type' => 'text',
176
                    'text' => "Error: Script not found: $script",
177
                ],
178
            ],
179
            'isError' => true,
180
        ];
181
    }
182
183
    // Record time before execution to find newly created log files
184
    $beforeExecution = time();
185
186
    // Execute the PHP script with profiling using php-dev.ini
187
    $env = "XDEBUG_MODE=$xdebugMode XDEBUG_CONFIG='compression_level=0'";
188
    $phpDevIni = __DIR__ . '/php-dev.ini';
189
    $command = "$env php -c " . escapeshellarg($phpDevIni) . ' ' . escapeshellarg($script) . ' 2>&1';
190
191
    $output = shell_exec($command);
192
193
    // Find semantic log files created during script execution
194
    $logDirectory = $GLOBALS['logDirectory'];
195
    $pattern = rtrim($logDirectory, '/') . '/semantic-dev-*.json';
196
197
    $files = glob($pattern);
198
    $newLogFiles = array_filter($files, static fn ($file) => filemtime($file) >= $beforeExecution);
199
200
    if (empty($newLogFiles)) {
201
        return [
202
            'content' => [
203
                [
204
                    'type' => 'text',
205
                    'text' => "Script executed but no new semantic log generated.\nOutput:\n$output",
206
                ],
207
            ],
208
            'isError' => false,
209
        ];
210
    }
211
212
    // Get the newest log file from this execution
213
    usort($newLogFiles, static fn ($a, $b) => filemtime($b) <=> filemtime($a));
214
    $executionLog = $newLogFiles[0];
215
216
    // Load and return the log data with analysis prompt
217
    $logData = getLog($executionLog);
218
    $analysisPrompt = getAnalysisPrompt();
219
220
    return [
221
        'content' => [
222
            [
223
                'type' => 'text',
224
                'text' => "Script executed successfully.\nLog file: $executionLog\n\n" . $analysisPrompt . "\n\n```json\n" . json_encode($logData, JSON_PRETTY_PRINT) . "\n```",
225
            ],
226
        ],
227
        'isError' => false,
228
    ];
229
}
230
231
/**
232
 * Generate analysis prompt for AI-native semantic web processing
233
 */
234
function getAnalysisPrompt(): string
235
{
236
    return <<<'PROMPT'
237
This is a BEAR.Resource application profiling log. Analyze YOUR APPLICATION CODE performance, not the framework itself.
238
239
The log contains schemaUrl fields. If necessary, refer to these schemas to understand the semantic meaning of the data structures.
240
241
Focus on business logic within resource methods and application-specific code. Ignore framework overhead and profiling overhead.
242
243
If no performance issues are found, provide:
244
- What the code is doing (business purpose)
245
- How it's implemented (technical approach)
246
- Implementation assessment (is this approach appropriate for the task?)
247
- Any architectural observations or suggestions for production readiness
248
249
Use the semantic profiling data to provide deep insights about code quality and appropriateness, not just performance metrics.
250
PROMPT;
251
}
252