Compare commits

...

4 Commits

Author SHA1 Message Date
Matthieu
73ebd6902d chore(release) : bump version to 1.9.3
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:17:39 +01:00
Matthieu
ded1f7a8b6 chore(submodule) : update frontend pointer (comment attachments + fixes)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:10:41 +01:00
Matthieu
3b35598b07 fix(structure) : stabilize piece/component/product ordering in machines
All findBy(['machine' => ...]) queries now sort by createdAt ASC.
Without explicit ORDER BY, PostgreSQL returned rows in heap order which
changed on every INSERT, causing the displayed order to shuffle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:02:36 +01:00
Matthieu
06ce9fb1f2 chore(config) : update reference.php + remove disabled config files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:49:59 +01:00
8 changed files with 57 additions and 50 deletions

View File

@@ -1 +1 @@
1.9.1
1.9.3

View File

@@ -1,20 +0,0 @@
mcp:
app: 'inventory'
version: '1.0.0'
description: 'Inventory MCP Server - Gestion inventaire industriel (machines, pièces, composants, produits)'
instructions: |
Serveur MCP pour gérer un inventaire industriel.
Entités principales : Machine, Composant, Pièce, Produit, Site, Constructeur.
Utilisez search_inventory pour chercher dans toutes les entités.
Utilisez get_model_type pour comprendre la structure attendue avant de créer un composant ou une pièce.
Consultez la resource inventory://schema/entities pour voir le schéma complet.
Authentification requise : envoyez X-Profile-Id et X-Profile-Password dans les headers HTTP.
client_transports:
stdio: true
http: true
http:
path: /_mcp
session:
store: file
directory: '%kernel.cache_dir%/mcp-sessions'
ttl: 3600

View File

@@ -1,6 +0,0 @@
framework:
rate_limiter:
mcp_auth:
policy: sliding_window
limit: 5
interval: '1 minute'

View File

