Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cli/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ protected function getDefaultCommands(): array
$defaultCommands[] = new LocalCommand\ConfigureCommand();
$defaultCommands[] = new LocalCommand\ProjectsCommand();
$defaultCommands[] = new LocalCommand\SelfUpdateCommand();
$defaultCommands[] = new LocalCommand\GenerateLLMInputCommand();

return $defaultCommands;
}
Expand Down
110 changes: 110 additions & 0 deletions Cli/Command/GenerateLLMInputCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

/*
* This file is part of the SymfonyInsight package.
*
* (c) Symfony <support@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SensioLabs\Insight\Cli\Command;

use SensioLabs\Insight\Cli\Helper\DescriptorHelper;
use SensioLabs\Insight\Sdk\Model\Analysis;
use SensioLabs\Insight\Sdk\Model\Violation;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class GenerateLLMInputCommand extends Command implements NeedConfigurationInterface
{
protected function configure(): void
{
$this
->setName('generate-llm-input')
->addArgument('project-uuid', InputArgument::REQUIRED)
->addOption('with-security-violations', null, InputOption::VALUE_NONE, 'Include security violations')
->addOption('show-ignored-violations', null, InputOption::VALUE_NONE, 'Show ignored violations')
->setDescription('Generate a LLM-ready prompt based on the last analysis of a project')
;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);

$projectUuid = $input->getArgument('project-uuid');

try {
$api = $this->getApplication()->getApi();

/** @var Analysis $analysis */
$analysis = $api->getProject($projectUuid)->getLastAnalysis();

if (!$analysis) {
$io->writeln('<error>There are no analyses</error>');

return Command::FAILURE;
}

$violations = $analysis->getViolations();

if (!$violations || 0 === $violations->count()) {
$io->writeln('<info>No violations found in the last analysis.</info>');

return Command::SUCCESS;
}

if (!$input->getOption('show-ignored-violations')) {
$violations->filter(function (Violation $violation) {
return !$violation->isIgnored();
});
}

$includeSecurity = false;

if ($input->getOption('with-security-violations')) {
$io->warning([
'Using the --with-security-violations option will expose the security vulnerabilities of your application in the prompt.',
'Make sure you do not share it with any public or untrusted agent.',
]);

$includeSecurity = $io->confirm('Do you really want to include these in the prompt?', false);
}

if (!$includeSecurity) {
$violations->filter(function (Violation $violation) {
return 'security' !== $violation->getCategory();
});
}

if (0 === $violations->count()) {
$io->writeln('<info>No violations found after applying filters.</info>');

return Command::SUCCESS;
}

if (!file_exists($promptTemplatePath = __DIR__.'/../Resources/prompt.md')) {
throw new \RuntimeException("Prompt template not found at: $promptTemplatePath");
}

if (($instructions = file_get_contents($promptTemplatePath)) === false) {
throw new \RuntimeException('Failed to read prompt template');
}

$output->writeln($instructions);
(new DescriptorHelper($api->getSerializer()))->describe($output, $analysis, 'md', true);

return Command::SUCCESS;
} catch (\Exception $e) {
$io->writeln(sprintf('<error>Error: %s</error>', $e->getMessage()));

return Command::FAILURE;
}
}
}
4 changes: 2 additions & 2 deletions Cli/Descriptor/JsonDescriptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

namespace SensioLabs\Insight\Cli\Descriptor;

use JMS\Serializer\Serializer;
use JMS\Serializer\SerializerInterface;
use SensioLabs\Insight\Sdk\Model\Analysis;

