@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.
- package/LICENSE +21 -0
- package/README.md +191 -2
- package/bin/prmt.mjs +174 -0
- package/dist/assets/AuditModule-BOO_iRy8.js +1 -0
- package/dist/assets/Audits-yUBm0EpW.js +1 -0
- package/dist/assets/BrainPage-FIWO_9Nc.js +3 -0
- package/dist/assets/BrainPage-XQCEGRc5.css +1 -0
- package/dist/assets/Carte-CPuiR1Ha.css +1 -0
- package/dist/assets/Carte-xycu1mQn.js +1 -0
- package/dist/assets/Dashboard-DKvCQcX8.js +2 -0
- package/dist/assets/Dashboard-XdhC6_hM.css +1 -0
- package/dist/assets/Field-C7c2mCbb.js +2 -0
- package/dist/assets/Journal-BLIIlh80.css +1 -0
- package/dist/assets/Journal-BaelFjwV.js +1 -0
- package/dist/assets/Landing-B2jxV3zs.css +1 -0
- package/dist/assets/Landing-Dr612Zdu.js +26 -0
- package/dist/assets/Register-DA_Aq5f8.js +1 -0
- package/dist/assets/Reports-8wfDNSxH.js +1 -0
- package/dist/assets/Reports-B8GXN95N.css +1 -0
- package/dist/assets/SavoirPage-BTxbH3LY.css +1 -0
- package/dist/assets/SavoirPage-Dp3eUCHp.js +1 -0
- package/dist/assets/SettingsPage-BElIP46c.css +1 -0
- package/dist/assets/SettingsPage-BiQbnw3o.js +1 -0
- package/dist/assets/Shell-BAyHVljp.css +1 -0
- package/dist/assets/Shell-CQRlx9-V.js +2 -0
- package/dist/assets/Table-DUmGel5e.js +1 -0
- package/dist/assets/Tabs-CfhbELZk.js +1 -0
- package/dist/assets/Terminal-Bv1IJfi9.js +3 -0
- package/dist/assets/Terminal-CEfj38NV.css +1 -0
- package/dist/assets/arrow-right-Cx3pAEhl.js +1 -0
- package/dist/assets/auditViews-BMza2Sdz.js +1 -0
- package/dist/assets/auditViews-BePWj26h.css +1 -0
- package/dist/assets/bricolage-grotesque-latin-ext-opsz-normal-IcJDqblK.woff2 +0 -0
- package/dist/assets/bricolage-grotesque-latin-opsz-normal-Cre6nC2_.woff2 +0 -0
- package/dist/assets/bricolage-grotesque-vietnamese-opsz-normal-D9N6E8K1.woff2 +0 -0
- package/dist/assets/charts-BcijSJ4J.js +1 -0
- package/dist/assets/circle-stop-C33BAcKW.js +1 -0
- package/dist/assets/command-ChA49Xk7.js +1 -0
- package/dist/assets/command-Ck4pdQCv.css +1 -0
- package/dist/assets/download-CeuKOenD.js +1 -0
- package/dist/assets/eye-CXXHBBpr.js +1 -0
- package/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/assets/habillage-B5mMBadn.js +1 -0
- package/dist/assets/index-BH1etemR.css +1 -0
- package/dist/assets/index-COSiM-R9.js +14 -0
- package/dist/assets/jetbrains-mono-cyrillic-ext-wght-normal-EocZY2iu.woff2 +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/dist/assets/layers-2x-Bpkbi35X.png +0 -0
- package/dist/assets/layers-BWBAp2CZ.png +0 -0
- package/dist/assets/markdown-DF87LQh1.css +1 -0
- package/dist/assets/markdown-o5sMhPHN.js +4 -0
- package/dist/assets/marker-icon-hN30_KVU.png +0 -0
- package/dist/assets/play-Daw4K_73.js +1 -0
- package/dist/assets/plus-D_QHm8ud.js +1 -0
- package/dist/assets/trash-DLpHM-s8.js +1 -0
- package/dist/assets/web-6j1-aY67.js +1 -0
- package/dist/favicon.svg +1 -0
- package/dist/index.html +18 -0
- package/docs/ANALYSE.md +87 -0
- package/docs/SECURITE.md +188 -0
- package/lib/scripts/lier.js +15 -0
- package/lib/scripts/searxng.js +91 -0
- package/lib/server/app.js +444 -0
- package/lib/server/audits/modules/local.js +429 -0
- package/lib/server/audits/modules/network.js +331 -0
- package/lib/server/audits/modules/web.js +302 -0
- package/lib/server/audits/net.js +141 -0
- package/lib/server/audits/registry.js +202 -0
- package/lib/server/audits/types.js +58 -0
- package/lib/server/brain/brain.js +624 -0
- package/lib/server/brain/conversations.js +82 -0
- package/lib/server/brain/ollama.js +197 -0
- package/lib/server/brain/prompt.js +188 -0
- package/lib/server/brain/provider.js +1 -0
- package/lib/server/cli/bridge.js +292 -0
- package/lib/server/cli/pont.js +62 -0
- package/lib/server/config.js +68 -0
- package/lib/server/engine/analyzer.js +205 -0
- package/lib/server/engine/catalog.js +229 -0
- package/lib/server/engine/decoder.js +91 -0
- package/lib/server/engine/engine.js +194 -0
- package/lib/server/engine/paths.js +129 -0
- package/lib/server/engine/policy.js +397 -0
- package/lib/server/engine/relax.js +10 -0
- package/lib/server/engine/runner.js +193 -0
- package/lib/server/errors.js +23 -0
- package/lib/server/http/guard.js +75 -0
- package/lib/server/http/router.js +154 -0
- package/lib/server/http/static.js +76 -0
- package/lib/server/index.js +40 -0
- package/lib/server/journal.js +139 -0
- package/lib/server/lien.js +33 -0
- package/lib/server/savoir/base.js +284 -0
- package/lib/server/savoir/lecture.js +406 -0
- package/lib/server/savoir/memoire.js +115 -0
- package/lib/server/search/categories.js +179 -0
- package/lib/server/search/fiche.js +326 -0
- package/lib/server/search/lieux.js +134 -0
- package/lib/server/search/overpass.js +216 -0
- package/lib/server/search/searxng.js +223 -0
- package/lib/server/search/tiles.js +103 -0
- package/lib/server/status.js +157 -0
- package/lib/server/stores.js +141 -0
- package/lib/server/telephone/acces.js +457 -0
- package/lib/server/telephone/certificat.js +79 -0
- package/lib/server/telephone/qr.js +308 -0
- package/lib/shared/analysis.js +40 -0
- package/lib/shared/schemas.js +105 -0
- package/lib/shared/types.js +10 -0
- package/package.json +81 -4
- package/searxng/settings.yml +35 -0
- package/tui/Modelfile +23 -0
- package/tui/README.md +103 -0
- package/tui/prmt_tui.py +65 -0
- package/tui/promethee/__init__.py +1 -0
- package/tui/promethee/__main__.py +4 -0
- package/tui/promethee/accueil.py +66 -0
- package/tui/promethee/agents.py +220 -0
- package/tui/promethee/app/__init__.py +4 -0
- package/tui/promethee/app/application.py +299 -0
- package/tui/promethee/app/clavier.py +99 -0
- package/tui/promethee/app/commandes_slash.py +164 -0
- package/tui/promethee/app/contexte.py +188 -0
- package/tui/promethee/app/definitions.py +518 -0
- package/tui/promethee/app/ecran.py +177 -0
- package/tui/promethee/app/envoi.py +141 -0
- package/tui/promethee/app/historique.py +373 -0
- package/tui/promethee/app/modele.py +108 -0
- package/tui/promethee/app/notes.py +63 -0
- package/tui/promethee/app/outils.py +589 -0
- package/tui/promethee/app/plateforme.py +409 -0
- package/tui/promethee/app/saisie.py +100 -0
- package/tui/promethee/app/taches.py +92 -0
- package/tui/promethee/app/tour.py +539 -0
- package/tui/promethee/app/validation.py +210 -0
- package/tui/promethee/appels.py +35 -0
- package/tui/promethee/commandes.py +154 -0
- package/tui/promethee/completion.py +140 -0
- package/tui/promethee/config.py +12 -0
- package/tui/promethee/consignes.py +278 -0
- package/tui/promethee/conversation.py +94 -0
- package/tui/promethee/etat.py +253 -0
- package/tui/promethee/fichiers.py +354 -0
- package/tui/promethee/journal.py +116 -0
- package/tui/promethee/logo.py +132 -0
- package/tui/promethee/memoire.py +50 -0
- package/tui/promethee/ollama.py +52 -0
- package/tui/promethee/plan.py +91 -0
- package/tui/promethee/politique.py +429 -0
- package/tui/promethee/preferences.py +65 -0
- package/tui/promethee/presse_papiers.py +44 -0
- package/tui/promethee/recherche.py +581 -0
- package/tui/promethee/securite.py +204 -0
- package/tui/promethee/shell.py +190 -0
- package/tui/promethee/textes.py +190 -0
- package/tui/promethee/theme.py +92 -0
- package/tui/promethee/widgets.py +493 -0
- package/tui/requirements.txt +1 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""/contexte, /code, retour en arrière (Esc Esc) et /init."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from rich.text import Text
|
|
8
|
+
from textual import work
|
|
9
|
+
from textual.widgets import Markdown, Static
|
|
10
|
+
|
|
11
|
+
from ..agents import agents_guide, list_agents
|
|
12
|
+
from ..commandes import INIT_EXISTING, INIT_PROMPT
|
|
13
|
+
from ..consignes import TOOL_GUIDE
|
|
14
|
+
from ..conversation import AUTO_COMPACT_PCT
|
|
15
|
+
from ..memoire import GLOBAL_MEMORY, MEMORY_NAME
|
|
16
|
+
from ..shell import SHELL_TAG
|
|
17
|
+
from ..ollama import OLLAMA
|
|
18
|
+
from ..theme import CODE_COLOR, DIM, GREEN, RED, YELLOW
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Contexte:
|
|
22
|
+
"""Partie de PrometheeApp : /contexte, /code, retour en arrière (Esc Esc) et /init."""
|
|
23
|
+
|
|
24
|
+
# ------------------------------------------------------------------ /contexte
|
|
25
|
+
def context_breakdown(self) -> list[tuple[str, int]]:
|
|
26
|
+
"""Ce qui occupe le contexte, en jetons estimés (≈ 3 caractères par jeton)."""
|
|
27
|
+
def tokens(chars: int) -> int:
|
|
28
|
+
return round(chars / 3.0)
|
|
29
|
+
|
|
30
|
+
parts: list[tuple[str, int]] = [("Consignes du modèle (Modelfile)", tokens(len(self.model_system or "")))]
|
|
31
|
+
if self.supports_tools:
|
|
32
|
+
parts.append(("Guide des outils", tokens(len(TOOL_GUIDE.format(cwd=self.cwd, date="00/00/0000")))))
|
|
33
|
+
agents = list_agents(self.cwd)
|
|
34
|
+
if agents:
|
|
35
|
+
parts.append((f"Agents ({len(agents)})", tokens(len(agents_guide(agents)))))
|
|
36
|
+
parts.append(("Définitions des outils", 1250))
|
|
37
|
+
memory = self.memory_text()
|
|
38
|
+
if memory:
|
|
39
|
+
parts.append(("Mémoire (PROMETHEE.md)", tokens(len(memory))))
|
|
40
|
+
if self.summary:
|
|
41
|
+
parts.append(("Résumé (compactage)", tokens(len(self.summary) + 60)))
|
|
42
|
+
asked = answers = outputs = attached = 0
|
|
43
|
+
for m in self.messages:
|
|
44
|
+
content = str(m.get("content") or "")
|
|
45
|
+
if m["role"] == "user":
|
|
46
|
+
if content.startswith(SHELL_TAG):
|
|
47
|
+
outputs += len(content)
|
|
48
|
+
else:
|
|
49
|
+
shown = len(m.get("display") or content)
|
|
50
|
+
asked += min(shown, len(content))
|
|
51
|
+
attached += max(0, len(content) - shown)
|
|
52
|
+
elif m["role"] == "assistant":
|
|
53
|
+
answers += len(content) + (len(json.dumps(m["tool_calls"], ensure_ascii=False)) if m.get("tool_calls") else 0)
|
|
54
|
+
else:
|
|
55
|
+
outputs += len(content)
|
|
56
|
+
parts += [("Tes messages", tokens(asked)), ("Fichiers joints (@)", tokens(attached)),
|
|
57
|
+
("Réponses de Prométhée", tokens(answers)), ("Sorties des outils et rapports d'agents", tokens(outputs))]
|
|
58
|
+
return [(label, n) for label, n in parts if n]
|
|
59
|
+
|
|
60
|
+
def cmd_context(self, arg: str = "") -> None:
|
|
61
|
+
parts = self.context_breakdown()
|
|
62
|
+
total = sum(n for _, n in parts)
|
|
63
|
+
used = max(total, self.ctx_used)
|
|
64
|
+
limit = self.num_ctx or 0
|
|
65
|
+
rows = "\n".join(f"| {label} | {n:,} | {100 * n / limit:.0f} % |".replace(",", " ") if limit
|
|
66
|
+
else f"| {label} | {n:,} | |".replace(",", " ") for label, n in parts)
|
|
67
|
+
bar = ""
|
|
68
|
+
if limit:
|
|
69
|
+
pct = min(100, round(100 * used / limit))
|
|
70
|
+
filled = round(pct / 5)
|
|
71
|
+
bar = f"`{'█' * filled}{'░' * (20 - filled)}` **{pct} %** de {limit:,} jetons".replace(",", " ")
|
|
72
|
+
tips = ("\n\n*Le contexte est la mémoire de travail du modèle. Au-delà de "
|
|
73
|
+
f"{AUTO_COMPACT_PCT} %, la conversation est compactée automatiquement ; `/compact` pour le faire maintenant, "
|
|
74
|
+
"`/clear` pour repartir de zéro. Les agents travaillent dans leur propre contexte : leurs longues sorties "
|
|
75
|
+
"n'arrivent pas ici, seulement leur rapport.*")
|
|
76
|
+
self.add_notice_md(f"**Contexte** {bar}\n\n| Contenu | Jetons (≈) | Part |\n|---|---:|---:|\n{rows}"
|
|
77
|
+
f"\n| **Total estimé** | **{total:,}** | |".replace(",", " ") + tips)
|
|
78
|
+
|
|
79
|
+
# ------------------------------------------------------------------ /code : IA de code
|
|
80
|
+
def cmd_code(self, arg: str = "") -> None:
|
|
81
|
+
word = arg.strip()
|
|
82
|
+
if word.lower() in ("off", "non", "stop"):
|
|
83
|
+
self.code_auto = False
|
|
84
|
+
self.add_notice("Bascule automatique coupée : Prométhée répond à tout, code compris. /code on pour la "
|
|
85
|
+
"rétablir.")
|
|
86
|
+
elif word.lower() in ("on", "oui"):
|
|
87
|
+
self.code_auto = True
|
|
88
|
+
self.add_notice(f"Bascule automatique activée : les demandes de programmation vont à {self.code_model}.",
|
|
89
|
+
CODE_COLOR)
|
|
90
|
+
elif word:
|
|
91
|
+
self.set_code_model(word)
|
|
92
|
+
else:
|
|
93
|
+
state = "activée" if self.code_auto else "coupée (/code on pour l'activer)"
|
|
94
|
+
self.add_notice_md(
|
|
95
|
+
f"**IA de code** : `{self.code_model}` · bascule automatique **{state}**\n\n"
|
|
96
|
+
"Quand tu demandes d'écrire, corriger ou expliquer du code, l'interpréteur le détecte et confie la "
|
|
97
|
+
"réponse à l'IA de code (même conversation, mêmes outils, tu valides toujours chaque commande). "
|
|
98
|
+
"Prométhée reprend la main au message suivant. Un changement de modèle prend quelques secondes "
|
|
99
|
+
"(chargement dans la carte graphique).\n\n"
|
|
100
|
+
"`/code off` · `/code on` · `/code <modèle>` pour en choisir un autre (il doit savoir utiliser des outils).")
|
|
101
|
+
|
|
102
|
+
@work(thread=True, exclusive=True, group="model")
|
|
103
|
+
def set_code_model(self, name: str) -> None:
|
|
104
|
+
name = name[:-7] if name.endswith(":latest") else name
|
|
105
|
+
self._caps.pop(name, None)
|
|
106
|
+
caps = self.model_caps(name)
|
|
107
|
+
if caps is None and name not in self._caps:
|
|
108
|
+
self.call_from_thread(self.add_notice, f"Ollama ne répond pas sur {OLLAMA} : impossible de vérifier « {name} ». "
|
|
109
|
+
"Lance l'application Ollama puis réessaie.", f"bold {RED}")
|
|
110
|
+
elif caps is None:
|
|
111
|
+
self.call_from_thread(self.add_notice, f"Modèle « {name} » introuvable. /modele pour voir la liste.", f"bold {RED}")
|
|
112
|
+
elif "tools" not in caps:
|
|
113
|
+
self.call_from_thread(self.add_notice, f"« {name} » ne sait pas utiliser d'outils : il ne pourrait ni écrire "
|
|
114
|
+
"de fichier ni compiler. Choisis-en un autre.", YELLOW)
|
|
115
|
+
else:
|
|
116
|
+
self.code_model, self.code_auto, self._code_warned = name, True, False
|
|
117
|
+
self.call_from_thread(self.add_notice, f"IA de code : {name}.", CODE_COLOR)
|
|
118
|
+
|
|
119
|
+
# ------------------------------------------------------------------ Esc Esc : revenir en arrière
|
|
120
|
+
def open_rewind(self) -> None:
|
|
121
|
+
"""Comme Claude Code : choisir un de ses messages ; la conversation repart juste avant, message à modifier."""
|
|
122
|
+
points = [(i, " ".join((m.get("display") or m["content"]).split())) for i, m in enumerate(self.messages)
|
|
123
|
+
if m["role"] == "user" and not str(m.get("content") or "").startswith(SHELL_TAG)]
|
|
124
|
+
if not points:
|
|
125
|
+
self.notify("Aucun message auquel revenir.", timeout=2)
|
|
126
|
+
return
|
|
127
|
+
points = points[-9:][::-1]
|
|
128
|
+
options = []
|
|
129
|
+
for k, (i, text) in enumerate(points):
|
|
130
|
+
later = sum(1 for m in self.messages[i:] if m["role"] == "user")
|
|
131
|
+
when = "ton dernier message" if k == 0 else f"il y a {later} messages"
|
|
132
|
+
options.append((str(i), f"{text[:70] + '…' if len(text) > 70 else text} ({when})"))
|
|
133
|
+
options.append(("no", "Annuler (Esc)"))
|
|
134
|
+
body = Text(" La conversation reprendra juste avant le message choisi, qui revient dans la saisie pour que tu "
|
|
135
|
+
"le modifies.\n Les commandes déjà exécutées et les fichiers déjà modifiés ne sont pas annulés.",
|
|
136
|
+
style=DIM)
|
|
137
|
+
|
|
138
|
+
def chosen(decision: str) -> None:
|
|
139
|
+
if decision.isdigit():
|
|
140
|
+
self.run_worker(self.rewind_to(int(decision)), exclusive=False)
|
|
141
|
+
|
|
142
|
+
self.ask("Revenir en arrière", body, "Reprendre avant quel message ?", options, chosen)
|
|
143
|
+
|
|
144
|
+
async def rewind_to(self, index: int) -> None:
|
|
145
|
+
if self.generating or index >= len(self.messages):
|
|
146
|
+
return
|
|
147
|
+
message = self.messages[index]
|
|
148
|
+
text = message.get("display") or message["content"]
|
|
149
|
+
self.messages = self.messages[:index]
|
|
150
|
+
self.tasks = []
|
|
151
|
+
self.render_tasks()
|
|
152
|
+
self.last_answer = next((m["content"] for m in reversed(self.messages)
|
|
153
|
+
if m["role"] == "assistant" and (m.get("content") or "").strip()), "")
|
|
154
|
+
await self.rebuild_chat()
|
|
155
|
+
self.add_notice("Conversation reprise avant ce message : modifie-le puis Entrée pour le renvoyer.", GREEN)
|
|
156
|
+
self.input.load_text(text)
|
|
157
|
+
self.input.move_cursor(self.input.document.end)
|
|
158
|
+
self.ctx_used = self.estimate_tokens()
|
|
159
|
+
self.update_status()
|
|
160
|
+
self.save_session()
|
|
161
|
+
|
|
162
|
+
async def rebuild_chat(self) -> None:
|
|
163
|
+
"""Réaffiche toute la conversation à partir des messages (reprise, retour en arrière)."""
|
|
164
|
+
await self.chat.remove_children()
|
|
165
|
+
await self.chat.mount_all(list(self._welcome_widgets()))
|
|
166
|
+
if self.summary:
|
|
167
|
+
await self.chat.mount(Static(Text.assemble(("⎿ ", DIM), ("Début de la conversation compacté. Résumé :", DIM)),
|
|
168
|
+
classes="notice"))
|
|
169
|
+
await self.chat.mount(Markdown(self.summary, classes="notice-md"))
|
|
170
|
+
await self.chat.mount_all(self._replay_widgets())
|
|
171
|
+
self.chat.scroll_end(animate=False)
|
|
172
|
+
self.call_after_refresh(self._follow)
|
|
173
|
+
|
|
174
|
+
# ------------------------------------------------------------------ /init
|
|
175
|
+
def cmd_init(self, arg: str = "") -> None:
|
|
176
|
+
if self.generating:
|
|
177
|
+
self.add_notice("Attends la fin de la réponse (ou Esc pour l'interrompre).", YELLOW)
|
|
178
|
+
return
|
|
179
|
+
if not self.supports_tools:
|
|
180
|
+
self.add_notice("Ce modèle ne sait pas utiliser les outils : /init a besoin de lire le dossier.", YELLOW)
|
|
181
|
+
return
|
|
182
|
+
path = self.cwd / MEMORY_NAME
|
|
183
|
+
if os.path.normcase(str(path)) == os.path.normcase(str(GLOBAL_MEMORY)):
|
|
184
|
+
self.add_notice("Ici, PROMETHEE.md est la mémoire globale : lance /init dans le dossier d'un projet "
|
|
185
|
+
"(cd dans ce dossier avec ! cd chemin).", YELLOW)
|
|
186
|
+
return
|
|
187
|
+
prompt = INIT_PROMPT.format(cwd=self.cwd, path=path, existing=INIT_EXISTING if path.exists() else "")
|
|
188
|
+
self.send_message("/init", prompt, intent=prompt, mode="action")
|