@@ -1,7 +1,5 @@
<?php
declare(strict_types=1);
// This file is auto-generated and is for apps only. Bundles SHOULD NOT rely on its content.
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
@@ -624,7 +622,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* }>,
* },
* rate_limiter?: bool|array{ // Rate limiter configuration
* enabled?: bool|Param, // Default: false
* enabled?: bool|Param, // Default: true
* limiters?: array<string, array{ // Default: []
* lock_factory?: scalar|null|Param, // The service ID of the lock factory used by this limiter (or null to disable locking). // Default: "auto"
* cache_pool?: scalar|null|Param, // The cache pool to use for storing the current limiter state. // Default: "cache.rate_limiter"
@@ -1387,7 +1385,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* mercure?: bool|array{
* enabled?: bool|Param, // Default: false
* hub_url?: scalar|null|Param, // The URL sent in the Link HTTP header. If not set, will default to the URL for MercureBundle's default hub. // Default: null
* include_type?: bool|Param, // Always include @var in updates (including delete ones). // Default: false
* include_type?: bool|Param, // Always include @type in updates (including delete ones). // Default: false
* },
* messenger?: bool|array{
* enabled?: bool|Param, // Default: false
@@ -1614,6 +1612,37 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* enable_static_query_cache?: bool|Param, // Default: true
* connection_keys?: list<mixed>,
* }
* @psalm-type McpConfig = array{
* app?: scalar|null|Param, // Default: "app"
* version?: scalar|null|Param, // Default: "0.0.1"
* description?: scalar|null|Param, // Default: null
* icons?: list<array{ // Default: []
* src: scalar|null|Param,
* mime_type?: scalar|null|Param, // Default: null
* sizes?: list<scalar|null|Param>,
* }>,
* website_url?: scalar|null|Param, // Default: null
* pagination_limit?: int|Param, // Default: 50
* instructions?: scalar|null|Param, // Default: null
* client_transports?: array{
* stdio?: bool|Param, // Default: false
* http?: bool|Param, // Default: false
* },
* discovery?: array{
* scan_dirs?: list<scalar|null|Param>,
* exclude_dirs?: list<scalar|null|Param>,
* },
* http?: array{
* path?: scalar|null|Param, // Default: "/_mcp"
* session?: array{
* store?: "file"|"memory"|"cache"|Param, // Default: "file"
* directory?: scalar|null|Param, // Default: "%kernel.cache_dir%/mcp-sessions"
* cache_pool?: scalar|null|Param, // Default: "cache.mcp.sessions"
* prefix?: scalar|null|Param, // Default: "mcp-"
* ttl?: int|Param, // Default: 3600
* },
* },
* }
* @psalm-type ConfigType = array{
* imports?: ImportsConfig,
* parameters?: ParametersConfig,
@@ -1626,6 +1655,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* nelmio_cors?: NelmioCorsConfig,
* api_platform?: ApiPlatformConfig,
* lexik_jwt_authentication?: LexikJwtAuthenticationConfig,
* mcp?: McpConfig,
* "when@dev"?: array{
* imports?: ImportsConfig,
* parameters?: ParametersConfig,
@@ -1638,6 +1668,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* nelmio_cors?: NelmioCorsConfig,
* api_platform?: ApiPlatformConfig,
* lexik_jwt_authentication?: LexikJwtAuthenticationConfig,
* mcp?: McpConfig,
* },
* "when@prod"?: array{
* imports?: ImportsConfig,
@@ -1651,6 +1682,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* nelmio_cors?: NelmioCorsConfig,
* api_platform?: ApiPlatformConfig,
* lexik_jwt_authentication?: LexikJwtAuthenticationConfig,
* mcp?: McpConfig,
* },
* "when@test"?: array{
* imports?: ImportsConfig,
@@ -1665,6 +1697,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* api_platform?: ApiPlatformConfig,
* lexik_jwt_authentication?: LexikJwtAuthenticationConfig,
* dama_doctrine_test?: DamaDoctrineTestConfig,
* mcp?: McpConfig,
* },
* ...<string, ExtensionType|array{ // extra keys must follow the when@%env% pattern or match an extension alias
* imports?: ImportsConfig,

View File

@@ -53,9 +53,9 @@ class MachineStructureController extends AbstractController
return $this->json(['success' => false, 'error' => 'Machine not found.'], 404);
}
$componentLinks = $this->machineComponentLinkRepository->findBy(['machine' => $machine]);
$pieceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $machine]);
$productLinks = $this->machineProductLinkRepository->findBy(['machine' => $machine]);
$componentLinks = $this->machineComponentLinkRepository->findBy(['machine' => $machine], ['createdAt' => 'ASC']);
$pieceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $machine], ['createdAt' => 'ASC']);
$productLinks = $this->machineProductLinkRepository->findBy(['machine' => $machine], ['createdAt' => 'ASC']);
return $this->json($this->normalizeStructureResponse(
$machine,
@@ -159,9 +159,9 @@ class MachineStructureController extends AbstractController
$this->entityManager->flush();
$componentLinks = $this->machineComponentLinkRepository->findBy(['machine' => $newMachine]);
$pieceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $newMachine]);
$productLinks = $this->machineProductLinkRepository->findBy(['machine' => $newMachine]);
$componentLinks = $this->machineComponentLinkRepository->findBy(['machine' => $newMachine], ['createdAt' => 'ASC']);
$pieceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $newMachine], ['createdAt' => 'ASC']);
$productLinks = $this->machineProductLinkRepository->findBy(['machine' => $newMachine], ['createdAt' => 'ASC']);
return $this->json($this->normalizeStructureResponse(
$newMachine,
@@ -209,7 +209,7 @@ class MachineStructureController extends AbstractController
*/
private function cloneComponentLinks(Machine $source, Machine $target): array
{
$sourceLinks = $this->machineComponentLinkRepository->findBy(['machine' => $source]);
$sourceLinks = $this->machineComponentLinkRepository->findBy(['machine' => $source], ['createdAt' => 'ASC']);
$linkMap = [];
// First pass: create all links without parent relationships
@@ -242,7 +242,7 @@ class MachineStructureController extends AbstractController
*/
private function clonePieceLinks(Machine $source, Machine $target, array $componentLinkMap): array
{
$sourceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $source]);
$sourceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $source], ['createdAt' => 'ASC']);
$linkMap = [];
foreach ($sourceLinks as $link) {
@@ -276,7 +276,7 @@ class MachineStructureController extends AbstractController
array $componentLinkMap,
array $pieceLinkMap,
): void {
$sourceLinks = $this->machineProductLinkRepository->findBy(['machine' => $source]);
$sourceLinks = $this->machineProductLinkRepository->findBy(['machine' => $source], ['createdAt' => 'ASC']);
$linkMap = [];
// First pass: create all links
@@ -319,7 +319,7 @@ class MachineStructureController extends AbstractController
private function applyComponentLinks(Machine $machine, array $payload): array|JsonResponse
{
$existing = $this->indexLinksById($this->machineComponentLinkRepository->findBy(['machine' => $machine]));
$existing = $this->indexLinksById($this->machineComponentLinkRepository->findBy(['machine' => $machine], ['createdAt' => 'ASC']));
$keepIds = [];
$pendingParents = [];
$links = [];
@@ -376,7 +376,7 @@ class MachineStructureController extends AbstractController
private function applyPieceLinks(Machine $machine, array $payload, array $componentLinks): array|JsonResponse
{
$existing = $this->indexLinksById($this->machinePieceLinkRepository->findBy(['machine' => $machine]));
$existing = $this->indexLinksById($this->machinePieceLinkRepository->findBy(['machine' => $machine], ['createdAt' => 'ASC']));
$componentIndex = $this->indexLinksById($componentLinks);
$keepIds = [];
$pendingParents = [];
@@ -443,7 +443,7 @@ class MachineStructureController extends AbstractController
array $componentLinks,
array $pieceLinks,
): array|JsonResponse {
$existing = $this->indexLinksById($this->machineProductLinkRepository->findBy(['machine' => $machine]));
$existing = $this->indexLinksById($this->machineProductLinkRepository->findBy(['machine' => $machine], ['createdAt' => 'ASC']));
$componentIndex = $this->indexLinksById($componentLinks);
$pieceIndex = $this->indexLinksById($pieceLinks);
$keepIds = [];

View File

@@ -123,7 +123,7 @@ class CloneMachineTool
*/
private function cloneComponentLinks(Machine $source, Machine $target): array
{
$sourceLinks = $this->machineComponentLinkRepository->findBy(['machine' => $source]);
$sourceLinks = $this->machineComponentLinkRepository->findBy(['machine' => $source], ['createdAt' => 'ASC']);
$linkMap = [];
// First pass: create all links without parent relationships
@@ -156,7 +156,7 @@ class CloneMachineTool
*/
private function clonePieceLinks(Machine $source, Machine $target, array $componentLinkMap): array
{
$sourceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $source]);
$sourceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $source], ['createdAt' => 'ASC']);
$linkMap = [];
foreach ($sourceLinks as $link) {
@@ -190,7 +190,7 @@ class CloneMachineTool
array $componentLinkMap,
array $pieceLinkMap,
): void {
$sourceLinks = $this->machineProductLinkRepository->findBy(['machine' => $source]);
$sourceLinks = $this->machineProductLinkRepository->findBy(['machine' => $source], ['createdAt' => 'ASC']);
$linkMap = [];
// First pass: create all links

View File

@@ -46,9 +46,9 @@ class MachineStructureTool
$this->mcpError('not_found', "Machine not found: {$machineId}");
}
$componentLinks = $this->machineComponentLinkRepository->findBy(['machine' => $machine]);
$pieceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $machine]);
$productLinks = $this->machineProductLinkRepository->findBy(['machine' => $machine]);
$componentLinks = $this->machineComponentLinkRepository->findBy(['machine' => $machine], ['createdAt' => 'ASC']);
$pieceLinks = $this->machinePieceLinkRepository->findBy(['machine' => $machine], ['createdAt' => 'ASC']);
$productLinks = $this->machineProductLinkRepository->findBy(['machine' => $machine], ['createdAt' => 'ASC']);
return $this->jsonResponse($this->normalizeStructureResponse(
$machine,