@nosserb/prmt 0.0.0-stage → 2.0.0

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.
Files changed (166) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +191 -2
  3. package/bin/prmt.mjs +174 -0
  4. package/dist/assets/AuditModule-BOO_iRy8.js +1 -0
  5. package/dist/assets/Audits-yUBm0EpW.js +1 -0
  6. package/dist/assets/BrainPage-FIWO_9Nc.js +3 -0
  7. package/dist/assets/BrainPage-XQCEGRc5.css +1 -0
  8. package/dist/assets/Carte-CPuiR1Ha.css +1 -0
  9. package/dist/assets/Carte-xycu1mQn.js +1 -0
  10. package/dist/assets/Dashboard-DKvCQcX8.js +2 -0
  11. package/dist/assets/Dashboard-XdhC6_hM.css +1 -0
  12. package/dist/assets/Field-C7c2mCbb.js +2 -0
  13. package/dist/assets/Journal-BLIIlh80.css +1 -0
  14. package/dist/assets/Journal-BaelFjwV.js +1 -0
  15. package/dist/assets/Landing-B2jxV3zs.css +1 -0
  16. package/dist/assets/Landing-Dr612Zdu.js +26 -0
  17. package/dist/assets/Register-DA_Aq5f8.js +1 -0
  18. package/dist/assets/Reports-8wfDNSxH.js +1 -0
  19. package/dist/assets/Reports-B8GXN95N.css +1 -0
  20. package/dist/assets/SavoirPage-BTxbH3LY.css +1 -0
  21. package/dist/assets/SavoirPage-Dp3eUCHp.js +1 -0
  22. package/dist/assets/SettingsPage-BElIP46c.css +1 -0
  23. package/dist/assets/SettingsPage-BiQbnw3o.js +1 -0
  24. package/dist/assets/Shell-BAyHVljp.css +1 -0
  25. package/dist/assets/Shell-CQRlx9-V.js +2 -0
  26. package/dist/assets/Table-DUmGel5e.js +1 -0
  27. package/dist/assets/Tabs-CfhbELZk.js +1 -0
  28. package/dist/assets/Terminal-Bv1IJfi9.js +3 -0
  29. package/dist/assets/Terminal-CEfj38NV.css +1 -0
  30. package/dist/assets/arrow-right-Cx3pAEhl.js +1 -0
  31. package/dist/assets/auditViews-BMza2Sdz.js +1 -0
  32. package/dist/assets/auditViews-BePWj26h.css +1 -0
  33. package/dist/assets/bricolage-grotesque-latin-ext-opsz-normal-IcJDqblK.woff2 +0 -0
  34. package/dist/assets/bricolage-grotesque-latin-opsz-normal-Cre6nC2_.woff2 +0 -0
  35. package/dist/assets/bricolage-grotesque-vietnamese-opsz-normal-D9N6E8K1.woff2 +0 -0
  36. package/dist/assets/charts-BcijSJ4J.js +1 -0
  37. package/dist/assets/circle-stop-C33BAcKW.js +1 -0
  38. package/dist/assets/command-ChA49Xk7.js +1 -0
  39. package/dist/assets/command-Ck4pdQCv.css +1 -0
  40. package/dist/assets/download-CeuKOenD.js +1 -0
  41. package/dist/assets/eye-CXXHBBpr.js +1 -0
  42. package/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  43. package/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  44. package/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  45. package/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  46. package/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  47. package/dist/assets/habillage-B5mMBadn.js +1 -0
  48. package/dist/assets/index-BH1etemR.css +1 -0
  49. package/dist/assets/index-COSiM-R9.js +14 -0
  50. package/dist/assets/jetbrains-mono-cyrillic-ext-wght-normal-EocZY2iu.woff2 +0 -0
  51. package/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  52. package/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  53. package/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  54. package/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  55. package/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  56. package/dist/assets/layers-2x-Bpkbi35X.png +0 -0
  57. package/dist/assets/layers-BWBAp2CZ.png +0 -0
  58. package/dist/assets/markdown-DF87LQh1.css +1 -0
  59. package/dist/assets/markdown-o5sMhPHN.js +4 -0
  60. package/dist/assets/marker-icon-hN30_KVU.png +0 -0
  61. package/dist/assets/play-Daw4K_73.js +1 -0
  62. package/dist/assets/plus-D_QHm8ud.js +1 -0
  63. package/dist/assets/trash-DLpHM-s8.js +1 -0
  64. package/dist/assets/web-6j1-aY67.js +1 -0
  65. package/dist/favicon.svg +1 -0
  66. package/dist/index.html +18 -0
  67. package/docs/ANALYSE.md +87 -0
  68. package/docs/SECURITE.md +188 -0
  69. package/lib/scripts/lier.js +15 -0
  70. package/lib/scripts/searxng.js +91 -0
  71. package/lib/server/app.js +444 -0
  72. package/lib/server/audits/modules/local.js +429 -0
  73. package/lib/server/audits/modules/network.js +331 -0
  74. package/lib/server/audits/modules/web.js +302 -0
  75. package/lib/server/audits/net.js +141 -0
  76. package/lib/server/audits/registry.js +202 -0
  77. package/lib/server/audits/types.js +58 -0
  78. package/lib/server/brain/brain.js +624 -0
  79. package/lib/server/brain/conversations.js +82 -0
  80. package/lib/server/brain/ollama.js +197 -0
  81. package/lib/server/brain/prompt.js +188 -0
  82. package/lib/server/brain/provider.js +1 -0
  83. package/lib/server/cli/bridge.js +292 -0
  84. package/lib/server/cli/pont.js +62 -0
  85. package/lib/server/config.js +68 -0
  86. package/lib/server/engine/analyzer.js +205 -0
  87. package/lib/server/engine/catalog.js +229 -0
  88. package/lib/server/engine/decoder.js +91 -0
  89. package/lib/server/engine/engine.js +194 -0
  90. package/lib/server/engine/paths.js +129 -0
  91. package/lib/server/engine/policy.js +397 -0
  92. package/lib/server/engine/relax.js +10 -0
  93. package/lib/server/engine/runner.js +193 -0
  94. package/lib/server/errors.js +23 -0
  95. package/lib/server/http/guard.js +75 -0
  96. package/lib/server/http/router.js +154 -0
  97. package/lib/server/http/static.js +76 -0
  98. package/lib/server/index.js +40 -0
  99. package/lib/server/journal.js +139 -0
  100. package/lib/server/lien.js +33 -0
  101. package/lib/server/savoir/base.js +284 -0
  102. package/lib/server/savoir/lecture.js +406 -0
  103. package/lib/server/savoir/memoire.js +115 -0
  104. package/lib/server/search/categories.js +179 -0
  105. package/lib/server/search/fiche.js +326 -0
  106. package/lib/server/search/lieux.js +134 -0
  107. package/lib/server/search/overpass.js +216 -0
  108. package/lib/server/search/searxng.js +223 -0
  109. package/lib/server/search/tiles.js +103 -0
  110. package/lib/server/status.js +157 -0
  111. package/lib/server/stores.js +141 -0
  112. package/lib/server/telephone/acces.js +457 -0
  113. package/lib/server/telephone/certificat.js +79 -0
  114. package/lib/server/telephone/qr.js +308 -0
  115. package/lib/shared/analysis.js +40 -0
  116. package/lib/shared/schemas.js +105 -0
  117. package/lib/shared/types.js +10 -0
  118. package/package.json +81 -4
  119. package/searxng/settings.yml +35 -0
  120. package/tui/Modelfile +23 -0
  121. package/tui/README.md +103 -0
  122. package/tui/prmt_tui.py +65 -0
  123. package/tui/promethee/__init__.py +1 -0
  124. package/tui/promethee/__main__.py +4 -0
  125. package/tui/promethee/accueil.py +66 -0
  126. package/tui/promethee/agents.py +220 -0
  127. package/tui/promethee/app/__init__.py +4 -0
  128. package/tui/promethee/app/application.py +299 -0
  129. package/tui/promethee/app/clavier.py +99 -0
  130. package/tui/promethee/app/commandes_slash.py +164 -0
  131. package/tui/promethee/app/contexte.py +188 -0
  132. package/tui/promethee/app/definitions.py +518 -0
  133. package/tui/promethee/app/ecran.py +177 -0
  134. package/tui/promethee/app/envoi.py +141 -0
  135. package/tui/promethee/app/historique.py +373 -0
  136. package/tui/promethee/app/modele.py +108 -0
  137. package/tui/promethee/app/notes.py +63 -0
  138. package/tui/promethee/app/outils.py +589 -0
  139. package/tui/promethee/app/plateforme.py +409 -0
  140. package/tui/promethee/app/saisie.py +100 -0
  141. package/tui/promethee/app/taches.py +92 -0
  142. package/tui/promethee/app/tour.py +539 -0
  143. package/tui/promethee/app/validation.py +210 -0
  144. package/tui/promethee/appels.py +35 -0
  145. package/tui/promethee/commandes.py +154 -0
  146. package/tui/promethee/completion.py +140 -0
  147. package/tui/promethee/config.py +12 -0
  148. package/tui/promethee/consignes.py +278 -0
  149. package/tui/promethee/conversation.py +94 -0
  150. package/tui/promethee/etat.py +253 -0
  151. package/tui/promethee/fichiers.py +354 -0
  152. package/tui/promethee/journal.py +116 -0
  153. package/tui/promethee/logo.py +132 -0
  154. package/tui/promethee/memoire.py +50 -0
  155. package/tui/promethee/ollama.py +52 -0
  156. package/tui/promethee/plan.py +91 -0
  157. package/tui/promethee/politique.py +429 -0
  158. package/tui/promethee/preferences.py +65 -0
  159. package/tui/promethee/presse_papiers.py +44 -0
  160. package/tui/promethee/recherche.py +581 -0
  161. package/tui/promethee/securite.py +204 -0
  162. package/tui/promethee/shell.py +190 -0
  163. package/tui/promethee/textes.py +190 -0
  164. package/tui/promethee/theme.py +92 -0
  165. package/tui/promethee/widgets.py +493 -0
  166. package/tui/requirements.txt +1 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Prométhée
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,192 @@
1
- # Temporary Holding Version
1
+ # Prométhée
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ IA locale de cybersécurité. Le modèle tourne sur ta machine avec Ollama, propose des commandes PowerShell, et rien ne s'exécute sans ton accord.
4
+
5
+ Ce dépôt contient la **console web locale** (version 2) et sa page de présentation. La TUI `prmt` (Python, Textual) vit à part dans `ollama/promethee`. Les deux interfaces partagent le modèle, la liste blanche, le périmètre réseau et un journal que chacune sait lire : la politique est écrite une fois, ici, et la TUI l'interroge.
6
+
7
+ ## Installer
8
+
9
+ Prométhée s'empaquette en un seul paquet npm qui porte la console **et** la TUI. Une commande, `prmt`, lance tout.
10
+
11
+ ```powershell
12
+ npm install -g github:nosserb/prom-th-e
13
+ prmt run # la console web : démarre le serveur et ouvre le navigateur
14
+ prmt # la TUI : l'interface dans le terminal
15
+ ```
16
+
17
+ C'est tout. L'installation ne tire qu'une dépendance (`zod`) : l'interface est déjà construite dans le dépôt, et le serveur y est en JavaScript compilé, donc rien n'est reconstruit sur la machine cible.
18
+
19
+ Prérequis sur la machine :
20
+
21
+ - **Node.js 24 ou plus** et **Windows** (le moteur de commandes vise PowerShell 5.1).
22
+ - **[Ollama](https://ollama.com)** avec au moins un modèle, pour le cerveau.
23
+ - **Python 3.10 ou plus** pour la TUI : au premier `prmt`, un environnement Python est créé tout seul et `textual` y est installé (dans `~/.promethee/tui-venv`). La console (`prmt run`) n'a pas besoin de Python.
24
+ - **Docker** seulement si tu veux la recherche web (`prmt searxng`).
25
+
26
+ Les données vont dans `~/.promethee/data` (console) et `Documents\Promethee` (partagé avec la TUI), jamais dans le paquet. Mets `PROMETHEE_DATA` pour en changer.
27
+
28
+ Sans accès au registre, le paquet s'installe aussi depuis une archive : `npm pack` produit un `.tgz` que l'on installe par `npm install -g .\<fichier>.tgz`.
29
+
30
+ ## Démarrer (développement)
31
+
32
+ Dans le dépôt, Node.js 24+, [Ollama](https://ollama.com) avec un modèle, PowerShell 5.1 (déjà dans Windows) :
33
+
34
+ ```powershell
35
+ npm install
36
+ npm run build
37
+ npm start # ou : prmt run
38
+ ```
39
+
40
+ Ouvre ensuite `http://127.0.0.1:4317`. Le serveur n'écoute que sur la boucle locale : il est inaccessible depuis le réseau, sauf si tu ouvres l'accès téléphone.
41
+
42
+ Pendant le développement, `npm run dev` lance le serveur (relancé à chaque modification) et Vite sur `http://127.0.0.1:5173`. `prmt` depuis le dépôt marche aussi : il utilise la source TypeScript et copie la TUI au besoin.
43
+
44
+ ## Relier la TUI
45
+
46
+ À chaque démarrage, le serveur écrit `Documents\Promethee\plateforme.json` : la TUI y lit où trouver Node, le pont de politique et les données communes. `npm run lier` écrit ce fichier sans démarrer le serveur.
47
+
48
+ Le pont (`server/cli/pont.ts`) est un petit programme que la TUI lance elle-même. Il analyse une commande et rend un verdict, sans jamais l'exécuter. La console n'a donc pas besoin de tourner pour que la TUI applique la politique.
49
+
50
+ ## Recherche web et carte
51
+
52
+ Quand une question demande une information récente ou précise, ou un lieu, le modèle cherche sur internet avant de répondre. La recherche passe par [SearXNG](https://docs.searxng.org), installé sur ta machine dans Docker (Docker Desktop doit tourner) :
53
+
54
+ ```powershell
55
+ npm run searxng # installe au premier lancement, sinon redémarre le conteneur
56
+ npm run searxng -- arreter # arrête le conteneur
57
+ ```
58
+
59
+ Le conteneur n'écoute que sur `127.0.0.1:8888`. Il interroge Google, Bing, DuckDuckGo et Brave, et Photon (OpenStreetMap) pour les lieux. Ses réglages sont copiés dans `Documents\Promethee\searxng\`, où tu peux les modifier.
60
+
61
+ - Un classificateur court, à part du routeur action/explication qui n'a pas changé, décide s'il faut chercher. Mesuré sur `promethee:latest` : 66 demandes bien classées sur 68, aucune question sur ce PC envoyée sur internet.
62
+ - La requête et les sources numérotées s'affichent dans la conversation. La réponse les cite par leur numéro. Chaque recherche est notée au journal.
63
+ - Après une recherche, le modèle répond sans l'outil de commande : un texte venu d'internet ne peut pas lui faire proposer une commande dans ce tour.
64
+ - Pour un lieu, la console affiche une carte OpenStreetMap. Les tuiles passent par le serveur local, qui les garde 7 jours dans `data/tuiles/`. La TUI donne l'adresse, les coordonnées et un lien.
65
+ - Pour plusieurs lieux (« tous les hôtels de Paris », « une pharmacie près de la cathédrale de Lyon »), la carte montre tous les points, cadrés pour tenir dans la vue, avec leur liste. Une liste fixe de 32 catégories repère ces demandes (`server/search/categories.ts`), la zone vient de Photon, les points d'[Overpass](https://wiki.openstreetmap.org/wiki/Overpass_API) (2 000 au plus). Overpass met de quelques secondes à une minute selon sa charge : la réponse n'attend pas, la carte arrive quand les points sont là, et ils restent 7 jours dans `data/lieux/`.
66
+ - Un clic sur un point ouvre sa fiche : l'article Wikipédia du lieu s'il en a un, sinon l'extrait et l'image trouvés par SearXNG, chacun avec sa source. Les images passent aussi par le serveur local.
67
+ - Un interrupteur dans les Réglages coupe la recherche, la carte et les fiches. Dans la TUI : `/recherche on` ou `/recherche off`.
68
+
69
+ ### Le savoir local
70
+
71
+ Après chaque recherche, le serveur lit en entier les 3 premières pages lisibles des résultats et en range le texte dans `data/savoir.db` (SQLite, recherche plein texte). Avant de répondre, le modèle relit les passages utiles : ceux des pages qu'il vient de lire, et ceux des pages lues lors de recherches précédentes quand ils parlent du même sujet. Pour une question d'explication sans recherche, il relit aussi son savoir si des passages collent à la question. Il répond mieux à mesure que le savoir grandit, mais le modèle lui-même ne change pas : rien n'est réentraîné.
72
+
73
+ - La conversation montre les pages lues (retenue, déjà connue, illisible) et les passages donnés au modèle, avec leur source. La réponse les cite par leur numéro.
74
+ - La page Savoir de la console liste ce qui est retenu, montre le texte d'une page, et permet d'en oublier une ou tout.
75
+ - Une page lue il y a moins de 7 jours n'est pas relue. Au-delà de 15 millions de caractères, les pages les moins utilisées sont oubliées.
76
+ - Les sites des pages lues sont joints directement par le serveur, sans SearXNG : ils voient ton adresse IP. Le serveur refuse toute adresse de ton réseau ou de ce PC (détail dans [docs/SECURITE.md](docs/SECURITE.md#savoir-local)).
77
+ - Les pages dont le texte n'apparaît qu'avec JavaScript ne se lisent pas. Le rappel cherche par mots, pas par le sens.
78
+ - Le réglage « Apprendre des pages lues » coupe la lecture et le rappel. La TUI n'utilise pas encore le savoir.
79
+
80
+ ## Depuis ton téléphone
81
+
82
+ Dans Réglages, Téléphone, ouvre l'accès : la console devient joignable depuis ton réseau Wi-Fi, en HTTPS, sur le port 4318. Scanne le QR code avec le téléphone (ou ouvre l'adresse affichée et tape le code). Le modèle reste sur le PC, le téléphone n'affiche que la console.
83
+
84
+ - Le PC et le téléphone doivent être sur le même Wi-Fi.
85
+ - À la première visite, le navigateur avertit que le certificat n'est signé par aucune autorité : c'est le PC qui l'a fabriqué. Compare le début de l'empreinte affichée sur le PC, puis continue.
86
+ - Seuls les appareils appairés accèdent à l'API. Depuis le téléphone, la politique ne peut pas être élargie (liste blanche, dossiers, langage contraint), et l'accès se gère sur le PC, où tu peux retirer un appareil.
87
+ - Le détail est dans [docs/SECURITE.md](docs/SECURITE.md).
88
+
89
+ ### De l'extérieur, avec Tailscale
90
+
91
+ [Tailscale](https://tailscale.com) relie le PC et le téléphone par un réseau privé chiffré, sans rien ouvrir sur internet. La console le reconnaît seule.
92
+
93
+ 1. Sur le PC, installe Tailscale (`winget install Tailscale.Tailscale`, Windows demande l'accord d'un administrateur) et connecte-toi.
94
+ 2. Sur le téléphone, installe l'application Tailscale et connecte-toi avec le même compte.
95
+ 3. Dans les 30 secondes, la console ajoute l'adresse Tailscale du PC (`100.x.y.z`) et la met en premier : c'est elle que porte le QR code. Le certificat change pour la couvrir, donc l'avertissement du navigateur revient une fois, avec une nouvelle empreinte.
96
+ 4. Appaire le téléphone sur cette adresse. Pour son navigateur, chaque adresse est un site à part : un appairage fait sur l'adresse Wi-Fi ne vaut pas pour l'adresse Tailscale.
97
+
98
+ Si le téléphone n'atteint pas le port, c'est le pare-feu de Windows. Dans un PowerShell administrateur, cette règle ouvre le port 4318 aux seuls appareils Tailscale :
99
+
100
+ ```powershell
101
+ New-NetFirewallRule -DisplayName "Prométhée, téléphone par Tailscale" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 4318 -RemoteAddress 100.64.0.0/10 -Program "C:\Program Files\nodejs\node.exe"
102
+ ```
103
+
104
+ ## Ce que fait la console
105
+
106
+ | Page | Contenu |
107
+ |---|---|
108
+ | Tableau de bord | État d'Ollama, modèle chargé, moteur PowerShell, politique, commandes sur 14 jours, alertes, état des audits, dernières opérations. Tout est mesuré, rien n'est simulé. |
109
+ | Terminal | PowerShell sous liste blanche : analyse, verdict (lecture, sensible, refusée), confirmation, exécution réelle, sortie en direct, annulation. |
110
+ | Cerveau | Conversation avec le modèle local. Il propose des commandes, tu les relis et tu décides. Il cherche sur le web quand la question le demande, sources et carte à l'appui, lit les meilleures pages et relit son savoir avant de répondre. Un texte trop long collé dans le champ devient une pièce jointe. Les sessions de la TUI sont visibles en lecture seule. |
111
+ | Savoir | Les pages lues et retenues après les recherches : titre, site, date, utilisations, texte. Oubli d'une page ou de tout. |
112
+ | Audits | Huit modules : surface d'attaque, ports, en-têtes HTTP, TLS, application web, fichiers exposés, configuration Windows, fichiers locaux. Les modules réseau refusent toute cible absente du périmètre déclaré. |
113
+ | Rapports | Constats ouverts par gravité, historique des audits, export Markdown. |
114
+ | Journal | Chaque commande exécutée ou refusée, audit, réponse du modèle, recherche web, cible déclarée, changement de réglage. Les actions faites dans la TUI y figurent aussi, marquées TUI. Export JSONL. |
115
+ | Réglages | Modèle, adresse d'Ollama, délais, mode de langage contraint, dossiers autorisés, liste blanche, recherche web et apprentissage des pages lues. |
116
+
117
+ Sans serveur local, la console affiche qu'elle est déconnectée. Elle n'invente ni sortie ni statistique.
118
+
119
+ ## Sécurité, en bref
120
+
121
+ - **Refus par défaut.** Une commande passe seulement si chaque élément de son arbre syntaxique est autorisé : commandes, appels de méthode, types, redirections, chemins écrits.
122
+ - **Analyse par PowerShell lui-même.** La commande est découpée par le parseur de PowerShell (sans être exécutée), pas par des expressions régulières.
123
+ - **Confirmation humaine côté serveur.** Un ticket à usage unique est délivré à la prévisualisation et exigé pour exécuter. Le modèle ne peut que proposer.
124
+ - **Périmètre.** Écritures limitées aux dossiers autorisés, tests de ports limités aux cibles déclarées avec attestation.
125
+ - **API fermée.** Boucle locale uniquement, contrôle de l'hôte et de l'origine, jeton de session.
126
+
127
+ Le détail, les limites connues et le modèle de menace sont dans [docs/SECURITE.md](docs/SECURITE.md).
128
+
129
+ ## Tests
130
+
131
+ ```powershell
132
+ npm test # 682 tests : politique, pont de la TUI, moteur réel, audits, recherche web, savoir local, API, interface
133
+ npm run test:e2e # 46 parcours dans Chrome, avec le vrai serveur et le vrai PowerShell
134
+ npm run verify # types + tests + parcours
135
+ ```
136
+
137
+ Les tests de la politique s'appuient sur de vraies analyses PowerShell enregistrées (`tests/server/fixtures`). Après avoir ajouté un cas dans `tests/server/cases.ts`, relance `node scripts/fixtures.ts` sous Windows.
138
+
139
+ Le parcours du cerveau n'est joué que si Ollama répond avec un modèle qui gère les outils.
140
+
141
+ ## Organisation
142
+
143
+ ```
144
+ shared/ contrats partagés : types, validation des entrées (zod)
145
+ server/ serveur local (Node, TypeScript exécuté tel quel)
146
+ engine/ analyse, liste blanche, politique, exécution PowerShell
147
+ cli/ pont de politique lancé par la TUI
148
+ brain/ fournisseur de modèles (Ollama), conversations, propositions
149
+ audits/ modules d'audit, périmètre, historique, rapports
150
+ search/ client SearXNG, tuiles de carte, lieux (Overpass), fiches
151
+ savoir/ lecture des pages, base du savoir (SQLite), passages relus par le modèle
152
+ telephone/ accès depuis le téléphone : écoute HTTPS, certificat, appairage, QR code
153
+ http/ routeur, garde de l'API, fichiers de l'interface
154
+ src/ interface (React, Vite)
155
+ console/ pages de la console
156
+ landing/ page de présentation
157
+ components/ styles/ lib/ services/
158
+ tests/ server (Vitest), ui (Vitest + Testing Library), e2e (Playwright)
159
+ scripts/ dev, captures d'écran, jeux d'essai, essai de la politique
160
+ reference/ vitrine statique v1, conservée telle quelle
161
+ docs/ analyse et architecture, sécurité
162
+ ```
163
+
164
+ ## Outils
165
+
166
+ - `node scripts/essai-politique.ts "Get-Process | Stop-Process"` : affiche le verdict de la politique pour une commande, sans rien exécuter.
167
+ - `node scripts/captures.ts captures 1440` : capture chaque page dans Chrome et signale les erreurs de console et les débordements.
168
+ - `node scripts/fixtures.ts` : réenregistre les analyses PowerShell des cas de test.
169
+ - `node scripts/captures-demo.ts captures 390` : capture les démos de la page de présentation, sur un serveur et des données jetables.
170
+ - `npm run lier` : écrit le fichier de liaison de la TUI.
171
+ - `npm run searxng` : installe ou redémarre SearXNG, le moteur de la recherche web.
172
+
173
+ ## Données et réglages
174
+
175
+ Les données restent dans `data/` (ignoré par git) : journal, réglages, périmètre, conversations, audits, tuiles de carte, lieux, savoir (`savoir.db`), appareils appairés et certificat du téléphone.
176
+
177
+ | Variable | Rôle | Défaut |
178
+ |---|---|---|
179
+ | `PROMETHEE_PORT` | port du serveur local | `4317` |
180
+ | `PROMETHEE_DATA` | dossier des données | `data/` |
181
+ | `PROMETHEE_TUI` | dossier de la TUI (sessions, journal, fichier de liaison) | `Documents\Promethee` |
182
+ | `OLLAMA_HOST` | adresse d'Ollama | `127.0.0.1:11434` |
183
+ | `PROMETHEE_SEARCH` | `0` : recherche web coupée tant que les réglages ne disent pas autre chose | active |
184
+ | `PROMETHEE_PORT_TELEPHONE` | port de l'accès téléphone (HTTPS, réseau local) | `4318` |
185
+
186
+ ## Cadre d'usage
187
+
188
+ Prométhée sert à apprendre, à se défendre et à s'entraîner en CTF, sur des machines et des sites que tu as le droit de tester.
189
+
190
+ Un réglage **Mode full cyber** (Réglages, Cerveau) débride les réponses du modèle sur l'offensif, pour un usage white hat autorisé. Il change ce que le modèle explique, jamais les protections d'exécution : la liste blanche, la confirmation de chaque commande et le périmètre réseau tiennent. Le détail et la responsabilité qui t'incombe sont dans [docs/SECURITE.md](docs/SECURITE.md#mode-full-cyber).
191
+
192
+ Sous full cyber, un **mode auto** (coupé par défaut) laisse Prométhée exécuter lui-même les commandes autorisées, à partir d'un but, jusqu'à l'atteindre ou 20 commandes. Il lève la confirmation par commande seulement pour ce que la politique permet déjà : une commande destructrice, interdite ou hors périmètre reste refusée, jamais lancée toute seule. « Arrêter » coupe la boucle. Détail dans [docs/SECURITE.md](docs/SECURITE.md#mode-auto).
package/bin/prmt.mjs ADDED
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * prmt : le lanceur unique de Prométhée.
4
+ *
5
+ * prmt run lance la console web (serveur + navigateur). Ctrl+C pour arrêter.
6
+ * prmt lance la TUI (interface dans le terminal). Comme prmt -m, -c, -r, "question".
7
+ * prmt searxng installe ou redémarre SearXNG (recherche web, Docker). « prmt searxng arreter » l'arrête.
8
+ * prmt lier écrit le fichier de liaison de la TUI sans démarrer le serveur.
9
+ * prmt --help cette aide. prmt --version : la version.
10
+ *
11
+ * La console est en Node (fournie par ce paquet). La TUI est en Python : au premier « prmt », un environnement
12
+ * Python est créé tout seul (il faut Python 3.10+ sur la machine). Ollama doit être installé pour le modèle.
13
+ */
14
+ import { spawn, spawnSync } from 'node:child_process'
15
+ import crypto from 'node:crypto'
16
+ import fs from 'node:fs'
17
+ import os from 'node:os'
18
+ import path from 'node:path'
19
+ import { fileURLToPath } from 'node:url'
20
+
21
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
22
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'))
23
+ const isWin = process.platform === 'win32'
24
+
25
+ /** Un module du serveur : le JS compilé (paquet installé), sinon la source .ts (développement). */
26
+ function modulePath(rel) {
27
+ const js = path.join(root, 'lib', `${rel}.js`)
28
+ return fs.existsSync(js) ? js : path.join(root, `${rel}.ts`)
29
+ }
30
+ const say = (s = '') => process.stdout.write(`${s}\n`)
31
+ const die = (s) => {
32
+ process.stderr.write(`${s}\n`)
33
+ process.exit(1)
34
+ }
35
+
36
+ function help() {
37
+ say(`Prométhée ${pkg.version} — IA locale de cybersécurité
38
+
39
+ prmt run Console web : démarre le serveur et ouvre le navigateur. Ctrl+C pour arrêter.
40
+ prmt TUI : l'interface dans le terminal (aussi : prmt -m MODELE, -c, -r, "ta question").
41
+ prmt searxng Installe ou redémarre SearXNG (recherche web, Docker). « arreter » pour l'arrêter.
42
+ prmt lier Écrit le fichier de liaison de la TUI sans démarrer le serveur.
43
+ prmt --help Cette aide. prmt --version : la version.
44
+
45
+ Prérequis : Node 24+, Ollama (https://ollama.com) avec un modèle. Pour la TUI : Python 3.10+.
46
+ Pour la recherche web : Docker. Le moteur de commandes vise Windows (PowerShell).`)
47
+ }
48
+
49
+ /** Lance une commande en premier plan, hérite des flux, et rend son code de sortie. */
50
+ function run(cmd, args, opts = {}) {
51
+ const r = spawnSync(cmd, args, { stdio: 'inherit', ...opts })
52
+ if (r.error) die(`Impossible de lancer « ${cmd} » : ${r.error.message}`)
53
+ return r.status ?? 1
54
+ }
55
+
56
+ // ------------------------------------------------------------------ Console web
57
+
58
+ function distPret() {
59
+ return fs.existsSync(path.join(root, 'dist', 'index.html'))
60
+ }
61
+
62
+ async function runConsole(args) {
63
+ if (!distPret()) {
64
+ const vite = path.join(root, 'node_modules', 'vite', 'bin', 'vite.js')
65
+ if (fs.existsSync(vite)) {
66
+ say('Construction de l’interface (première fois)…')
67
+ if (run(process.execPath, [vite, 'build'], { cwd: root }) !== 0) die('La construction de l’interface a échoué.')
68
+ } else {
69
+ die('L’interface n’est pas construite (dist/ manquant) et l’outil de construction n’est pas là. Réinstalle le paquet.')
70
+ }
71
+ }
72
+ const port = process.env.PROMETHEE_PORT || '4317'
73
+ const url = `http://127.0.0.1:${port}`
74
+ // Données hors du paquet (un node_modules global n'est pas le bon endroit), sauf si l'utilisateur fixe PROMETHEE_DATA.
75
+ const env = { ...process.env }
76
+ if (!env.PROMETHEE_DATA) env.PROMETHEE_DATA = path.join(os.homedir(), '.promethee', 'data')
77
+ const serveur = spawn(process.execPath, [modulePath('server/index'), ...args], { cwd: root, stdio: 'inherit', env })
78
+ serveur.on('exit', (code) => process.exit(code ?? 0))
79
+ for (const sig of ['SIGINT', 'SIGTERM']) process.on(sig, () => serveur.kill(sig))
80
+ // Dès que le serveur répond, on ouvre le navigateur (sans bloquer les journaux).
81
+ void ouvrirQuandPret(url)
82
+ }
83
+
84
+ async function ouvrirQuandPret(url) {
85
+ const fin = Date.now() + 20_000
86
+ while (Date.now() < fin) {
87
+ try {
88
+ const res = await fetch(`${url}/api/session`, { signal: AbortSignal.timeout(1500) })
89
+ if (res.ok) {
90
+ ouvrir(url)
91
+ return
92
+ }
93
+ } catch {
94
+ /* pas encore prêt */
95
+ }
96
+ await new Promise((r) => setTimeout(r, 400))
97
+ }
98
+ }
99
+
100
+ function ouvrir(url) {
101
+ const [cmd, args] = isWin ? ['cmd', ['/c', 'start', '""', url]] : process.platform === 'darwin' ? ['open', [url]] : ['xdg-open', [url]]
102
+ spawn(cmd, args, { stdio: 'ignore', detached: true }).on('error', () => {}).unref()
103
+ }
104
+
105
+ // ------------------------------------------------------------------ TUI (Python)
106
+
107
+ function tuiDir() {
108
+ const local = path.join(root, 'tui')
109
+ if (fs.existsSync(path.join(local, 'prmt_tui.py'))) return local
110
+ // En développement, la TUI n'est pas encore copiée : on la génère depuis sa source.
111
+ const packer = path.join(root, 'scripts', 'pack-tui.mjs')
112
+ if (fs.existsSync(packer) && run(process.execPath, [packer], { cwd: root }) === 0 && fs.existsSync(path.join(local, 'prmt_tui.py'))) return local
113
+ return null
114
+ }
115
+
116
+ /** Trouve un Python 3.10+ sur la machine. Rend la commande (tableau), ou null. */
117
+ function trouverPython() {
118
+ const candidats = isWin ? [['py', ['-3']], ['python', []], ['python3', []]] : [['python3', []], ['python', []]]
119
+ for (const [cmd, pre] of candidats) {
120
+ const r = spawnSync(cmd, [...pre, '-c', 'import sys;print("%d.%d"%sys.version_info[:2])'], { encoding: 'utf8' })
121
+ if (r.status === 0) {
122
+ const [maj, min] = String(r.stdout).trim().split('.').map(Number)
123
+ if (maj === 3 && min >= 10) return [cmd, pre]
124
+ if (maj > 3) return [cmd, pre]
125
+ }
126
+ }
127
+ return null
128
+ }
129
+
130
+ function venvPython(venv) {
131
+ return isWin ? path.join(venv, 'Scripts', 'python.exe') : path.join(venv, 'bin', 'python')
132
+ }
133
+
134
+ /** Crée l'environnement Python de la TUI au premier lancement, puis à chaque changement des dépendances. */
135
+ function preparerVenv(dir) {
136
+ const venv = path.join(os.homedir(), '.promethee', 'tui-venv')
137
+ const reqs = fs.readFileSync(path.join(dir, 'requirements.txt'), 'utf8')
138
+ const empreinte = crypto.createHash('sha256').update(reqs).digest('hex').slice(0, 16)
139
+ const marque = path.join(venv, '.prmt-reqs')
140
+ const py = venvPython(venv)
141
+ if (fs.existsSync(py) && fs.existsSync(marque) && fs.readFileSync(marque, 'utf8') === empreinte) return py
142
+
143
+ const python = trouverPython()
144
+ if (!python) die('Python 3.10+ est introuvable. Installe-le depuis https://www.python.org, puis relance « prmt ».')
145
+ if (!fs.existsSync(py)) {
146
+ say('Préparation de l’environnement Python de la TUI (première fois)…')
147
+ fs.mkdirSync(path.dirname(venv), { recursive: true })
148
+ const [cmd, pre] = python
149
+ if (run(cmd, [...pre, '-m', 'venv', venv]) !== 0) die('Création de l’environnement Python impossible.')
150
+ }
151
+ say('Installation des dépendances de la TUI (textual)…')
152
+ if (run(py, ['-m', 'pip', 'install', '--disable-pip-version-check', '-q', '-r', path.join(dir, 'requirements.txt')]) !== 0) die('Installation des dépendances de la TUI impossible.')
153
+ fs.writeFileSync(marque, empreinte)
154
+ return py
155
+ }
156
+
157
+ function runTui(args) {
158
+ const dir = tuiDir()
159
+ if (!dir) die('La TUI n’est pas incluse dans cette installation.')
160
+ // where/which rend 0 si trouvé : on n'empêche pas le lancement, on prévient seulement.
161
+ if (spawnSync(isWin ? 'where' : 'which', ['ollama'], { stdio: 'ignore' }).status !== 0) say('Note : Ollama est introuvable. Installe-le depuis https://ollama.com pour le modèle.')
162
+ const py = preparerVenv(dir)
163
+ process.exit(run(py, [path.join(dir, 'prmt_tui.py'), ...args], { cwd: dir }))
164
+ }
165
+
166
+ // ------------------------------------------------------------------ Aiguillage
167
+
168
+ const [sous, ...reste] = process.argv.slice(2)
169
+ if (sous === 'run') void runConsole(reste)
170
+ else if (sous === 'searxng') process.exit(run(process.execPath, [modulePath('scripts/searxng'), ...reste], { cwd: root }))
171
+ else if (sous === 'lier') process.exit(run(process.execPath, [modulePath('scripts/lier'), ...reste], { cwd: root }))
172
+ else if (sous === '--version' || sous === '-v') say(pkg.version)
173
+ else if (sous === 'help' || sous === '--help') help()
174
+ else runTui(process.argv.slice(2))
@@ -0,0 +1 @@
1
+ import{p as e}from"./Shell-CQRlx9-V.js";import{t}from"./play-Daw4K_73.js";import{t as n}from"./plus-D_QHm8ud.js";import{$ as r,A as i,D as ee,G as a,I as te,K as o,L as s,M as ne,O as re,Ot as c,P as l,Q as ie,R as u,S as ae,_ as oe,b as se,ft as d,ht as f,i as ce,k as p,lt as le,n as m,p as ue,w as h,z as de}from"./index-COSiM-R9.js";import{f as g,n as fe,r as pe}from"./Field-C7c2mCbb.js";import{c as _,i as v,r as me,s as he,t as y}from"./Register-DA_Aq5f8.js";import{c as ge,d as _e,g as ve,h as ye,l as be,o as xe,p as Se,r as Ce,s as we,t as Te,u as Ee,v as De}from"./auditViews-BMza2Sdz.js";var b=c(),x=r();function S({module:r}){let c=h(`/api/audits/modules`),S=h(`/api/audits/history?module=${r}`),C=h(`/api/scope`),{refresh:w}=ee(),{report:Oe}=ae(),T=re(),E=(0,b.useId)(),D=c.data?.modules.find(e=>e.id===r),[O,k]=(0,b.useState)({}),[ke,A]=(0,b.useState)(!1),[j,M]=(0,b.useState)(null),[N,P]=(0,b.useState)(null),[F,I]=(0,b.useState)(null),[L,R]=(0,b.useState)(null),[Ae,z]=(0,b.useState)(``),[B,V]=(0,b.useState)(null),H=oe(ue.etroit),U={lancer:(0,b.useId)(),resultat:(0,b.useId)(),historique:(0,b.useId)(),explication:(0,b.useId)(),manque:(0,b.useId)(),commandes:(0,b.useId)(),refus:(0,b.useId)()},W=(0,b.useRef)(null),[G,je]=(0,b.useState)(0);(0,b.useEffect)(()=>{G&&(document.activeElement&&document.activeElement!==document.body||W.current?.focus(),L&&document.getElementById(U.refus)?.scrollIntoView({block:`nearest`}))},[G]);let K=S.data?.runs[0]?.id;if((0,b.useEffect)(()=>{!K||N||j||i(`GET`,`/api/audits/${K}`).then(P).catch(()=>void 0)},[K]),!D)return(0,x.jsx)(`div`,{className:`vue`,children:(0,x.jsxs)(`div`,{className:`vue-contenu audit-page`,children:[(0,x.jsx)(_,{title:`Module d’audit`}),c.error?(0,x.jsx)(s,{message:c.error,onRetry:c.reload}):(0,x.jsx)(u,{label:`Chargement du module`})]})});let q=be(D.input),J=D.fields[0],Y=D.fields.filter(e=>e.required&&!(O[e.key]??``).trim()),X=D.input===`none`?`cette machine`:(O[J?.key??``]??``).trim(),Z=C.data?.targets??[],Q=q?[D.input===`url`?`http://127.0.0.1`:`127.0.0.1`,...Z.map(e=>D.input===`url`?`https://${e.host}`:e.host)]:[],Me=async()=>{A(!1),I(null),R(null),M({label:`Démarrage`,done:0,total:1}),z(`Audit « ${D.title} » lancé sur ${X}.`);let e=se(),t=null,n=null;try{await ne(`/api/audits/run`,{module:r,input:O,confirm:!0},e=>{e.type===`progress`?M({label:e.label,done:e.done,total:e.total}):e.type===`result`?(t=e.run,P(e.run)):(n=e.message,I(e.message))})}catch(e){Oe(e),e instanceof p&&e.code===`target_out_of_scope`?R(e.message):(n=l(e),I(n))}finally{e(),M(null),je(e=>e+1),S.reload(),w()}let i=t;z(i?i.status===`error`?`Audit « ${D.title} » en échec : ${i.error??i.summary}`:`Audit « ${D.title} » terminé. ${De(Ee(ye(i.findings)))}.`:n?`Audit « ${D.title} » en échec : ${n}`:``)},Ne=async e=>{try{P(await i(`GET`,`/api/audits/${e}`)),I(null)}catch(e){T(`erreur`,`Passage illisible`,l(e))}},Pe=e=>{e.preventDefault(),Y.length===0&&!j&&A(!0)},Fe=N&&N.id!==K?`Passage du ${le(N.startedAt)}`:`Dernier résultat`,$=S.data?.runs??[];return(0,x.jsx)(`div`,{className:`vue`,children:(0,x.jsxs)(`div`,{className:`vue-contenu audit-page`,children:[(0,x.jsxs)(_,{title:D.title,actions:(0,x.jsx)(o,{size:`s`,variant:`nu`,href:m({page:`audits`}),icon:(0,x.jsx)(e,{"aria-hidden":`true`}),children:`Tous les modules`}),children:[(0,x.jsx)(he,{letter:D.letter,name:ve(D.letter)}),` `,d(D.objective)]}),(0,x.jsx)(`p`,{className:`sr`,role:`status`,children:Ae}),(0,x.jsxs)(`div`,{className:`audit-grille`,children:[(0,x.jsx)(y,{labelledBy:U.lancer,className:`audit-lancer`,head:(0,x.jsx)(`h2`,{id:U.lancer,className:`t-titre-3`,children:`Lancer`}),children:(0,x.jsxs)(`form`,{className:`audit-formulaire`,onSubmit:Pe,children:[D.fields.map((e,t)=>(0,x.jsxs)(b.Fragment,{children:[(0,x.jsx)(fe,{label:e.label,optional:!e.required,help:d(e.help),error:t===0&&L?`Hors de ton périmètre autorisé.`:void 0,children:(0,x.jsx)(pe,{mono:!0,value:O[e.key]??``,onChange:n=>{k(t=>({...t,[e.key]:n.target.value})),t===0&&R(null)},placeholder:e.placeholder,autoComplete:`off`,spellCheck:!1,disabled:j!==null})}),t===0&&Q.length>0?(0,x.jsxs)(`div`,{className:`audit-puces`,role:`group`,"aria-labelledby":E,children:[(0,x.jsx)(`span`,{id:E,className:`audit-puces-etiquette`,children:d(`Ton périmètre :`)}),Q.map(e=>(0,x.jsx)(a,{size:`s`,variant:`nu`,className:`audit-puce`,"aria-pressed":(O[J?.key??``]??``)===e,disabled:j!==null,onClick:()=>{J&&(k(t=>({...t,[J.key]:e})),R(null))},children:e},e))]}):null]},e.key)),q?(0,x.jsxs)(`p`,{className:`phrase-note`,children:[`Ce module envoie du trafic vers la cible. Le serveur refuse toute cible hors de ton périmètre autorisé`,C.data&&Z.length===0?`, qui ne contient que cette machine.`:`.`]}):null,D.input===`none`?(0,x.jsxs)(`p`,{className:`phrase-note`,children:[`Ce module n’a rien à remplir`,`\xA0`,`: il lit la configuration de cette machine. Sans les droits administrateur, certaines vérifications sont marquées «`,`\xA0`,`Non vérifié`,`\xA0`,`».`]}):null,j?(0,x.jsxs)(`div`,{className:`audit-progression`,children:[(0,x.jsx)(ie,{done:j.done,total:j.total,label:j.label}),(0,x.jsx)(`span`,{className:`audit-progression-etape`,children:j.label})]}):(0,x.jsxs)(`div`,{className:`audit-envoi`,children:[(0,x.jsx)(a,{ref:W,type:`submit`,variant:`feu`,icon:(0,x.jsx)(t,{"aria-hidden":`true`}),disabled:Y.length>0,"aria-label":`Lancer le module ${D.title}`,"aria-describedby":Y.length>0?U.manque:void 0,children:`Lancer le module`}),Y.length>0?(0,x.jsx)(`p`,{id:U.manque,className:`phrase-note`,children:Se(Y)}):null]}),L?(0,x.jsx)(de,{id:U.refus,className:`audit-refus`,issue:`refusee`,word:`Refusée`,role:`alert`,fresh:!0,action:(0,x.jsx)(o,{size:`s`,href:m({page:`audits`}),icon:(0,x.jsx)(n,{"aria-hidden":`true`}),children:`Déclarer une cible`}),children:L}):null,F?(0,x.jsx)(s,{message:F}):null]})}),(0,x.jsxs)(`div`,{className:`audit-principal`,children:[(0,x.jsx)(y,{labelledBy:U.resultat,className:`audit-dernier`,children:N&&!j?(0,x.jsx)(xe,{run:N,titre:Fe,titreId:U.resultat}):(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(`h2`,{id:U.resultat,className:`t-titre-3`,children:`Dernier résultat`}),j?(0,x.jsx)(`p`,{className:`phrase-note`,children:`Le résultat s’affiche ici à la fin du passage.`}):S.loading&&!S.data?(0,x.jsx)(u,{label:`Chargement du dernier passage`}):$.length===0?(0,x.jsx)(te,{children:`Pas encore de résultat. Lance le module pour voir ici ses constats et le détail de chaque vérification.`}):null]})}),$.length>0?(0,x.jsx)(y,{labelledBy:U.historique,className:`audit-historique-bande`,head:(0,x.jsxs)(`h2`,{id:U.historique,className:`t-titre-3`,children:[`Historique de ce module `,(0,x.jsx)(`span`,{className:`audit-compte`,children:f($.length,`passage`,`passages`)})]}),children:(0,x.jsx)(Ce,{caption:`Historique du module ${D.title}`,runs:$,courant:j?void 0:N?.id,onVoir:e=>void Ne(e.id),onSupprimer:V})}):null]}),(0,x.jsxs)(y,{labelledBy:U.explication,className:`audit-explication`,head:(0,x.jsx)(`h2`,{id:U.explication,className:`t-titre-3`,children:`Ce que fait ce module`}),children:[(0,x.jsxs)(me,{layout:`pile`,children:[(0,x.jsx)(v,{label:`Cible`,children:ge[D.input]}),(0,x.jsx)(v,{label:`Périmètre du test`,children:d(D.perimeter)}),(0,x.jsx)(v,{label:`Résultats`,children:d(D.results)})]}),D.commands?(0,x.jsxs)(`details`,{className:`audit-details`,children:[(0,x.jsxs)(`summary`,{children:[`Voir les `,D.commands.length,` commandes du module`]}),(0,x.jsx)(`ol`,{className:`audit-commandes-liste`,children:D.commands.map(e=>(0,x.jsx)(`li`,{children:(0,x.jsx)(g,{code:e,as:`bloc`})},e))})]}):null]})]}),ke?(0,x.jsxs)(ce,{title:`Lancer « ${D.title} » ?`,confirmLabel:`Lancer`,confirmIcon:(0,x.jsx)(t,{"aria-hidden":`true`}),initialFocus:q?`cancel`:`confirm`,size:`l`,onConfirm:()=>void Me(),onCancel:()=>A(!1),children:[(0,x.jsxs)(`p`,{className:`audit-objet`,children:[`Cible`,`\xA0`,`: `,(0,x.jsx)(Te,{target:X})]}),(0,x.jsx)(`p`,{children:d(D.perimeter)}),D.commands?(0,x.jsxs)(`div`,{className:`audit-commandes`,children:[(0,x.jsxs)(`p`,{id:U.commandes,className:`audit-commandes-titre`,children:[`Le module exécute `,f(D.commands.length,`commande`,`commandes`),`, dans cet ordre`,`\xA0`,`:`]}),(0,x.jsx)(`div`,{className:`audit-commandes-defile`,"data-bloc":H?``:void 0,...H?{role:`region`,tabIndex:0,"aria-labelledby":U.commandes}:{},children:(0,x.jsx)(`ol`,{className:`audit-commandes-liste`,"aria-labelledby":U.commandes,children:D.commands.map(e=>(0,x.jsx)(`li`,{children:(0,x.jsx)(g,{code:e,as:`bloc`})},e))})})]}):null,q?(0,x.jsx)(`p`,{children:`Le serveur refuse toute cible hors de ton périmètre autorisé.`}):(0,x.jsxs)(`p`,{children:[`Lecture seule`,`\xA0`,`: rien n’est modifié sur ta machine.`]})]}):null,B?(0,x.jsx)(we,{run:B,titre:D.title,apres:_e(B,$),onClose:()=>V(null),onSupprime:e=>{V(null),N?.id===e&&P(null),S.reload(),w()}}):null]})})}export{S as default};
@@ -0,0 +1 @@
1
+ import{t as e}from"./arrow-right-Cx3pAEhl.js";import{$ as t,D as n,K as r,L as i,Ot as a,R as o,ft as s,n as c,ot as l,w as u}from"./index-COSiM-R9.js";import{c as d,s as f,t as p}from"./Register-DA_Aq5f8.js";import{a as m,c as h,f as g,g as _,i as v,u as y}from"./auditViews-BMza2Sdz.js";var b=a(),x=t();function S(){let t=u(`/api/audits/modules`),{status:a}=n(),S=(0,b.useId)(),C=(0,b.useId)(),w=a?.audits??[],T=w.filter(e=>e.last).length,E=w.reduce((e,t)=>e+(t.last&&t.last.status===`done`?y(t.last.counts):0),0),D=t.data?.modules.length??8;return(0,x.jsx)(`div`,{className:`vue`,children:(0,x.jsxs)(`div`,{className:`vue-contenu audits-page`,children:[(0,x.jsx)(d,{title:`Audits de sécurité`,actions:(0,x.jsx)(r,{size:`s`,href:c({page:`reports`}),iconEnd:(0,x.jsx)(e,{"aria-hidden":`true`}),children:`Rapports et historique`}),children:a?g(T,D,E,`modules`):s(`Chaque module vise cette machine ou une cible de ton périmètre autorisé.`)}),(0,x.jsx)(v,{titreId:S}),(0,x.jsxs)(p,{labelledBy:C,head:(0,x.jsx)(`h2`,{id:C,className:`t-titre-3`,children:`Modules`}),children:[t.error?(0,x.jsx)(i,{message:t.error,onRetry:t.reload}):null,t.loading&&!t.data?(0,x.jsx)(o,{label:`Chargement des modules`}):null,(0,x.jsx)(`ol`,{className:`audits-liste`,children:(t.data?.modules??[]).map(t=>{let n=w.find(e=>e.module===t.id)?.last??null,r=`module-${t.id}`;return(0,x.jsx)(`li`,{children:(0,x.jsxs)(`a`,{className:`audits-module`,href:c({page:`audit`,module:t.id}),"aria-labelledby":`${r}-titre`,"aria-describedby":`${r}-ordinal ${r}-type ${r}-etat ${r}-objectif`,children:[(0,x.jsx)(`span`,{id:`${r}-ordinal`,className:`audits-module-ordinal`,children:(0,x.jsx)(f,{letter:t.letter,name:_(t.letter)})}),(0,x.jsx)(`span`,{id:`${r}-titre`,className:`audits-module-titre`,children:t.title}),(0,x.jsx)(`span`,{id:`${r}-type`,className:`audits-module-type`,children:h[t.input]}),(0,x.jsx)(`span`,{id:`${r}-objectif`,className:`audits-module-objectif`,children:s(t.objective)}),(0,x.jsx)(`span`,{id:`${r}-etat`,className:`audits-module-etat`,children:n?(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(m,{run:n}),(0,x.jsx)(`span`,{className:`audits-module-date`,children:l(n.startedAt)})]}):(0,x.jsx)(`span`,{className:`audits-module-jamais`,children:`Jamais lancé`})}),(0,x.jsx)(e,{className:`audits-module-fleche`,"aria-hidden":`true`})]})},t.id)})})]})]})})}export{S as default};
@@ -0,0 +1,3 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Carte-xycu1mQn.js","assets/index-COSiM-R9.js","assets/index-BH1etemR.css","assets/web-6j1-aY67.js","assets/Carte-CPuiR1Ha.css"])))=>i.map(i=>d[i]);
2
+ import{c as e,d as t,f as n,s as r,u as i}from"./Shell-CQRlx9-V.js";import{c as a,d as o,f as s,n as c,o as l,p as u}from"./Field-C7c2mCbb.js";import{t as d}from"./circle-stop-C33BAcKW.js";import{t as f}from"./eye-CXXHBBpr.js";import{$ as p,A as m,B as ee,Ct as h,D as te,Et as g,G as _,H as ne,L as re,M as ie,O as ae,Ot as v,P as y,R as b,S as oe,U as x,V as S,Y as C,_ as se,a as ce,b as le,bt as ue,dt as w,f as de,ft as fe,g as pe,gt as T,ht as E,i as me,l as D,mt as O,n as k,o as he,ot as ge,p as _e,q as A,st as j,t as M,w as ve,wt as N,xt as ye,yt as be,z as P}from"./index-COSiM-R9.js";import{t as xe}from"./plus-D_QHm8ud.js";import{t as Se}from"./trash-DLpHM-s8.js";import{n as F,o as Ce,s as we,t as Te}from"./command-ChA49Xk7.js";import{i as I,o as L,r as Ee}from"./Register-DA_Aq5f8.js";import{n as De,t as Oe}from"./markdown-o5sMhPHN.js";import{n as R,t as z}from"./web-6j1-aY67.js";var ke={name:`globe`,size:24,node:[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20`,key:`13o1zl`}],[`path`,{d:`M2 12h20`,key:`9i4pu4`}]]};ke.node;var Ae=g(ke),je={name:`list`,size:24,node:[[`path`,{d:`M3 5h.01`,key:`18ugdj`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M3 19h.01`,key:`noohij`}],[`path`,{d:`M8 5h13`,key:`1pao27`}],[`path`,{d:`M8 12h13`,key:`1za7za`}],[`path`,{d:`M8 19h13`,key:`m83p4d`}]]};je.node;var Me=g(je),B={name:`messages-square`,size:24,node:[[`path`,{d:`M16 10a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 14.286V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z`,key:`1n2ejm`}],[`path`,{d:`M20 9a2 2 0 0 1 2 2v10.286a.71.71 0 0 1-1.212.502l-2.202-2.202A2 2 0 0 0 17.172 19H10a2 2 0 0 1-2-2v-1`,key:`1qfcsi`}]]};B.node;var Ne=g(B),Pe={name:`send`,size:24,node:[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]};Pe.node;var Fe=g(Pe),V=v();function Ie(e){let[t,n]=(0,V.useState)(()=>Date.now());return(0,V.useEffect)(()=>{if(e===null)return;n(Date.now());let t=window.setInterval(()=>n(Date.now()),1e3);return()=>window.clearInterval(t)},[e]),e===null?null:Math.max(0,Math.floor((t-e)/1e3))}var H=p();function Le(){return(0,H.jsx)(`p`,{className:`phrase-note recherche-carte-absente`,children:`La carte n’a pas pu se charger. Recharge la page pour la voir.`})}var U=(0,V.lazy)(()=>M(()=>import(`./Carte-xycu1mQn.js`),__vite__mapDeps([0,1,2,3,4])).catch(()=>({default:Le}))),W=[];function Re(e){if(!e)return null;let t=new Date(e);return Number.isNaN(t.getTime())?null:t.toLocaleDateString(`fr-FR`,{day:`numeric`,month:`short`,year:`numeric`})}function G(e){let t=new Set,n=[];for(let r of e)!t.has(r.n)&&z(r.url)&&(t.add(r.n),n.push(r));return n}function K(e){let t=new Set(e.sources.map(e=>e.n));return G((e.extracts??[]).filter(e=>!e.fresh&&!t.has(e.n)))}var ze=e=>({n:e.n,title:e.title,url:e.url,snippet:e.text,engines:[],publishedDate:null}),q=new WeakMap;function Be(e){if(!e.search&&!e.recall)return null;let t=q.get(e);if(t)return t;let n=[...e.search?.extracts??[],...e.recall?.extracts??[]],r=e.search?.sources??[];if(n.length>0){let e=new Set(r.map(e=>e.n));r=[...r,...G(n).filter(t=>!e.has(t.n)).map(ze)]}return q.set(e,r),r}function J({extrait:e,lue:t}){let n=Re(e.learnedAt);return(0,H.jsxs)(`li`,{value:e.n,className:`recherche-source`,"data-savoir":``,children:[(0,H.jsx)(`span`,{className:`recherche-numero`,"aria-hidden":`true`,children:e.n}),(0,H.jsxs)(`div`,{className:`recherche-source-corps`,children:[(0,H.jsx)(`a`,{className:`recherche-source-titre`,href:e.url,target:`_blank`,rel:`noopener noreferrer`,children:e.title||R(e.url)}),(0,H.jsxs)(`p`,{className:`recherche-source-meta`,children:[(0,H.jsx)(`span`,{className:`t-donnee`,children:e.host||R(e.url)}),n?(0,H.jsx)(`span`,{children:`${t} ${n}`}):null]}),e.text?(0,H.jsx)(`p`,{className:`recherche-extrait`,children:e.text}):null]})]})}function Y({sources:e,memoire:t}){return(0,H.jsxs)(`ol`,{className:`recherche-sources`,"aria-label":`Sources`,children:[e.map(e=>{let t=Re(e.publishedDate);return(0,H.jsxs)(`li`,{value:e.n,className:`recherche-source`,children:[(0,H.jsx)(`span`,{className:`recherche-numero`,"aria-hidden":`true`,children:e.n}),(0,H.jsxs)(`div`,{className:`recherche-source-corps`,children:[(0,H.jsx)(`a`,{className:`recherche-source-titre`,href:e.url,target:`_blank`,rel:`noopener noreferrer`,children:e.title}),(0,H.jsxs)(`p`,{className:`recherche-source-meta`,children:[(0,H.jsx)(`span`,{className:`t-donnee`,children:R(e.url)}),t?(0,H.jsx)(`span`,{children:t}):null]}),e.snippet?(0,H.jsx)(`p`,{className:`recherche-extrait`,children:e.snippet}):null]})]},e.n)}),t.map(e=>(0,H.jsx)(J,{extrait:e,lue:`déjà lue le`},`savoir-${e.n}`))]})}var Ve={reading:`en-cours`,learned:`reussie`,known:`neutre`,failed:`echec`};function X(e){switch(e.state){case`reading`:return`En lecture`;case`learned`:return e.chars>0?fe(`Retenue, ${O(e.chars)} caractères`):`Retenue`;case`known`:return`Déjà dans le savoir`;case`failed`:return`${fe(`Non lue :`)} ${D(e.error??`page illisible.`)}`}}function He({pages:e,enFlux:t}){let n=e.filter(e=>e.state===`reading`).length;return n>0?(0,H.jsxs)(`p`,{className:`recherche-pages-etat`,role:`status`,children:[(0,H.jsx)(x,{kind:t?`en-cours`:`neutre`}),(0,H.jsx)(`span`,{children:t?`Lecture de ${E(n,`page`,`pages`)}…`:`Lecture des pages interrompue.`})]}):(0,H.jsxs)(`div`,{className:`recherche-pages`,children:[(0,H.jsxs)(`p`,{className:`recherche-pages-titre`,children:[(0,H.jsx)(`span`,{children:`Pages lues pour le savoir`}),(0,H.jsx)(`a`,{className:`recherche-lien`,href:k({page:`savoir`}),children:`Voir le savoir`})]}),(0,H.jsx)(`ul`,{className:`recherche-pages-liste`,"aria-label":`Pages lues pour le savoir`,children:e.map(e=>(0,H.jsxs)(`li`,{className:`recherche-page`,"data-etat":e.state,children:[(0,H.jsx)(`span`,{className:`recherche-numero`,"aria-hidden":`true`,children:e.n}),(0,H.jsxs)(`span`,{className:`recherche-page-corps`,children:[(0,H.jsx)(`span`,{className:`t-donnee recherche-page-site`,children:R(e.url)}),(0,H.jsxs)(`span`,{className:`recherche-page-issue`,children:[(0,H.jsx)(x,{kind:Ve[e.state]}),(0,H.jsx)(`span`,{children:X(e)})]})]})]},`${e.n}-${e.url}`))})]})}function Ue({recall:e}){let t=(0,V.useId)(),r=(0,V.useMemo)(()=>G(e.extracts),[e]);return(0,H.jsxs)(`section`,{className:`recherche recherche-rappel`,"aria-labelledby":t,children:[(0,H.jsxs)(`h2`,{id:t,className:`t-interface recherche-titre`,children:[(0,H.jsx)(n,{"aria-hidden":`true`}),(0,H.jsx)(`span`,{children:`Relu dans le savoir de Prométhée`})]}),(0,H.jsxs)(`p`,{className:`recherche-etat`,children:[(0,H.jsx)(`span`,{children:E(r.length,`page relue`,`pages relues`)}),(0,H.jsx)(`a`,{className:`recherche-lien`,href:k({page:`savoir`}),children:`Voir le savoir`})]}),r.length>0?(0,H.jsx)(`ol`,{className:`recherche-sources`,"aria-label":`Pages relues`,children:r.map(e=>(0,H.jsx)(J,{extrait:e,lue:`lue le`},e.n))}):null]})}function We({lieu:e}){let[t,n]=(0,V.useState)(null);return(0,H.jsxs)(`figure`,{className:`recherche-lieu`,children:[(0,H.jsx)(V.Suspense,{fallback:(0,H.jsx)(`div`,{className:`recherche-carte-attente`,"aria-hidden":`true`}),children:(0,H.jsx)(U,{lieu:e,choix:t,onChoisir:n})}),(0,H.jsxs)(`figcaption`,{className:`recherche-legende`,children:[(0,H.jsx)(`span`,{className:`recherche-lieu-nom`,children:e.name}),e.address?(0,H.jsx)(`span`,{className:`recherche-lieu-adresse`,children:e.address}):null,(0,H.jsx)(_,{variant:`nu`,size:`s`,className:`recherche-voir-fiche`,onClick:()=>n({rang:0,centrer:!0}),children:`Voir la fiche`}),z(e.osmUrl)?(0,H.jsx)(`a`,{className:`recherche-lien`,href:e.osmUrl,target:`_blank`,rel:`noopener noreferrer`,children:`Ouvrir dans OpenStreetMap`}):null]})]})}function Ge(e){let t=/^([^\s-]+)(.*)$/u.exec(e);if(!t)return e;let[,n=``,r=``]=t;return(n.endsWith(`eaux`)?n.slice(0,-1):n.endsWith(`aux`)?`${n.slice(0,-3)}al`:n.endsWith(`s`)?n.slice(0,-1):n)+r}var Ke=e=>e.mode===`around`&&e.radius!==null?`à moins de ${O(e.radius)} m de ${e.zone}`:`dans ${e.zone}`;function qe(e,t){return`${O(t)} ${t>1?e.label:Ge(e.label)} ${Ke(e)}, d’après OpenStreetMap`}var Z=e=>`/api/map/places?${new URLSearchParams({category:e.request.category,where:JSON.stringify(e.request.where)})}`,Je=(0,V.memo)(function({ensemble:e}){let[t,n]=(0,V.useState)(null),[r,i]=(0,V.useState)(!1),[a,o]=(0,V.useState)(0),[s,c]=(0,V.useState)(()=>({etat:`attente`,depuis:Date.now()})),l=(0,V.useId)(),u=Z(e);(0,V.useEffect)(()=>{let e=new AbortController;return c({etat:`attente`,depuis:Date.now()}),n(null),m(`GET`,u,void 0,e.signal).then(t=>{e.signal.aborted||c({etat:`pret`,resultat:t})}).catch(t=>{e.signal.aborted||c({etat:`echec`,message:y(t)})}),()=>e.abort()},[u,a]);let d=Ie(s.etat===`attente`?s.depuis:null),f=s.etat===`pret`?s.resultat.points:W,p=(0,V.useMemo)(()=>f.map((e,t)=>({p:e,rang:t})).sort((e,t)=>e.p.name.localeCompare(t.p.name,`fr`)),[f]);if(s.etat===`attente`)return(0,H.jsxs)(`div`,{className:`recherche-lieux recherche-lieux-attente`,children:[(0,H.jsx)(b,{label:`Recherche des ${e.label} ${Ke(e)} sur OpenStreetMap`}),d!==null&&d>=1?(0,H.jsx)(`span`,{className:`recherche-lieux-secondes`,"aria-hidden":`true`,children:`${d} s`}):null]});if(s.etat===`echec`)return(0,H.jsx)(P,{issue:`echec`,word:`Échec`,action:(0,H.jsx)(_,{size:`s`,icon:(0,H.jsx)(De,{"aria-hidden":`true`}),onClick:()=>o(e=>e+1),children:`Réessayer`}),children:D(s.message)});let{total:ee}=s.resultat;return f.length===0?(0,H.jsx)(`p`,{className:`phrase-note`,children:D(`Aucun lieu trouvé pour « ${e.label} » ${Ke(e)}.`)}):(0,H.jsxs)(`figure`,{className:`recherche-lieu recherche-lieux`,children:[(0,H.jsx)(V.Suspense,{fallback:(0,H.jsx)(`div`,{className:`recherche-carte-attente`,"aria-hidden":`true`}),children:(0,H.jsx)(U,{ensemble:e,points:f,choix:t,onChoisir:n})}),(0,H.jsxs)(`figcaption`,{className:`recherche-legende`,children:[(0,H.jsx)(`span`,{className:`recherche-lieu-nom`,children:D(qe(e,ee))}),f.length<ee?(0,H.jsx)(`span`,{children:`Seuls les ${O(f.length)} premiers sont sur la carte.`}):null,(0,H.jsx)(_,{variant:`nu`,size:`s`,icon:(0,H.jsx)(Me,{"aria-hidden":`true`}),className:`recherche-voir-liste`,"aria-expanded":r,"aria-controls":l,onClick:()=>i(e=>!e),children:r?`Masquer la liste`:f.length>1?`Voir la liste des ${O(f.length)} ${e.label}`:`Voir la liste`})]}),(0,H.jsx)(`ul`,{id:l,className:`recherche-lieux-liste`,"aria-label":`Liste des ${e.label}`,hidden:!r,children:r?p.map(({p:e,rang:r})=>(0,H.jsxs)(`li`,{children:[(0,H.jsx)(`button`,{type:`button`,className:`recherche-lieux-choix`,"aria-current":t?.rang===r?`true`:void 0,onClick:()=>n({rang:r,centrer:!0}),children:e.name}),e.address?(0,H.jsx)(`span`,{className:`recherche-lieux-adresse`,children:e.address}):null]},`${e.osm}-${r}`)):null})]})});function Ye({search:e,enFlux:t}){let n=(0,V.useId)(),r=ye(e,t),i=r.kind===`en-cours`,[a,o]=(0,V.useState)(null);i&&a===null&&o(Date.now());let s=Ie(i?a:null),c=e.sources.filter(e=>z(e.url)),l=(0,V.useMemo)(()=>K(e),[e]);return(0,H.jsxs)(`section`,{className:`recherche`,"data-etat":e.state,"aria-labelledby":n,"aria-busy":i?!0:void 0,children:[(0,H.jsxs)(`h2`,{id:n,className:`t-interface recherche-titre`,children:[(0,H.jsx)(Ae,{"aria-hidden":`true`}),(0,H.jsxs)(`span`,{children:[`Recherche web`,`\xA0`,`: `,(0,H.jsxs)(`span`,{className:`recherche-requete`,children:[`«`,`\xA0`,e.query,`\xA0`,`»`]})]})]}),e.state===`failed`?r.mot===T.mot?(0,H.jsx)(P,{issue:T.kind,word:T.mot,children:`Tu as arrêté la recherche.`}):(0,H.jsx)(P,{issue:`echec`,word:`Échec`,action:(0,H.jsx)(`a`,{className:`recherche-lien`,href:k({page:`settings`,partie:`recherche`}),children:`Voir les réglages`}),children:D(e.error??`La recherche n’a pas abouti.`)}):(0,H.jsxs)(`p`,{className:`recherche-etat`,children:[(0,H.jsx)(S,{kind:r.kind,mot:r.mot,detail:i&&s!==null&&s>=1?`${s} s`:void 0}),e.state===`done`?(0,H.jsx)(`span`,{children:c.length===0?`aucune source`:E(c.length,`source`,`sources`)}):null,e.state===`done`&&l.length>0?(0,H.jsx)(`span`,{children:E(l.length,`page relue dans le savoir`,`pages relues dans le savoir`)}):null,e.state===`done`&&e.durationMs!==null?(0,H.jsx)(`span`,{children:w(e.durationMs)}):null]}),e.places?(0,H.jsx)(Je,{ensemble:e.places}):e.place?(0,H.jsx)(We,{lieu:e.place}):e.placesNote&&e.state!==`running`?(0,H.jsx)(`p`,{className:`phrase-note`,children:D(e.placesNote)}):e.state===`done`&&e.placeQuery?(0,H.jsxs)(`p`,{className:`phrase-note`,children:[`Lieu introuvable sur la carte`,`\xA0`,`: «`,`\xA0`,(0,H.jsx)(`span`,{className:`recherche-requete`,children:e.placeQuery}),`\xA0`,`».`]}):null,c.length>0||l.length>0?(0,H.jsx)(Y,{sources:c,memoire:l}):null,e.pages&&e.pages.length>0?(0,H.jsx)(He,{pages:e.pages,enFlux:t}):null]})}var Q={tools:`propose des commandes`,vision:`lit les images`,thinking:`raisonne à part`,embedding:`vecteurs`},Xe=`Entrée pour envoyer, Maj + Entrée pour aller à la ligne.`,Ze=1800,Qe=16e3,$e=[`Quels ports écoutent sur ma machine ?`,`Mon pare-feu Windows est-il activé ?`,`Explique ce qu’est une attaque par force brute.`,`Quels comptes locaux existent sur ce PC ?`],et=`Réponse interrompue.`,tt={pending:`Commande proposée`,running:`Commande lancée`,done:`Commande exécutée`,failed:`Commande exécutée`,refused:`Commande refusée par la politique`,denied:`Commande écartée`,expired:`Commande expirée`};function nt(e){let[t,n]=(0,V.useState)(()=>typeof ResizeObserver>`u`);return(0,V.useLayoutEffect)(()=>{let t=e.current;if(!t||typeof ResizeObserver>`u`)return;let r=()=>de[1]*pe(),i=getComputedStyle(t);n(t.clientWidth-Number.parseFloat(i.paddingLeft)-Number.parseFloat(i.paddingRight)>=r());let a=new ResizeObserver(([e])=>{e&&n(e.contentRect.width>=r())});return a.observe(t),()=>a.disconnect()},[e]),t}function rt({nom:e}){let t=e.indexOf(`:`);return t>0?(0,H.jsxs)(H.Fragment,{children:[e.slice(0,t),(0,H.jsx)(`wbr`,{}),e.slice(t)]}):e}function it({modeles:e,occupe:n,fullCyber:r,auto:i,onChanger:a}){let[o,s]=(0,V.useState)(!1),c=(0,V.useId)(),l=e.installed.find(t=>t.name===e.selected),d=e.loaded.find(t=>t.name===e.selected),f=l?.capabilities.includes(`tools`)??!1,p=(l?.capabilities??[]).flatMap(e=>Q[e]?[Q[e]]:[]);return(0,H.jsxs)(`div`,{className:`cerveau-modele`,children:[(0,H.jsxs)(`p`,{className:`cerveau-modele-ligne`,children:[(0,H.jsx)(t,{"aria-hidden":`true`}),(0,H.jsx)(`span`,{className:`sr`,children:`Modèle : `}),(0,H.jsx)(`span`,{className:`cerveau-modele-nom`,children:e.selected?(0,H.jsx)(rt,{nom:e.selected}):`aucun`}),(0,H.jsx)(`span`,{className:`cerveau-modele-etat`,"data-charge":d?``:void 0,children:d?`chargé`:`non chargé`}),(0,H.jsx)(`span`,{className:`cerveau-modele-capacite`,"data-outils":f?``:void 0,children:f?`propose des commandes`:`répond en texte seulement`}),r?(0,H.jsxs)(`a`,{className:`cerveau-cyber`,href:`#console-reglages`,title:`Mode full cyber actif. Réponses offensives sans retenue, pour un usage white hat autorisé. Régler dans les Réglages, Cerveau.`,children:[`full cyber`,i?` · auto`:``]}):null,(0,H.jsx)(_,{variant:`nu`,size:`s`,className:`cerveau-modele-details`,"aria-expanded":o,"aria-controls":c,iconEnd:(0,H.jsx)(u,{"aria-hidden":`true`}),onClick:()=>s(e=>!e),children:(0,H.jsx)(`span`,{className:`cerveau-modele-details-mot`,children:`Détails`})})]}),o?(0,H.jsxs)(`div`,{id:c,className:`cerveau-modele-fiche`,children:[l?(0,H.jsxs)(Ee,{children:[(0,H.jsxs)(I,{label:`Taille`,literal:!0,children:[l.parameterSize||`?`,`, `,l.quantization||`?`]}),(0,H.jsx)(I,{label:`Famille`,literal:!0,children:l.family||`?`}),(0,H.jsx)(I,{label:`Contexte`,literal:!0,children:l.contextLength?`${O(l.contextLength)} tokens`:`inconnu`}),(0,H.jsx)(I,{label:`Sur le disque`,literal:!0,children:j(l.sizeBytes)}),(0,H.jsx)(I,{label:`En mémoire`,literal:!0,children:d?`${j(d.sizeVram)} sur le GPU`:`non chargé`}),p.length>0?(0,H.jsx)(I,{label:`Sait`,children:p.join(`, `)}):null]}):null,(0,H.jsx)(_,{size:`s`,icon:(0,H.jsx)(t,{"aria-hidden":`true`}),onClick:a,disabled:n||e.installed.length<2,children:`Changer de modèle`})]}):null]})}function at({rubrique:e,conversations:t,chargement:n,sessions:r,courante:i,occupe:a,courant:o,onNouvelle:s,onOuvrir:c,onSupprimer:l,onSession:u}){return(0,H.jsxs)(`div`,{className:`cerveau-conversations`,children:[(0,H.jsxs)(`div`,{className:`cerveau-conv-tete`,children:[e?(0,H.jsx)(L,{as:`h2`,children:`Conversations`}):null,(0,H.jsx)(_,{size:`s`,icon:(0,H.jsx)(xe,{"aria-hidden":`true`}),className:`cerveau-nouvelle`,onClick:s,children:`Nouvelle conversation`})]}),t&&t.length>0?(0,H.jsx)(`ul`,{className:`cerveau-conv-liste`,children:t.map(e=>(0,H.jsxs)(`li`,{className:`cerveau-conv`,children:[(0,H.jsxs)(`button`,{ref:e.id===i?o:void 0,type:`button`,className:`cerveau-conv-ouvrir`,"aria-current":e.id===i?`true`:void 0,onClick:()=>c(e.id),disabled:a,children:[(0,H.jsx)(`span`,{className:`cerveau-conv-nom`,children:e.title}),(0,H.jsxs)(`span`,{className:`cerveau-conv-meta`,children:[E(e.count,`message`,`messages`),` · `,ge(e.updatedAt)]})]}),(0,H.jsx)(A,{className:`cerveau-conv-supprimer`,label:`Supprimer la conversation « ${e.title} »`,icon:(0,H.jsx)(Se,{"aria-hidden":`true`}),onClick:()=>l(e),disabled:a})]},e.id))}):(0,H.jsx)(`p`,{className:`cerveau-conv-vide`,children:n?`Chargement des conversations…`:`Aucune conversation enregistrée.`}),r.length>0?(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(L,{as:`h2`,children:`Sessions de la TUI`}),(0,H.jsx)(`ul`,{className:`cerveau-conv-liste`,children:r.map(e=>(0,H.jsx)(`li`,{className:`cerveau-conv`,children:(0,H.jsxs)(`button`,{type:`button`,className:`cerveau-conv-ouvrir`,"aria-haspopup":`dialog`,onClick:()=>u(e),children:[(0,H.jsx)(`span`,{className:`cerveau-conv-nom`,children:e.title}),(0,H.jsxs)(`span`,{className:`cerveau-conv-meta`,children:[`lecture seule`,e.updated?` · ${ge(e.updated)}`:``]})]})},e.id))})]}):null]})}function ot({proposal:e,live:t,enTete:n,occupe:r,frais:i,onRelire:a,onEcarter:c}){let l=(0,V.useId)(),{status:u,verdict:d,result:p}=e,[m,ee]=(0,V.useState)(null);u===`running`&&m===null&&ee(Date.now());let te=Ie(u===`running`?m:null),g=p?.output??t??``,re=h(d.level),ie=(u===`done`||u===`failed`)&&p?be(p):ue(e);return(0,H.jsxs)(`section`,{className:`cerveau-prop`,"data-etat":u,"aria-labelledby":l,"aria-busy":u===`running`||void 0,children:[(0,H.jsx)(`h2`,{id:l,className:`t-interface cerveau-prop-titre`,children:tt[u]}),(0,H.jsx)(s,{as:`bloc`,code:e.command}),u===`pending`?(0,H.jsx)(F,{verdict:d}):null,u===`refused`?(0,H.jsx)(Te,{verdict:d,frais:i}):null,e.explanation?(0,H.jsx)(`p`,{className:`cerveau-prop-explication`,children:e.explanation}):null,g?(0,H.jsx)(o,{className:`cerveau-sortie`,children:g}):null,u===`refused`?null:(0,H.jsxs)(`p`,{className:`cerveau-prop-etat`,children:[(0,H.jsx)(S,{kind:ie.kind,mot:ie.mot,detail:u===`running`&&te!==null&&te>=1?`${te}\u00a0s`:void 0}),p&&!(p.cancelled&&p.durationMs===0)?(0,H.jsx)(`span`,{children:w(p.durationMs)}):null,u!==`pending`&&re?(0,H.jsx)(ne,{level:re}):null,p?.truncated?(0,H.jsxs)(`span`,{children:[`sortie coupée à 1`,`\xA0`,`Mo`]}):null,p&&!p.cancelled&&!p.output?(0,H.jsx)(`span`,{children:`aucune sortie`}):null]}),u===`pending`?(0,H.jsxs)(`div`,{className:`cerveau-prop-actions`,children:[(0,H.jsx)(_,{variant:n?`feu`:`contour`,icon:(0,H.jsx)(f,{"aria-hidden":`true`}),onClick:()=>a(e),disabled:r,children:`Relire et exécuter`}),(0,H.jsx)(_,{icon:(0,H.jsx)(N,{"aria-hidden":`true`}),onClick:()=>c(e),disabled:r,children:`Écarter`}),(0,H.jsx)(`p`,{className:`phrase-note cerveau-prop-note`,children:`Rien ne s’exécute sans ton accord. Si tu envoies un autre message, cette proposition expire.`})]}):null]})}function st({charge:e}){return(0,H.jsxs)(`div`,{className:`cerveau-tour`,"data-qui":`modele`,"aria-busy":`true`,children:[(0,H.jsxs)(`span`,{className:`cerveau-marge`,children:[(0,H.jsx)(C,{animated:!0,className:`cerveau-flamme`}),(0,H.jsx)(`span`,{className:`sr`,children:`Prométhée`})]}),(0,H.jsx)(`div`,{className:`cerveau-reponse`,children:(0,H.jsx)(`p`,{className:`cerveau-attente`,children:e?`Réflexion du modèle`:`Chargement du modèle en mémoire`})})]})}function ct({attachment:e,onRetirer:t}){let[n,r]=(0,V.useState)(!1);return(0,H.jsxs)(`span`,{className:`piece-jointe`,children:[(0,H.jsxs)(`button`,{type:`button`,className:`piece-jointe-ouvrir`,onClick:()=>r(!0),"aria-haspopup":`dialog`,"aria-label":`Voir ${e.name}`,children:[(0,H.jsx)(i,{"aria-hidden":`true`}),(0,H.jsx)(`span`,{className:`piece-jointe-nom`,children:e.name}),(0,H.jsxs)(`span`,{className:`piece-jointe-taille`,children:[O(e.text.length),` caractères`]})]}),t?(0,H.jsx)(A,{className:`piece-jointe-retirer`,size:`s`,label:`Retirer ${e.name}`,icon:(0,H.jsx)(N,{"aria-hidden":`true`}),onClick:t}):null,n?(0,H.jsx)(ce,{title:e.name,size:`l`,onClose:()=>r(!1),children:(0,H.jsx)(`pre`,{className:`piece-jointe-texte`,children:e.text})}):null]})}var lt=(0,V.memo)(function({message:e,enFlux:t,flamme:n,live:r,enTete:i,occupe:a,frais:o,sources:s,onRelire:c,onEcarter:l}){if(e.role===`user`)return(0,H.jsxs)(`div`,{className:`cerveau-tour`,"data-qui":`toi`,children:[(0,H.jsx)(`span`,{className:`cerveau-marge cerveau-toi`,children:`Toi`}),(0,H.jsxs)(`div`,{className:`cerveau-question-bloc`,children:[e.content?(0,H.jsx)(`p`,{className:`cerveau-question`,children:e.content}):null,e.attachments&&e.attachments.length>0?(0,H.jsx)(`ul`,{className:`piece-jointe-liste`,"aria-label":`Pièces jointes`,children:e.attachments.map((e,t)=>(0,H.jsx)(`li`,{children:(0,H.jsx)(ct,{attachment:e})},t))}):null]})]});let u=t&&!e.content&&!e.proposal&&!e.error&&!e.search&&!e.recall,d=t&&e.search?.state===`running`,f=e.stats&&e.stats.tokens>0?e.stats:null;return(0,H.jsxs)(`div`,{className:`cerveau-tour`,"data-qui":`modele`,"aria-busy":t?!0:void 0,children:[(0,H.jsxs)(`span`,{className:`cerveau-marge`,children:[n?(0,H.jsx)(C,{animated:u||d,className:`cerveau-flamme`}):null,(0,H.jsx)(`span`,{className:`sr`,children:`Prométhée`})]}),(0,H.jsxs)(`div`,{className:`cerveau-reponse`,children:[u?(0,H.jsx)(`p`,{className:`cerveau-attente`,children:`Réflexion du modèle`}):null,e.search?(0,H.jsx)(Ye,{search:e.search,enFlux:t}):null,e.recall?(0,H.jsx)(Ue,{recall:e.recall}):null,e.content?(0,H.jsx)(Oe,{source:e.content,curseur:t&&!e.proposal&&!f,sources:s}):null,e.proposal?(0,H.jsx)(ot,{proposal:e.proposal,live:r,enTete:i,occupe:a,frais:o,onRelire:c,onEcarter:l}):null,e.unverified&&e.unverified.length>0?(0,H.jsxs)(P,{issue:`a-toi`,word:`À vérifier`,children:[`Ces valeurs n’apparaissent dans aucune sortie de commande, le modèle a pu les inventer`,`\xA0`,`: `,(0,H.jsx)(`span`,{className:`cerveau-litteral`,children:e.unverified.join(`, `)})]}):null,e.error?e.error===et?(0,H.jsx)(P,{issue:T.kind,word:T.mot,children:`Tu as arrêté la réponse.`}):(0,H.jsx)(P,{issue:`echec`,word:`Échec`,children:e.error}):null,f?(0,H.jsxs)(`p`,{className:`cerveau-stats`,children:[e.model,` · `,O(f.tokens),` tokens · `,O(f.tokensPerSec),` tokens/s · `,w(f.totalMs)]}):null]})]})});function ut(){let{status:n,refresh:i}=te(),{report:o}=oe(),u=ae(),f=ve(`/api/brain/conversations`),p=ve(`/api/tui/sessions`),h=f.reload,[g,ne]=(0,V.useState)(``),[v,b]=(0,V.useState)(null),[x,S]=(0,V.useState)([]),[C,ue]=(0,V.useState)(null),[w,de]=(0,V.useState)(!1),[pe,T]=(0,V.useState)({}),[D,O]=(0,V.useState)(``),[k,A]=(0,V.useState)([]),[j,M]=(0,V.useState)(null),[N,ye]=(0,V.useState)(null),[be,xe]=(0,V.useState)(!1),[F,Te]=(0,V.useState)(null),[I,L]=(0,V.useState)(!1),[Ee,De]=(0,V.useState)(!1),[R,z]=(0,V.useState)(``),[ke,Ae]=(0,V.useState)(!1),[je,Me]=(0,V.useState)(!1),[B,Pe]=(0,V.useState)(null),[Ie,Le]=(0,V.useState)(!1),[U,W]=(0,V.useState)(!1),Re=(0,V.useRef)(null),G=(0,V.useRef)(null),K=(0,V.useRef)(null),ze=(0,V.useRef)(null),q=(0,V.useRef)(!0),J=(0,V.useRef)(!1),Y=(0,V.useRef)(new Set),Ve=(0,V.useRef)(null),X=nt(Re),He=nt(Ve),Ue=se(_e.etroit),We=e(),Ge=(0,V.useId)(),Ke=n!==null&&!n.ollama.available,qe=n!==null&&n.ollama.available&&n.models.installed.length===0,Z=n!==null&&n.ollama.available&&n.models.installed.length>0;(0,V.useEffect)(()=>{m(`GET`,`/api/engine/cwd`).then(e=>ne(e.cwd)).catch(()=>ne(``))},[]),(0,V.useEffect)(()=>{Z&&K.current?.focus()},[Z]),(0,V.useEffect)(()=>{!be&&!U&&!I&&J.current&&(J.current=!1,K.current?.focus())},[be,U,I]),(0,V.useEffect)(()=>{X&&W(!1)},[X]),(0,V.useEffect)(()=>{let e=G.current;e&&q.current&&(e.scrollTop=e.scrollHeight)},[x,pe]);let Je=(0,V.useCallback)(async e=>{M(null);try{let t=await m(`GET`,`/api/brain/conversations/${e}`);q.current=!0,Y.current.clear(),b(e),S(t.messages),T({})}catch(e){o(e),M(y(e))}},[o]),Ye=(0,V.useCallback)(e=>{switch(e.type){case`message`:S(t=>t.some(t=>t.id===e.message.id)?t.map(t=>t.id===e.message.id?e.message:t):[...t,e.message]),e.message.role===`assistant`?ue(e.message.id):e.message.role===`user`&&h();break;case`token`:S(t=>t.map(t=>t.id===e.messageId?{...t,content:t.content+e.text}:t));break;case`proposal`:e.proposal.status===`refused`&&Y.current.add(e.proposal.id),S(t=>t.map(t=>t.id===e.messageId?{...t,proposal:e.proposal}:t));break;case`exec`:if(e.event.type===`out`){let t=e.event.text;T(n=>({...n,[e.proposalId]:((n[e.proposalId]??``)+t).slice(-6e4)}))}break;case`stats`:S(t=>t.map(t=>t.id===e.messageId?{...t,stats:e.stats}:t));break;case`search`:S(t=>t.map(t=>t.id===e.messageId?{...t,search:e.search}:t));break;case`recall`:S(t=>t.map(t=>t.id===e.messageId?{...t,recall:e.recall}:t))}},[h]),Q=(0,V.useCallback)(async(e,t,n)=>{de(!0);let r=le();try{await ie(t,n,Ye)}catch(t){o(t),u(`erreur`,`Le cerveau n’a pas pu répondre`,y(t)),Je(e)}finally{r(),de(!1),ue(null),h()}},[Ye,o,u,Je,h]),et=(0,V.useCallback)(async(e,t)=>{let n=e.trim();if(!n&&t.length===0||w||!Z)return;if(n.length+t.reduce((e,t)=>e+t.text.length,0)>Qe){u(`erreur`,`Message trop long`,`Texte et pièces jointes réunis, ${Qe} caractères au plus.`);return}O(``),A([]),K.current?.focus(),q.current=!0;let r=v;if(!r)try{r=(await m(`POST`,`/api/brain/conversations`,{})).id,Y.current.clear(),b(r),S([]),T({})}catch(n){o(n),O(e),A(t),u(`erreur`,`Conversation impossible à créer`,y(n));return}S(e=>e.map(e=>e.proposal?.status===`pending`||e.proposal?.status===`running`?{...e,proposal:{...e.proposal,status:`expired`,ticket:null}}:e)),await Q(r,`/api/brain/conversations/${r}/send`,{text:n,...t.length>0?{attachments:t}:{}})},[w,Z,v,o,Q,u]),tt=(0,V.useCallback)(async(e,t,n=!1)=>{v&&(q.current=!0,await Q(v,`/api/brain/conversations/${v}/decision`,{proposalId:e.id,decision:t,acknowledge:n}))},[v,Q]),rt=(0,V.useCallback)(e=>{if(!e.ticket)return;let t={ticket:e.ticket,command:e.command,cwd:g,verdict:e.verdict,expiresAt:null};we(t)&&(ye({proposal:e,preview:t}),xe(!0))},[g]),ot=(0,V.useCallback)(e=>{K.current?.focus(),tt(e,`deny`)},[tt]),ut=async()=>{if(v){K.current?.focus();try{await m(`POST`,`/api/brain/conversations/${v}/stop`)}catch(e){u(`erreur`,`Arrêt impossible`,y(e))}}},dt=()=>{Y.current.clear(),b(null),S([]),T({}),M(null),U?(J.current=!0,W(!1)):K.current?.focus()},ft=e=>{Je(e),U&&(J.current=!0,W(!1))},pt=async()=>{if(F){De(!0);try{await m(`DELETE`,`/api/brain/conversations/${F.id}`),F.id===v&&(b(null),S([]),T({})),u(`ok`,`Conversation supprimée`,F.title),h()}catch(e){u(`erreur`,`Suppression impossible`,y(e))}finally{De(!1),J.current=!0,L(!1)}}},mt=async()=>{Me(!0);try{await m(`PUT`,`/api/settings`,{model:R}),i(),u(`ok`,`Modèle changé`,`${R} répondra à tes prochains messages.`)}catch(e){u(`erreur`,`Changement de modèle impossible`,y(e))}finally{Me(!1),Ae(!1)}},ht=e=>{O(e),K.current?.focus()},gt=e=>{e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),et(D,k))},_t=e=>{let t=e.clipboardData.getData(`text`)||e.clipboardData.getData(`text/plain`);t.length<Ze||(e.preventDefault(),A(e=>{let n=e.filter(e=>/^Texte collé( \d+)?\.txt$/.test(e.name)).length;return[...e,{name:n===0?`Texte collé.txt`:`Texte collé ${n+1}.txt`,text:t}]}),u(`info`,`Texte collé en pièce jointe`,`Trop long pour le champ, il part avec ton message.`))},vt=e=>{A(t=>t.filter((t,n)=>n!==e)),K.current?.focus()},yt=Z&&(D.trim().length>0||k.length>0),bt=[...x].reverse().find(e=>e.proposal?.status===`pending`)?.proposal?.id??null,$=n&&n.ollama.available&&n.models.installed.length>0?n.models:null,xt=(n?.fullCyber??!1)&&(n?.autoRun??!1),St=w&&C===null&&!x.some(e=>e.proposal?.status===`pending`||e.proposal?.status===`running`),Ct=$?.loaded.some(e=>e.name===$.selected)??!1,wt=St?null:[...x].reverse().find(e=>e.role===`assistant`)?.id??null,Tt=(0,V.useMemo)(()=>{let e=new Map,t=[];for(let n of x)n.role===`user`?t=[]:n.search||n.recall?t=Be(n)??[]:t.length>0&&e.set(n.id,t);return e},[x]),Et=(0,H.jsx)(at,{rubrique:X,conversations:f.data?.conversations??null,chargement:f.loading,sessions:p.data?.sessions??[],courante:v,occupe:w,courant:ze,onNouvelle:dt,onOuvrir:ft,onSupprimer:e=>{Te(e),L(!0)},onSession:e=>{Pe(e),Le(!0)}}),Dt=X?null:(0,H.jsx)(_,{size:We?void 0:`s`,icon:We?void 0:(0,H.jsx)(Ne,{"aria-hidden":`true`}),className:`cerveau-ouvrir`,"aria-haspopup":`dialog`,"aria-expanded":U,onClick:()=>W(!0),children:`Conversations`});return(0,H.jsxs)(`div`,{className:`vue cerveau-vue`,children:[(0,H.jsxs)(`div`,{ref:Re,className:`vue-contenu cerveau-page`,children:[(0,H.jsx)(r,{children:Dt}),We?(0,H.jsx)(`h1`,{className:`t-titre-2 sr`,tabIndex:-1,children:`Cerveau`}):(0,H.jsxs)(`header`,{className:`cerveau-entete`,children:[(0,H.jsx)(`h1`,{className:`t-titre-2 cerveau-titre`,tabIndex:-1,children:`Cerveau`}),(0,H.jsx)(`p`,{className:`cerveau-moteur`,children:n?.ollama.available?`Ollama${n.ollama.version?` ${n.ollama.version}`:``}, sur ta machine`:null}),Dt]}),Ke?(0,H.jsx)(re,{message:(0,H.jsxs)(H.Fragment,{children:[`Ollama ne répond pas sur `,(0,H.jsx)(`span`,{className:`cerveau-litteral`,children:n.ollama.baseUrl}),`. Lance-le (l’application Ollama, ou `,(0,H.jsx)(s,{code:`ollama serve`}),`), la page se mettra à jour seule.`]}),onRetry:i}):null,qe?(0,H.jsxs)(P,{issue:`a-toi`,word:`Aucun modèle`,children:[`Installe un modèle dans Ollama, par exemple avec `,(0,H.jsx)(s,{code:`ollama pull qwen3.5:4b`}),`, ou crée «`,`\xA0`,`promethee`,`\xA0`,`» à partir de son Modelfile.`]}):null,(0,H.jsxs)(`div`,{className:`cerveau-corps`,children:[X?(0,H.jsx)(`aside`,{className:`cerveau-colonne`,"aria-label":`Conversations`,children:Et}):null,(0,H.jsxs)(`div`,{ref:Ve,className:`cerveau-poste`,children:[$?(0,H.jsx)(it,{modeles:$,occupe:w,fullCyber:n?.fullCyber??!1,auto:(n?.fullCyber??!1)&&(n?.autoRun??!1),onChanger:()=>{z($.selected??$.installed[0]?.name??``),Ae(!0)}}):n===null?(0,H.jsx)(`p`,{className:`cerveau-modele-ligne`,children:(0,H.jsx)(ee,{signs:16})}):(0,H.jsx)(`span`,{}),(0,H.jsxs)(`div`,{ref:G,className:`cerveau-fil`,role:`log`,"aria-label":`Fil de la conversation`,onScroll:e=>{let t=e.currentTarget;q.current=t.scrollHeight-t.scrollTop-t.clientHeight<40},children:[j?(0,H.jsx)(re,{message:j}):null,x.length===0&&!j?(0,H.jsxs)(`div`,{className:`cerveau-accueil`,children:[(0,H.jsxs)(`p`,{className:`cerveau-accueil-phrase`,children:[`Pose une question à Prométhée. Sur ta machine, il peut proposer une commande`,`\xA0`,`: tu la relis, puis tu l’exécutes ou tu l’écartes. Une question de cours reçoit une réponse directe.`]}),Z?(0,H.jsx)(`ul`,{className:`cerveau-suggestions`,"aria-label":`Exemples de questions`,children:$e.map(e=>(0,H.jsx)(`li`,{children:(0,H.jsx)(`button`,{type:`button`,className:`cerveau-suggestion`,onClick:()=>ht(e),children:fe(e)})},e))}):null]}):null,x.map(e=>(0,H.jsx)(lt,{message:e,enFlux:w&&e.id===C,flamme:e.id===wt,live:e.proposal?pe[e.proposal.id]:void 0,enTete:e.proposal!==void 0&&e.proposal.id===bt,occupe:w,frais:e.proposal!==void 0&&Y.current.has(e.proposal.id),sources:Tt.get(e.id),onRelire:rt,onEcarter:ot},e.id)),St?(0,H.jsx)(st,{charge:Ct}):null]}),k.length>0?(0,H.jsx)(`ul`,{className:`piece-jointe-liste piece-jointe-composeur`,"aria-label":`Pièces jointes à envoyer`,children:k.map((e,t)=>(0,H.jsx)(`li`,{children:(0,H.jsx)(ct,{attachment:e,onRetirer:()=>vt(t)})},t))}):null,(0,H.jsxs)(`div`,{className:`cerveau-saisie`,onClick:e=>{e.target.closest(`button, textarea`)||K.current?.focus()},children:[(0,H.jsx)(a,{ref:K,className:`cerveau-champ`,value:D,onChange:e=>O(e.target.value),onKeyDown:gt,onPaste:_t,rows:Math.min(6,Math.max(1,D.split(`
3
+ `).length)),placeholder:Z?xt?`Ton but. Prométhée exécutera les commandes autorisées jusqu’à l’atteindre.`:He?`Ta question. ${Xe}`:`Ta question`:n===null?`Connexion au modèle…`:`Le cerveau n’est pas disponible.`,disabled:!Z,"aria-label":`Message pour Prométhée`,"aria-describedby":Z&&!He?Ge:void 0,enterKeyHint:`send`}),Z&&!He?(0,H.jsx)(`span`,{id:Ge,hidden:!0,children:Xe}):null,w?(0,H.jsx)(_,{className:`cerveau-envoyer`,icon:(0,H.jsx)(d,{"aria-hidden":`true`}),onClick:()=>void ut(),children:(0,H.jsx)(`span`,{className:`cerveau-envoyer-mot`,children:`Arrêter`})}):(0,H.jsx)(_,{className:`cerveau-envoyer`,variant:bt?`contour`:`feu`,icon:(0,H.jsx)(Fe,{"aria-hidden":`true`}),onClick:()=>void et(D,k),disabled:!yt,children:(0,H.jsx)(`span`,{className:`cerveau-envoyer-mot`,children:`Envoyer`})})]})]})]})]}),X?null:(0,H.jsx)(he,{side:Ue?`gauche`:`bas`,title:`Conversations`,open:U,onClose:()=>W(!1),initialFocus:ze,children:Et}),N?(0,H.jsx)(Ce,{open:be,preview:N.preview,origine:`modele`,explication:N.proposal.explanation||void 0,onCancel:()=>xe(!1),onConfirm:e=>{J.current=!0,xe(!1),tt(N.proposal,`approve`,e)}}):null,F?(0,H.jsxs)(me,{open:I,title:`Supprimer cette conversation ?`,tone:`danger`,confirmLabel:`Supprimer`,confirmIcon:(0,H.jsx)(Se,{"aria-hidden":`true`}),busy:Ee,onConfirm:()=>void pt(),onCancel:()=>L(!1),children:[(0,H.jsxs)(`p`,{className:`cerveau-objet`,children:[`« `,F.title,` », `,E(F.count,`message`,`messages`),`, `,ge(F.updatedAt),`.`]}),(0,H.jsx)(`p`,{children:`Ses messages sont effacés du disque. Le journal garde les lignes de ses réponses et de ses commandes.`})]}):null,$?(0,H.jsxs)(me,{open:ke,title:`Changer de modèle ?`,confirmLabel:`Changer de modèle`,confirmIcon:(0,H.jsx)(t,{"aria-hidden":`true`}),busy:je,confirmDisabled:R===$.selected,initialFocus:`field`,onConfirm:()=>void mt(),onCancel:()=>Ae(!1),children:[(0,H.jsx)(c,{label:`Modèle`,children:(0,H.jsx)(l,{value:R,onChange:e=>z(e.target.value),children:$.installed.map(e=>(0,H.jsx)(`option`,{value:e.name,children:e.name},e.name))})}),(0,H.jsx)(`p`,{children:`Le modèle choisi répondra à tes prochains messages, dans toutes les conversations. Le même réglage est dans Réglages.`})]}):null,B?(0,H.jsx)(ce,{open:Ie,title:B.title,litteraux:[B.title],subtitle:`Session de la TUI, ${B.model}${B.updated?`, ${ge(B.updated)}`:``}`,onClose:()=>Le(!1),footer:(0,H.jsx)(_,{onClick:()=>Le(!1),children:`Fermer`}),children:(0,H.jsxs)(`div`,{className:`cerveau-session`,children:[(0,H.jsx)(`p`,{className:`cerveau-litteral`,children:B.cwd}),B.summary?(0,H.jsx)(Oe,{source:B.summary}):(0,H.jsx)(`p`,{children:`Cette session n’a pas de résumé enregistré.`}),(0,H.jsxs)(`p`,{className:`phrase-note`,children:[`Pour la reprendre, lance `,(0,H.jsx)(s,{code:`prmt -r`}),` dans un terminal. La console ne fait que lire ces sessions.`]})]})}):null]})}export{ut as default};
@@ -0,0 +1 @@
1
+ @layer pages{.recherche{gap:var(--esp-3);min-inline-size:0;display:grid}.recherche-titre{align-items:baseline;gap:var(--esp-2);color:var(--texte);font:var(--t-interface);font-weight:var(--graisse-moyenne);letter-spacing:normal;overflow-wrap:anywhere;margin:0;display:flex}.recherche-titre>svg{inline-size:var(--ico-s);block-size:var(--ico-s);color:var(--texte-2);stroke-width:var(--ico-trait);align-self:center}.recherche-requete{overflow-wrap:anywhere}.recherche-etat{align-items:center;column-gap:var(--esp-3);row-gap:var(--esp-1);font:var(--t-note);color:var(--texte-2);font-variant-numeric:tabular-nums;flex-wrap:wrap;margin:0;display:flex}.recherche-sources{border-block-start:1px solid var(--trait);margin:0;padding:0;list-style:none;display:grid}.recherche-source{column-gap:var(--esp-3);padding-block:var(--esp-2);border-block-end:1px solid var(--trait);grid-template-columns:2ch minmax(0,1fr);display:grid}.recherche-numero{color:var(--texte-2);font:var(--t-donnee);line-height:inherit;text-align:end}.recherche-source-corps{gap:var(--esp-1);min-inline-size:0;display:grid}.recherche-source-titre{color:var(--or);font:var(--t-interface);font-weight:var(--graisse-moyenne);text-underline-offset:.2em;overflow-wrap:anywhere;justify-self:start;text-decoration:underline}.recherche-source-titre:hover{color:var(--texte)}.recherche-source-meta{column-gap:var(--esp-2);font:var(--t-note);color:var(--texte-2);overflow-wrap:anywhere;flex-wrap:wrap;margin:0;display:flex}.recherche-source-meta>*+:before{content:"·";margin-inline-end:var(--esp-2)}.recherche-extrait{font:var(--t-note);color:var(--texte-2);overflow-wrap:anywhere;-webkit-line-clamp:3;-webkit-box-orient:vertical;margin:0;display:-webkit-box;overflow:hidden}.recherche-lieu{--carte-h:clamp(11rem, 38dvh, 18rem);gap:var(--esp-2);min-inline-size:0;display:grid}.recherche-carte-attente{block-size:var(--carte-h);border:1px solid var(--trait-2);background:var(--surface-2)}.recherche-carte-absente{margin:0}.recherche-legende{align-items:baseline;column-gap:var(--esp-3);row-gap:var(--esp-1);font:var(--t-note);color:var(--texte-2);flex-wrap:wrap;display:flex}.recherche-lieu-nom{color:var(--texte);font:var(--t-interface);font-weight:var(--graisse-moyenne);overflow-wrap:anywhere}.recherche-lieu-adresse{overflow-wrap:anywhere}.recherche-lien{min-block-size:var(--ctl-m);color:var(--or);font:var(--t-interface);font-weight:var(--graisse-moyenne);text-underline-offset:.2em;align-items:center;text-decoration:underline;display:inline-flex}.recherche-lien:hover{color:var(--texte)}.recherche-lieux{--carte-h:clamp(14rem, 50dvh, 26rem)}.recherche-lieux-attente{justify-content:center;align-items:center;gap:var(--esp-2) var(--esp-3);min-block-size:var(--carte-h);padding:var(--esp-3);border:1px solid var(--trait-2);background:var(--surface-2);color:var(--texte-2);font:var(--t-note);text-align:center;flex-wrap:wrap;display:flex}.recherche-lieux-secondes{font:var(--t-donnee);font-variant-numeric:tabular-nums}.recherche-voir-fiche,.recherche-voir-liste{align-self:center}.recherche-lieux-liste{overscroll-behavior:contain;border-block:1px solid var(--trait);max-block-size:16rem;margin:0;padding:0;list-style:none;display:grid;overflow:auto}.recherche-lieux-liste[hidden]{display:none}.recherche-lieux-liste>li{padding-block:var(--esp-1);padding-inline:var(--esp-1);border-block-end:1px solid var(--trait);display:grid}.recherche-lieux-liste>li:last-child{border-block-end:0}.recherche-lieux-choix{min-block-size:var(--ctl-s);color:var(--or);font:var(--t-interface);font-weight:var(--graisse-moyenne);text-align:start;text-underline-offset:.2em;overflow-wrap:anywhere;cursor:pointer;background:0 0;border:0;justify-self:start;padding:0;text-decoration:underline}.recherche-lieux-choix:hover{color:var(--texte)}.recherche-lieux-choix[aria-current=true]{color:var(--feu)}.recherche-lieux-choix:focus-visible{outline:2px solid var(--anneau);outline-offset:2px}.recherche-lieux-adresse{font:var(--t-note);color:var(--texte-2);overflow-wrap:anywhere}.recherche-pages-etat{align-items:center;gap:var(--esp-2);font:var(--t-note);color:var(--texte-2);margin:0;display:flex}.recherche-pages{gap:var(--esp-1);min-inline-size:0;display:grid}.recherche-pages-titre{align-items:center;column-gap:var(--esp-3);font:var(--t-note);color:var(--texte-2);flex-wrap:wrap;margin:0;display:flex}.recherche-pages-liste{margin:0;padding:0;list-style:none;display:grid}.recherche-page{column-gap:var(--esp-3);padding-block:var(--esp-1);font:var(--t-note);color:var(--texte-2);grid-template-columns:2ch minmax(0,1fr);display:grid}.recherche-page-corps{align-items:baseline;gap:0 var(--esp-3);flex-wrap:wrap;min-inline-size:0;display:flex}.recherche-page-site{color:var(--texte);overflow-wrap:anywhere}.recherche-page-issue{align-items:center;gap:var(--esp-2);overflow-wrap:anywhere;min-inline-size:0;display:inline-flex}.cerveau-vue{padding-block-end:var(--esp-4)}.cerveau-page{gap:var(--esp-3);flex-direction:column;display:flex}@media (height>=30rem){.cerveau-vue{block-size:calc(100dvh - var(--ossature-barre,0px))}.cerveau-page{block-size:100%}}.cerveau-entete{align-items:center;column-gap:var(--esp-4);min-block-size:var(--barre-h);border-block-end:1px solid var(--trait);display:flex}.cerveau-titre{color:var(--texte);flex:none}.cerveau-titre:focus-visible{outline-offset:4px}.cerveau-moteur{min-inline-size:0;font:var(--t-note);color:var(--texte-2);flex:1 1 0;margin:0}.cerveau-ouvrir{flex:none}.cerveau-corps{gap:var(--esp-5);flex:auto;grid-template-rows:minmax(0,1fr);grid-template-columns:minmax(0,1fr);min-block-size:0;display:grid}@container page (width>=44rem){.cerveau-corps{grid-template-columns:clamp(15rem,25cqi,17.5rem) minmax(0,1fr)}}.cerveau-colonne{min-block-size:0;padding-block:var(--esp-2);overscroll-behavior:contain;border-inline-end:1px solid var(--trait);padding-inline-end:var(--esp-4);overflow-y:auto}.cerveau-conversations{align-content:start;gap:var(--esp-3);display:grid}.cerveau-conv-tete{justify-content:space-between;align-items:center;gap:var(--esp-2);flex-wrap:wrap;display:flex}.cerveau-conv-liste{margin:0;padding:0;list-style:none;display:grid}.cerveau-conv{border-block-end:1px solid var(--trait);grid-template-columns:minmax(0,1fr) auto;align-items:center;display:grid}.cerveau-conv-ouvrir{gap:var(--esp-1);min-inline-size:0;min-block-size:var(--cible-min);padding:var(--esp-2) var(--esp-2) var(--esp-2) var(--esp-3);color:var(--texte);font:var(--t-interface);text-align:start;cursor:pointer;transition:background-color var(--mvt-survol);background:0 0;border:0;border-inline-start:2px solid #0000;border-radius:0;display:grid}.cerveau-conv-ouvrir:focus-visible{outline-offset:-2px}.cerveau-conv-ouvrir[aria-current=true]{border-inline-start-color:var(--or);background:var(--surface-2)}.cerveau-conv-ouvrir:disabled{cursor:not-allowed}@media (hover:hover){.cerveau-conv-ouvrir:hover:not(:disabled){background-color:var(--surface-2)}}.cerveau-conv-nom{font-weight:var(--graisse-moyenne);overflow-wrap:anywhere;-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.cerveau-conv-meta{font:var(--t-note);color:var(--texte-2)}.cerveau-conv-vide{font:var(--t-interface);color:var(--texte-2);margin:0}@media (hover:hover){.cerveau-colonne .cerveau-conv:not(:hover,:focus-within) .cerveau-conv-supprimer{opacity:0}}.cerveau-poste{gap:var(--esp-2);grid-template-rows:auto minmax(0,1fr) auto;min-block-size:0;display:grid}.cerveau-modele{gap:var(--esp-2);border-block-end:1px solid var(--trait);padding-block-end:var(--esp-1);display:grid}.cerveau-modele-ligne{align-items:center;column-gap:var(--esp-3);min-block-size:var(--ligne-min);font:var(--t-note);color:var(--texte-2);margin:0;display:flex}.cerveau-modele-ligne>svg{inline-size:var(--ico-s);block-size:var(--ico-s);stroke-width:var(--ico-trait);flex:none}.cerveau-modele-nom{max-inline-size:50%;color:var(--texte);font:var(--t-donnee);overflow-wrap:anywhere;flex:none}.cerveau-modele-etat{flex:none}.cerveau-modele-etat[data-charge]{color:var(--texte)}.cerveau-cyber{padding-inline:var(--esp-2);border-radius:var(--r-controle);background-color:color-mix(in srgb, var(--feu) 16%, transparent);color:var(--feu);font:var(--t-etiquette);letter-spacing:.04em;text-transform:uppercase;white-space:nowrap;flex:none;text-decoration:none}.cerveau-cyber:hover,.cerveau-cyber:focus-visible{background-color:color-mix(in srgb, var(--feu) 26%, transparent)}.cerveau-modele-details{flex:none;margin-inline-start:auto}.cerveau-modele-details[aria-expanded=true]>svg:last-child{rotate:180deg}.cerveau-modele-fiche{justify-items:start;gap:var(--esp-3);padding-block:var(--esp-1) var(--esp-2);display:grid}@container page (width<28rem){.cerveau-modele-ligne{column-gap:var(--esp-2);grid-template-columns:auto minmax(0,max-content) max-content 1fr;display:grid}.cerveau-modele-nom{min-inline-size:0;max-inline-size:none}.cerveau-modele-capacite{order:1;grid-column:1/-1}.cerveau-cyber{order:2;grid-column:1/-1;justify-self:start}.cerveau-modele-details{min-inline-size:var(--cible-min);grid-column:4;justify-self:end}.cerveau-modele-capacite[data-outils],.cerveau-modele-details-mot{clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;position:absolute;overflow:hidden}}.cerveau-fil{align-content:start;gap:var(--esp-5);min-block-size:0;padding-block:var(--esp-3) var(--esp-4);overscroll-behavior:contain;padding-inline-end:var(--esp-2);display:grid;position:relative;overflow-y:auto}@media (height<30rem){.cerveau-fil{min-block-size:50dvh}}.cerveau-accueil{gap:var(--esp-4);max-inline-size:42rem;padding-inline-start:var(--esp-7);display:grid}.cerveau-accueil-phrase{font:var(--t-interface);color:var(--texte-2);margin:0}.cerveau-suggestions{border-block-start:1px solid var(--trait);margin:0;padding:0;list-style:none;display:grid}.cerveau-suggestion{inline-size:100%;min-block-size:var(--cible-min);padding:var(--esp-2);border:0;border-block-end:1px solid var(--trait);color:var(--texte);font:var(--t-interface);text-align:start;cursor:pointer;transition:background-color var(--mvt-survol);background:0 0;border-radius:0}@media (hover:hover){.cerveau-suggestion:hover{background-color:var(--surface-2)}}.cerveau-suggestion:focus-visible{outline-offset:-2px}.cerveau-tour{grid-template-columns:var(--esp-7) minmax(0, 1fr);align-items:start;display:grid}.cerveau-tour[data-qui=toi]:not(:first-child){border-block-start:1px solid var(--trait);padding-block-start:var(--esp-5)}.cerveau-marge{min-inline-size:0;display:flex}.cerveau-toi{font:var(--t-note);line-height:var(--esp-5);color:var(--texte-2)}.cerveau-flamme{inline-size:var(--flamme);block-size:auto}.cerveau-question{max-inline-size:42rem;color:var(--texte);font:var(--t-interface);font-weight:var(--graisse-moyenne);line-height:var(--esp-5);white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.cerveau-question-bloc{justify-items:start;gap:var(--esp-2);min-inline-size:0;display:grid}.piece-jointe-liste{gap:var(--esp-2);flex-wrap:wrap;margin:0;padding:0;list-style:none;display:flex}.piece-jointe-composeur{margin-block-start:var(--esp-2)}.piece-jointe{border:1px solid var(--trait);border-radius:var(--r-controle);background-color:var(--surface-1);align-items:stretch;max-inline-size:100%;display:inline-flex}.piece-jointe-ouvrir{align-items:center;gap:var(--esp-2);min-inline-size:0;padding:var(--esp-2) var(--esp-3);color:var(--texte);font:var(--t-donnee);text-align:start;cursor:pointer;background:0 0;border:0;display:inline-flex}.piece-jointe-ouvrir:hover{background-color:var(--surface-2)}.piece-jointe-ouvrir>svg{color:var(--texte-2);flex:none}.piece-jointe-nom{text-overflow:ellipsis;white-space:nowrap;min-inline-size:0;overflow:hidden}.piece-jointe-taille{color:var(--texte-3);font:var(--t-note);flex:none}.piece-jointe-retirer{border-inline-start:1px solid var(--trait);flex:none}.piece-jointe-texte{max-block-size:60vh;color:var(--texte);font:var(--t-donnee);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;overflow:auto}.cerveau-reponse{gap:var(--esp-3);min-inline-size:0;max-inline-size:42rem;color:var(--texte);font:var(--t-interface);display:grid}.cerveau-attente{min-block-size:var(--flamme);color:var(--texte-2);animation:apparait var(--duree-2) linear var(--attente) backwards;align-items:center;margin:0;display:flex}.cerveau-stats{font:var(--t-note);color:var(--texte-2);font-variant-numeric:tabular-nums;margin:0}.cerveau-litteral{color:var(--texte);font:var(--t-donnee);overflow-wrap:anywhere}@container page (width<28rem){.cerveau-tour{row-gap:var(--esp-1);grid-template-columns:minmax(0,1fr)}.cerveau-accueil{padding-inline-start:0}}.cerveau-prop{gap:var(--esp-3);min-inline-size:0;padding:var(--esp-4);border:1px solid var(--trait-2);background:var(--surface-1);display:grid}.cerveau-prop[data-etat=pending]{border-color:var(--trait-fort)}.cerveau-prop-titre{color:var(--texte);font:var(--t-interface);font-weight:var(--graisse-moyenne);letter-spacing:normal;margin:0}.cerveau-prop-explication{color:var(--texte-2);margin:0}.cerveau-sortie{max-block-size:min(26.25rem,60dvh);overflow-y:auto}.cerveau-prop-etat{align-items:center;column-gap:var(--esp-3);row-gap:var(--esp-1);font:var(--t-note);color:var(--texte-2);font-variant-numeric:tabular-nums;flex-wrap:wrap;margin:0;display:flex}.cerveau-prop-actions{align-items:center;gap:var(--esp-2) var(--esp-3);flex-wrap:wrap;display:flex}.cerveau-prop-note{flex:14rem;margin:0}@container page (width<28rem){.cerveau-prop{padding:var(--esp-3)}}.cerveau-saisie{align-items:flex-end;gap:var(--esp-2);min-block-size:var(--esp-7);padding:var(--esp-1) var(--esp-1) var(--esp-1) var(--esp-3);border:1px solid var(--trait-fort);border-radius:var(--r-controle);background:var(--creux);transition:border-color var(--mvt-survol);display:flex}@media (hover:hover){.cerveau-saisie:hover:not(:focus-within){border-color:var(--texte-3)}}.cerveau-saisie:has(.cerveau-champ:focus-visible){outline:2px solid var(--anneau);outline-offset:2px}.cerveau-saisie:has(.cerveau-champ:disabled){border-color:var(--trait-2)}.cerveau-champ{inline-size:auto;min-inline-size:0;min-block-size:var(--ligne-min);max-block-size:min(calc(6lh + 2 * var(--esp-2)), 30dvh);padding:var(--esp-2) 0;color:var(--texte);caret-color:var(--ambre);font:var(--t-saisie-texte);field-sizing:content;resize:none;background:0 0;border:0;flex:1 1 0;align-self:stretch;transition:none}.cerveau-champ:focus-visible{outline:none}.cerveau-champ:disabled{background:0 0}.cerveau-envoyer{flex:none}@container page (width<28rem){.cerveau-envoyer{min-inline-size:var(--bouton-h);padding-inline:0}.cerveau-envoyer-mot{clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;position:absolute;overflow:hidden}}.cerveau-objet{color:var(--texte);font-weight:var(--graisse-moyenne);overflow-wrap:anywhere}.cerveau-session{gap:var(--esp-3);display:grid}}
@@ -0,0 +1 @@
1
+ @layer composants{.leaflet-pane,.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-tile-container,.leaflet-pane>svg,.leaflet-pane>canvas,.leaflet-zoom-box,.leaflet-image-layer,.leaflet-layer{position:absolute;top:0;left:0}.leaflet-container{overflow:hidden}.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow{-webkit-user-select:none;user-select:none;-webkit-user-drag:none}.leaflet-tile::selection{background:0 0}.leaflet-safari .leaflet-tile{image-rendering:-webkit-optimize-contrast}.leaflet-safari .leaflet-tile-container{-webkit-transform-origin:0 0;width:1600px;height:1600px}.leaflet-marker-icon,.leaflet-marker-shadow{display:block}.leaflet-container .leaflet-overlay-pane svg{max-width:none!important;max-height:none!important}.leaflet-container .leaflet-marker-pane img,.leaflet-container .leaflet-shadow-pane img,.leaflet-container .leaflet-tile-pane img,.leaflet-container img.leaflet-image-layer,.leaflet-container .leaflet-tile{width:auto;padding:0;max-width:none!important;max-height:none!important}.leaflet-container img.leaflet-tile{mix-blend-mode:plus-lighter}.leaflet-container.leaflet-touch-zoom{-ms-touch-action:pan-x pan-y;touch-action:pan-x pan-y}.leaflet-container.leaflet-touch-drag{-ms-touch-action:pinch-zoom;touch-action:none;touch-action:pinch-zoom}.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom{-ms-touch-action:none;touch-action:none}.leaflet-container{-webkit-tap-highlight-color:transparent}.leaflet-container a{-webkit-tap-highlight-color:#33b5e566}.leaflet-tile{filter:inherit;visibility:hidden}.leaflet-tile-loaded{visibility:inherit}.leaflet-zoom-box{box-sizing:border-box;z-index:800;width:0;height:0}.leaflet-overlay-pane svg{-moz-user-select:none}.leaflet-pane{z-index:400}.leaflet-tile-pane{z-index:200}.leaflet-overlay-pane{z-index:400}.leaflet-shadow-pane{z-index:500}.leaflet-marker-pane{z-index:600}.leaflet-tooltip-pane{z-index:650}.leaflet-popup-pane{z-index:700}.leaflet-map-pane canvas{z-index:100}.leaflet-map-pane svg{z-index:200}.leaflet-vml-shape{width:1px;height:1px}.lvml{behavior:url(#default#VML);display:inline-block;position:absolute}.leaflet-control{z-index:800;pointer-events:visiblePainted;pointer-events:auto;position:relative}.leaflet-top,.leaflet-bottom{z-index:1000;pointer-events:none;position:absolute}.leaflet-top{top:0}.leaflet-right{right:0}.leaflet-bottom{bottom:0}.leaflet-left{left:0}.leaflet-control{float:left;clear:both}.leaflet-right .leaflet-control{float:right}.leaflet-top .leaflet-control{margin-top:10px}.leaflet-bottom .leaflet-control{margin-bottom:10px}.leaflet-left .leaflet-control{margin-left:10px}.leaflet-right .leaflet-control{margin-right:10px}.leaflet-fade-anim .leaflet-popup{opacity:0;transition:opacity .2s linear}.leaflet-fade-anim .leaflet-map-pane .leaflet-popup{opacity:1}.leaflet-zoom-animated{transform-origin:0 0}svg.leaflet-zoom-animated{will-change:transform}.leaflet-zoom-anim .leaflet-zoom-animated{-webkit-transition:-webkit-transform .25s cubic-bezier(0,0,.25,1);-moz-transition:-moz-transform .25s cubic-bezier(0,0,.25,1);transition:transform .25s cubic-bezier(0,0,.25,1)}.leaflet-zoom-anim .leaflet-tile,.leaflet-pan-anim .leaflet-tile{transition:none}.leaflet-zoom-anim .leaflet-zoom-hide{visibility:hidden}.leaflet-interactive{cursor:pointer}.leaflet-grab{cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.leaflet-crosshair,.leaflet-crosshair .leaflet-interactive{cursor:crosshair}.leaflet-popup-pane,.leaflet-control{cursor:auto}.leaflet-dragging .leaflet-grab,.leaflet-dragging .leaflet-grab .leaflet-interactive,.leaflet-dragging .leaflet-marker-draggable{cursor:move;cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-image-layer,.leaflet-pane>svg path,.leaflet-tile-container{pointer-events:none}.leaflet-marker-icon.leaflet-interactive,.leaflet-image-layer.leaflet-interactive,.leaflet-pane>svg path.leaflet-interactive,svg.leaflet-image-layer.leaflet-interactive path{pointer-events:visiblePainted;pointer-events:auto}.leaflet-container{outline-offset:1px;background:#ddd}.leaflet-container a{color:#0078a8}.leaflet-zoom-box{background:#ffffff80;border:2px dotted #38f}.leaflet-container{font-family:Helvetica Neue,Arial,Helvetica,sans-serif;font-size:.75rem;line-height:1.5}.leaflet-bar{border-radius:4px;box-shadow:0 1px 5px #000000a6}.leaflet-bar a{text-align:center;color:#000;background-color:#fff;border-bottom:1px solid #ccc;width:26px;height:26px;line-height:26px;text-decoration:none;display:block}.leaflet-bar a,.leaflet-control-layers-toggle{background-position:50%;background-repeat:no-repeat;display:block}.leaflet-bar a:hover,.leaflet-bar a:focus{background-color:#f4f4f4}.leaflet-bar a:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.leaflet-bar a:last-child{border-bottom:none;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.leaflet-bar a.leaflet-disabled{cursor:default;color:#bbb;background-color:#f4f4f4}.leaflet-touch .leaflet-bar a{width:30px;height:30px;line-height:30px}.leaflet-touch .leaflet-bar a:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.leaflet-touch .leaflet-bar a:last-child{border-bottom-right-radius:2px;border-bottom-left-radius:2px}.leaflet-control-zoom-in,.leaflet-control-zoom-out{text-indent:1px;font:700 18px Lucida Console,Monaco,monospace}.leaflet-touch .leaflet-control-zoom-in,.leaflet-touch .leaflet-control-zoom-out{font-size:22px}.leaflet-control-layers{background:#fff;border-radius:5px;box-shadow:0 1px 5px #0006}.leaflet-control-layers-toggle{background-image:url(/assets/layers-BWBAp2CZ.png);width:36px;height:36px}.leaflet-retina .leaflet-control-layers-toggle{background-image:url(/assets/layers-2x-Bpkbi35X.png);background-size:26px 26px}.leaflet-touch .leaflet-control-layers-toggle{width:44px;height:44px}.leaflet-control-layers .leaflet-control-layers-list,.leaflet-control-layers-expanded .leaflet-control-layers-toggle{display:none}.leaflet-control-layers-expanded .leaflet-control-layers-list{display:block;position:relative}.leaflet-control-layers-expanded{color:#333;background:#fff;padding:6px 10px 6px 6px}.leaflet-control-layers-scrollbar{padding-right:5px;overflow:hidden scroll}.leaflet-control-layers-selector{margin-top:2px;position:relative;top:1px}.leaflet-control-layers label{font-size:1.08333em;display:block}.leaflet-control-layers-separator{border-top:1px solid #ddd;height:0;margin:5px -10px 5px -6px}.leaflet-default-icon-path{background-image:url(/assets/marker-icon-hN30_KVU.png)}.leaflet-container .leaflet-control-attribution{background:#fffc;margin:0}.leaflet-control-attribution,.leaflet-control-scale-line{color:#333;padding:0 5px;line-height:1.4}.leaflet-control-attribution a{text-decoration:none}.leaflet-control-attribution a:hover,.leaflet-control-attribution a:focus{text-decoration:underline}.leaflet-attribution-flag{width:1em;height:.6669em;vertical-align:baseline!important;display:inline!important}.leaflet-left .leaflet-control-scale{margin-left:5px}.leaflet-bottom .leaflet-control-scale{margin-bottom:5px}.leaflet-control-scale-line{white-space:nowrap;box-sizing:border-box;text-shadow:1px 1px #fff;background:#fffc;border:2px solid #777;border-top:none;padding:2px 5px 1px;line-height:1.1}.leaflet-control-scale-line:not(:first-child){border-top:2px solid #777;border-bottom:none;margin-top:-2px}.leaflet-control-scale-line:not(:first-child):not(:last-child){border-bottom:2px solid #777}.leaflet-touch .leaflet-control-attribution,.leaflet-touch .leaflet-control-layers,.leaflet-touch .leaflet-bar{box-shadow:none}.leaflet-touch .leaflet-control-layers,.leaflet-touch .leaflet-bar{background-clip:padding-box;border:2px solid #0003}.leaflet-popup{text-align:center;margin-bottom:20px;position:absolute}.leaflet-popup-content-wrapper{text-align:left;border-radius:12px;padding:1px}.leaflet-popup-content{min-height:1px;margin:13px 24px 13px 20px;font-size:1.08333em;line-height:1.3}.leaflet-popup-content p{margin:1.3em 0}.leaflet-popup-tip-container{pointer-events:none;width:40px;height:20px;margin-top:-1px;margin-left:-20px;position:absolute;left:50%;overflow:hidden}.leaflet-popup-tip{pointer-events:auto;width:17px;height:17px;margin:-10px auto 0;padding:1px;transform:rotate(45deg)}.leaflet-popup-content-wrapper,.leaflet-popup-tip{color:#333;background:#fff;box-shadow:0 3px 14px #0006}.leaflet-container a.leaflet-popup-close-button{text-align:center;color:#757575;background:0 0;border:none;width:24px;height:24px;font:16px/24px Tahoma,Verdana,sans-serif;text-decoration:none;position:absolute;top:0;right:0}.leaflet-container a.leaflet-popup-close-button:hover,.leaflet-container a.leaflet-popup-close-button:focus{color:#585858}.leaflet-popup-scrolled{overflow:auto}.leaflet-oldie .leaflet-popup-content-wrapper{-ms-zoom:1}.leaflet-oldie .leaflet-popup-tip{-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";width:24px;filter:progid:DXImageTransform.Microsoft.Matrix(M11=.707107, M12=.707107, M21=-.707107, M22=.707107);margin:0 auto}.leaflet-oldie .leaflet-control-zoom,.leaflet-oldie .leaflet-control-layers,.leaflet-oldie .leaflet-popup-content-wrapper,.leaflet-oldie .leaflet-popup-tip{border:1px solid #999}.leaflet-div-icon{background:#fff;border:1px solid #666}.leaflet-tooltip{color:#222;white-space:nowrap;-webkit-user-select:none;user-select:none;pointer-events:none;background-color:#fff;border:1px solid #fff;border-radius:3px;padding:6px;position:absolute;box-shadow:0 1px 3px #0006}.leaflet-tooltip.leaflet-interactive{cursor:pointer;pointer-events:auto}.leaflet-tooltip-top:before,.leaflet-tooltip-bottom:before,.leaflet-tooltip-left:before,.leaflet-tooltip-right:before{pointer-events:none;content:"";background:0 0;border:6px solid #0000;position:absolute}.leaflet-tooltip-bottom{margin-top:6px}.leaflet-tooltip-top{margin-top:-6px}.leaflet-tooltip-bottom:before,.leaflet-tooltip-top:before{margin-left:-6px;left:50%}.leaflet-tooltip-top:before{border-top-color:#fff;margin-bottom:-12px;bottom:0}.leaflet-tooltip-bottom:before{border-bottom-color:#fff;margin-top:-12px;margin-left:-6px;top:0}.leaflet-tooltip-left{margin-left:-6px}.leaflet-tooltip-right{margin-left:6px}.leaflet-tooltip-left:before,.leaflet-tooltip-right:before{margin-top:-6px;top:50%}.leaflet-tooltip-left:before{border-left-color:#fff;margin-right:-12px;right:0}.leaflet-tooltip-right:before{border-right-color:#fff;margin-left:-12px;left:0}@media print{.leaflet-control{print-color-adjust:exact}}}@layer pages{.carte{gap:var(--esp-2);min-inline-size:0;display:grid}.carte-cadre{--carte-bas:1.75rem;isolation:isolate;border:1px solid var(--trait-2);min-inline-size:0;position:relative;container:carte/inline-size}.carte-leaflet{isolation:isolate;block-size:var(--carte-h);background:var(--surface-2);font:var(--t-interface)}.carte-leaflet:focus-visible{outline:2px solid var(--anneau);outline-offset:2px}.carte-leaflet .leaflet-tile-pane{filter:saturate(.6)sepia(.12)brightness(.9)}.carte-repere{box-sizing:border-box;border:3px solid var(--fond);background:var(--or);outline:2px solid var(--or);outline-offset:0;cursor:pointer}.carte-repere[data-choisi]{background:var(--feu);outline-color:var(--feu)}.carte-leaflet .leaflet-bar{border:1px solid var(--trait-fort);border-radius:var(--r-controle);box-shadow:none}.carte-leaflet .leaflet-bar a{inline-size:var(--ctl-s);block-size:var(--ctl-s);border-block-end-color:var(--trait-fort);background:var(--surface-1);color:var(--texte);font:var(--t-interface);font-weight:var(--graisse-moyenne);line-height:var(--ctl-s);border-radius:0}.carte-leaflet .leaflet-bar a:hover{background:var(--surface-3);color:var(--texte)}.carte-leaflet .leaflet-bar a.leaflet-disabled{background:var(--surface-1);color:var(--texte-3)}.carte-leaflet .leaflet-bar a:focus-visible{outline:2px solid var(--anneau);outline-offset:-2px}.carte-attribution{z-index:1;max-inline-size:100%;padding:0 var(--esp-2);background:var(--surface-1);color:var(--texte-2);font:var(--t-note);margin:0;position:absolute;inset-block-end:0;inset-inline-end:0}.carte-attribution a{color:var(--or);text-underline-offset:.2em;text-decoration:underline}.carte-attribution a:hover{color:var(--texte)}.fiche-lieu{z-index:2;align-content:start;gap:var(--esp-2);inline-size:min(18rem, calc(50% - var(--esp-4)));max-block-size:calc(100% - var(--esp-2) - var(--carte-bas));padding:var(--esp-3);overscroll-behavior:contain;border:1px solid var(--trait-fort);border-radius:var(--r-flottant);background:var(--surface-1);box-shadow:var(--elev-flottant);color:var(--texte);font:var(--t-note);display:grid;position:absolute;inset-block-start:var(--esp-2);inset-inline-end:var(--esp-2);overflow:auto}.fiche-lieu-tete{align-items:start;gap:var(--esp-2);grid-template-columns:minmax(0,1fr) auto;display:grid}.fiche-lieu-nom{color:var(--texte);font:var(--t-interface);font-weight:var(--graisse-moyenne);overflow-wrap:anywhere;margin:0}.fiche-lieu-nom:focus-visible{outline:2px solid var(--anneau);outline-offset:2px}.fiche-lieu-fermer{margin-block-start:calc(-1 * var(--esp-1));margin-inline-end:calc(-1 * var(--esp-1))}.fiche-lieu-image{gap:var(--esp-1);margin:0;display:grid}.fiche-lieu-image img,.fiche-lieu-image-attente{object-fit:cover;background:var(--surface-2);block-size:9rem;inline-size:100%;display:block}.fiche-lieu-description{gap:var(--esp-1);display:grid}.fiche-lieu-description p,.fiche-lieu p{overflow-wrap:anywhere;margin:0}.fiche-lieu-description>p:first-child{color:var(--texte)}.fiche-lieu-source,.fiche-lieu-adresse{color:var(--texte-2)}.fiche-lieu-source a{color:var(--or);text-underline-offset:.2em;text-decoration:underline}.fiche-lieu-source a:hover{color:var(--texte)}.fiche-lieu-liens{column-gap:var(--esp-3);flex-wrap:wrap;display:flex}@container carte (inline-size<30rem){.fiche-lieu{inset-block-start:auto;inset-block-end:var(--carte-bas);inset-inline:var(--esp-2);inline-size:auto;max-block-size:calc(50% - var(--carte-bas) - var(--esp-3));padding:var(--esp-2)}.fiche-lieu-image img,.fiche-lieu-image-attente{block-size:4rem}}}