agentic-api 2.0.26 → 2.0.314
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/README.md +224 -60
- package/dist/src/agents/agents.example.js +21 -22
- package/dist/src/agents/authentication.js +1 -2
- package/dist/src/agents/prompts.d.ts +5 -4
- package/dist/src/agents/prompts.js +42 -87
- package/dist/src/agents/reducer.core.d.ts +24 -2
- package/dist/src/agents/reducer.core.js +125 -35
- package/dist/src/agents/reducer.loaders.d.ts +55 -1
- package/dist/src/agents/reducer.loaders.js +114 -1
- package/dist/src/agents/reducer.types.d.ts +45 -2
- package/dist/src/agents/semantic.js +1 -2
- package/dist/src/agents/simulator.d.ts +4 -0
- package/dist/src/agents/simulator.executor.d.ts +5 -1
- package/dist/src/agents/simulator.executor.js +41 -9
- package/dist/src/agents/simulator.js +86 -28
- package/dist/src/agents/simulator.prompts.d.ts +3 -2
- package/dist/src/agents/simulator.prompts.js +52 -78
- package/dist/src/agents/simulator.types.d.ts +20 -5
- package/dist/src/agents/simulator.utils.d.ts +7 -2
- package/dist/src/agents/simulator.utils.js +33 -11
- package/dist/src/agents/system.js +1 -2
- package/dist/src/execute.d.ts +17 -3
- package/dist/src/execute.js +156 -158
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/{princing.openai.d.ts → pricing.llm.d.ts} +6 -0
- package/dist/src/pricing.llm.js +234 -0
- package/dist/src/prompts.d.ts +13 -4
- package/dist/src/prompts.js +221 -114
- package/dist/src/rag/embeddings.d.ts +36 -18
- package/dist/src/rag/embeddings.js +125 -128
- package/dist/src/rag/index.d.ts +5 -5
- package/dist/src/rag/index.js +14 -17
- package/dist/src/rag/parser.d.ts +2 -1
- package/dist/src/rag/parser.js +11 -14
- package/dist/src/rag/rag.examples.d.ts +27 -0
- package/dist/src/rag/rag.examples.js +151 -0
- package/dist/src/rag/rag.manager.d.ts +383 -0
- package/dist/src/rag/rag.manager.js +1378 -0
- package/dist/src/rag/types.d.ts +128 -12
- package/dist/src/rag/types.js +100 -1
- package/dist/src/rag/usecase.d.ts +37 -0
- package/dist/src/rag/usecase.js +96 -7
- package/dist/src/rules/git/git.e2e.helper.js +1 -0
- package/dist/src/rules/git/git.health.d.ts +57 -0
- package/dist/src/rules/git/git.health.js +281 -1
- package/dist/src/rules/git/index.d.ts +2 -2
- package/dist/src/rules/git/index.js +12 -1
- package/dist/src/rules/git/repo.d.ts +117 -0
- package/dist/src/rules/git/repo.js +536 -0
- package/dist/src/rules/git/repo.tools.d.ts +22 -1
- package/dist/src/rules/git/repo.tools.js +50 -1
- package/dist/src/rules/types.d.ts +16 -14
- package/dist/src/rules/utils.matter.d.ts +0 -4
- package/dist/src/rules/utils.matter.js +26 -7
- package/dist/src/scrapper.d.ts +15 -22
- package/dist/src/scrapper.js +57 -110
- package/dist/src/stategraph/index.d.ts +1 -1
- package/dist/src/stategraph/stategraph.d.ts +31 -2
- package/dist/src/stategraph/stategraph.js +93 -6
- package/dist/src/stategraph/stategraph.storage.js +4 -0
- package/dist/src/stategraph/types.d.ts +22 -0
- package/dist/src/types.d.ts +4 -2
- package/dist/src/types.js +1 -1
- package/dist/src/usecase.d.ts +11 -2
- package/dist/src/usecase.js +27 -35
- package/dist/src/utils.d.ts +32 -18
- package/dist/src/utils.js +60 -126
- package/package.json +7 -2
- package/dist/src/agents/digestor.test.d.ts +0 -1
- package/dist/src/agents/digestor.test.js +0 -45
- package/dist/src/agents/reducer.example.d.ts +0 -28
- package/dist/src/agents/reducer.example.js +0 -118
- package/dist/src/agents/reducer.process.d.ts +0 -16
- package/dist/src/agents/reducer.process.js +0 -143
- package/dist/src/agents/reducer.tools.d.ts +0 -29
- package/dist/src/agents/reducer.tools.js +0 -157
- package/dist/src/agents/simpleExample.d.ts +0 -3
- package/dist/src/agents/simpleExample.js +0 -38
- package/dist/src/agents/system-review.d.ts +0 -5
- package/dist/src/agents/system-review.js +0 -181
- package/dist/src/agents/systemReview.d.ts +0 -4
- package/dist/src/agents/systemReview.js +0 -22
- package/dist/src/princing.openai.js +0 -54
- package/dist/src/rag/tools.d.ts +0 -76
- package/dist/src/rag/tools.js +0 -196
- package/dist/src/rules/user.mapper.d.ts +0 -61
- package/dist/src/rules/user.mapper.js +0 -160
- package/dist/src/rules/utils/slug.d.ts +0 -22
- package/dist/src/rules/utils/slug.js +0 -35
|
@@ -33,6 +33,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.gitIDRegistryExists = gitIDRegistryExists;
|
|
37
|
+
exports.gitGenerateNextID = gitGenerateNextID;
|
|
38
|
+
exports.gitReloadIDRegistry = gitReloadIDRegistry;
|
|
39
|
+
exports.gitRegisterExistingID = gitRegisterExistingID;
|
|
40
|
+
exports.gitIDRegistryRename = gitIDRegistryRename;
|
|
41
|
+
exports.gitEnsureMatterID = gitEnsureMatterID;
|
|
42
|
+
exports.gitFileStrictMatter = gitFileStrictMatter;
|
|
36
43
|
exports.gitEnsureRepositoryConfiguration = gitEnsureRepositoryConfiguration;
|
|
37
44
|
exports.gitEnsureRemoteConfiguration = gitEnsureRemoteConfiguration;
|
|
38
45
|
exports.gitInit = gitInit;
|
|
@@ -51,6 +58,486 @@ const errors_1 = require("../errors");
|
|
|
51
58
|
const path_1 = require("path");
|
|
52
59
|
const fs = __importStar(require("fs/promises"));
|
|
53
60
|
const repo_tools_1 = require("./repo.tools");
|
|
61
|
+
/**
|
|
62
|
+
* Service singleton pour gérer le registre d'IDs en mémoire
|
|
63
|
+
*/
|
|
64
|
+
class IDRegistryService {
|
|
65
|
+
constructor() {
|
|
66
|
+
this.registry = null;
|
|
67
|
+
this.repoPath = '';
|
|
68
|
+
this.isDirty = false;
|
|
69
|
+
}
|
|
70
|
+
static get() {
|
|
71
|
+
return IDRegistryService.instance || (IDRegistryService.instance = new IDRegistryService());
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Initialise le service avec le chemin du repository
|
|
75
|
+
*/
|
|
76
|
+
init(repoPath) {
|
|
77
|
+
// Skip if already initialized
|
|
78
|
+
if (this.registry) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (this.repoPath !== repoPath || !this.registry) {
|
|
82
|
+
this.repoPath = repoPath;
|
|
83
|
+
this.registry = this.loadFromDisk();
|
|
84
|
+
this.isDirty = false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Force le rechargement du registre depuis le disque
|
|
89
|
+
* Utilisé principalement pour les tests qui simulent un redémarrage
|
|
90
|
+
*/
|
|
91
|
+
forceReload() {
|
|
92
|
+
if (!this.repoPath) {
|
|
93
|
+
throw new Error('IDRegistryService not initialized. Call init() first.');
|
|
94
|
+
}
|
|
95
|
+
this.registry = this.loadFromDisk();
|
|
96
|
+
this.isDirty = false;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Charge le registre depuis le disque
|
|
100
|
+
*/
|
|
101
|
+
loadFromDisk() {
|
|
102
|
+
const registryPath = (0, path_1.join)(this.repoPath, '.git', 'with-ids.json');
|
|
103
|
+
if (!(0, fs_1.existsSync)(registryPath)) {
|
|
104
|
+
return {
|
|
105
|
+
last: 980,
|
|
106
|
+
used: [],
|
|
107
|
+
updated: new Date().toISOString(),
|
|
108
|
+
matters: {}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const data = JSON.parse((0, fs_1.readFileSync)(registryPath, 'utf8'));
|
|
113
|
+
// Migration : ajouter matters si absent (compatibilité anciens registres)
|
|
114
|
+
if (!data.matters) {
|
|
115
|
+
data.matters = {};
|
|
116
|
+
}
|
|
117
|
+
return data;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
console.warn('⚠️ Registre d\'IDs corrompu, création d\'un nouveau');
|
|
121
|
+
return {
|
|
122
|
+
last: 980,
|
|
123
|
+
used: [],
|
|
124
|
+
updated: new Date().toISOString(),
|
|
125
|
+
matters: {}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Sauvegarde le registre sur le disque (seulement si modifié)
|
|
131
|
+
*/
|
|
132
|
+
save() {
|
|
133
|
+
if (!this.registry || !this.isDirty) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const gitDir = (0, path_1.join)(this.repoPath, '.git');
|
|
137
|
+
const registryPath = (0, path_1.join)(gitDir, 'with-ids.json');
|
|
138
|
+
// S'assurer que le répertoire .git existe
|
|
139
|
+
if (!(0, fs_1.existsSync)(gitDir)) {
|
|
140
|
+
console.warn(`⚠️ Cannot save ID registry: .git directory not found at ${this.repoPath}`);
|
|
141
|
+
return; // Ne pas sauvegarder si le repo n'est pas initialisé
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
this.registry.updated = new Date().toISOString();
|
|
145
|
+
(0, fs_1.writeFileSync)(registryPath, JSON.stringify(this.registry, null, 2), 'utf8');
|
|
146
|
+
this.isDirty = false;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.warn(`⚠️ Failed to save ID registry:`, error);
|
|
150
|
+
// Ne pas propager l'erreur, le registre est une optimisation
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Récupère le registre (lecture seule)
|
|
155
|
+
*/
|
|
156
|
+
getRegistry() {
|
|
157
|
+
if (!this.registry) {
|
|
158
|
+
throw new Error('IDRegistryService not initialized. Call init() first.');
|
|
159
|
+
}
|
|
160
|
+
return this.registry;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Génère un nouvel ID unique
|
|
164
|
+
*/
|
|
165
|
+
generateNextID() {
|
|
166
|
+
if (!this.registry) {
|
|
167
|
+
throw new Error('IDRegistryService not initialized. Call init() first.');
|
|
168
|
+
}
|
|
169
|
+
const newID = this.registry.last + 20;
|
|
170
|
+
this.registry.last = newID;
|
|
171
|
+
this.registry.used.push(newID);
|
|
172
|
+
this.isDirty = true;
|
|
173
|
+
return newID;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Vérifie si un ID appartient déjà à un fichier spécifique
|
|
177
|
+
*/
|
|
178
|
+
isIDOwnedByFile(id, branch, file) {
|
|
179
|
+
if (!this.registry) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
const cacheKey = `${branch}:${file}`;
|
|
183
|
+
const cachedMatter = this.registry.matters[cacheKey];
|
|
184
|
+
return cachedMatter?.id === id;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Enregistre un ID existant
|
|
188
|
+
*
|
|
189
|
+
* @param id L'ID à enregistrer
|
|
190
|
+
* @param branch Branche du fichier (optionnel, pour vérification de propriété)
|
|
191
|
+
* @param file Nom du fichier (optionnel, pour vérification de propriété)
|
|
192
|
+
* @throws Error si l'ID est déjà utilisé par un autre fichier
|
|
193
|
+
*/
|
|
194
|
+
registerExistingID(id, branch, file) {
|
|
195
|
+
if (!this.registry) {
|
|
196
|
+
throw new Error('IDRegistryService not initialized. Call init() first.');
|
|
197
|
+
}
|
|
198
|
+
// Si l'ID est déjà utilisé
|
|
199
|
+
if (this.registry.used.includes(id)) {
|
|
200
|
+
// Vérifier si c'est le même fichier (pas un doublon)
|
|
201
|
+
if (branch && file && this.isIDOwnedByFile(id, branch, file)) {
|
|
202
|
+
// Même fichier → OK, pas d'erreur
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// ID utilisé par un autre fichier → Erreur
|
|
206
|
+
const error = new Error(`ID ${id} est déjà utilisé`);
|
|
207
|
+
error.code = 'id_already_used';
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
// Nouvel ID → Enregistrer
|
|
211
|
+
this.registry.used.push(id);
|
|
212
|
+
if (id > this.registry.last) {
|
|
213
|
+
this.registry.last = id;
|
|
214
|
+
}
|
|
215
|
+
this.isDirty = true;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Récupère un matter depuis le cache
|
|
219
|
+
* Note: Le champ 'updated' est filtré pour ne pas être exposé à l'extérieur
|
|
220
|
+
*/
|
|
221
|
+
getMatterCache(branch, file) {
|
|
222
|
+
if (!this.registry) {
|
|
223
|
+
throw new Error('IDRegistryService not initialized. Call init() first.');
|
|
224
|
+
}
|
|
225
|
+
const cacheKey = `${branch}:${file}`;
|
|
226
|
+
const cached = this.registry.matters[cacheKey];
|
|
227
|
+
if (!cached) {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
// Retourner uniquement les champs publics (sans 'updated')
|
|
231
|
+
return {
|
|
232
|
+
id: cached.id,
|
|
233
|
+
title: cached.title,
|
|
234
|
+
service: cached.service,
|
|
235
|
+
oldfile: cached.oldfile // FIXME (check if needed) ✅ Inclure oldfile temporaire si présent
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Met à jour le cache d'un matter
|
|
240
|
+
*/
|
|
241
|
+
setMatterCache(branch, file, matter) {
|
|
242
|
+
if (!this.registry) {
|
|
243
|
+
throw new Error('IDRegistryService not initialized. Call init() first.');
|
|
244
|
+
}
|
|
245
|
+
const cacheKey = `${branch}:${file}`;
|
|
246
|
+
this.registry.matters[cacheKey] = {
|
|
247
|
+
id: matter.id,
|
|
248
|
+
title: matter.title,
|
|
249
|
+
service: matter.service,
|
|
250
|
+
oldfile: matter.oldfile, // ✅ Inclure oldfile temporaire
|
|
251
|
+
updated: new Date().toISOString()
|
|
252
|
+
};
|
|
253
|
+
this.isDirty = true;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Supprime une entrée du cache
|
|
257
|
+
*/
|
|
258
|
+
deleteMatterCache(branch, file) {
|
|
259
|
+
if (!this.registry) {
|
|
260
|
+
throw new Error('IDRegistryService not initialized. Call init() first.');
|
|
261
|
+
}
|
|
262
|
+
const cacheKey = `${branch}:${file}`;
|
|
263
|
+
delete this.registry.matters[cacheKey];
|
|
264
|
+
this.isDirty = true;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Renomme une entrée dans le cache du registre
|
|
268
|
+
*
|
|
269
|
+
* Cette méthode gère le renommage d'un fichier dans le cache:
|
|
270
|
+
* - Supprime l'ancienne clé `${branch}:${oldFile}`
|
|
271
|
+
* - Crée une nouvelle clé `${branch}:${newFile}` avec les mêmes données
|
|
272
|
+
* - Préserve l'ID et les métadonnées
|
|
273
|
+
*
|
|
274
|
+
* @param oldFile Ancien nom du fichier
|
|
275
|
+
* @param newFile Nouveau nom du fichier
|
|
276
|
+
* @param branch Branche concernée
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```typescript
|
|
280
|
+
* // Après un rename Git
|
|
281
|
+
* idRegistryService.rename('old-name.md', 'new-name.md', 'rule-validation-1');
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
rename(oldFile, newFile, branch) {
|
|
285
|
+
if (!this.registry) {
|
|
286
|
+
throw new Error('IDRegistryService not initialized. Call init() first.');
|
|
287
|
+
}
|
|
288
|
+
const oldKey = `${branch}:${oldFile}`;
|
|
289
|
+
const newKey = `${branch}:${newFile}`;
|
|
290
|
+
// Récupérer le cache existant
|
|
291
|
+
const cached = this.registry.matters[oldKey];
|
|
292
|
+
if (!cached) {
|
|
293
|
+
// Pas de cache pour l'ancien fichier, rien à renommer
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
// Supprimer l'ancienne clé
|
|
297
|
+
delete this.registry.matters[oldKey];
|
|
298
|
+
//
|
|
299
|
+
// Créer la nouvelle clé avec les mêmes données
|
|
300
|
+
// ⚠️ NE PAS inclure oldfile - c'est temporaire uniquement pour notification client
|
|
301
|
+
this.registry.matters[newKey] = {
|
|
302
|
+
id: cached.id,
|
|
303
|
+
title: cached.title,
|
|
304
|
+
service: cached.service,
|
|
305
|
+
updated: new Date().toISOString()
|
|
306
|
+
};
|
|
307
|
+
this.isDirty = true;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
IDRegistryService.instance = null;
|
|
311
|
+
// ✅ Instance singleton du service
|
|
312
|
+
const idRegistryService = IDRegistryService.get();
|
|
313
|
+
/**
|
|
314
|
+
* Vérifie si le fichier de registre d'IDs existe dans le repository Git
|
|
315
|
+
*
|
|
316
|
+
* Cette fonction est utile pour détecter si le système d'ID natif a été initialisé
|
|
317
|
+
* dans le repository. Le fichier `with-ids.json` est créé automatiquement lors du
|
|
318
|
+
* premier appel à `gitGenerateNextID()` ou `gitEnsureMatterID()`.
|
|
319
|
+
*
|
|
320
|
+
* @param config Configuration Git optionnelle (utilise la config par défaut si non fournie)
|
|
321
|
+
* @returns `true` si le fichier `.git/with-ids.json` existe, `false` sinon
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* ```typescript
|
|
325
|
+
* const config = gitLoad({ repoPath: './my-repo' });
|
|
326
|
+
*
|
|
327
|
+
* if (gitIDRegistryExists(config)) {
|
|
328
|
+
* console.log('Le registre d\'IDs existe déjà');
|
|
329
|
+
* // On peut charger le registre existant
|
|
330
|
+
* gitReloadIDRegistry(config);
|
|
331
|
+
* } else {
|
|
332
|
+
* console.log('Première utilisation du système d\'IDs');
|
|
333
|
+
* // Le registre sera créé au premier gitGenerateNextID()
|
|
334
|
+
* }
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
function gitIDRegistryExists(config) {
|
|
338
|
+
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
339
|
+
const registryPath = (0, path_1.join)(gitConf.repoPath, '.git', 'with-ids.json');
|
|
340
|
+
return (0, fs_1.existsSync)(registryPath);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Génère un nouvel ID unique en incrémentant de +20
|
|
344
|
+
* @param config Configuration Git optionnelle
|
|
345
|
+
* @returns Un nouvel ID unique
|
|
346
|
+
*/
|
|
347
|
+
function gitGenerateNextID(config) {
|
|
348
|
+
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
349
|
+
idRegistryService.init(gitConf.repoPath);
|
|
350
|
+
const newID = idRegistryService.generateNextID();
|
|
351
|
+
idRegistryService.save();
|
|
352
|
+
return newID;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Force le rechargement du registre d'IDs depuis le disque
|
|
356
|
+
*
|
|
357
|
+
* **Utilisé principalement pour les tests qui simulent un redémarrage du serveur.**
|
|
358
|
+
*
|
|
359
|
+
* En production, cette fonction n'est pas nécessaire car le singleton est
|
|
360
|
+
* réinitialisé à chaque redémarrage du process Node.js.
|
|
361
|
+
*
|
|
362
|
+
* @param config Configuration Git optionnelle
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* ```typescript
|
|
366
|
+
* // Dans un test : simuler un redémarrage
|
|
367
|
+
* await gitCreateOrEditFile(...); // Modifie le registre
|
|
368
|
+
* gitReloadIDRegistry(); // Force le rechargement depuis le disque
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
function gitReloadIDRegistry(config) {
|
|
372
|
+
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
373
|
+
idRegistryService.init(gitConf.repoPath);
|
|
374
|
+
idRegistryService.forceReload();
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Enregistre un ID existant dans le registre
|
|
378
|
+
*
|
|
379
|
+
* @param id L'ID à enregistrer
|
|
380
|
+
* @param branch Branche du fichier (optionnel, pour vérification de propriété)
|
|
381
|
+
* @param file Nom du fichier (optionnel, pour vérification de propriété)
|
|
382
|
+
* @param config Configuration Git optionnelle
|
|
383
|
+
* @throws GitOperationError si l'ID est déjà utilisé par un autre fichier
|
|
384
|
+
*
|
|
385
|
+
* **Note:** Si `branch` et `file` sont fournis, la fonction vérifie si l'ID appartient
|
|
386
|
+
* déjà au même fichier. Si oui, aucune erreur n'est levée (cas de re-scan).
|
|
387
|
+
*/
|
|
388
|
+
function gitRegisterExistingID(id, branch, file, config) {
|
|
389
|
+
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
390
|
+
idRegistryService.init(gitConf.repoPath);
|
|
391
|
+
idRegistryService.registerExistingID(id, branch, file);
|
|
392
|
+
idRegistryService.save();
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Renomme un fichier dans le cache du registre d'IDs
|
|
396
|
+
*
|
|
397
|
+
* Cette fonction met à jour le cache lorsqu'un fichier est renommé:
|
|
398
|
+
* - Supprime l'entrée avec l'ancien nom
|
|
399
|
+
* - Crée une nouvelle entrée avec le nouveau nom
|
|
400
|
+
* - Préserve l'ID et les métadonnées
|
|
401
|
+
*
|
|
402
|
+
* @param oldFile Ancien nom du fichier
|
|
403
|
+
* @param newFile Nouveau nom du fichier
|
|
404
|
+
* @param branch Branche concernée
|
|
405
|
+
* @param config Configuration Git optionnelle
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* ```typescript
|
|
409
|
+
* // Après un rename dans Git
|
|
410
|
+
* gitIDRegistryRename('procedure-old.md', 'procedure-new.md', 'rule-validation-1');
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
function gitIDRegistryRename(oldFile, newFile, branch, config) {
|
|
414
|
+
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
415
|
+
idRegistryService.init(gitConf.repoPath);
|
|
416
|
+
idRegistryService.rename(oldFile, newFile, branch);
|
|
417
|
+
idRegistryService.save();
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Valide et assure qu'un matter a un ID valide
|
|
421
|
+
* @param matter Le matter à valider/compléter
|
|
422
|
+
* @param config Configuration Git optionnelle
|
|
423
|
+
* @returns Le matter mis à jour avec un ID valide
|
|
424
|
+
*/
|
|
425
|
+
function gitEnsureMatterID(matter, config) {
|
|
426
|
+
// Si ID existe et est valide
|
|
427
|
+
// FIXME 999 should be a constant in config
|
|
428
|
+
if (matter.id && typeof matter.id === 'number' && matter.id > 999) {
|
|
429
|
+
try {
|
|
430
|
+
// Pas de branch/file car utilisé pour nouveaux fichiers ou contexte inconnu
|
|
431
|
+
gitRegisterExistingID(matter.id, undefined, undefined, config);
|
|
432
|
+
return matter;
|
|
433
|
+
}
|
|
434
|
+
catch (error) {
|
|
435
|
+
// ID déjà utilisé → générer un nouveau (silencieux, géré par le caller)
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
// Générer un nouvel ID
|
|
439
|
+
matter.id = gitGenerateNextID(config);
|
|
440
|
+
return matter;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Valide le format du matter (ID et title obligatoires)
|
|
444
|
+
* @param matter Le matter à valider
|
|
445
|
+
* @throws GitOperationError si le matter est invalide
|
|
446
|
+
*/
|
|
447
|
+
function validateMatter(matter) {
|
|
448
|
+
if (!matter || typeof matter !== 'object') {
|
|
449
|
+
throw new errors_1.GitOperationError('Le matter est invalide', 'invalid_matter');
|
|
450
|
+
}
|
|
451
|
+
//
|
|
452
|
+
// ✅ FIX: Vérifier que l'ID existe et est un nombre
|
|
453
|
+
if (!matter.id || typeof matter.id !== 'number') {
|
|
454
|
+
throw new errors_1.GitOperationError('Le matter doit contenir un champ "id" de type number', 'missing_id', { matter });
|
|
455
|
+
}
|
|
456
|
+
if (matter.id <= 999) {
|
|
457
|
+
throw new errors_1.GitOperationError(`L'ID ${matter.id} est réservé (doit être >= 1000)`, 'invalid_id', { id: matter.id });
|
|
458
|
+
}
|
|
459
|
+
if (!matter.title || typeof matter.title !== 'string') {
|
|
460
|
+
throw new errors_1.GitOperationError('Le matter doit contenir un champ "title" de type string', 'missing_title', { matter });
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Extraction rapide du matter depuis une chaîne de contenu (helper interne)
|
|
465
|
+
* @internal
|
|
466
|
+
*/
|
|
467
|
+
function extractMatterFromContent(content) {
|
|
468
|
+
if (!content) {
|
|
469
|
+
return { id: 0, title: undefined, service: undefined, oldfile: undefined };
|
|
470
|
+
}
|
|
471
|
+
// Regex pour extraire id (format: "id: 1234" ou "id: '1234'")
|
|
472
|
+
const idMatch = content.match(/^id:\s*['"]?(\d+)['"]?/m);
|
|
473
|
+
const id = idMatch ? parseInt(idMatch[1], 10) : undefined;
|
|
474
|
+
// Regex pour extraire title (format: "title: Mon Titre" ou "title: 'Mon Titre'")
|
|
475
|
+
const titleMatch = content.match(/^title:\s*["']?([^"'\n]+)["']?/m);
|
|
476
|
+
const title = titleMatch ? titleMatch[1].trim() : undefined;
|
|
477
|
+
const serviceMatch = content.match(/^service:\s*["']?([^"'\n]+)["']?/m);
|
|
478
|
+
const service = serviceMatch ? serviceMatch[1].trim() : undefined;
|
|
479
|
+
//
|
|
480
|
+
// ✅ Extraction de oldfile (champ temporaire pour notifier les renames)
|
|
481
|
+
const oldfileMatch = content.match(/^oldfile:\s*["']?([^"'\n]+)["']?/m);
|
|
482
|
+
const oldfile = oldfileMatch ? oldfileMatch[1].trim() : undefined;
|
|
483
|
+
return { id, title, service, oldfile };
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Lecture rapide et stricte du matter d'un fichier (id + title uniquement)
|
|
487
|
+
*
|
|
488
|
+
* **Optimisation : Utilise le cache du registre d'IDs pour éviter de lire le fichier.**
|
|
489
|
+
*
|
|
490
|
+
* Cette fonction :
|
|
491
|
+
* 1. Vérifie d'abord le cache dans `.git/with-ids.json`
|
|
492
|
+
* 2. Si absent ou invalidé, lit le fichier avec regex (pas de parsing complet)
|
|
493
|
+
* 3. Met à jour le cache automatiquement
|
|
494
|
+
*
|
|
495
|
+
* @param git Instance SimpleGit
|
|
496
|
+
* @param filePath Chemin du fichier
|
|
497
|
+
* @param branch Nom de la branche
|
|
498
|
+
* @param config Configuration Git optionnelle
|
|
499
|
+
* @returns { id, title } ou { id: undefined, title: undefined } si absent
|
|
500
|
+
*
|
|
501
|
+
* @example
|
|
502
|
+
* ```typescript
|
|
503
|
+
* const matter = await gitFileStrictMatter(git, 'doc.md', 'main');
|
|
504
|
+
* console.log(matter.id); // 1234
|
|
505
|
+
* console.log(matter.title); // "Mon Document"
|
|
506
|
+
* ```
|
|
507
|
+
*/
|
|
508
|
+
async function gitFileStrictMatter(git, filePath, branch, config) {
|
|
509
|
+
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
510
|
+
idRegistryService.init(gitConf.repoPath);
|
|
511
|
+
try {
|
|
512
|
+
// ✅ ÉTAPE 1: Vérifier le cache
|
|
513
|
+
const cached = idRegistryService.getMatterCache(branch, filePath);
|
|
514
|
+
if (cached) {
|
|
515
|
+
// Cache trouvé, retourner directement
|
|
516
|
+
return {
|
|
517
|
+
id: cached.id,
|
|
518
|
+
title: cached.title,
|
|
519
|
+
oldfile: cached.oldfile // ✅ Inclure oldfile temporaire
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
// ❌ ÉTAPE 2: Cache absent, lire le fichier
|
|
523
|
+
const content = await git.show([`${branch}:${filePath}`]);
|
|
524
|
+
if (!content) {
|
|
525
|
+
return { id: undefined, title: undefined, oldfile: undefined };
|
|
526
|
+
}
|
|
527
|
+
// ✅ ÉTAPE 3: Extraction rapide avec regex (sans matterParse complet)
|
|
528
|
+
const matter = extractMatterFromContent(content);
|
|
529
|
+
// ✅ ÉTAPE 4: Mettre à jour le cache
|
|
530
|
+
idRegistryService.setMatterCache(branch, filePath, matter);
|
|
531
|
+
idRegistryService.save();
|
|
532
|
+
return matter;
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
if (gitConf.verbose) {
|
|
536
|
+
console.warn(`⚠️ Erreur lecture matter de ${filePath}:`, error);
|
|
537
|
+
}
|
|
538
|
+
return { id: undefined, title: undefined, oldfile: undefined };
|
|
539
|
+
}
|
|
540
|
+
}
|
|
54
541
|
/**
|
|
55
542
|
* Vérifie et configure un repository Git existant pour s'assurer qu'il a la configuration requise
|
|
56
543
|
* @param git Instance SimpleGit
|
|
@@ -391,6 +878,35 @@ async function gitCreateOrEditFile(git, filePath, PR, content, user, config) {
|
|
|
391
878
|
let currentBranch;
|
|
392
879
|
try {
|
|
393
880
|
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
881
|
+
// ===== VALIDATION DES IDs (si activée) =====
|
|
882
|
+
if (gitConf.withID) {
|
|
883
|
+
try {
|
|
884
|
+
// Import dynamique pour éviter les dépendances circulaires
|
|
885
|
+
const { matterParse, matterSerialize } = await Promise.resolve().then(() => __importStar(require('../utils.matter')));
|
|
886
|
+
const parsed = matterParse(content);
|
|
887
|
+
if (gitConf.strictID) {
|
|
888
|
+
// Mode strict : valider que l'ID existe et est correct
|
|
889
|
+
validateMatter(parsed.matter);
|
|
890
|
+
// Enregistrer l'ID existant
|
|
891
|
+
// ✅ Passer branch (PR) et file (filePath) pour vérifier propriété
|
|
892
|
+
gitRegisterExistingID(parsed.matter.id, PR, filePath, gitConf);
|
|
893
|
+
}
|
|
894
|
+
else {
|
|
895
|
+
// Mode permissif : générer l'ID si manquant
|
|
896
|
+
parsed.matter = gitEnsureMatterID(parsed.matter, gitConf);
|
|
897
|
+
// Re-sérialiser avec l'ID mis à jour
|
|
898
|
+
content = matterSerialize(parsed.content, parsed.matter);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
catch (error) {
|
|
902
|
+
if (error.code === 'id_already_used') {
|
|
903
|
+
throw new errors_1.GitOperationError(`Impossible de créer le fichier: ${error.message}`, 'duplicate_id', { filePath, error });
|
|
904
|
+
}
|
|
905
|
+
// Propager les autres erreurs de validation
|
|
906
|
+
throw error;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
// ===== FIN VALIDATION IDs =====
|
|
394
910
|
//
|
|
395
911
|
// secure main and draft branches (on production)
|
|
396
912
|
if (!gitConf?.canForce && PR == gitConf.mainBranch) {
|
|
@@ -408,6 +924,26 @@ async function gitCreateOrEditFile(git, filePath, PR, content, user, config) {
|
|
|
408
924
|
// without note the branche is not a valid PR branch
|
|
409
925
|
const oldNote = await (0, repo_tools_1.gitReadNote)(git, PR, gitConf.gitNotes.namespace, 10);
|
|
410
926
|
const commit = await _writeFileAndCommit(git, filePath, content, user, gitConf, `commit: ${filePath}`);
|
|
927
|
+
// ✅ Mettre à jour le cache du matter après sauvegarde
|
|
928
|
+
// NOTE: Le cache est TOUJOURS mis à jour, indépendamment de withID
|
|
929
|
+
// C'est une opération de cache, pas une validation
|
|
930
|
+
try {
|
|
931
|
+
const { matterParse } = await Promise.resolve().then(() => __importStar(require('../utils.matter')));
|
|
932
|
+
const parsed = matterParse(content);
|
|
933
|
+
idRegistryService.init(gitConf.repoPath);
|
|
934
|
+
idRegistryService.setMatterCache(PR, filePath, {
|
|
935
|
+
id: parsed.matter.id,
|
|
936
|
+
title: parsed.matter.title
|
|
937
|
+
// ⚠️ Ne PAS persister oldfile dans le cache - temporaire uniquement pour client
|
|
938
|
+
});
|
|
939
|
+
idRegistryService.save();
|
|
940
|
+
}
|
|
941
|
+
catch (cacheError) {
|
|
942
|
+
// Erreur non critique, ne pas bloquer la sauvegarde
|
|
943
|
+
if (gitConf.verbose) {
|
|
944
|
+
console.warn('⚠️ Erreur mise à jour cache matter:', cacheError);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
411
947
|
if (!oldNote) {
|
|
412
948
|
return {
|
|
413
949
|
hash: commit.commit,
|
|
@@ -2,11 +2,32 @@ import { SimpleGit } from 'simple-git';
|
|
|
2
2
|
import { RulesGitConfig, PRMetadata, GitCommitHistory, GitFileSummary } from '../types';
|
|
3
3
|
export declare function lock(key: string): Promise<void>;
|
|
4
4
|
export declare function unlock(key: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* Valide si une valeur est un entier valide pour un ID
|
|
7
|
+
*
|
|
8
|
+
* Un ID valide doit être:
|
|
9
|
+
* - Un nombre (type number)
|
|
10
|
+
* - Un entier (pas de décimales)
|
|
11
|
+
* - Supérieur à 999 (réservé pour les IDs système)
|
|
12
|
+
* - Fini (pas NaN, pas Infinity)
|
|
13
|
+
*
|
|
14
|
+
* @param id Valeur à valider
|
|
15
|
+
* @returns true si l'ID est valide, false sinon
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* isValidInt(1234) // true
|
|
19
|
+
* isValidInt(999) // false (trop petit)
|
|
20
|
+
* isValidInt(1.5) // false (pas un entier)
|
|
21
|
+
* isValidInt(NaN) // false
|
|
22
|
+
* isValidInt("1234") // false (pas un nombre)
|
|
23
|
+
*/
|
|
24
|
+
export declare function isValidInt(id: any): boolean;
|
|
5
25
|
/**
|
|
6
26
|
* Configuration et initialisation du client Git
|
|
27
|
+
* @param defaultConfig Configuration partielle optionnelle pour override
|
|
7
28
|
* @returns Configuration Git avec l'instance et les chemins
|
|
8
29
|
*/
|
|
9
|
-
export declare function gitLoad(defaultConfig?: RulesGitConfig): RulesGitConfig;
|
|
30
|
+
export declare function gitLoad(defaultConfig?: Partial<RulesGitConfig>): RulesGitConfig;
|
|
10
31
|
/**
|
|
11
32
|
* Récupère la prévisualisation d'un fichier depuis Git (opération bas niveau atomique),
|
|
12
33
|
* sans les métadonnées.
|
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.lock = lock;
|
|
37
37
|
exports.unlock = unlock;
|
|
38
|
+
exports.isValidInt = isValidInt;
|
|
38
39
|
exports.gitLoad = gitLoad;
|
|
39
40
|
exports.gitGetFilePreview = gitGetFilePreview;
|
|
40
41
|
exports.gitGetFileContent = gitGetFileContent;
|
|
@@ -76,11 +77,50 @@ function unlock(key) {
|
|
|
76
77
|
releasers.delete(key);
|
|
77
78
|
}
|
|
78
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Valide si une valeur est un entier valide pour un ID
|
|
82
|
+
*
|
|
83
|
+
* Un ID valide doit être:
|
|
84
|
+
* - Un nombre (type number)
|
|
85
|
+
* - Un entier (pas de décimales)
|
|
86
|
+
* - Supérieur à 999 (réservé pour les IDs système)
|
|
87
|
+
* - Fini (pas NaN, pas Infinity)
|
|
88
|
+
*
|
|
89
|
+
* @param id Valeur à valider
|
|
90
|
+
* @returns true si l'ID est valide, false sinon
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* isValidInt(1234) // true
|
|
94
|
+
* isValidInt(999) // false (trop petit)
|
|
95
|
+
* isValidInt(1.5) // false (pas un entier)
|
|
96
|
+
* isValidInt(NaN) // false
|
|
97
|
+
* isValidInt("1234") // false (pas un nombre)
|
|
98
|
+
*/
|
|
99
|
+
function isValidInt(id) {
|
|
100
|
+
// Vérifier que c'est un nombre
|
|
101
|
+
if (typeof id !== 'number') {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
// Vérifier que c'est un nombre fini (pas NaN, pas Infinity)
|
|
105
|
+
if (!Number.isFinite(id)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
// Vérifier que c'est un entier
|
|
109
|
+
if (!Number.isInteger(id)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
// Vérifier que c'est supérieur à 999
|
|
113
|
+
if (id <= 999) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
79
118
|
// Global variables for git config and instance
|
|
80
119
|
let gitConfig;
|
|
81
120
|
let git;
|
|
82
121
|
/**
|
|
83
122
|
* Configuration et initialisation du client Git
|
|
123
|
+
* @param defaultConfig Configuration partielle optionnelle pour override
|
|
84
124
|
* @returns Configuration Git avec l'instance et les chemins
|
|
85
125
|
*/
|
|
86
126
|
function gitLoad(defaultConfig) {
|
|
@@ -99,6 +139,13 @@ function gitLoad(defaultConfig) {
|
|
|
99
139
|
const validationToken = defaultConfig?.validationToken || process.env.DEFAULT_VALIDATION_TOKEN;
|
|
100
140
|
const sshKeyPath = process.env.GIT_SSH_KEY_PATH;
|
|
101
141
|
const sshPassphrase = process.env.GIT_SSH_PASSPHRASE;
|
|
142
|
+
// Configuration de la validation des IDs
|
|
143
|
+
const withID = defaultConfig?.withID !== undefined
|
|
144
|
+
? defaultConfig.withID
|
|
145
|
+
: process.env.GIT_WITH_ID == 'true';
|
|
146
|
+
const strictID = defaultConfig?.strictID !== undefined
|
|
147
|
+
? defaultConfig.strictID
|
|
148
|
+
: process.env.GIT_STRICT_ID == 'true';
|
|
102
149
|
if (!repoPath || !draftBranch || !uploadPath || !mainBranch || !validationToken) {
|
|
103
150
|
throw new errors_1.GitConfigurationError(messages_1.i18nRules.git_config_incomplete, 'repoPath|draftBranch|uploadPath|mainBranch|validationToken');
|
|
104
151
|
}
|
|
@@ -152,7 +199,9 @@ function gitLoad(defaultConfig) {
|
|
|
152
199
|
remoteUrl,
|
|
153
200
|
verbose,
|
|
154
201
|
canForce: defaultConfig?.canForce,
|
|
155
|
-
reset: defaultConfig?.reset
|
|
202
|
+
reset: defaultConfig?.reset,
|
|
203
|
+
withID,
|
|
204
|
+
strictID
|
|
156
205
|
};
|
|
157
206
|
git = gitInstance;
|
|
158
207
|
return gitConfig;
|