agentic-api 2.0.314 → 2.0.585
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 +37 -34
- package/dist/src/agents/prompts.d.ts +1 -1
- package/dist/src/agents/prompts.js +9 -7
- package/dist/src/agents/reducer.core.js +2 -2
- package/dist/src/agents/simulator.d.ts +33 -4
- package/dist/src/agents/simulator.dashboard.d.ts +140 -0
- package/dist/src/agents/simulator.dashboard.js +344 -0
- 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 +103 -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 +39 -4
- package/dist/src/agents/simulator.utils.d.ts +22 -1
- package/dist/src/agents/simulator.utils.js +27 -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 +29 -0
- package/dist/src/execute/modelconfig.js +72 -0
- package/dist/src/execute/responses.d.ts +55 -0
- package/dist/src/execute/responses.js +595 -0
- package/dist/src/execute/shared.d.ts +83 -0
- package/dist/src/execute/shared.js +188 -0
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.js +21 -2
- package/dist/src/llm/config.d.ts +25 -0
- package/dist/src/llm/config.js +38 -0
- package/dist/src/llm/index.d.ts +48 -0
- package/dist/src/llm/index.js +115 -0
- package/dist/src/llm/openai.d.ts +6 -0
- package/dist/src/llm/openai.js +154 -0
- package/dist/src/llm/pricing.d.ts +26 -0
- package/dist/src/llm/pricing.js +129 -0
- package/dist/src/llm/xai.d.ts +17 -0
- package/dist/src/llm/xai.js +90 -0
- package/dist/src/pricing.llm.d.ts +3 -15
- package/dist/src/pricing.llm.js +10 -230
- package/dist/src/prompts.d.ts +0 -1
- package/dist/src/prompts.js +51 -118
- package/dist/src/rag/embeddings.d.ts +5 -1
- package/dist/src/rag/embeddings.js +23 -7
- package/dist/src/rag/parser.js +1 -1
- package/dist/src/rag/rag.manager.d.ts +33 -2
- package/dist/src/rag/rag.manager.js +159 -61
- package/dist/src/rag/types.d.ts +2 -0
- package/dist/src/rag/usecase.js +8 -11
- 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 +113 -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 +57 -7
- package/dist/src/rules/git/repo.js +326 -39
- package/dist/src/rules/git/repo.pr.d.ts +8 -0
- package/dist/src/rules/git/repo.pr.js +161 -13
- package/dist/src/rules/git/repo.tools.d.ts +5 -1
- package/dist/src/rules/git/repo.tools.js +54 -7
- package/dist/src/rules/types.d.ts +25 -0
- package/dist/src/rules/utils.matter.d.ts +0 -20
- package/dist/src/rules/utils.matter.js +58 -81
- package/dist/src/scrapper.js +3 -2
- 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.d.ts +0 -8
- package/dist/src/utils.js +26 -29
- package/package.json +9 -7
- package/dist/src/execute.d.ts +0 -63
|
@@ -40,6 +40,7 @@ exports.gitGetPRMetadata = gitGetPRMetadata;
|
|
|
40
40
|
exports.gitGetAllPR = gitGetAllPR;
|
|
41
41
|
exports.gitGetClosedPRs = gitGetClosedPRs;
|
|
42
42
|
exports.gitLoadPR = gitLoadPR;
|
|
43
|
+
exports.gitPRReplaceFile = gitPRReplaceFile;
|
|
43
44
|
exports.gitPRUpdateComments = gitPRUpdateComments;
|
|
44
45
|
exports.gitClosePR = gitClosePR;
|
|
45
46
|
exports.gitClosePRRobust = gitClosePRRobust;
|
|
@@ -321,7 +322,7 @@ async function gitLoadPR(git, branch) {
|
|
|
321
322
|
if (!metadata) {
|
|
322
323
|
throw new errors_1.GitOperationError(`PR not found for branch ${branch}`, 'pr_load', { branch });
|
|
323
324
|
}
|
|
324
|
-
const files = metadata.files || await (0, repo_tools_1.gitGetDiffFiles)(git, branch, metadata?.mergeBase, '.md');
|
|
325
|
+
const files = metadata.files || (await (0, repo_tools_1.gitGetDiffFiles)(git, branch, metadata?.mergeBase, '.md'));
|
|
325
326
|
// Récupérer les infos du dernier commit de la branche
|
|
326
327
|
const log = await git.log({ from: branch, to: branch, maxCount: 1 });
|
|
327
328
|
const lastCommit = log.latest;
|
|
@@ -341,6 +342,49 @@ async function gitLoadPR(git, branch) {
|
|
|
341
342
|
throw new errors_1.GitOperationError(`Failed to retrieve PR: ${error}`, 'pr_load');
|
|
342
343
|
}
|
|
343
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* Remplace explicitement un nom de fichier dans les métadonnées d'une PR.
|
|
347
|
+
* Utilisé pour refléter immédiatement les renames sans dépendre de git diff.
|
|
348
|
+
*/
|
|
349
|
+
async function gitPRReplaceFile(git, branch, options = {}, config) {
|
|
350
|
+
const { remove, add } = options;
|
|
351
|
+
if (!remove && !add) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
355
|
+
const metadata = await gitGetPRMetadata(git, branch, config);
|
|
356
|
+
if (!metadata) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const currentFiles = Array.isArray(metadata.files) ? metadata.files : [];
|
|
360
|
+
const seen = new Set();
|
|
361
|
+
const nextFiles = [];
|
|
362
|
+
for (const file of currentFiles) {
|
|
363
|
+
if (!file) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (remove && file === remove) {
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (seen.has(file)) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
seen.add(file);
|
|
373
|
+
nextFiles.push(file);
|
|
374
|
+
}
|
|
375
|
+
if (add && !seen.has(add)) {
|
|
376
|
+
nextFiles.push(add);
|
|
377
|
+
seen.add(add);
|
|
378
|
+
}
|
|
379
|
+
const changed = currentFiles.length !== nextFiles.length ||
|
|
380
|
+
currentFiles.some((file, idx) => file !== nextFiles[idx]);
|
|
381
|
+
if (!changed) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
metadata.files = nextFiles;
|
|
385
|
+
const headCommitHash = (await git.revparse([branch])).trim();
|
|
386
|
+
await (0, repo_tools_1.gitWriteNote)(git, headCommitHash, metadata, gitConf.gitNotes.namespace);
|
|
387
|
+
}
|
|
344
388
|
async function gitPRUpdateComments(git, branch, details, config) {
|
|
345
389
|
const gitConf = (0, repo_tools_1.gitLoad)(config);
|
|
346
390
|
const metadata = await gitGetPRMetadata(git, branch, config);
|
|
@@ -407,6 +451,21 @@ async function gitClosePRRobust(git, branch, closedBy, message, config) {
|
|
|
407
451
|
if (!originalMetadata) {
|
|
408
452
|
throw new errors_1.PRClosureError(`Could not find metadata on branch ${branch}. Cannot close.`, branch, 'metadata_not_found');
|
|
409
453
|
}
|
|
454
|
+
// 2. Nettoyer tout état de merge en cours avant de commencer
|
|
455
|
+
try {
|
|
456
|
+
await git.raw(['merge', '--abort']).catch(() => {
|
|
457
|
+
// Ignorer si pas de merge en cours
|
|
458
|
+
});
|
|
459
|
+
// Reset de l'index au cas où il serait dans un état instable
|
|
460
|
+
await git.raw(['reset', '--merge']).catch(() => {
|
|
461
|
+
// Ignorer si pas nécessaire
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
catch (cleanupError) {
|
|
465
|
+
if (gitConf.verbose) {
|
|
466
|
+
console.warn('Cleanup before merge failed (non-critical):', cleanupError);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
410
469
|
// 3. Update the metadata note on the PR branch itself to mark it as closed
|
|
411
470
|
const finalMetadata = {
|
|
412
471
|
...originalMetadata,
|
|
@@ -420,32 +479,106 @@ async function gitClosePRRobust(git, branch, closedBy, message, config) {
|
|
|
420
479
|
await (0, repo_tools_1.gitWriteNote)(git, headCommitHash, finalMetadata, gitConf.gitNotes.namespace);
|
|
421
480
|
// 4. Now, merge the updated PR branch into the target branch
|
|
422
481
|
await git.checkout(originalMetadata.mergeBase || gitConf.draftBranch);
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
482
|
+
// 5. Stratégie de merge robuste : FORCER la préservation des changements de la branche PR
|
|
483
|
+
// Note: "ours" dans ce contexte signifie "garder la version de la branche qu'on merge" (la PR)
|
|
484
|
+
// car nous sommes sur rule-editor et on merge la PR
|
|
485
|
+
let mergeResult;
|
|
486
|
+
try {
|
|
487
|
+
mergeResult = await git
|
|
488
|
+
.env({
|
|
489
|
+
GIT_AUTHOR_NAME: closedBy.name,
|
|
490
|
+
GIT_AUTHOR_EMAIL: closedBy.email,
|
|
491
|
+
GIT_COMMITTER_NAME: closedBy.name,
|
|
492
|
+
GIT_COMMITTER_EMAIL: closedBy.email,
|
|
493
|
+
})
|
|
494
|
+
.merge([
|
|
495
|
+
'--no-ff',
|
|
496
|
+
'--strategy', 'recursive',
|
|
497
|
+
'--strategy-option', 'theirs',
|
|
498
|
+
'-m', `Merge branch '${branch}'`,
|
|
499
|
+
branch
|
|
500
|
+
]);
|
|
501
|
+
}
|
|
502
|
+
catch (mergeError) {
|
|
503
|
+
if (gitConf.verbose) {
|
|
504
|
+
console.error('Merge failed with recursive/theirs, trying ours strategy:', mergeError);
|
|
505
|
+
}
|
|
506
|
+
// Nettoyer le merge échoué
|
|
507
|
+
await git.raw(['merge', '--abort']).catch(() => { });
|
|
508
|
+
// Stratégie de fallback ultra-agressive: stratégie "ours" qui prend TOUJOURS la version de la branche source
|
|
509
|
+
// ATTENTION: Ici "ours" = la branche de destination (rule-editor), donc on inverse la logique
|
|
510
|
+
// Solution: utiliser --strategy-option theirs avec merge forcé
|
|
511
|
+
try {
|
|
512
|
+
// Récupérer les fichiers de la PR
|
|
513
|
+
const prFiles = originalMetadata.files || [];
|
|
514
|
+
// Merger avec stratégie ours d'abord (pour créer le commit de merge)
|
|
515
|
+
await git
|
|
516
|
+
.env({
|
|
517
|
+
GIT_AUTHOR_NAME: closedBy.name,
|
|
518
|
+
GIT_AUTHOR_EMAIL: closedBy.email,
|
|
519
|
+
GIT_COMMITTER_NAME: closedBy.name,
|
|
520
|
+
GIT_COMMITTER_EMAIL: closedBy.email,
|
|
521
|
+
})
|
|
522
|
+
.merge([
|
|
523
|
+
'--no-ff',
|
|
524
|
+
'--strategy', 'ours',
|
|
525
|
+
'-m', `Merge branch '${branch}'`,
|
|
526
|
+
branch
|
|
527
|
+
]);
|
|
528
|
+
// Puis checkout des fichiers depuis la branche PR pour forcer leurs contenus
|
|
529
|
+
for (const file of prFiles) {
|
|
530
|
+
try {
|
|
531
|
+
await git.raw(['checkout', branch, '--', file]);
|
|
532
|
+
}
|
|
533
|
+
catch (fileError) {
|
|
534
|
+
if (gitConf.verbose) {
|
|
535
|
+
console.warn(`Could not checkout ${file} from ${branch}:`, fileError);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
// Amend le commit de merge avec les bons contenus
|
|
540
|
+
await git.commit('--amend', ['--no-edit'], {
|
|
541
|
+
'--author': `${closedBy.name} <${closedBy.email}>`
|
|
542
|
+
});
|
|
543
|
+
mergeResult = { summary: { changes: prFiles.length } };
|
|
544
|
+
}
|
|
545
|
+
catch (fallbackError) {
|
|
546
|
+
throw new errors_1.PRClosureError(`Failed to merge PR ${branch} with all strategies: ${mergeError}\nFallback error: ${fallbackError}`, branch, 'merge_failed');
|
|
547
|
+
}
|
|
548
|
+
}
|
|
433
549
|
const result = {
|
|
434
550
|
metadata: finalMetadata,
|
|
435
551
|
failed: false,
|
|
436
|
-
conflicts: mergeResult
|
|
552
|
+
conflicts: mergeResult?.conflicts || [],
|
|
437
553
|
raw: mergeResult,
|
|
438
554
|
};
|
|
439
555
|
return result;
|
|
440
556
|
}
|
|
441
557
|
catch (error) {
|
|
558
|
+
// Nettoyer l'état en cas d'erreur
|
|
559
|
+
try {
|
|
560
|
+
await git.raw(['merge', '--abort']).catch(() => { });
|
|
561
|
+
await git.raw(['reset', '--merge']).catch(() => { });
|
|
562
|
+
}
|
|
563
|
+
catch (cleanupError) {
|
|
564
|
+
if (gitConf.verbose) {
|
|
565
|
+
console.error('Failed to cleanup merge state:', cleanupError);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
442
568
|
if (error instanceof errors_1.PRClosureError)
|
|
443
569
|
throw error;
|
|
444
570
|
throw new errors_1.PRClosureError(`Failed to close PR ${branch}: ${error}`, branch, 'unknown');
|
|
445
571
|
}
|
|
446
572
|
finally {
|
|
447
573
|
if (currentBranch) {
|
|
448
|
-
|
|
574
|
+
try {
|
|
575
|
+
await git.checkout(currentBranch);
|
|
576
|
+
}
|
|
577
|
+
catch (checkoutError) {
|
|
578
|
+
if (gitConf.verbose) {
|
|
579
|
+
console.error(`Failed to checkout back to ${currentBranch}:`, checkoutError);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
449
582
|
}
|
|
450
583
|
(0, repo_tools_1.unlock)('checkout');
|
|
451
584
|
}
|
|
@@ -506,6 +639,21 @@ async function gitNewValidationRequest(git, files, description, author, options
|
|
|
506
639
|
throw new errors_1.PRCreationError('Author is required', undefined, files);
|
|
507
640
|
}
|
|
508
641
|
try {
|
|
642
|
+
// ✅ CLEANUP: Nettoyer tout état de merge corrompu avant de créer la branche
|
|
643
|
+
// Cela évite l'erreur "you need to resolve your current index first"
|
|
644
|
+
try {
|
|
645
|
+
await git.raw(['merge', '--abort']).catch(() => {
|
|
646
|
+
// Ignorer si pas de merge en cours
|
|
647
|
+
});
|
|
648
|
+
await git.raw(['reset', '--merge']).catch(() => {
|
|
649
|
+
// Ignorer si pas nécessaire
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
catch (cleanupError) {
|
|
653
|
+
if (gitConfig.verbose) {
|
|
654
|
+
console.warn('Cleanup before branch creation failed (non-critical):', cleanupError);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
509
657
|
const nextID = await gitGetNextPRNumber(git, validationBranchPrefix);
|
|
510
658
|
const newBranchName = `${validationBranchPrefix}${nextID}`;
|
|
511
659
|
await git.checkoutBranch(newBranchName, sourceBranch);
|
|
@@ -56,7 +56,11 @@ export declare function gitReadFileOutsideRepo(git: SimpleGit, filePath: string)
|
|
|
56
56
|
content: string;
|
|
57
57
|
date: Date;
|
|
58
58
|
}>;
|
|
59
|
-
export declare function gitGetFileHistory(git: SimpleGit, filename: string,
|
|
59
|
+
export declare function gitGetFileHistory(git: SimpleGit, filename: string, options?: {
|
|
60
|
+
hash?: string;
|
|
61
|
+
branch?: string;
|
|
62
|
+
maxCommits?: number;
|
|
63
|
+
}): Promise<GitCommitHistory[]>;
|
|
60
64
|
/**
|
|
61
65
|
* Récupère le dernier commit d'une branche (opération bas niveau atomique)
|
|
62
66
|
* @param git Instance SimpleGit
|
|
@@ -338,10 +338,23 @@ async function gitReadFileOutsideRepo(git, filePath) {
|
|
|
338
338
|
throw error;
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
|
-
async function gitGetFileHistory(git, filename,
|
|
341
|
+
async function gitGetFileHistory(git, filename, options) {
|
|
342
|
+
// - Normalisation des paramètres pour compatibilité
|
|
342
343
|
try {
|
|
343
|
-
|
|
344
|
-
|
|
344
|
+
// - Utiliser git.log() pour obtenir l'historique des commits
|
|
345
|
+
// - git.log() retourne déjà les commits du plus récent au plus ancien (ordre standard Git)
|
|
346
|
+
const branch = options?.branch || 'HEAD';
|
|
347
|
+
const logArgs = [];
|
|
348
|
+
if (branch !== 'HEAD') {
|
|
349
|
+
logArgs.push(branch);
|
|
350
|
+
}
|
|
351
|
+
logArgs.push('--', filename);
|
|
352
|
+
const log = await git.log(logArgs);
|
|
353
|
+
if (log.all.length === 0) {
|
|
354
|
+
return [];
|
|
355
|
+
}
|
|
356
|
+
// - Construire l'historique (déjà dans l'ordre du plus récent au plus ancien)
|
|
357
|
+
let all = log.all.map(commit => ({
|
|
345
358
|
hash: commit.hash,
|
|
346
359
|
date: new Date(commit.date),
|
|
347
360
|
message: commit.message,
|
|
@@ -350,10 +363,44 @@ async function gitGetFileHistory(git, filename, hash) {
|
|
|
350
363
|
email: commit.author_email
|
|
351
364
|
}
|
|
352
365
|
}));
|
|
353
|
-
// Si un hash est fourni,
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
366
|
+
// - Si un hash est fourni, s'assurer qu'il est inclus avant l'échantillonnage
|
|
367
|
+
let requestedHashIndex = -1;
|
|
368
|
+
if (options?.hash) {
|
|
369
|
+
requestedHashIndex = all.findIndex(commit => commit.hash === options.hash);
|
|
370
|
+
}
|
|
371
|
+
// - Limitation du nombre de commits avec échantillonnage uniforme
|
|
372
|
+
// - Garantit que le premier (plus récent) et dernier (plus ancien) commit sont inclus
|
|
373
|
+
// - Si un hash spécifique est demandé, il est aussi garanti d'être inclus
|
|
374
|
+
if (options?.maxCommits && all.length > options.maxCommits) {
|
|
375
|
+
const step = Math.ceil((all.length - 2) / (options.maxCommits - 2)) || 1;
|
|
376
|
+
const sampled = [all[0]]; // Premier commit (plus récent)
|
|
377
|
+
const includedIndices = new Set([0]); // Track des indices déjà inclus
|
|
378
|
+
// - Si un hash spécifique est demandé et n'est pas le premier, l'ajouter
|
|
379
|
+
if (requestedHashIndex > 0 && requestedHashIndex < all.length - 1) {
|
|
380
|
+
sampled.push(all[requestedHashIndex]);
|
|
381
|
+
includedIndices.add(requestedHashIndex);
|
|
382
|
+
}
|
|
383
|
+
// - Échantillonnage des commits intermédiaires
|
|
384
|
+
for (let i = 1; i < all.length - 1; i += step) {
|
|
385
|
+
if (!includedIndices.has(i)) {
|
|
386
|
+
sampled.push(all[i]);
|
|
387
|
+
includedIndices.add(i);
|
|
388
|
+
}
|
|
389
|
+
if (sampled.length >= options.maxCommits - 1)
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
// - Dernier commit (plus ancien) si on a encore de la place
|
|
393
|
+
if (sampled.length < options.maxCommits && all.length > 1 && !includedIndices.has(all.length - 1)) {
|
|
394
|
+
sampled.push(all[all.length - 1]);
|
|
395
|
+
}
|
|
396
|
+
// - Trier par date décroissante pour maintenir l'ordre (plus récent en premier)
|
|
397
|
+
sampled.sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
398
|
+
all = sampled;
|
|
399
|
+
}
|
|
400
|
+
// - Si un hash est fourni, retourner le contenu du fichier à ce hash
|
|
401
|
+
if (options?.hash) {
|
|
402
|
+
const fileContent = await gitGetFileContent(git, filename, options.hash);
|
|
403
|
+
const index = all.findIndex(commit => commit.hash === options.hash);
|
|
357
404
|
if (index !== -1 && fileContent) {
|
|
358
405
|
all[index] = fileContent;
|
|
359
406
|
}
|
|
@@ -334,6 +334,20 @@ export interface GitCommitHistory {
|
|
|
334
334
|
/** Branche où s'est produit ce commit (optionnel) */
|
|
335
335
|
branch?: string;
|
|
336
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* Structure simplifiée d'un commit pour la prévisualisation
|
|
339
|
+
*
|
|
340
|
+
* Utilisée dans loadPreview() pour retourner uniquement les informations essentielles
|
|
341
|
+
* sans le contenu complet du commit.
|
|
342
|
+
*/
|
|
343
|
+
export interface CommitPreview {
|
|
344
|
+
/** Hash unique du commit */
|
|
345
|
+
hash: string;
|
|
346
|
+
/** Date et heure du commit */
|
|
347
|
+
date: Date;
|
|
348
|
+
/** Nom de l'auteur du commit */
|
|
349
|
+
author: string;
|
|
350
|
+
}
|
|
337
351
|
/**
|
|
338
352
|
* Résumé d'un fichier Git avec son commit associé
|
|
339
353
|
*
|
|
@@ -510,3 +524,14 @@ export interface GitHealthStatus {
|
|
|
510
524
|
/** Recommandations de réparation */
|
|
511
525
|
recommendations: string[];
|
|
512
526
|
}
|
|
527
|
+
/**
|
|
528
|
+
* Rapport de migration des notes Git
|
|
529
|
+
*/
|
|
530
|
+
export interface GitPrNoteMigrationReport {
|
|
531
|
+
migrated: number;
|
|
532
|
+
alreadyOk: number;
|
|
533
|
+
lost: Array<{
|
|
534
|
+
branch: string;
|
|
535
|
+
prNumber: number;
|
|
536
|
+
}>;
|
|
537
|
+
}
|
|
@@ -40,23 +40,3 @@ export declare function matterParse(markdown: string): {
|
|
|
40
40
|
*/
|
|
41
41
|
export declare function matterSerializeFromRule(rule: Rule): string;
|
|
42
42
|
export declare function matterSerialize(content: string, matter: FrontMatter | any): string;
|
|
43
|
-
/**
|
|
44
|
-
* Extrait le front-matter (entre les deux premiers '---') et le contenu Markdown.
|
|
45
|
-
* Fonction 100% vanilla : aucun paquet externe requis.
|
|
46
|
-
* PROS:
|
|
47
|
-
* Code plus propre et maintenable
|
|
48
|
-
* - Typage TypeScript strict
|
|
49
|
-
* - Plus robuste (ignore lignes indentées)
|
|
50
|
-
* - Séparation des responsabilités
|
|
51
|
-
* - Meilleure architecture (parsing pur)
|
|
52
|
-
* CONS:
|
|
53
|
-
* - Perte de fonctionnalité (slugs/tags)
|
|
54
|
-
*
|
|
55
|
-
* @param markdown Texte Markdown brut
|
|
56
|
-
* @returns Objet avec matter, content et data
|
|
57
|
-
*/
|
|
58
|
-
export declare function matterParse_OTHER(markdown: string): {
|
|
59
|
-
matter: Record<string, any>;
|
|
60
|
-
content: string;
|
|
61
|
-
data: Record<string, any>;
|
|
62
|
-
};
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.matterParse = matterParse;
|
|
4
4
|
exports.matterSerializeFromRule = matterSerializeFromRule;
|
|
5
5
|
exports.matterSerialize = matterSerialize;
|
|
6
|
-
exports.matterParse_OTHER = matterParse_OTHER;
|
|
7
6
|
/**
|
|
8
7
|
* Parse le front-matter YAML et le contenu Markdown d'un document
|
|
9
8
|
*
|
|
@@ -53,9 +52,17 @@ function matterParse(markdown) {
|
|
|
53
52
|
const [rawKey, ...rawValue] = line.split(':');
|
|
54
53
|
const key = rawKey.trim();
|
|
55
54
|
const value = rawValue.join(':').trim();
|
|
56
|
-
//
|
|
57
|
-
if (
|
|
55
|
+
// Détection de null explicite (YAML: null, ~) - ne pas créer la clé
|
|
56
|
+
if (value === 'null' || value === '~' || value === 'Null' || value === 'NULL') {
|
|
57
|
+
// Si la valeur est null, ne pas créer la clé (comme undefined)
|
|
58
58
|
continue;
|
|
59
|
+
}
|
|
60
|
+
// Si la valeur est vide (chaîne vide après trim), définir comme chaîne vide
|
|
61
|
+
// L'utilisateur peut définir un string vide pour indiquer qu'il n'a pas de valeur pour ce champ
|
|
62
|
+
if (!value) {
|
|
63
|
+
matter[key] = '';
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
59
66
|
// Détection et parsing des arrays YAML
|
|
60
67
|
if (value.startsWith('[') && value.endsWith(']')) {
|
|
61
68
|
try {
|
|
@@ -122,13 +129,10 @@ function matterSerializeFromRule(rule) {
|
|
|
122
129
|
function matterSerialize(content, matter) {
|
|
123
130
|
// Créer un objet propre pour le front-matter (exclure oldfile)
|
|
124
131
|
const cleanMatter = { ...matter };
|
|
125
|
-
// //
|
|
126
|
-
// // FIX: Convertir la Date en string pour éviter l'erreur YAML
|
|
127
|
-
// cleanMatter.lastModified = (cleanMatter.lastModified instanceof Date) ? `${new Date().toISOString()}` : `${cleanMatter.lastModified}`;
|
|
128
132
|
const result = Object.keys(cleanMatter).reduce((acc, key) => {
|
|
129
133
|
const value = cleanMatter[key];
|
|
130
|
-
// Ignorer les valeurs undefined ou
|
|
131
|
-
if (value === undefined || value === null) {
|
|
134
|
+
// Ignorer les valeurs undefined, null ou chaînes vides
|
|
135
|
+
if (value === undefined || value === null || value === '') {
|
|
132
136
|
return acc;
|
|
133
137
|
}
|
|
134
138
|
if (Array.isArray(value)) {
|
|
@@ -142,86 +146,59 @@ function matterSerialize(content, matter) {
|
|
|
142
146
|
// ✅ FIX: Ne PAS mettre de guillemets autour des booléens
|
|
143
147
|
return acc + `${key}: ${value}\n`;
|
|
144
148
|
}
|
|
149
|
+
else if (value instanceof Date) {
|
|
150
|
+
// ✅ FIX: Convertir Date en ISO string avec guillemets
|
|
151
|
+
return acc + `${key}: '${value.toISOString()}'\n`;
|
|
152
|
+
}
|
|
145
153
|
else {
|
|
146
|
-
|
|
147
|
-
return acc + `${key}:
|
|
154
|
+
const formatted = formatYAMLString(value.toString());
|
|
155
|
+
return acc + `${key}: ${formatted}\n`;
|
|
148
156
|
}
|
|
149
157
|
}, '');
|
|
150
158
|
return `---
|
|
151
159
|
${result}---
|
|
152
160
|
${content}`;
|
|
153
161
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
* Code plus propre et maintenable
|
|
159
|
-
* - Typage TypeScript strict
|
|
160
|
-
* - Plus robuste (ignore lignes indentées)
|
|
161
|
-
* - Séparation des responsabilités
|
|
162
|
-
* - Meilleure architecture (parsing pur)
|
|
163
|
-
* CONS:
|
|
164
|
-
* - Perte de fonctionnalité (slugs/tags)
|
|
165
|
-
*
|
|
166
|
-
* @param markdown Texte Markdown brut
|
|
167
|
-
* @returns Objet avec matter, content et data
|
|
168
|
-
*/
|
|
169
|
-
function matterParse_OTHER(markdown) {
|
|
170
|
-
// 1. Séparer les lignes
|
|
171
|
-
const lines = markdown.split(/\r?\n/);
|
|
172
|
-
if (lines[0].trim() !== '---') {
|
|
173
|
-
return { matter: {}, content: markdown, data: {} }; // Pas de front-matter
|
|
162
|
+
function formatYAMLString(value) {
|
|
163
|
+
const shouldQuote = needsQuotes(value);
|
|
164
|
+
if (!shouldQuote) {
|
|
165
|
+
return value;
|
|
174
166
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
while (end < lines.length && lines[end].trim() !== '---')
|
|
178
|
-
end++;
|
|
179
|
-
// 3. Parser le bloc front-matter (simple clé-valeur)
|
|
180
|
-
const matter = {};
|
|
181
|
-
for (let i = 1; i < end; i++) {
|
|
182
|
-
const line = lines[i];
|
|
183
|
-
if (!line.trim())
|
|
184
|
-
continue; // ignorer les lignes vides
|
|
185
|
-
// Ignorer les lignes indentées (structures complexes non supportées)
|
|
186
|
-
if (line.startsWith(' ') || line.startsWith('\t')) {
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
const trimmedLine = line.trim();
|
|
190
|
-
if (trimmedLine.includes(':')) {
|
|
191
|
-
const [rawKey, ...rawValue] = trimmedLine.split(':');
|
|
192
|
-
const key = rawKey.trim();
|
|
193
|
-
const value = rawValue.join(':').trim();
|
|
194
|
-
if (value) {
|
|
195
|
-
// Détection et parsing des arrays YAML
|
|
196
|
-
if (value.startsWith('[') && value.endsWith(']')) {
|
|
197
|
-
try {
|
|
198
|
-
const parsed = JSON.parse(value);
|
|
199
|
-
if (Array.isArray(parsed)) {
|
|
200
|
-
matter[key] = parsed;
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
matter[key] = value.replace(/^["']|["']$/g, '');
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
catch (e) {
|
|
207
|
-
matter[key] = value.replace(/^["']|["']$/g, '');
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// Tentative de typage léger : nombre, booléen, sinon chaîne
|
|
211
|
-
else if (/^(true|false)$/i.test(value)) {
|
|
212
|
-
matter[key] = value.toLowerCase() === 'true';
|
|
213
|
-
}
|
|
214
|
-
else if (!isNaN(Number(value)) && value !== '') {
|
|
215
|
-
matter[key] = Number(value);
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
matter[key] = value.replace(/^["']|["']$/g, '');
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
167
|
+
if (process.env.DEBUG_YAML === '1') {
|
|
168
|
+
console.warn('[matterSerialize] quoting value:', value);
|
|
222
169
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
170
|
+
const escaped = value.replace(/'/g, "''");
|
|
171
|
+
return `'${escaped}'`;
|
|
172
|
+
}
|
|
173
|
+
function needsQuotes(value) {
|
|
174
|
+
if (value.length === 0) {
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
const firstChar = value[0];
|
|
178
|
+
const lastChar = value[value.length - 1];
|
|
179
|
+
if (firstChar === ' ' || lastChar === ' ') {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
if (/[:#{}\[\],&*?]/.test(value)) {
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
if (/^-/.test(value)) {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
if (/^\d/.test(value)) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
if (value.includes('\n')) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
if (value.includes('- ')) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
if (value.includes('"')) {
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
if (value.includes("'")) {
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
227
204
|
}
|
package/dist/src/scrapper.js
CHANGED
|
@@ -13,7 +13,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
13
13
|
const fs_1 = __importDefault(require("fs"));
|
|
14
14
|
const jsdom_1 = require("jsdom");
|
|
15
15
|
const readability_1 = require("@mozilla/readability");
|
|
16
|
-
const
|
|
16
|
+
const pricing_1 = require("./llm/pricing");
|
|
17
17
|
const prompts_1 = require("./prompts");
|
|
18
18
|
const utils_1 = require("./utils");
|
|
19
19
|
const execute_1 = require("./execute");
|
|
@@ -37,7 +37,7 @@ async function extractCaptcha(base64Image, openai) {
|
|
|
37
37
|
messages: [{ role: "user", content }],
|
|
38
38
|
max_completion_tokens: 50,
|
|
39
39
|
});
|
|
40
|
-
const cost = (0,
|
|
40
|
+
const cost = (0, pricing_1.calculateCost)(model, response.usage);
|
|
41
41
|
// Récupérer la réponse markdown
|
|
42
42
|
const number = response.choices[0].message.content;
|
|
43
43
|
return { number, cost };
|
|
@@ -190,6 +190,7 @@ async function pdf2markdown(outputDir, pdf, matter, model = "MEDIUM-fast") {
|
|
|
190
190
|
// Ca ne marche pas mieux que pdftotext
|
|
191
191
|
// const { stdout } = await execFileAsync("python3", ["./bin/extract_text_with_links.py", pdf]);
|
|
192
192
|
// const { text, links } = JSON.parse(stdout);
|
|
193
|
+
// `pdftotext -f 1 -l 2 -layout -eol unix -nodiag "${pdf}" "${outputPath}"`;
|
|
193
194
|
await execAsync(`pdftotext -nodiag -nopgbrk "${pdf}" "${outputPath}"`);
|
|
194
195
|
const links = await extractLinksFromPDF(pdf, outputDir);
|
|
195
196
|
const text = fs_1.default.readFileSync(outputPath, "utf8");
|
|
@@ -17,6 +17,14 @@ export declare class AgentStateGraph implements IAgentStateGraph {
|
|
|
17
17
|
createOrRestore(agentName: string, description?: string): AgentDiscussion;
|
|
18
18
|
/**
|
|
19
19
|
* Ajoute un message à la discussion d'un agent
|
|
20
|
+
* Gère tous types de messages : user, assistant, system, tool, function_call_output, etc.
|
|
21
|
+
*
|
|
22
|
+
* Utilisée par:
|
|
23
|
+
* - readCompletionsStream (responses.ts) : messages assistant avec tool_calls, content
|
|
24
|
+
* - batchProcessToolCalls (helpers.ts) : messages function_call_output
|
|
25
|
+
* - executeAgentSet (responses.ts) : messages user
|
|
26
|
+
* - stategraph.storage.ts : migration ancien format
|
|
27
|
+
*
|
|
20
28
|
* @param agentName Nom de l'agent
|
|
21
29
|
* @param message Message sans ID ni timestamp (auto-générés)
|
|
22
30
|
*/
|
|
@@ -30,8 +38,14 @@ export declare class AgentStateGraph implements IAgentStateGraph {
|
|
|
30
38
|
set(agentName: string, content: string): void;
|
|
31
39
|
/**
|
|
32
40
|
* Ajoute une étape au CONTEXT TRAIL et met à jour le message system
|
|
41
|
+
* Injecte automatiquement le trail dans le system message via updateSystemMessage()
|
|
42
|
+
*
|
|
43
|
+
* Utilisée par:
|
|
44
|
+
* - readCompletionsStream (responses.ts) : après chaque tool call exécuté
|
|
45
|
+
* - Tests d'intégration pour validation du context trail
|
|
46
|
+
*
|
|
33
47
|
* @param agentName Nom de l'agent
|
|
34
|
-
* @param step Étape à ajouter au trail
|
|
48
|
+
* @param step Étape à ajouter au trail (tool, context, reason, id optionnel)
|
|
35
49
|
*/
|
|
36
50
|
addStep(agentName: string, step: StepTrail): void;
|
|
37
51
|
/**
|
|
@@ -60,6 +74,17 @@ export declare class AgentStateGraph implements IAgentStateGraph {
|
|
|
60
74
|
/**
|
|
61
75
|
* Retourne une vue filtrée pour le client
|
|
62
76
|
* Supprime les messages system et les métadonnées d'outils
|
|
77
|
+
*
|
|
78
|
+
* Filtre appliqué:
|
|
79
|
+
* - Exclut: system, tool, messages avec name (Chat Completions function results)
|
|
80
|
+
* - Exclut: function_call_output (Responses API)
|
|
81
|
+
* - Exclut: messages assistant avec tool_calls mais sans content
|
|
82
|
+
* - Nettoie: <memories> tags dans le content
|
|
83
|
+
*
|
|
84
|
+
* Utilisée par:
|
|
85
|
+
* - ctrl/agent.ts (agentic-server) : ctrlGetHistory, ctrlExecuteAgent
|
|
86
|
+
* - Tests d'intégration pour validation
|
|
87
|
+
*
|
|
63
88
|
* @param agentName Nom de l'agent
|
|
64
89
|
* @returns Discussion filtrée pour l'affichage client
|
|
65
90
|
*/
|