Files
Spark b102a4a206 feat(core): moteur PromptKey — bibliothèque .md, variables, injection, raccourcis
- PromptStore/Frontmatter : un prompt = un fichier Markdown, en-tête au
  sous-ensemble strict du document d'architecture (§7), écriture UTF-8
- VariableEngine : variables typées + automatiques (selection, clipboard,
  date, app, cursor), résolution et profils de destination
- Injector/ClipboardGuard : focus capturé/rendu, presse-papiers sauvegardé
  puis restauré conditionnellement, aucun envoi automatique par défaut
- Search : classement flou insensible aux accents, pondéré par l'usage
- UsageStats (usage.json), HotkeyManager (conflits signalés, jamais muets)
- Settings : config.ini + profils par IA (claude, chatgpt, qwen, terminal…)
- PromptKey.ahk : tray, instance unique, capture du contexte, surveillance
  de la bibliothèque, installation du pack au premier lancement
2026-10-11 10:17:30 -04:00

101 lines
3.4 KiB
AutoHotkey

; Util.ahk — Fonctions utilitaires de PromptKey (dates, GUID, normalisation, journal).
; Aucune dépendance. Voir le document d'architecture, section 19.
class Util {
; Journal local : horodatage + message. JAMAIS de contenu de prompt (architecture §11.6 / §18).
static LogFile := ""
static Log(msg) {
if (Util.LogFile = "")
return
try {
line := FormatTime(, "yyyy-MM-dd HH:mm:ss") " " msg "`r`n"
FileAppend(line, Util.LogFile, "UTF-8")
; Rotation grossière : au-delà d'environ 1 Mo, on repart de zéro.
if (FileGetSize(Util.LogFile) > 1048576)
FileMove(Util.LogFile, Util.LogFile ".bak", true)
}
}
static NewGuid() {
; GUID via l'API Windows (CoCreateGuid), formaté en minuscules avec tirets.
buf := Buffer(16, 0)
DllCall("ole32\CoCreateGuid", "Ptr", buf.Ptr)
g := ""
fmt := [4, 2, 2, 2, 6] ; tailles en octets des groupes 8-4-4-4-12 (hex)
off := 0
parts := []
for i, sz in fmt {
hex := ""
; Le premier groupe est un entier little-endian : on lit les octets dans l'ordre inverse pour les groupes 1 à 3.
if (i <= 3) {
loop sz {
hex := Format("{:02x}", NumGet(buf, off + A_Index - 1, "UChar")) hex
}
} else {
loop sz {
hex .= Format("{:02x}", NumGet(buf, off + A_Index - 1, "UChar"))
}
}
parts.Push(hex)
off += sz
}
return parts[1] "-" parts[2] "-" parts[3] "-" parts[4] "-" parts[5]
}
static NowIso() {
return FormatTime(, "yyyy-MM-ddTHH:mm:ss")
}
static Today() {
return FormatTime(, "yyyy-MM-dd")
}
; Normalisation pour la recherche : minuscules + suppression des accents (architecture §14.1).
static Normalize(s) {
s := StrLower(s)
static accents := Map(
"à", "a", "á", "a", "â", "a", "ä", "a", "ã", "a",
"è", "e", "é", "e", "ê", "e", "ë", "e",
"ì", "i", "í", "i", "î", "i", "ï", "i",
"ò", "o", "ó", "o", "ô", "o", "ö", "o", "õ", "o",
"ù", "u", "ú", "u", "û", "u", "ü", "u",
"ç", "c", "ñ", "n", "ÿ", "y")
out := ""
loop parse s {
out .= accents.Has(A_LoopField) ? accents[A_LoopField] : A_LoopField
}
return out
}
; Tronque proprement pour les aperçus.
static Truncate(s, n) {
if (StrLen(s) <= n)
return s
return SubStr(s, 1, n) "…"
}
; Nom de fichier sûr à partir d'un titre (minuscules, tirets, sans accents).
static Slugify(title) {
s := Util.Normalize(Trim(title))
s := RegExReplace(s, "[^a-z0-9]+", "-")
s := Trim(s, "-")
return (s = "") ? "sans-titre" : s
}
; Échappe une valeur pour l'en-tête : guillemets si la valeur contient un caractère spécial du format.
static QuoteIfNeeded(s) {
if (s = "")
return s
if RegExMatch(s, "[,\[\]#:]") || (Trim(s) != s)
return '"' StrReplace(s, '"', '\"') '"'
return s
}
static Unquote(s) {
s := Trim(s)
if (StrLen(s) >= 2 && SubStr(s, 1, 1) = '"' && SubStr(s, -1) = '"')
s := StrReplace(SubStr(s, 2, StrLen(s) - 2), '\"', '"')
return s
}
}