@imenam/mcp-feature-analyzer 1.0.19 → 1.0.20
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 +4 -3
- package/dist/shared/schemas/analysis.schema.d.ts +28 -1
- package/dist/shared/schemas/analysis.schema.js +5 -1
- package/dist/shared/schemas/api.schema.d.ts +13 -0
- package/dist/shared/schemas/api.schema.js +6 -0
- package/dist/shared/schemas/ipc.schema.d.ts +1 -1
- package/dist/shared/schemas/ipc.schema.js +1 -0
- package/dist/src/core/migrate.d.ts +5 -0
- package/dist/src/core/migrate.js +38 -1
- package/dist/src/core/review-actions.d.ts +16 -3
- package/dist/src/core/review-actions.js +25 -0
- package/dist/src/gui-worker.js +7 -1
- package/dist/src/index.js +8 -2
- package/dist/src/tools/format.js +1 -1
- package/dist/src/tools/get-review-feedback.js +5 -3
- package/dist/src/tools/mark-feedback-processed.d.ts +2 -3
- package/dist/src/tools/mark-feedback-processed.js +4 -17
- package/gui/dist/assets/{angular-html-BG32ZSEg.js → angular-html-DjjSiqQZ.js} +1 -1
- package/gui/dist/assets/{angular-ts-W997xU6j.js → angular-ts-BTRcXEj8.js} +1 -1
- package/gui/dist/assets/{apl-6ogEEQiK.js → apl-By3131Sn.js} +1 -1
- package/gui/dist/assets/{astro-DBxTz6gT.js → astro-GOx0I6tH.js} +1 -1
- package/gui/dist/assets/{blade-PbZvkn0I.js → blade-SxDzr2ab.js} +1 -1
- package/gui/dist/assets/{c-C5-3wfrB.js → c-rXSNR5kl.js} +1 -1
- package/gui/dist/assets/{chapel-KHYeKJD5.js → chapel-nBfsanOz.js} +1 -1
- package/gui/dist/assets/{cobol-D51AxaJB.js → cobol-BiZycENC.js} +1 -1
- package/gui/dist/assets/{coffee-4h6_4dhl.js → coffee-BlljDtvu.js} +1 -1
- package/gui/dist/assets/{cpp-B63oWnHV.js → cpp-B_sYZ92I.js} +1 -1
- package/gui/dist/assets/{crystal-OG_TkIE7.js → crystal-Cg0a9qqm.js} +1 -1
- package/gui/dist/assets/{css-Csea3soR.js → css-LHykI9SM.js} +1 -1
- package/gui/dist/assets/{edge-HBaaYuuJ.js → edge-5wEkHYNr.js} +1 -1
- package/gui/dist/assets/{elixir-DZlxxd9b.js → elixir-B2Ez6C_y.js} +1 -1
- package/gui/dist/assets/{elm-DZAjSs9M.js → elm-CnwUpgFN.js} +1 -1
- package/gui/dist/assets/{erb-BurFBvpV.js → erb-9ibbHo7M.js} +1 -1
- package/gui/dist/assets/{git-rebase-B7wPwCu-.js → git-rebase-DffAuf0G.js} +1 -1
- package/gui/dist/assets/{glimmer-js-Bgk8Z51T.js → glimmer-js-VAknUS9x.js} +1 -1
- package/gui/dist/assets/{glimmer-ts-ldZtmANh.js → glimmer-ts-DcrYlRqt.js} +1 -1
- package/gui/dist/assets/{glsl-7SImpJuS.js → glsl-CYGBzxMW.js} +1 -1
- package/gui/dist/assets/{graphql-CJ0BLjCq.js → graphql-Bv55IETC.js} +1 -1
- package/gui/dist/assets/{hack-D50FsJQB.js → hack-D8V-_7lb.js} +1 -1
- package/gui/dist/assets/{haml-xkw_a2ii.js → haml-Bp-WEz3w.js} +1 -1
- package/gui/dist/assets/{handlebars-C0upK5dG.js → handlebars-B5v0_vx8.js} +1 -1
- package/gui/dist/assets/{html-CerDkvKq.js → html-BudjcI9P.js} +1 -1
- package/gui/dist/assets/{html-derivative-BfB3QMj5.js → html-derivative-BVPFhHTi.js} +1 -1
- package/gui/dist/assets/{http-pXaTY6-R.js → http-BNWhTfh4.js} +1 -1
- package/gui/dist/assets/{hurl-BNtMT88T.js → hurl-BQXVMX2w.js} +1 -1
- package/gui/dist/assets/{index-CN9ojYe6.css → index-DVca12tD.css} +1 -1
- package/gui/dist/assets/{index-CMjVOwnL.js → index-TuSnqzFd.js} +17 -17
- package/gui/dist/assets/{java-B3e3IyVz.js → java-U-bszQtz.js} +1 -1
- package/gui/dist/assets/{javascript-DgggYE1f.js → javascript-BOp_I2j_.js} +1 -1
- package/gui/dist/assets/{jinja-BHtm4gvT.js → jinja-CJ8_uK8s.js} +1 -1
- package/gui/dist/assets/{jison-B2YK1Y49.js → jison-CsIefIrr.js} +1 -1
- package/gui/dist/assets/{json-7jbWqmUr.js → json-BwmgqzNJ.js} +1 -1
- package/gui/dist/assets/{jsx-BFPQ2oqh.js → jsx-BLTVsDXL.js} +1 -1
- package/gui/dist/assets/{julia-DX1Bsm0x.js → julia-BEeV8R5w.js} +1 -1
- package/gui/dist/assets/{just-D524YAex.js → just-BwQDH9rp.js} +1 -1
- package/gui/dist/assets/{latex-Dc0dzAGl.js → latex-BJn4gKgg.js} +1 -1
- package/gui/dist/assets/{liquid-DXohsHev.js → liquid-B5SMgGD6.js} +1 -1
- package/gui/dist/assets/{lua-G_rux6Ay.js → lua-CVTScK8G.js} +1 -1
- package/gui/dist/assets/{marko-BdidjG96.js → marko-BneKfb4h.js} +1 -1
- package/gui/dist/assets/{mdc-DxAZb3tM.js → mdc-DHkkf3Ef.js} +1 -1
- package/gui/dist/assets/{nginx-CuvNT-q8.js → nginx-DxGETPm7.js} +1 -1
- package/gui/dist/assets/{nim-DuDgLkQa.js → nim-DV7N6lGB.js} +1 -1
- package/gui/dist/assets/{org-BJKUhgoL.js → org-D9idAuxR.js} +1 -1
- package/gui/dist/assets/{perl-BdJ-pZH6.js → perl-itV17GnJ.js} +1 -1
- package/gui/dist/assets/{php-DUOUy2DX.js → php-CCAkcfa5.js} +1 -1
- package/gui/dist/assets/{pug-WUnoGP-C.js → pug-C5resLq0.js} +1 -1
- package/gui/dist/assets/{qml-Dl8tY0zd.js → qml-BkHobuTC.js} +1 -1
- package/gui/dist/assets/{r-Ci9Hbbcn.js → r-BqWX-dEx.js} +1 -1
- package/gui/dist/assets/{razor-0bx4DTys.js → razor-BpA2ENLe.js} +1 -1
- package/gui/dist/assets/{regexp-C0ZlJfpq.js → regexp-C-XnPPLY.js} +1 -1
- package/gui/dist/assets/{rst-BC_vqA0U.js → rst-CUTbSAax.js} +1 -1
- package/gui/dist/assets/{ruby-DPPk42YS.js → ruby-D7bW5EZD.js} +1 -1
- package/gui/dist/assets/{sas-B8jfw3hR.js → sas-w8fOFl4u.js} +1 -1
- package/gui/dist/assets/{scss-7mTWL496.js → scss-BNjT1ImJ.js} +1 -1
- package/gui/dist/assets/{shellscript-CYNcJqc-.js → shellscript-CMWcepnG.js} +1 -1
- package/gui/dist/assets/{shellsession-Dh2E3t_B.js → shellsession-D5YeFBMB.js} +1 -1
- package/gui/dist/assets/{soy-BVR-TmA2.js → soy-CaNGX-mM.js} +1 -1
- package/gui/dist/assets/{sql-D3S51lwn.js → sql-DxGfvOCg.js} +1 -1
- package/gui/dist/assets/{stata-BjuRTlAG.js → stata-Bp4oSjfv.js} +1 -1
- package/gui/dist/assets/{surrealql-BKRHdvyc.js → surrealql-C8Utj_WH.js} +1 -1
- package/gui/dist/assets/{svelte-DIKo_e2T.js → svelte-BFHeACD2.js} +1 -1
- package/gui/dist/assets/{templ-DC42iqks.js → templ-CxVazkuY.js} +1 -1
- package/gui/dist/assets/{tex-BZ2lfoiV.js → tex-CSoJ8Afo.js} +1 -1
- package/gui/dist/assets/{ts-tags-o8CUeNFk.js → ts-tags-BUTYhDKV.js} +1 -1
- package/gui/dist/assets/{tsx-DeMh4Cat.js → tsx-BvqayBnu.js} +1 -1
- package/gui/dist/assets/{twig-BUr_lvSK.js → twig-DWygjTq9.js} +1 -1
- package/gui/dist/assets/{typescript-DeKHrHpS.js → typescript-C7DqIINO.js} +1 -1
- package/gui/dist/assets/{typst-CcbUABTI.js → typst-Dp1YSMkC.js} +1 -1
- package/gui/dist/assets/{vue-JHDlnmNz.js → vue-C6O_bBVG.js} +1 -1
- package/gui/dist/assets/{vue-html-soMMIiuc.js → vue-html-CMX7hzAZ.js} +1 -1
- package/gui/dist/assets/{vue-vine-D8TZS6Lm.js → vue-vine-DnhOPozF.js} +1 -1
- package/gui/dist/assets/{xml-9isD2blC.js → xml-03xiog6c.js} +1 -1
- package/gui/dist/assets/{xsl-chWKvWOz.js → xsl-Di6xLqaY.js} +1 -1
- package/gui/dist/assets/{yaml-DEY2M1js.js → yaml-BfGI9DCW.js} +1 -1
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -197,7 +197,7 @@ Chaque nœud a un `id`, un `label`, une forme `shape` (`box` par défaut, `pill`
|
|
|
197
197
|
| Outil | Effet |
|
|
198
198
|
|---|---|
|
|
199
199
|
| `get_review_feedback` | Une fois la revue soumise : décision (`approve`, `request_changes`, `reject`), état du traitement (à traiter, ou traité avec sa date et sa note), constats et remarques retenus avec leur détail, et le prompt généré, recopié tel quel. Après une nouvelle soumission, il liste aussi ce qui a changé depuis la version soumise précédente (décision, constats et remarques ajoutés, modifiés ou retirés) et rappelle comment celle-ci avait été traitée. Avant la soumission, ou pendant que le relecteur modifie une revue soumise : l'avancement seul (fichiers revus, constats ignorés, remarques). Lecture seule. |
|
|
200
|
-
| `mark_feedback_processed` | Marque traité le retour soumis, avec la date et une `note` facultative (« corrigé par 12785d6e3 et 1ff5baaad », « réponses données en conversation »). Sert quand `refresh_analysis` ne convient pas : analyse d'un commit précis corrigée dans d'autres commits, remarques auxquelles l'agent a répondu dans la conversation. Le retour reste lisible avec `get_review_feedback`. Refusé tant que la revue n'est pas soumise ; un nouveau marquage remplace le précédent. |
|
|
200
|
+
| `mark_feedback_processed` | Marque traité le retour soumis, avec la date et une `note` facultative (« corrigé par 12785d6e3 et 1ff5baaad », « réponses données en conversation »). Sert quand `refresh_analysis` ne convient pas : analyse d'un commit précis corrigée dans d'autres commits, remarques auxquelles l'agent a répondu dans la conversation. Le retour reste lisible avec `get_review_feedback`. Refusé tant que la revue n'est pas soumise ; un nouveau marquage remplace le précédent. Le relecteur peut aussi marquer un retour traité depuis l'accueil de la GUI ; le traitement enregistre son auteur, et `get_review_feedback` l'indique (« by the agent » ou « by the reviewer »). |
|
|
201
201
|
|
|
202
202
|
Le retour se lit **avant** `refresh_analysis`, qui le remplace par une revue vierge : le recalcul vaut traitement, puisqu'il relance la revue.
|
|
203
203
|
|
|
@@ -242,7 +242,7 @@ Thème sombre. La barre supérieure porte la marque (un clic ramène à l'accuei
|
|
|
242
242
|
|
|
243
243
|
### Accueil (`#/`)
|
|
244
244
|
|
|
245
|
-
Les analyses sont rangées par projet, dans des sections repliables. L'en-tête d'un projet compte ses analyses par état de revue. Chaque analyse est une carte séparée des autres. Son titre s'affiche en entier sur toute la largeur et passe à la ligne s'il le faut. Dessous, sur une seconde ligne : ses refs, la date de sa dernière modification, la progression des fichiers revus, ses constats ouverts par gravité (exigences manquantes comprises, ce que dit l'infobulle) et son état de revue : « Non commencée », « En cours », « Fichiers revus » ou « Soumise », suivi de la décision, puis « Traitée » une fois que l'agent a marqué le retour traité (date et note en infobulle) ; la pastille disparaît dès que le relecteur modifie la revue, qui repasse en cours. Quand
|
|
245
|
+
Les analyses sont rangées par projet, dans des sections repliables. L'en-tête d'un projet compte ses analyses par état de revue. Chaque analyse est une carte séparée des autres. Son titre s'affiche en entier sur toute la largeur et passe à la ligne s'il le faut. Dessous, sur une seconde ligne : ses refs, la date de sa dernière modification, la progression des fichiers revus, ses constats ouverts par gravité (exigences manquantes comprises, ce que dit l'infobulle) et son état de revue : « Non commencée », « En cours », « Fichiers revus » ou « Soumise », suivi de la décision, puis « Traitée » une fois que l'agent a marqué le retour traité (date et note en infobulle) ; la pastille disparaît dès que le relecteur modifie la revue, qui repasse en cours. Quand le retour est marqué traité, une ligne sous les références donne la note, l'auteur du marquage (l'agent, ou le relecteur) et la date. Dans le filtre « À traiter par l'agent », chaque carte porte à droite du titre un bouton « Marquer comme traité » : il ouvre une petite fenêtre avec une note facultative (Entrée confirme, Échap referme), et la revue passe dans « Traitées par l'agent », comme avec `mark_feedback_processed`. Le reste de la carte mène à l'analyse. Une colonne à gauche filtre la liste, chaque filtre avec son icône et son nombre d'analyses : « À relire » (par défaut, revues pas encore soumises), « À traiter par l'agent » (retour soumis que l'agent n'a pas encore traité), « Traitées par l'agent » (retour traité, corrections à vérifier ; ce filtre ressort en sarcelle tant qu'il n'est pas vide), « Approuvées », et « Toutes ». Les quatre premiers se partagent les analyses sans se recouvrir. Sous 900 px de large, les filtres passent au-dessus de la liste. L'accueil n'ouvre aucune analyse d'office ; sans analyse, il explique que l'agent les crée avec `create_analysis`.
|
|
246
246
|
|
|
247
247
|
### Écran Feature (`#/<id>`)
|
|
248
248
|
|
|
@@ -259,7 +259,8 @@ L'ajustement à la fenêtre ne descend jamais sous l'échelle **0,85** : en dess
|
|
|
259
259
|
|
|
260
260
|
### Écran Revue (`#/<id>/review/<chemin>`)
|
|
261
261
|
|
|
262
|
-
- **
|
|
262
|
+
- **Progression** — dans la barre supérieure, à gauche de « Terminer la revue » : « 3/7 revus » et une barre étroite, visibles quel que soit le défilement et même panneau des fichiers masqué.
|
|
263
|
+
- **Panneau des fichiers** — nombre de fichiers, fichiers groupés par dossier, état revu, pastilles des constats ouverts par gravité et, en bout de ligne, la lettre du statut git à la manière de VS Code : `M` modifié, `A` ajouté, `D` supprimé, `R` renommé, `U` non suivi (libellé complet en infobulle). Un nom trop long est tronqué au milieu (`reminder-sch…uler.ts`), l'extension reste visible et le chemin complet est en infobulle. Chaque pastille est un lien : elle ouvre le fichier sur son premier constat ouvert de cette gravité (`?line=N`) ; son infobulle le dit (« 3 constats mineurs ouverts — aller au premier »). Sa largeur se règle en glissant son bord droit (entre 200 et 600 px ; flèches gauche et droite quand la poignée a le focus, double-clic pour revenir à 280 px) et se conserve dans le navigateur d'un rechargement à l'autre. Le bouton en tête de l'en-tête du fichier masque ou réaffiche le panneau, pour toute la session : le diff s'élargit vers la gauche, la colonne de droite garde sa largeur. Il reste affiché quand le chemin demandé ne fait pas partie de l'analyse.
|
|
263
264
|
- **En-tête du fichier** — bascule du panneau des fichiers, chemin, `+`/`−`, statut, fichier précédent et suivant, « Remarque sur le fichier », « Marquer comme revu ».
|
|
264
265
|
- **Diff** — code coloré selon le langage du fichier, déduit de son extension ou de son nom (grammaires de [Shiki](https://shiki.style), chargées à la demande) : le côté nouveau à partir du contenu complet du fichier quand le snapshot le conserve, sinon bloc par bloc ; les lignes supprimées bloc par bloc ; chaque correctif proposé séparément ; les lignes barrées par un correctif restent sans couleur. Un fichier dont le langage n'est pas reconnu s'affiche sans coloration ; une grammaire qui ne se charge pas est signalée dans la barre du diff. Numéros du côté nouveau et repère vertical à la couleur de la gravité le long des lignes visées par un constat. La barre du diff porte trois réglages, communs à tous les fichiers et conservés dans le navigateur d'un rechargement à l'autre : chacun est un bouton compact qui affiche sa valeur courante, et un clic ouvre la liste de ses choix, chacun avec son icône et une description d'une ligne (un clic dehors, Échap ou un défilement la referme). « Afficher » choisit entre « Modifications » (les blocs du diff git, entourés de leurs lignes de contexte) et « Fichier entier » (tout le fichier en un seul bloc : les lignes inchangées, tirées du contenu conservé, s'intercalent entre les modifications, ce qui donne à lire en entier une fonction modifiée en son milieu ; les deux autres sélecteurs s'y appliquent de la même façon, un correctif dont les lignes chevauchaient deux blocs s'y affiche, et « Copier une demande d'explication » porte alors sur tout le fichier). En « Fichier entier », une mini-carte de 22 px longe le bord droit du diff et reste à l'écran pendant le défilement : toute sa hauteur représente tout le fichier affiché. Sa piste de gauche place les lignes ajoutées (vert), supprimées (rouge), supprimées et ajoutées en vis-à-vis en vue « Côte à côte » (moitié rouge, moitié verte) ou seulement réindentées (violet) ; sa piste de droite porte un point par constat, à la couleur de sa gravité (atténué s'il n'est plus ouvert), et un point par ligne portant une remarque. Un cadre bleuté suit la portion visible. Le survol d'un repère en donne la description (« 12 lignes ajoutées · lignes 120 à 131 », « Constat 3 · Majeur » et son titre) ; un clic ou un glissé sur la carte fait défiler le diff jusqu'à l'endroit visé. « Fichier entier » est inactif pour un fichier dont le contenu n'est pas conservé ; la liste en donne la raison à la place de sa description. « Code » choisit entre « Unifié » (une seule colonne : lignes supprimées sur fond rouge au-dessus des lignes ajoutées sur fond vert), « Côte à côte » (ancien code à gauche avec ses numéros du côté ancien, nouveau code à droite : lignes de contexte des deux côtés, lignes supprimées et ajoutées appariées ligne à ligne, case hachurée en face d'une ligne sans vis-à-vis ; remarques, repères et lignes proposées par un correctif sont du côté droit, le bandeau d'un correctif sur toute la largeur) et « Nouveau code » (le code du côté nouveau seul, dans les mêmes blocs : les lignes supprimées ne sont pas affichées et les lignes ajoutées portent un fin filet vert à la place de leur fond et de leur marque ; une explication de code supprimé s'aligne alors sur la ligne voisine du bloc). « Correctifs » choisit entre « Sans correctif », « Avant / après » et « Code corrigé ». Le correctif proposé s'affiche à l'endroit où il s'applique : bandeau « Correctif proposé par l'agent — remplace les lignes X à Y » avec le numéro du constat et « Masquer le correctif », lignes visées barrées sur fond ambre, lignes proposées juste en dessous sur fond violet (marque « › », sans numéro). Le correctif est affiché d'office pour un constat ouvert ; masqué, ou pour un constat sans correctif, une pastille numérotée marque la première ligne visée. Un filet sarcelle longe les lignes décrites par une explication. En « Modifications », quand le contenu du fichier est conservé, l'en-tête de chaque bloc porte un réglage « −5 · N lignes · +5 » : « +5 » ajoute cinq lignes de contexte au-dessus et cinq en dessous du bloc, « −5 » les retire, et le compteur donne le nombre de lignes de contexte au-dessus de la première modification. Les lignes ajoutées s'insèrent sous l'en-tête et après le bloc, si bien que le réglage ne bouge pas à l'écran ; elles se distinguent par un fond plus sombre et un filet gris (« Contexte ajouté » dans la légende). Les lignes entre deux blocs vont d'abord au bloc du dessus ; quand plus aucune ligne masquée ne les sépare, les deux blocs n'en forment plus qu'un, sous un seul en-tête dont « +5 » et « −5 » s'appliquent à chacun des blocs réunis. « +5 » s'éteint quand le bloc atteint les bords du fichier. Le contexte choisi est propre à chaque fichier et dure le temps de la session. L'en-tête de chaque bloc porte aussi « Copier une demande d'explication » (icône du robot) : le bouton copie un prompt à coller dans la conversation de l'agent, qui situe le bloc (analyse, dépôt et refs, fichier, lignes des deux côtés, code tel que figé) et lui demande de l'expliquer en enregistrant ses explications avec `add_explanations`, ou `update_explanation` si une explication couvre déjà ces lignes. Deux correctifs dont les lignes se recouvrent ne s'affichent pas ensemble. Le fond ambre des lignes visées se distingue du rouge des lignes `−` supprimées par la feature. Une légende suit le diff, limitée aux fonds que la vue et le mode affichent : « Ajouté par la feature » (fond ou filet selon la vue), « Supprimé par la feature » (Unifié et Côte à côte), « Lignes remplacées par le correctif » (Avant / après), « Correctif proposé » ou « Correctif appliqué », « Code décrit par une explication ». Quand une ligne supprimée et la ligne ajoutée qui la remplace se ressemblent (la moitié de leurs mots au moins en commun), seules leurs parties modifiées sont surlignées, en rouge sur l'ancienne ligne et en vert sur la nouvelle, sans fond sur le reste de la ligne ; dans chaque suite de lignes supprimées puis ajoutées, la i-ème ligne supprimée est comparée à la i-ème ligne ajoutée, mot à mot. Une ligne sans correspondante proche garde son fond entier (« Partie modifiée de la ligne » dans la légende). Un clic sur un numéro de ligne ouvre la saisie d'une remarque sur cette ligne. Les exigences manquantes sans emplacement s'affichent en bandeau au-dessus du diff de chaque fichier ; le bandeau « N exigences manquantes » se replie, et reste replié pour la session.
|
|
265
266
|
- **Affichage des correctifs** — le sélecteur « Correctifs », au-dessus du diff, propose trois modes, conservés d'un fichier à l'autre et d'un rechargement à l'autre :
|
|
@@ -191,10 +191,17 @@ export declare const DiagramSchema: z.ZodObject<{
|
|
|
191
191
|
}, z.core.$strip>>;
|
|
192
192
|
updatedAt: z.ZodString;
|
|
193
193
|
}, z.core.$strip>;
|
|
194
|
-
/**
|
|
194
|
+
/**
|
|
195
|
+
* Traitement d'un retour : date, note facultative (commits, réponses données…) et
|
|
196
|
+
* auteur du marquage — l'agent, ou le relecteur depuis la GUI.
|
|
197
|
+
*/
|
|
195
198
|
export declare const ProcessingSchema: z.ZodObject<{
|
|
196
199
|
at: z.ZodString;
|
|
197
200
|
note: z.ZodNullable<z.ZodString>;
|
|
201
|
+
by: z.ZodEnum<{
|
|
202
|
+
agent: "agent";
|
|
203
|
+
user: "user";
|
|
204
|
+
}>;
|
|
198
205
|
}, z.core.$strip>;
|
|
199
206
|
/**
|
|
200
207
|
* Dernière version soumise d'une revue, conservée quand le relecteur la modifie
|
|
@@ -211,6 +218,10 @@ export declare const SubmissionRecordSchema: z.ZodObject<{
|
|
|
211
218
|
processed: z.ZodNullable<z.ZodObject<{
|
|
212
219
|
at: z.ZodString;
|
|
213
220
|
note: z.ZodNullable<z.ZodString>;
|
|
221
|
+
by: z.ZodEnum<{
|
|
222
|
+
agent: "agent";
|
|
223
|
+
user: "user";
|
|
224
|
+
}>;
|
|
214
225
|
}, z.core.$strip>>;
|
|
215
226
|
findings: z.ZodArray<z.ZodObject<{
|
|
216
227
|
id: z.ZodString;
|
|
@@ -244,6 +255,10 @@ export declare const ReviewSchema: z.ZodObject<{
|
|
|
244
255
|
processed: z.ZodNullable<z.ZodObject<{
|
|
245
256
|
at: z.ZodString;
|
|
246
257
|
note: z.ZodNullable<z.ZodString>;
|
|
258
|
+
by: z.ZodEnum<{
|
|
259
|
+
agent: "agent";
|
|
260
|
+
user: "user";
|
|
261
|
+
}>;
|
|
247
262
|
}, z.core.$strip>>;
|
|
248
263
|
previousSubmission: z.ZodNullable<z.ZodObject<{
|
|
249
264
|
decision: z.ZodEnum<{
|
|
@@ -255,6 +270,10 @@ export declare const ReviewSchema: z.ZodObject<{
|
|
|
255
270
|
processed: z.ZodNullable<z.ZodObject<{
|
|
256
271
|
at: z.ZodString;
|
|
257
272
|
note: z.ZodNullable<z.ZodString>;
|
|
273
|
+
by: z.ZodEnum<{
|
|
274
|
+
agent: "agent";
|
|
275
|
+
user: "user";
|
|
276
|
+
}>;
|
|
258
277
|
}, z.core.$strip>>;
|
|
259
278
|
findings: z.ZodArray<z.ZodObject<{
|
|
260
279
|
id: z.ZodString;
|
|
@@ -440,6 +459,10 @@ export declare const AnalysisSchema: z.ZodObject<{
|
|
|
440
459
|
processed: z.ZodNullable<z.ZodObject<{
|
|
441
460
|
at: z.ZodString;
|
|
442
461
|
note: z.ZodNullable<z.ZodString>;
|
|
462
|
+
by: z.ZodEnum<{
|
|
463
|
+
agent: "agent";
|
|
464
|
+
user: "user";
|
|
465
|
+
}>;
|
|
443
466
|
}, z.core.$strip>>;
|
|
444
467
|
previousSubmission: z.ZodNullable<z.ZodObject<{
|
|
445
468
|
decision: z.ZodEnum<{
|
|
@@ -451,6 +474,10 @@ export declare const AnalysisSchema: z.ZodObject<{
|
|
|
451
474
|
processed: z.ZodNullable<z.ZodObject<{
|
|
452
475
|
at: z.ZodString;
|
|
453
476
|
note: z.ZodNullable<z.ZodString>;
|
|
477
|
+
by: z.ZodEnum<{
|
|
478
|
+
agent: "agent";
|
|
479
|
+
user: "user";
|
|
480
|
+
}>;
|
|
454
481
|
}, z.core.$strip>>;
|
|
455
482
|
findings: z.ZodArray<z.ZodObject<{
|
|
456
483
|
id: z.ZodString;
|
|
@@ -122,10 +122,14 @@ export const DiagramSchema = z.object({
|
|
|
122
122
|
links: z.array(DiagramLinkSchema),
|
|
123
123
|
updatedAt: IsoDateSchema,
|
|
124
124
|
});
|
|
125
|
-
/**
|
|
125
|
+
/**
|
|
126
|
+
* Traitement d'un retour : date, note facultative (commits, réponses données…) et
|
|
127
|
+
* auteur du marquage — l'agent, ou le relecteur depuis la GUI.
|
|
128
|
+
*/
|
|
126
129
|
export const ProcessingSchema = z.object({
|
|
127
130
|
at: IsoDateSchema,
|
|
128
131
|
note: z.string().min(1).nullable(),
|
|
132
|
+
by: z.enum(EDITORS),
|
|
129
133
|
});
|
|
130
134
|
/**
|
|
131
135
|
* Dernière version soumise d'une revue, conservée quand le relecteur la modifie
|
|
@@ -40,7 +40,13 @@ export declare const SubmitReviewBodySchema: z.ZodObject<{
|
|
|
40
40
|
noteIds: z.ZodArray<z.ZodString>;
|
|
41
41
|
baseRevision: z.ZodNumber;
|
|
42
42
|
}, z.core.$strict>;
|
|
43
|
+
/** Marquage du retour soumis comme traité par le relecteur, avec une note facultative. */
|
|
44
|
+
export declare const MarkProcessedBodySchema: z.ZodObject<{
|
|
45
|
+
note: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
46
|
+
baseRevision: z.ZodNumber;
|
|
47
|
+
}, z.core.$strict>;
|
|
43
48
|
export type SetFileReviewedBody = z.infer<typeof SetFileReviewedBodySchema>;
|
|
49
|
+
export type MarkProcessedBody = z.infer<typeof MarkProcessedBodySchema>;
|
|
44
50
|
export type SetFindingStatusBody = z.infer<typeof SetFindingStatusBodySchema>;
|
|
45
51
|
export type AddNoteBody = z.infer<typeof AddNoteBodySchema>;
|
|
46
52
|
export type UpdateNoteBody = z.infer<typeof UpdateNoteBodySchema>;
|
|
@@ -108,3 +114,10 @@ export declare const SubmitReviewRequestSchema: z.ZodObject<{
|
|
|
108
114
|
baseRevision: z.ZodNumber;
|
|
109
115
|
}, z.core.$strict>;
|
|
110
116
|
}, z.core.$strict>;
|
|
117
|
+
export declare const MarkProcessedRequestSchema: z.ZodObject<{
|
|
118
|
+
analysisId: z.ZodString;
|
|
119
|
+
body: z.ZodObject<{
|
|
120
|
+
note: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
121
|
+
baseRevision: z.ZodNumber;
|
|
122
|
+
}, z.core.$strict>;
|
|
123
|
+
}, z.core.$strict>;
|
|
@@ -39,6 +39,11 @@ export const SubmitReviewBodySchema = z.strictObject({
|
|
|
39
39
|
noteIds: z.array(z.string().min(1)),
|
|
40
40
|
baseRevision: BaseRevisionSchema,
|
|
41
41
|
});
|
|
42
|
+
/** Marquage du retour soumis comme traité par le relecteur, avec une note facultative. */
|
|
43
|
+
export const MarkProcessedBodySchema = z.strictObject({
|
|
44
|
+
note: z.string().trim().min(1, "the note is empty").nullable().optional(),
|
|
45
|
+
baseRevision: BaseRevisionSchema,
|
|
46
|
+
});
|
|
42
47
|
/** Données IPC des requêtes de la GUI qui visent une analyse. */
|
|
43
48
|
export const AnalysisRequestSchema = z.strictObject({ analysisId: z.string().min(1) });
|
|
44
49
|
export const SetFileReviewedRequestSchema = AnalysisRequestSchema.extend({ body: SetFileReviewedBodySchema });
|
|
@@ -56,3 +61,4 @@ export const DeleteNoteRequestSchema = AnalysisRequestSchema.extend({
|
|
|
56
61
|
body: DeleteNoteBodySchema,
|
|
57
62
|
});
|
|
58
63
|
export const SubmitReviewRequestSchema = AnalysisRequestSchema.extend({ body: SubmitReviewBodySchema });
|
|
64
|
+
export const MarkProcessedRequestSchema = AnalysisRequestSchema.extend({ body: MarkProcessedBodySchema });
|
|
@@ -40,5 +40,5 @@ export type ChangesResponse = {
|
|
|
40
40
|
events: IPCMessage[];
|
|
41
41
|
};
|
|
42
42
|
/** Requêtes du GUI worker au maître ; chacune reçoit une réponse de même `correlationId`. */
|
|
43
|
-
export declare const GUI_REQUEST_TYPES: readonly ["GET_CONFIG", "LIST_ANALYSES", "GET_ANALYSIS", "GET_DIFF", "SET_FILE_REVIEWED", "SET_FINDING_STATUS", "ADD_NOTE", "UPDATE_NOTE", "DELETE_NOTE", "SUBMIT_REVIEW"];
|
|
43
|
+
export declare const GUI_REQUEST_TYPES: readonly ["GET_CONFIG", "LIST_ANALYSES", "GET_ANALYSIS", "GET_DIFF", "SET_FILE_REVIEWED", "SET_FINDING_STATUS", "ADD_NOTE", "UPDATE_NOTE", "DELETE_NOTE", "SUBMIT_REVIEW", "MARK_PROCESSED"];
|
|
44
44
|
export type GuiRequestType = (typeof GUI_REQUEST_TYPES)[number];
|
|
@@ -21,6 +21,11 @@ export declare const addNoteFindingIds: MigrationStep;
|
|
|
21
21
|
* avant ce format est à traiter, sans version précédente.
|
|
22
22
|
*/
|
|
23
23
|
export declare const addReviewProcessing: MigrationStep;
|
|
24
|
+
/**
|
|
25
|
+
* Ajoute `by: "agent"` aux traitements enregistrés sans auteur, dans la revue et
|
|
26
|
+
* dans sa version soumise précédente : seul l'agent pouvait alors les poser.
|
|
27
|
+
*/
|
|
28
|
+
export declare const addProcessingAuthor: MigrationStep;
|
|
24
29
|
/** Étapes appliquées aux analyses (`analyses/<id>.json`), dans l'ordre. */
|
|
25
30
|
export declare const ANALYSIS_MIGRATIONS: readonly MigrationStep[];
|
|
26
31
|
/** Étapes appliquées aux snapshots de diff (`diffs/<id>.json`), dans l'ordre. */
|
package/dist/src/core/migrate.js
CHANGED
|
@@ -49,8 +49,45 @@ export const addReviewProcessing = (doc) => {
|
|
|
49
49
|
return null;
|
|
50
50
|
return { ...doc, review: { ...raw, processed: raw.processed ?? null, previousSubmission: raw.previousSubmission ?? null } };
|
|
51
51
|
};
|
|
52
|
+
/** `processed` augmenté de `by: "agent"` quand il n'a pas d'auteur ; null quand il n'y a rien à changer. */
|
|
53
|
+
function withProcessingAuthor(processed) {
|
|
54
|
+
if (!processed || typeof processed !== "object" || Array.isArray(processed))
|
|
55
|
+
return null;
|
|
56
|
+
const raw = processed;
|
|
57
|
+
return raw.by !== undefined ? null : { ...raw, by: "agent" };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Ajoute `by: "agent"` aux traitements enregistrés sans auteur, dans la revue et
|
|
61
|
+
* dans sa version soumise précédente : seul l'agent pouvait alors les poser.
|
|
62
|
+
*/
|
|
63
|
+
export const addProcessingAuthor = (doc) => {
|
|
64
|
+
const review = doc.review;
|
|
65
|
+
if (!review || typeof review !== "object" || Array.isArray(review))
|
|
66
|
+
return null;
|
|
67
|
+
const raw = review;
|
|
68
|
+
const processed = withProcessingAuthor(raw.processed);
|
|
69
|
+
const previous = raw.previousSubmission;
|
|
70
|
+
const previousProcessed = previous && typeof previous === "object" ? withProcessingAuthor(previous.processed) : null;
|
|
71
|
+
if (processed === null && previousProcessed === null)
|
|
72
|
+
return null;
|
|
73
|
+
return {
|
|
74
|
+
...doc,
|
|
75
|
+
review: {
|
|
76
|
+
...raw,
|
|
77
|
+
...(processed === null ? {} : { processed }),
|
|
78
|
+
...(previousProcessed === null ? {} : { previousSubmission: { ...previous, processed: previousProcessed } }),
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
};
|
|
52
82
|
/** Étapes appliquées aux analyses (`analyses/<id>.json`), dans l'ordre. */
|
|
53
|
-
export const ANALYSIS_MIGRATIONS = [
|
|
83
|
+
export const ANALYSIS_MIGRATIONS = [
|
|
84
|
+
addProject,
|
|
85
|
+
addOverview,
|
|
86
|
+
addExplanations,
|
|
87
|
+
addNoteFindingIds,
|
|
88
|
+
addReviewProcessing,
|
|
89
|
+
addProcessingAuthor,
|
|
90
|
+
];
|
|
54
91
|
/** Étapes appliquées aux snapshots de diff (`diffs/<id>.json`), dans l'ordre. */
|
|
55
92
|
export const SNAPSHOT_MIGRATIONS = [];
|
|
56
93
|
/** Applique `steps` à la suite. Renvoie null si aucune étape n'a modifié le document. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Analysis } from "../../shared/schemas/analysis.schema.js";
|
|
2
|
-
import type { AddNoteBody, DeleteNoteBody, SetFileReviewedBody, SetFindingStatusBody, SubmitReviewBody, UpdateNoteBody } from "../../shared/schemas/api.schema.js";
|
|
3
|
-
import type { AnalysisStore } from "./analysis-store.js";
|
|
1
|
+
import type { Analysis, Editor } from "../../shared/schemas/analysis.schema.js";
|
|
2
|
+
import type { AddNoteBody, DeleteNoteBody, MarkProcessedBody, SetFileReviewedBody, SetFindingStatusBody, SubmitReviewBody, UpdateNoteBody } from "../../shared/schemas/api.schema.js";
|
|
3
|
+
import type { AnalysisStore, MutateOptions } from "./analysis-store.js";
|
|
4
4
|
/**
|
|
5
5
|
* Modifications faites par le relecteur depuis la GUI. Chacune passe par
|
|
6
6
|
* `store.mutate(id, "user", …, { baseRevision })` et renvoie l'analyse écrite.
|
|
@@ -25,6 +25,19 @@ export declare function addNote(store: AnalysisStore, analysisId: string, body:
|
|
|
25
25
|
export declare function updateNote(store: AnalysisStore, analysisId: string, noteId: string, body: UpdateNoteBody): Analysis;
|
|
26
26
|
/** Supprime une remarque et la retire de la sélection de la revue. */
|
|
27
27
|
export declare function deleteNote(store: AnalysisStore, analysisId: string, noteId: string, body: DeleteNoteBody): Analysis;
|
|
28
|
+
/** Analyse marquée traitée, et date du marquage qu'elle remplace s'il y en avait un. */
|
|
29
|
+
export interface MarkProcessedResult {
|
|
30
|
+
analysis: Analysis;
|
|
31
|
+
replaced: string | null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Marque traité le retour soumis d'une analyse : date, note facultative et
|
|
35
|
+
* auteur (`agent` par l'outil MCP, `user` depuis la GUI). Refusé tant que la
|
|
36
|
+
* revue n'est pas soumise ; un nouveau marquage remplace le précédent.
|
|
37
|
+
*/
|
|
38
|
+
export declare function markFeedbackProcessed(store: AnalysisStore, analysisId: string, editor: Editor, note: string | null, options?: MutateOptions): MarkProcessedResult;
|
|
39
|
+
/** Marque traité, depuis la GUI, le retour soumis d'une analyse. */
|
|
40
|
+
export declare function markProcessedByReviewer(store: AnalysisStore, analysisId: string, body: MarkProcessedBody): Analysis;
|
|
28
41
|
/**
|
|
29
42
|
* Soumet la revue : décision, points retenus et prompt calculé ici. La revue
|
|
30
43
|
* soumise est à traiter par l'agent. Une nouvelle soumission remplace la
|
|
@@ -86,6 +86,31 @@ export function deleteNote(store, analysisId, noteId, body) {
|
|
|
86
86
|
draft.review.selectedNoteIds = draft.review.selectedNoteIds.filter((id) => id !== noteId);
|
|
87
87
|
}, { baseRevision: body.baseRevision });
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Marque traité le retour soumis d'une analyse : date, note facultative et
|
|
91
|
+
* auteur (`agent` par l'outil MCP, `user` depuis la GUI). Refusé tant que la
|
|
92
|
+
* revue n'est pas soumise ; un nouveau marquage remplace le précédent.
|
|
93
|
+
*/
|
|
94
|
+
export function markFeedbackProcessed(store, analysisId, editor, note, options = {}) {
|
|
95
|
+
let replaced = null;
|
|
96
|
+
const analysis = store.mutate(analysisId, editor, (draft) => {
|
|
97
|
+
const review = draft.review;
|
|
98
|
+
if (review.state !== "submitted") {
|
|
99
|
+
const reopened = review.previousSubmission;
|
|
100
|
+
throw new AnalysisError(reopened
|
|
101
|
+
? `The review of analysis "${analysisId}" is not submitted: the reviewer reopened the feedback submitted at ${reopened.submittedAt} and is changing it. ` +
|
|
102
|
+
`Wait until it is submitted again, then read it with get_review_feedback.`
|
|
103
|
+
: `The review of analysis "${analysisId}" is not submitted yet: there is no feedback to mark processed.`);
|
|
104
|
+
}
|
|
105
|
+
replaced = review.processed?.at ?? null;
|
|
106
|
+
review.processed = { at: new Date().toISOString(), note, by: editor };
|
|
107
|
+
}, options);
|
|
108
|
+
return { analysis, replaced };
|
|
109
|
+
}
|
|
110
|
+
/** Marque traité, depuis la GUI, le retour soumis d'une analyse. */
|
|
111
|
+
export function markProcessedByReviewer(store, analysisId, body) {
|
|
112
|
+
return markFeedbackProcessed(store, analysisId, "user", body.note ?? null, { baseRevision: body.baseRevision }).analysis;
|
|
113
|
+
}
|
|
89
114
|
function assertKnownIds(label, ids, known) {
|
|
90
115
|
const knownSet = new Set(known);
|
|
91
116
|
const unknown = ids.filter((id) => !knownSet.has(id));
|
package/dist/src/gui-worker.js
CHANGED
|
@@ -7,7 +7,7 @@ import fs from "fs";
|
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
8
|
import { randomUUID } from "crypto";
|
|
9
9
|
import { IPCMessageSchema, PUSHED_EVENT_TYPES } from "../shared/schemas/ipc.schema.js";
|
|
10
|
-
import { AddNoteBodySchema, DeleteNoteBodySchema, SetFileReviewedBodySchema, SetFindingStatusBodySchema, SubmitReviewBodySchema, UpdateNoteBodySchema, } from "../shared/schemas/api.schema.js";
|
|
10
|
+
import { AddNoteBodySchema, DeleteNoteBodySchema, MarkProcessedBodySchema, SetFileReviewedBodySchema, SetFindingStatusBodySchema, SubmitReviewBodySchema, UpdateNoteBodySchema, } from "../shared/schemas/api.schema.js";
|
|
11
11
|
import { resolveLogDir } from "./core/log-dir.js";
|
|
12
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
function findProjectRoot(startDir) {
|
|
@@ -276,6 +276,12 @@ app.post("/api/analyses/:id/review", async (c) => {
|
|
|
276
276
|
return read.response;
|
|
277
277
|
return forward(c, "SUBMIT_REVIEW", { analysisId: c.req.param("id"), body: read.body });
|
|
278
278
|
});
|
|
279
|
+
app.post("/api/analyses/:id/review/processed", async (c) => {
|
|
280
|
+
const read = await readBody(c, MarkProcessedBodySchema);
|
|
281
|
+
if ("response" in read)
|
|
282
|
+
return read.response;
|
|
283
|
+
return forward(c, "MARK_PROCESSED", { analysisId: c.req.param("id"), body: read.body });
|
|
284
|
+
});
|
|
279
285
|
/** Route d'API inconnue : 404 explicite plutôt que la page de la SPA. */
|
|
280
286
|
app.all("/api/*", (c) => c.json({ error: `Unknown API route: ${c.req.method} ${c.req.path}` }, 404));
|
|
281
287
|
// Fichiers statiques de la SPA
|
package/dist/src/index.js
CHANGED
|
@@ -16,9 +16,9 @@ import { DEFAULT_HEAD_REF, localRepo } from "./core/git.js";
|
|
|
16
16
|
import { agentRepo } from "./core/agent-repo.js";
|
|
17
17
|
import { EXEC_ARG, handleAgentExec } from "./core/gateway-exec.js";
|
|
18
18
|
import { resolveRole } from "./core/role.js";
|
|
19
|
-
import { addNote, deleteNote, setFileReviewed, setFindingStatus, submitReview, updateNote } from "./core/review-actions.js";
|
|
19
|
+
import { addNote, deleteNote, markProcessedByReviewer, setFileReviewed, setFindingStatus, submitReview, updateNote, } from "./core/review-actions.js";
|
|
20
20
|
import { GUI_REQUEST_TYPES, IPCMessageSchema } from "../shared/schemas/ipc.schema.js";
|
|
21
|
-
import { AddNoteRequestSchema, AnalysisRequestSchema, DeleteNoteRequestSchema, SetFileReviewedRequestSchema, SetFindingStatusRequestSchema, SubmitReviewRequestSchema, UpdateNoteRequestSchema, } from "../shared/schemas/api.schema.js";
|
|
21
|
+
import { AddNoteRequestSchema, AnalysisRequestSchema, DeleteNoteRequestSchema, SetFileReviewedRequestSchema, SetFindingStatusRequestSchema, SubmitReviewRequestSchema, MarkProcessedRequestSchema, UpdateNoteRequestSchema, } from "../shared/schemas/api.schema.js";
|
|
22
22
|
import { ANALYSIS_MODES, DIAGRAM_KINDS, EXPLANATION_SIDES, FINDING_KINDS, NODE_SHAPES, NODE_STATUSES, SEVERITIES, } from "../shared/schemas/analysis.schema.js";
|
|
23
23
|
import { errorResult, textResult } from "./tools/types.js";
|
|
24
24
|
import { createAnalysis } from "./tools/create-analysis.js";
|
|
@@ -223,6 +223,12 @@ function handleGuiRequest(msg) {
|
|
|
223
223
|
afterUserMutation(analysis.id);
|
|
224
224
|
return { analysis };
|
|
225
225
|
}
|
|
226
|
+
case "MARK_PROCESSED": {
|
|
227
|
+
const request = parseRequest(MarkProcessedRequestSchema, msg.data);
|
|
228
|
+
const analysis = markProcessedByReviewer(store, request.analysisId, request.body);
|
|
229
|
+
afterUserMutation(analysis.id);
|
|
230
|
+
return { analysis };
|
|
231
|
+
}
|
|
226
232
|
default:
|
|
227
233
|
throw new Error(`GUI request ${msg.type} has no handler.`);
|
|
228
234
|
}
|
package/dist/src/tools/format.js
CHANGED
|
@@ -83,7 +83,7 @@ export function progressLabel(progress) {
|
|
|
83
83
|
? "pending processing"
|
|
84
84
|
: progress.processed === null
|
|
85
85
|
? "nothing to process"
|
|
86
|
-
: `processed at ${progress.processed.at}`;
|
|
86
|
+
: `processed at ${progress.processed.at}${progress.processed.by === "user" ? " by the reviewer" : ""}`;
|
|
87
87
|
const decision = progress.state === "submitted" ? `, decision ${progress.decision}, ${processing}` : "";
|
|
88
88
|
return `${REVIEW_PROGRESS_TEXT[progress.state]}${decision} (${progress.reviewedFiles}/${progress.totalFiles} files reviewed)`;
|
|
89
89
|
}
|
|
@@ -2,10 +2,12 @@ import { hasNoChanges, needsProcessing, recordSubmission, reviewProgress, submis
|
|
|
2
2
|
import { sortBySeverity } from "../../shared/severity.js";
|
|
3
3
|
import { findingLine, indentBlock, noteLocationLabel, overviewLines, progressLabel } from "./format.js";
|
|
4
4
|
import { rejectUnknownFields, requireString, textResult } from "./types.js";
|
|
5
|
-
/** `processed at <date> (note: …)`, `nothing to process (approved)` ou `not processed`. */
|
|
5
|
+
/** `processed at <date> by the agent (note: …)`, `nothing to process (approved)` ou `not processed`. */
|
|
6
6
|
function processingLabel(decision, processed) {
|
|
7
|
-
if (processed !== null)
|
|
8
|
-
|
|
7
|
+
if (processed !== null) {
|
|
8
|
+
const by = processed.by === "user" ? "the reviewer" : "the agent";
|
|
9
|
+
return `processed at ${processed.at} by ${by}${processed.note === null ? "" : ` (note: ${processed.note})`}`;
|
|
10
|
+
}
|
|
9
11
|
return decision === "approve" ? "nothing to process (approved)" : "not processed";
|
|
10
12
|
}
|
|
11
13
|
/** `submitted at <date>, decision <d>, processed at <date>…` : rappel d'une version soumise. */
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { AnalysisStore } from "../core/analysis-store.js";
|
|
2
2
|
import { type Args, type MutationResult } from "./types.js";
|
|
3
3
|
/**
|
|
4
|
-
* Marque
|
|
5
|
-
* facultative. Le retour reste lisible avec get_review_feedback.
|
|
6
|
-
* que la revue n'est pas soumise ; un nouveau marquage remplace le précédent.
|
|
4
|
+
* Marque traité, au nom de l'agent, le retour soumis d'une analyse, avec la date
|
|
5
|
+
* et une note facultative. Le retour reste lisible avec get_review_feedback.
|
|
7
6
|
*/
|
|
8
7
|
export declare function markFeedbackProcessed(store: AnalysisStore, args: Args): MutationResult;
|
|
@@ -1,27 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { markFeedbackProcessed as markProcessed } from "../core/review-actions.js";
|
|
2
2
|
import { optionalString, rejectUnknownFields, requireString, textResult } from "./types.js";
|
|
3
3
|
/**
|
|
4
|
-
* Marque
|
|
5
|
-
* facultative. Le retour reste lisible avec get_review_feedback.
|
|
6
|
-
* que la revue n'est pas soumise ; un nouveau marquage remplace le précédent.
|
|
4
|
+
* Marque traité, au nom de l'agent, le retour soumis d'une analyse, avec la date
|
|
5
|
+
* et une note facultative. Le retour reste lisible avec get_review_feedback.
|
|
7
6
|
*/
|
|
8
7
|
export function markFeedbackProcessed(store, args) {
|
|
9
8
|
rejectUnknownFields(args, ["analysis_id", "note"]);
|
|
10
9
|
const id = requireString(args, "analysis_id");
|
|
11
10
|
const note = optionalString(args, "note") ?? null;
|
|
12
|
-
|
|
13
|
-
const updated = store.mutate(id, "agent", (draft) => {
|
|
14
|
-
const review = draft.review;
|
|
15
|
-
if (review.state !== "submitted") {
|
|
16
|
-
const reopened = review.previousSubmission;
|
|
17
|
-
throw new AnalysisError(reopened
|
|
18
|
-
? `The review of analysis "${id}" is not submitted: the reviewer reopened the feedback submitted at ${reopened.submittedAt} and is changing it. ` +
|
|
19
|
-
`Wait until it is submitted again, then read it with get_review_feedback.`
|
|
20
|
-
: `The review of analysis "${id}" is not submitted yet: there is no feedback to mark processed.`);
|
|
21
|
-
}
|
|
22
|
-
replaced = review.processed?.at ?? null;
|
|
23
|
-
review.processed = { at: new Date().toISOString(), note };
|
|
24
|
-
});
|
|
11
|
+
const { analysis: updated, replaced } = markProcessed(store, id, "agent", note);
|
|
25
12
|
const processed = updated.review.processed;
|
|
26
13
|
const lines = [
|
|
27
14
|
`Marked the feedback of "${updated.title}" (${updated.id}), submitted at ${updated.review.submittedAt}, as processed at ${processed.at}.`,
|