class JsonDescriptor extends AbstractDescriptor
{
private $serializer;

public function __construct(Serializer $serializer)
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
Expand Down
41 changes: 41 additions & 0 deletions Cli/Descriptor/MarkdownDescriptor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace SensioLabs\Insight\Cli\Descriptor;

use SensioLabs\Insight\Sdk\Model\Analysis;
use SensioLabs\Insight\Sdk\Model\Violation;

class MarkdownDescriptor extends AbstractDescriptor
{
protected function describeAnalysis(Analysis $argument, array $options = [])
{
$lines = [
'| Title | Category | Severity | Message | File | Line |',
'|-------|----------|----------|---------|------|------|',
];

foreach ($argument->getViolations() as $violation) {
$lines[] = $this->buildRow($violation);
}

$table = implode("\n", $lines);
$options['output']->writeln($table);
}

private function buildRow(Violation $violation): string
{
$title = $this->escape($violation->getTitle() ?? $violation->getMessage() ?? 'N/A');
$category = $violation->getCategory() ?? 'N/A';
$severity = $violation->getSeverity() ?? 'N/A';
$message = $this->escape($violation->getMessage() ?? 'N/A');
$file = \is_string($violation->getResource()) ? $violation->getResource() : 'N/A';
$line = $violation->getLine() ?: 'N/A';

return sprintf('| %s | %s | %s | %s | %s | %s |', $title, $category, $severity, $message, $file, $line);
}

private function escape(string $text): string
{
return str_replace(['|', "\r", "\n"], ['/', ' ', ' '], $text);
}
}
4 changes: 2 additions & 2 deletions Cli/Descriptor/XmlDescriptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

namespace SensioLabs\Insight\Cli\Descriptor;

use JMS\Serializer\Serializer;
use JMS\Serializer\SerializerInterface;
use SensioLabs\Insight\Sdk\Model\Analysis;

class XmlDescriptor extends AbstractDescriptor
{
private $serializer;

public function __construct(Serializer $serializer)
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
Expand Down
6 changes: 4 additions & 2 deletions Cli/Helper/DescriptorHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@

namespace SensioLabs\Insight\Cli\Helper;

use JMS\Serializer\Serializer;
use JMS\Serializer\SerializerInterface;
use SensioLabs\Insight\Cli\Descriptor\AbstractDescriptor;
use SensioLabs\Insight\Cli\Descriptor\JsonDescriptor;
use SensioLabs\Insight\Cli\Descriptor\MarkdownDescriptor;
use SensioLabs\Insight\Cli\Descriptor\PmdDescriptor;
use SensioLabs\Insight\Cli\Descriptor\TextDescriptor;
use SensioLabs\Insight\Cli\Descriptor\XmlDescriptor;
Expand All @@ -24,13 +25,14 @@ class DescriptorHelper extends Helper
{
private $descriptors = [];

public function __construct(Serializer $serializer)
public function __construct(SerializerInterface $serializer)
{
$this
->register('json', new JsonDescriptor($serializer))
->register('pmd', new PmdDescriptor())
->register('txt', new TextDescriptor())
->register('xml', new XmlDescriptor($serializer))
->register('md', new MarkdownDescriptor())
;
}

Expand Down
124 changes: 124 additions & 0 deletions Cli/Resources/prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Symfony Insight Report Analysis & Resolution Guide

You are a Symfony and PHP expert specialized in analyzing Symfony Insight reports and providing actionable solutions following current Symfony LTS best practices and modern PHP standards.

## Context

Symfony Insight analyzes projects across multiple dimensions:
- **Security**: Vulnerabilities, outdated dependencies, unsafe practices
- **Performance**: Inefficient code patterns, missing optimizations, caching issues
- **Best Practices**: Symfony conventions, code organization, configuration
- **Bugs**: Deprecated code, potential runtime errors, type inconsistencies
- **Code Quality**: Complexity, maintainability, SOLID principles adherence
- **Architecture**: Service configuration, dependency injection, design patterns

## Your Task

Analyze the provided Symfony Insight report and deliver solutions respecting:

1. **Current Standards**
- Use syntax and features compatible with the current Symfony LTS and its minimum required PHP version
- Apply modern PHP type declarations (union types, return types, property types)
- Follow Symfony coding standards and conventions
- Respect PSR-12 coding style
- Maintain dependency inversion principle
- Ensure proper separation of concerns
- Keep code testable and maintainable
- Avoid unnecessary complexity

2. **Prioritization**
- Address issues by severity (critical → major → minor)
- Security vulnerabilities take absolute priority
- Group related issues for coherent refactoring

## Response Format

### For Chat/Conversational Context (without code access)

For each issue, provide:

```
### [SEVERITY] Issue Title
**Category**: Security/Performance/Best Practices/Bugs/Quality/Architecture
**File**: path/to/file.php (if available)
**Priority**: Critical/High/Medium/Low

**Problem Description**:
Clear explanation of what's wrong and why it matters

**Impact**:
- Consequences if not fixed
- Related risks or technical debt

**Solution Strategy**:
Step-by-step approach to resolve the issue

**Code Example**:
```php
// ❌ Current problematic pattern
class Example {
// Bad implementation
}

// ✅ Recommended solution
class Example {
// Good implementation following current standards
}
```

**Additional Considerations**:
- Migration path if breaking changes
- Testing recommendations
- Related documentation
```

### For IDE-Integrated Context (with code access)

For each issue, provide ready-to-apply fixes as diffs:

```diff
--- a/src/Path/To/File.php
+++ b/src/Path/To/File.php
@@ -10,8 +10,10 @@

-// Problematic code
+// Fixed code following current Symfony LTS standards
+// Inline comment only if clarification is needed for complex changes
```

**Key principles for diffs**:
- Minimal, focused changes addressing the specific issue
- Preserve existing code style and conventions
- Include inline comments only when the fix rationale isn't obvious
- Ensure changes are immediately applicable without breaking existing functionality
- Respect the project's namespace structure and service configuration

## Analysis Workflow

1. **Parse the report** and extract all violations
2. **Group issues** by severity and category
3. **Identify dependencies** between issues (some fixes may resolve multiple problems)
4. **Generate solutions** respecting the context (chat vs IDE)
5. **Provide summary** with overall recommendations and prioritized action plan

## Important Guidelines

- **Never add features not requested** - fix only what's reported
- **Respect existing conventions** - match the project's coding style
- **Maintain backward compatibility** when possible - flag breaking changes clearly
- **Ensure testability** - all fixes should allow for unit/integration testing
- **Use proper Symfony services** - leverage the framework's capabilities
- **Follow DI best practices** - constructor injection, interface type-hints
- **Avoid complexity** - simplest solution that properly addresses the issue

## Symfony Insight Report to Analyze

**IMPORTANT**: Analyze the report provided below and immediately deliver solutions following the guidelines above.

**Delivery Mode**:
- If this is a chat/conversational context (ChatGPT, Claude, etc.): Provide detailed explanations with code examples
- If this is an IDE-integrated context (Cursor, GitHub Copilot, etc.): Provide ready-to-apply diffs

**Start your analysis immediately below this line.**

---
Loading