agentic-api 2.0.314 → 2.0.491
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/dist/src/agents/prompts.d.ts +1 -1
- package/dist/src/agents/prompts.js +9 -7
- package/dist/src/agents/simulator.d.ts +7 -3
- package/dist/src/agents/simulator.executor.d.ts +9 -3
- package/dist/src/agents/simulator.executor.js +43 -17
- package/dist/src/agents/simulator.js +47 -19
- package/dist/src/agents/simulator.prompts.d.ts +9 -8
- package/dist/src/agents/simulator.prompts.js +68 -62
- package/dist/src/agents/simulator.types.d.ts +4 -1
- package/dist/src/agents/simulator.utils.js +0 -2
- package/dist/src/execute/helpers.d.ts +75 -0
- package/dist/src/execute/helpers.js +139 -0
- package/dist/src/execute/index.d.ts +11 -0
- package/dist/src/execute/index.js +44 -0
- package/dist/src/execute/legacy.d.ts +46 -0
- package/dist/src/{execute.js → execute/legacy.js} +130 -232
- package/dist/src/execute/modelconfig.d.ts +19 -0
- package/dist/src/execute/modelconfig.js +56 -0
- package/dist/src/execute/responses.d.ts +55 -0
- package/dist/src/execute/responses.js +594 -0
- package/dist/src/execute/shared.d.ts +83 -0
- package/dist/src/execute/shared.js +188 -0
- package/dist/src/index.js +1 -1
- package/dist/src/pricing.llm.d.ts +1 -1
- package/dist/src/pricing.llm.js +39 -18
- package/dist/src/rag/embeddings.js +8 -2
- package/dist/src/rag/rag.manager.js +27 -15
- package/dist/src/rules/git/git.e2e.helper.js +21 -2
- package/dist/src/rules/git/git.health.d.ts +4 -2
- package/dist/src/rules/git/git.health.js +58 -16
- package/dist/src/rules/git/index.d.ts +1 -1
- package/dist/src/rules/git/index.js +3 -2
- package/dist/src/rules/git/repo.d.ts +46 -3
- package/dist/src/rules/git/repo.js +264 -23
- package/dist/src/rules/git/repo.pr.js +117 -13
- package/dist/src/rules/types.d.ts +11 -0
- package/dist/src/rules/utils.matter.js +16 -7
- package/dist/src/scrapper.js +1 -0
- package/dist/src/stategraph/stategraph.d.ts +26 -1
- package/dist/src/stategraph/stategraph.js +43 -2
- package/dist/src/stategraph/stategraph.storage.js +4 -0
- package/dist/src/stategraph/types.d.ts +5 -0
- package/dist/src/types.d.ts +42 -7
- package/dist/src/types.js +8 -7
- package/dist/src/usecase.js +1 -1
- package/dist/src/utils.js +28 -4
- package/package.json +9 -7
- package/dist/src/execute.d.ts +0 -63
|
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.
|
|
18
|
-
exports.gitNewPR = void 0;
|
|
17
|
+
exports.gitGetNextPRNumber = exports.gitClosePRRobust = exports.gitClosePR = exports.gitPRUpdateComments = exports.gitLoadPR = exports.gitGetClosedPRs = exports.gitGetAllPR = exports.gitGetPRMetadata = exports.gitIsPRClosedRobust = exports.gitIsPRClosed = exports.gitSyncPR = exports.gitIDRegistryRename = exports.gitIDRegistryExists = exports.gitFileStrictMatter = exports.gitEnsureMatterID = exports.gitRegisterExistingID = exports.gitReloadIDRegistry = exports.gitGenerateNextID = exports.gitDeleteFile = exports.gitRenameFile = exports.gitEditFile = exports.gitCreateOrEditFile = exports.gitGetValidationBranchHealth = exports.gitGetBranchHealth = exports.gitCheckConfiguration = exports.gitShowConfiguration = exports.gitSetupRepository = exports.gitEnsureRemoteConfiguration = exports.gitEnsureRepositoryConfiguration = exports.gitInit = exports.gitDeleteNote = exports.gitWriteNote = exports.gitReadNote = exports.gitGetDiffFiles = exports.gitGetAllBranches = exports.gitGetUnmergedBranchesForFile = exports.gitReadFileOutsideRepo = exports.gitGetFileHistory = exports.gitGetFilePreview = exports.gitGetFileContent = exports.gitGetFilesSummary = exports.gitFileExistsInBranch = exports.gitListFilesOutsideRepo = exports.gitListFilesInBranch = exports.gitLastCommit = exports.gitIsFileMerged = exports.isValidInt = exports.gitLoad = exports.unlock = exports.lock = void 0;
|
|
18
|
+
exports.gitNewPR = exports.gitNewValidationRequest = void 0;
|
|
19
19
|
// === OPÉRATIONS GIT BAS NIVEAU ===
|
|
20
20
|
// Fonctions atomiques pour manipuler Git directement
|
|
21
21
|
var repo_tools_1 = require("./repo.tools");
|
|
@@ -53,6 +53,7 @@ Object.defineProperty(exports, "gitSetupRepository", { enumerable: true, get: fu
|
|
|
53
53
|
Object.defineProperty(exports, "gitShowConfiguration", { enumerable: true, get: function () { return repo_1.gitShowConfiguration; } });
|
|
54
54
|
Object.defineProperty(exports, "gitCheckConfiguration", { enumerable: true, get: function () { return repo_1.gitCheckConfiguration; } });
|
|
55
55
|
Object.defineProperty(exports, "gitGetBranchHealth", { enumerable: true, get: function () { return repo_1.gitGetBranchHealth; } });
|
|
56
|
+
Object.defineProperty(exports, "gitGetValidationBranchHealth", { enumerable: true, get: function () { return repo_1.gitGetValidationBranchHealth; } });
|
|
56
57
|
Object.defineProperty(exports, "gitCreateOrEditFile", { enumerable: true, get: function () { return repo_1.gitCreateOrEditFile; } });
|
|
57
58
|
Object.defineProperty(exports, "gitEditFile", { enumerable: true, get: function () { return repo_1.gitEditFile; } });
|
|
58
59
|
Object.defineProperty(exports, "gitRenameFile", { enumerable: true, get: function () { return repo_1.gitRenameFile; } });
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { SimpleGit } from 'simple-git';
|
|
2
2
|
import { RulesGitConfig, GitCommitHistory, RuleUser, GitHealthStatus } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Structure du cache matter pour un fichier
|
|
5
|
+
*/
|
|
6
|
+
interface MatterStrict {
|
|
7
|
+
id?: number;
|
|
8
|
+
title?: string;
|
|
9
|
+
service?: string;
|
|
10
|
+
oldfile?: string;
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* Vérifie si le fichier de registre d'IDs existe dans le repository Git
|
|
5
14
|
*
|
|
@@ -52,7 +61,7 @@ export declare function gitReloadIDRegistry(config?: RulesGitConfig): void;
|
|
|
52
61
|
/**
|
|
53
62
|
* Enregistre un ID existant dans le registre
|
|
54
63
|
*
|
|
55
|
-
* @param
|
|
64
|
+
* @param matter Le matter contenant l'ID à enregistrer
|
|
56
65
|
* @param branch Branche du fichier (optionnel, pour vérification de propriété)
|
|
57
66
|
* @param file Nom du fichier (optionnel, pour vérification de propriété)
|
|
58
67
|
* @param config Configuration Git optionnelle
|
|
@@ -60,8 +69,11 @@ export declare function gitReloadIDRegistry(config?: RulesGitConfig): void;
|
|
|
60
69
|
*
|
|
61
70
|
* **Note:** Si `branch` et `file` sont fournis, la fonction vérifie si l'ID appartient
|
|
62
71
|
* déjà au même fichier. Si oui, aucune erreur n'est levée (cas de re-scan).
|
|
72
|
+
*
|
|
73
|
+
* **Note:** `setMatterCache()` est appelé automatiquement avant l'enregistrement
|
|
74
|
+
* pour garantir la cohérence du cache.
|
|
63
75
|
*/
|
|
64
|
-
export declare function gitRegisterExistingID(
|
|
76
|
+
export declare function gitRegisterExistingID(matter: MatterStrict, branch?: string, file?: string, config?: RulesGitConfig): void;
|
|
65
77
|
/**
|
|
66
78
|
* Renomme un fichier dans le cache du registre d'IDs
|
|
67
79
|
*
|
|
@@ -84,11 +96,18 @@ export declare function gitRegisterExistingID(id: number, branch?: string, file?
|
|
|
84
96
|
export declare function gitIDRegistryRename(oldFile: string, newFile: string, branch: string, config?: RulesGitConfig): void;
|
|
85
97
|
/**
|
|
86
98
|
* Valide et assure qu'un matter a un ID valide
|
|
99
|
+
*
|
|
100
|
+
* **Principe d'identité stable**: Un fichier conserve son ID à travers les branches.
|
|
101
|
+
* Cette fonction cherche d'abord si le fichier a déjà un ID dans le registre
|
|
102
|
+
* (peu importe la branche), et le réutilise pour garantir la cohérence.
|
|
103
|
+
*
|
|
87
104
|
* @param matter Le matter à valider/compléter
|
|
88
105
|
* @param config Configuration Git optionnelle
|
|
106
|
+
* @param branch Branche du fichier (optionnel, peut être undefined lors de createPullRequest)
|
|
107
|
+
* @param file Nom du fichier (requis pour chercher l'ID existant)
|
|
89
108
|
* @returns Le matter mis à jour avec un ID valide
|
|
90
109
|
*/
|
|
91
|
-
export declare function gitEnsureMatterID(matter:
|
|
110
|
+
export declare function gitEnsureMatterID(matter: MatterStrict, config?: RulesGitConfig, branch?: string, file?: string): any;
|
|
92
111
|
/**
|
|
93
112
|
* Lecture rapide et stricte du matter d'un fichier (id + title uniquement)
|
|
94
113
|
*
|
|
@@ -243,3 +262,27 @@ export declare function gitDeleteFile(git: SimpleGit, filePath: string, branch:
|
|
|
243
262
|
* @returns Promise<GitHealthStatus> Diagnostic complet avec liste des problèmes et recommandations de réparation
|
|
244
263
|
*/
|
|
245
264
|
export declare function gitGetBranchHealth(git: SimpleGit, branch?: string): Promise<GitHealthStatus>;
|
|
265
|
+
/**
|
|
266
|
+
* Version optimisée de gitGetBranchHealth pour les branches de validation
|
|
267
|
+
*
|
|
268
|
+
* Cette fonction utilise une approche en cascade pour diagnostiquer rapidement
|
|
269
|
+
* l'état d'une branche de validation sans effectuer de checkout coûteux.
|
|
270
|
+
*
|
|
271
|
+
* Tests effectués dans l'ordre (arrêt au premier échec) :
|
|
272
|
+
* 1. Branche existe ? (git rev-parse --verify)
|
|
273
|
+
* 2. Note Git présente sur HEAD ? (gitReadNote avec maxCommit=1)
|
|
274
|
+
* 3. Note correspond au bon PR ? (note.id === prNumber)
|
|
275
|
+
*
|
|
276
|
+
* Avantages :
|
|
277
|
+
* - ✅ Pas de checkout (gain 80-90% performance)
|
|
278
|
+
* - ✅ Lecture directe du HEAD sans changer de branche
|
|
279
|
+
* - ✅ Tests cascade (arrêt dès qu'un problème est détecté)
|
|
280
|
+
* - ✅ Optimisé pour branches temporaires (validations)
|
|
281
|
+
*
|
|
282
|
+
* @param git Instance SimpleGit
|
|
283
|
+
* @param branch Nom de la branche de validation à diagnostiquer
|
|
284
|
+
* @param config Configuration Git optionnelle
|
|
285
|
+
* @returns GitHealthStatus avec diagnostic optimisé
|
|
286
|
+
*/
|
|
287
|
+
export declare function gitGetValidationBranchHealth(git: SimpleGit, branch: string, config?: RulesGitConfig): Promise<GitHealthStatus>;
|
|
288
|
+
export {};
|
|
@@ -53,6 +53,7 @@ exports.gitRenameFile_fs = gitRenameFile_fs;
|
|
|
53
53
|
exports.gitRenameFile = gitRenameFile;
|
|
54
54
|
exports.gitDeleteFile = gitDeleteFile;
|
|
55
55
|
exports.gitGetBranchHealth = gitGetBranchHealth;
|
|
56
|
+
exports.gitGetValidationBranchHealth = gitGetValidationBranchHealth;
|
|
56
57
|
const fs_1 = require("fs");
|
|
57
58
|
const errors_1 = require("../errors");
|
|
58
59
|
const path_1 = require("path");
|
|
@@ -70,16 +71,32 @@ class IDRegistryService {
|
|
|
70
71
|
static get() {
|
|
71
72
|
return IDRegistryService.instance || (IDRegistryService.instance = new IDRegistryService());
|
|
72
73
|
}
|
|
74
|
+
toString() {
|
|
75
|
+
return JSON.stringify(this.registry, null, 2);
|
|
76
|
+
}
|
|
77
|
+
clear() {
|
|
78
|
+
this.registry = null;
|
|
79
|
+
this.repoPath = '';
|
|
80
|
+
this.isDirty = false;
|
|
81
|
+
}
|
|
73
82
|
/**
|
|
74
83
|
* Initialise le service avec le chemin du repository
|
|
75
84
|
*/
|
|
76
85
|
init(repoPath) {
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (this.repoPath !== repoPath || !this.registry) {
|
|
86
|
+
// ✅ BUGFIX: Toujours mettre à jour repoPath même si le registre existe déjà
|
|
87
|
+
// Car gitReloadIDRegistry peut être appelé avec un nouveau repoPath pour un nouveau test
|
|
88
|
+
// et le repo précédent peut avoir été nettoyé
|
|
89
|
+
if (this.repoPath !== repoPath) {
|
|
82
90
|
this.repoPath = repoPath;
|
|
91
|
+
// Si le registre existe déjà, le recharger depuis le nouveau chemin
|
|
92
|
+
if (this.registry) {
|
|
93
|
+
this.registry = this.loadFromDisk();
|
|
94
|
+
this.isDirty = false;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Si le registre n'existe pas encore, le créer
|
|
99
|
+
if (!this.registry) {
|
|
83
100
|
this.registry = this.loadFromDisk();
|
|
84
101
|
this.isDirty = false;
|
|
85
102
|
}
|
|
@@ -172,16 +189,64 @@ class IDRegistryService {
|
|
|
172
189
|
this.isDirty = true;
|
|
173
190
|
return newID;
|
|
174
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Obtient l'ID d'un fichier (peu importe la branche)
|
|
194
|
+
*
|
|
195
|
+
* Un fichier a UN SEUL ID quelque soit la branche où il se trouve.
|
|
196
|
+
* Cette fonction cherche le fichier dans toutes les branches du cache.
|
|
197
|
+
*
|
|
198
|
+
* @param file Nom du fichier (ex: 'procedure.md')
|
|
199
|
+
* @returns L'ID du fichier ou undefined si le fichier n'a pas d'ID
|
|
200
|
+
*/
|
|
201
|
+
getFileID(file) {
|
|
202
|
+
if (!this.registry) {
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
// Chercher le fichier dans toutes les branches
|
|
206
|
+
for (const [cacheKey, matter] of Object.entries(this.registry.matters)) {
|
|
207
|
+
const [, cachedFile] = cacheKey.split(':');
|
|
208
|
+
if (cachedFile === file) {
|
|
209
|
+
return matter.id;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
175
214
|
/**
|
|
176
215
|
* Vérifie si un ID appartient déjà à un fichier spécifique
|
|
216
|
+
*
|
|
217
|
+
* Un fichier garde son ID peu importe la branche, donc cette fonction
|
|
218
|
+
* cherche dans toutes les branches pour vérifier la propriété.
|
|
219
|
+
*
|
|
220
|
+
* @param id L'ID à vérifier
|
|
221
|
+
* @param file Nom du fichier
|
|
222
|
+
* @returns true si ce fichier possède cet ID
|
|
177
223
|
*/
|
|
178
|
-
isIDOwnedByFile(id,
|
|
224
|
+
isIDOwnedByFile(id, file) {
|
|
179
225
|
if (!this.registry) {
|
|
180
226
|
return false;
|
|
181
227
|
}
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
return
|
|
228
|
+
// Chercher le fichier dans toutes les branches
|
|
229
|
+
const fileID = this.getFileID(file);
|
|
230
|
+
return fileID === id;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Trouve quel fichier possède un ID donné
|
|
234
|
+
*
|
|
235
|
+
* @param id L'ID à chercher
|
|
236
|
+
* @returns Le nom du fichier qui possède cet ID, ou undefined
|
|
237
|
+
*/
|
|
238
|
+
getFileByID(id) {
|
|
239
|
+
if (!this.registry) {
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
// Chercher l'ID dans le cache
|
|
243
|
+
for (const [cacheKey, matter] of Object.entries(this.registry.matters)) {
|
|
244
|
+
if (matter.id === id) {
|
|
245
|
+
const [, file] = cacheKey.split(':');
|
|
246
|
+
return file;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return undefined;
|
|
185
250
|
}
|
|
186
251
|
/**
|
|
187
252
|
* Enregistre un ID existant
|
|
@@ -198,7 +263,8 @@ class IDRegistryService {
|
|
|
198
263
|
// Si l'ID est déjà utilisé
|
|
199
264
|
if (this.registry.used.includes(id)) {
|
|
200
265
|
// Vérifier si c'est le même fichier (pas un doublon)
|
|
201
|
-
|
|
266
|
+
// Note: isIDOwnedByFile() cherche maintenant dans TOUTES les branches
|
|
267
|
+
if (file && this.isIDOwnedByFile(id, file)) {
|
|
202
268
|
// Même fichier → OK, pas d'erreur
|
|
203
269
|
return;
|
|
204
270
|
}
|
|
@@ -212,6 +278,10 @@ class IDRegistryService {
|
|
|
212
278
|
if (id > this.registry.last) {
|
|
213
279
|
this.registry.last = id;
|
|
214
280
|
}
|
|
281
|
+
// ⚠️ IMPORTANT: Ne PAS créer d'entrée dans matters ici
|
|
282
|
+
// setMatterCache() DOIT être appelé AVANT registerExistingID() par l'appelant
|
|
283
|
+
// car registerExistingID() n'a pas le contexte complet (title, service)
|
|
284
|
+
// Si branch/file sont fournis mais que le cache n'existe pas, c'est une erreur de programmation
|
|
215
285
|
this.isDirty = true;
|
|
216
286
|
}
|
|
217
287
|
/**
|
|
@@ -348,6 +418,9 @@ function gitGenerateNextID(config) {
|
|
|
348
418
|
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
349
419
|
idRegistryService.init(gitConf.repoPath);
|
|
350
420
|
const newID = idRegistryService.generateNextID();
|
|
421
|
+
// FIXME: Double save - gitGenerateNextID() et gitRegisterExistingID() appellent tous deux save()
|
|
422
|
+
// Refactorisation future: Retirer save() d'ici et le faire uniquement dans gitRegisterExistingID()
|
|
423
|
+
// quand matter est fourni (processus atomique: generate → setCache → register → save)
|
|
351
424
|
idRegistryService.save();
|
|
352
425
|
return newID;
|
|
353
426
|
}
|
|
@@ -370,13 +443,16 @@ function gitGenerateNextID(config) {
|
|
|
370
443
|
*/
|
|
371
444
|
function gitReloadIDRegistry(config) {
|
|
372
445
|
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
446
|
+
if (config?.reset) {
|
|
447
|
+
idRegistryService.clear();
|
|
448
|
+
}
|
|
373
449
|
idRegistryService.init(gitConf.repoPath);
|
|
374
450
|
idRegistryService.forceReload();
|
|
375
451
|
}
|
|
376
452
|
/**
|
|
377
453
|
* Enregistre un ID existant dans le registre
|
|
378
454
|
*
|
|
379
|
-
* @param
|
|
455
|
+
* @param matter Le matter contenant l'ID à enregistrer
|
|
380
456
|
* @param branch Branche du fichier (optionnel, pour vérification de propriété)
|
|
381
457
|
* @param file Nom du fichier (optionnel, pour vérification de propriété)
|
|
382
458
|
* @param config Configuration Git optionnelle
|
|
@@ -384,11 +460,36 @@ function gitReloadIDRegistry(config) {
|
|
|
384
460
|
*
|
|
385
461
|
* **Note:** Si `branch` et `file` sont fournis, la fonction vérifie si l'ID appartient
|
|
386
462
|
* déjà au même fichier. Si oui, aucune erreur n'est levée (cas de re-scan).
|
|
463
|
+
*
|
|
464
|
+
* **Note:** `setMatterCache()` est appelé automatiquement avant l'enregistrement
|
|
465
|
+
* pour garantir la cohérence du cache.
|
|
387
466
|
*/
|
|
388
|
-
function gitRegisterExistingID(
|
|
467
|
+
function gitRegisterExistingID(matter, branch, file, config) {
|
|
389
468
|
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
390
469
|
idRegistryService.init(gitConf.repoPath);
|
|
391
|
-
|
|
470
|
+
// ✅ Validation: matter doit avoir id et title
|
|
471
|
+
if (!matter.id || !matter.title) {
|
|
472
|
+
throw new errors_1.GitOperationError('Le matter est invalide (id et title requis)', 'invalid_matter');
|
|
473
|
+
}
|
|
474
|
+
// ✅ IMPORTANT: Vérifier AVANT de mettre à jour le cache
|
|
475
|
+
// Si l'ID existe déjà, vérifier qu'il appartient au MÊME fichier
|
|
476
|
+
const registry = idRegistryService.getRegistry();
|
|
477
|
+
if (registry.used.includes(matter.id)) {
|
|
478
|
+
const ownerFile = idRegistryService.getFileByID(matter.id);
|
|
479
|
+
if (ownerFile && ownerFile !== file) {
|
|
480
|
+
// ID utilisé par un AUTRE fichier → Erreur
|
|
481
|
+
const error = new Error(`ID ${matter.id} est déjà utilisé`);
|
|
482
|
+
error.code = 'id_already_used';
|
|
483
|
+
throw error;
|
|
484
|
+
}
|
|
485
|
+
// Même fichier OU pas de fichier dans le cache → OK, continuer
|
|
486
|
+
}
|
|
487
|
+
// ✅ Mettre à jour le cache (maintenant qu'on sait que l'ID est valide)
|
|
488
|
+
if (branch && file) {
|
|
489
|
+
idRegistryService.setMatterCache(branch, file, matter);
|
|
490
|
+
}
|
|
491
|
+
// ✅ Enregistrer l'ID dans used[] si pas déjà dedans
|
|
492
|
+
idRegistryService.registerExistingID(matter.id, branch, file);
|
|
392
493
|
idRegistryService.save();
|
|
393
494
|
}
|
|
394
495
|
/**
|
|
@@ -418,25 +519,61 @@ function gitIDRegistryRename(oldFile, newFile, branch, config) {
|
|
|
418
519
|
}
|
|
419
520
|
/**
|
|
420
521
|
* Valide et assure qu'un matter a un ID valide
|
|
522
|
+
*
|
|
523
|
+
* **Principe d'identité stable**: Un fichier conserve son ID à travers les branches.
|
|
524
|
+
* Cette fonction cherche d'abord si le fichier a déjà un ID dans le registre
|
|
525
|
+
* (peu importe la branche), et le réutilise pour garantir la cohérence.
|
|
526
|
+
*
|
|
421
527
|
* @param matter Le matter à valider/compléter
|
|
422
528
|
* @param config Configuration Git optionnelle
|
|
529
|
+
* @param branch Branche du fichier (optionnel, peut être undefined lors de createPullRequest)
|
|
530
|
+
* @param file Nom du fichier (requis pour chercher l'ID existant)
|
|
423
531
|
* @returns Le matter mis à jour avec un ID valide
|
|
424
532
|
*/
|
|
425
|
-
function gitEnsureMatterID(matter, config) {
|
|
426
|
-
|
|
533
|
+
function gitEnsureMatterID(matter, config, branch, file) {
|
|
534
|
+
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
535
|
+
idRegistryService.init(gitConf.repoPath);
|
|
536
|
+
// ✅ NOUVEAU: Chercher d'abord l'ID existant du fichier (peu importe la branche)
|
|
537
|
+
const existingFileID = file ? idRegistryService.getFileID(file) : undefined;
|
|
538
|
+
if (existingFileID) {
|
|
539
|
+
// Le fichier a déjà un ID → le réutiliser pour garantir la cohérence
|
|
540
|
+
matter.id = existingFileID;
|
|
541
|
+
// Mettre à jour le cache si branch est définie (sinon ce sera fait plus tard)
|
|
542
|
+
if (branch && file && matter.title) {
|
|
543
|
+
idRegistryService.setMatterCache(branch, file, {
|
|
544
|
+
id: matter.id,
|
|
545
|
+
title: matter.title,
|
|
546
|
+
service: matter.service
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
return matter;
|
|
550
|
+
}
|
|
551
|
+
// Si matter a un ID fourni manuellement (ex: import ou test)
|
|
427
552
|
// FIXME 999 should be a constant in config
|
|
428
553
|
if (matter.id && typeof matter.id === 'number' && matter.id > 999) {
|
|
429
554
|
try {
|
|
430
|
-
//
|
|
431
|
-
gitRegisterExistingID(matter
|
|
555
|
+
// Essayer d'enregistrer cet ID
|
|
556
|
+
gitRegisterExistingID(matter, branch, file, config);
|
|
432
557
|
return matter;
|
|
433
558
|
}
|
|
434
559
|
catch (error) {
|
|
435
|
-
// ID déjà utilisé
|
|
560
|
+
// ID déjà utilisé par un AUTRE fichier → générer un nouveau
|
|
561
|
+
// (Si même fichier, registerExistingID ne lève pas d'erreur)
|
|
436
562
|
}
|
|
437
563
|
}
|
|
438
564
|
// Générer un nouvel ID
|
|
439
565
|
matter.id = gitGenerateNextID(config);
|
|
566
|
+
// FIXME: Double save ici - gitGenerateNextID() fait save() puis gitRegisterExistingID() fait save() aussi
|
|
567
|
+
// Refactorisation future: Retirer save() de gitGenerateNextID() et le faire uniquement dans gitRegisterExistingID()
|
|
568
|
+
// quand matter est fourni (processus atomique: generate → setCache → register → save)
|
|
569
|
+
// ✅ Mettre à jour le cache avec le nouvel ID (seulement si branch est définie)
|
|
570
|
+
if (branch && file && matter.title) {
|
|
571
|
+
idRegistryService.setMatterCache(branch, file, {
|
|
572
|
+
id: matter.id,
|
|
573
|
+
title: matter.title,
|
|
574
|
+
service: matter.service
|
|
575
|
+
});
|
|
576
|
+
}
|
|
440
577
|
return matter;
|
|
441
578
|
}
|
|
442
579
|
/**
|
|
@@ -887,19 +1024,48 @@ async function gitCreateOrEditFile(git, filePath, PR, content, user, config) {
|
|
|
887
1024
|
if (gitConf.strictID) {
|
|
888
1025
|
// Mode strict : valider que l'ID existe et est correct
|
|
889
1026
|
validateMatter(parsed.matter);
|
|
1027
|
+
// ✅ gitRegisterExistingID() appelle maintenant setMatterCache() automatiquement si matter est fourni
|
|
890
1028
|
// Enregistrer l'ID existant
|
|
891
1029
|
// ✅ Passer branch (PR) et file (filePath) pour vérifier propriété
|
|
892
|
-
gitRegisterExistingID(parsed.matter
|
|
1030
|
+
gitRegisterExistingID(parsed.matter, PR, filePath, gitConf);
|
|
893
1031
|
}
|
|
894
1032
|
else {
|
|
895
1033
|
// Mode permissif : générer l'ID si manquant
|
|
896
|
-
|
|
897
|
-
//
|
|
898
|
-
|
|
1034
|
+
// ✅ IMPORTANT: Ne PAS ré-assigner l'ID s'il est déjà valide
|
|
1035
|
+
// Le contenu a peut-être déjà été traité par gitEnsureMatterID() dans le caller
|
|
1036
|
+
const hasValidID = parsed.matter.id &&
|
|
1037
|
+
typeof parsed.matter.id === 'number' &&
|
|
1038
|
+
parsed.matter.id > 999;
|
|
1039
|
+
if (!hasValidID) {
|
|
1040
|
+
// Seulement si l'ID est manquant ou invalide
|
|
1041
|
+
parsed.matter = gitEnsureMatterID(parsed.matter, gitConf, PR, filePath);
|
|
1042
|
+
// Re-sérialiser avec l'ID mis à jour
|
|
1043
|
+
content = matterSerialize(parsed.content, parsed.matter);
|
|
1044
|
+
}
|
|
1045
|
+
else {
|
|
1046
|
+
// ✅ L'ID existe déjà : gitRegisterExistingID() appelle maintenant setMatterCache() automatiquement
|
|
1047
|
+
try {
|
|
1048
|
+
gitRegisterExistingID(parsed.matter, PR, filePath, gitConf);
|
|
1049
|
+
}
|
|
1050
|
+
catch (error) {
|
|
1051
|
+
// Si l'ID est déjà utilisé par un autre fichier, générer un nouvel ID
|
|
1052
|
+
if (error.code === 'id_already_used') {
|
|
1053
|
+
// En mode non-strict, générer un nouvel ID si doublon détecté
|
|
1054
|
+
parsed.matter = gitEnsureMatterID(parsed.matter, gitConf, PR, filePath);
|
|
1055
|
+
content = matterSerialize(parsed.content, parsed.matter);
|
|
1056
|
+
// ✅ Ne pas propager l'erreur, continuer avec le nouvel ID généré
|
|
1057
|
+
}
|
|
1058
|
+
else {
|
|
1059
|
+
throw error;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
899
1063
|
}
|
|
900
1064
|
}
|
|
901
1065
|
catch (error) {
|
|
902
|
-
|
|
1066
|
+
// En mode strict, propager l'erreur id_already_used
|
|
1067
|
+
// En mode permissif, cette erreur devrait déjà être gérée dans le bloc ci-dessus
|
|
1068
|
+
if (error.code === 'id_already_used' && gitConf.strictID) {
|
|
903
1069
|
throw new errors_1.GitOperationError(`Impossible de créer le fichier: ${error.message}`, 'duplicate_id', { filePath, error });
|
|
904
1070
|
}
|
|
905
1071
|
// Propager les autres erreurs de validation
|
|
@@ -1398,6 +1564,81 @@ async function gitGetBranchHealth(git, branch) {
|
|
|
1398
1564
|
(health.clean || (health.modifiedFiles === 0 && health.stagedFiles === 0));
|
|
1399
1565
|
return health;
|
|
1400
1566
|
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Version optimisée de gitGetBranchHealth pour les branches de validation
|
|
1569
|
+
*
|
|
1570
|
+
* Cette fonction utilise une approche en cascade pour diagnostiquer rapidement
|
|
1571
|
+
* l'état d'une branche de validation sans effectuer de checkout coûteux.
|
|
1572
|
+
*
|
|
1573
|
+
* Tests effectués dans l'ordre (arrêt au premier échec) :
|
|
1574
|
+
* 1. Branche existe ? (git rev-parse --verify)
|
|
1575
|
+
* 2. Note Git présente sur HEAD ? (gitReadNote avec maxCommit=1)
|
|
1576
|
+
* 3. Note correspond au bon PR ? (note.id === prNumber)
|
|
1577
|
+
*
|
|
1578
|
+
* Avantages :
|
|
1579
|
+
* - ✅ Pas de checkout (gain 80-90% performance)
|
|
1580
|
+
* - ✅ Lecture directe du HEAD sans changer de branche
|
|
1581
|
+
* - ✅ Tests cascade (arrêt dès qu'un problème est détecté)
|
|
1582
|
+
* - ✅ Optimisé pour branches temporaires (validations)
|
|
1583
|
+
*
|
|
1584
|
+
* @param git Instance SimpleGit
|
|
1585
|
+
* @param branch Nom de la branche de validation à diagnostiquer
|
|
1586
|
+
* @param config Configuration Git optionnelle
|
|
1587
|
+
* @returns GitHealthStatus avec diagnostic optimisé
|
|
1588
|
+
*/
|
|
1589
|
+
async function gitGetValidationBranchHealth(git, branch, config) {
|
|
1590
|
+
const gitConfig = config || (0, repo_tools_1.gitLoad)();
|
|
1591
|
+
const health = {
|
|
1592
|
+
branch,
|
|
1593
|
+
exists: false,
|
|
1594
|
+
accessible: false,
|
|
1595
|
+
clean: true, // Par défaut OK pour validation (pas de working dir check)
|
|
1596
|
+
mergeInProgress: false,
|
|
1597
|
+
conflictedFiles: 0,
|
|
1598
|
+
modifiedFiles: 0,
|
|
1599
|
+
untrackedFiles: 0,
|
|
1600
|
+
stagedFiles: 0,
|
|
1601
|
+
indexReadable: true,
|
|
1602
|
+
healthy: false,
|
|
1603
|
+
issues: [],
|
|
1604
|
+
recommendations: []
|
|
1605
|
+
};
|
|
1606
|
+
try {
|
|
1607
|
+
// 1. CASCADE: Vérifier existence (très rapide, sans checkout)
|
|
1608
|
+
const branchExists = await git.raw(['rev-parse', '--verify', branch])
|
|
1609
|
+
.then(() => true)
|
|
1610
|
+
.catch(() => false);
|
|
1611
|
+
if (!branchExists) {
|
|
1612
|
+
health.issues.push(`Branche '${branch}' n'existe pas`);
|
|
1613
|
+
health.recommendations.push(`Créer la branche ou vérifier le nom`);
|
|
1614
|
+
return health;
|
|
1615
|
+
}
|
|
1616
|
+
health.exists = true;
|
|
1617
|
+
health.accessible = true; // Si rev-parse OK, branche accessible
|
|
1618
|
+
// 2. CASCADE: Vérifier note sur HEAD (rapide, sans checkout)
|
|
1619
|
+
const headCommit = await git.raw(['rev-parse', branch]).then(s => s.trim());
|
|
1620
|
+
const note = await (0, repo_tools_1.gitReadNote)(git, headCommit, gitConfig.gitNotes.namespace, 1);
|
|
1621
|
+
if (!note) {
|
|
1622
|
+
health.issues.push(`Pas de note Git sur HEAD de '${branch}'`);
|
|
1623
|
+
health.recommendations.push(`Note perdue, utiliser git-notes-list-lost.sh pour la localiser`);
|
|
1624
|
+
return health;
|
|
1625
|
+
}
|
|
1626
|
+
// 3. CASCADE: Vérifier que la note correspond au PR
|
|
1627
|
+
const prNumber = parseInt(branch.split('-').pop() || '0', 10);
|
|
1628
|
+
if (note.id !== prNumber) {
|
|
1629
|
+
health.issues.push(`Note incorrecte: ID=${note.id}, attendu PR=${prNumber}`);
|
|
1630
|
+
health.recommendations.push(`Corriger la note ou supprimer la branche`);
|
|
1631
|
+
return health;
|
|
1632
|
+
}
|
|
1633
|
+
// ✅ Tous les tests essentiels passés
|
|
1634
|
+
health.healthy = true;
|
|
1635
|
+
}
|
|
1636
|
+
catch (error) {
|
|
1637
|
+
health.issues.push(`Erreur diagnostic: ${error.message}`);
|
|
1638
|
+
health.recommendations.push(`Vérifier l'état du dépôt Git`);
|
|
1639
|
+
}
|
|
1640
|
+
return health;
|
|
1641
|
+
}
|
|
1401
1642
|
/**
|
|
1402
1643
|
* Fonction helper pour créer un statut unhealthy
|
|
1403
1644
|
*/
|