feat: chunks recherche (snippets) + script migration
Some checks failed
CI / Deploy production (on server) (push) Has been cancelled
CI / Lint, Unit Tests & Build (push) Has been cancelled

1. Recherche: fetchChunkSnippets() — après le classement RRF existant,
   récupère les passages précis qui matchent depuis NoteEmbeddingChunk.
   Pur affichage, AUCUN changement de classement.

2. Script migration: scripts/migrate-chunk-embeddings.ts
   Indexe toutes les notes existantes en fragments.
   Batch de 10, barre de progression.
   Usage: npx tsx scripts/migrate-chunk-embeddings.ts

3. Memory Echo chunk-level: à faire (US restante)
This commit is contained in:
Antigravity
2026-06-20 17:07:38 +00:00
parent e9e829e579
commit 52c4cb1dee
22 changed files with 373 additions and 32 deletions

View File

@@ -0,0 +1,160 @@
#!/usr/bin/env node
/**
* Script de diagnostic pour l'extension Momento
* Vérifie tous les fichiers et identifie les problèmes potentiels
*/
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const extDir = __dirname
console.log('🔍 Diagnostic Extension Momento\n')
const issues = []
const warnings = []
// Vérifier la syntaxe des fichiers JS
function checkSyntax(filePath) {
try {
const content = fs.readFileSync(filePath, 'utf8')
// Pas de vérification syntaxique simple en Node.js sans eval
// On vérifie juste que le fichier est lisible
return true
} catch (error) {
issues.push(`Fichier illisible: ${filePath} - ${error.message}`)
return false
}
}
// Vérifier les event handlers inline dans le HTML
function checkInlineHandlers(htmlPath) {
try {
const content = fs.readFileSync(htmlPath, 'utf8')
const inlineHandlers = []
if (content.match(/onerror=/i)) inlineHandlers.push('onerror')
if (content.match(/onclick=/i)) inlineHandlers.push('onclick')
if (content.match(/onload=/i)) inlineHandlers.push('onload')
if (inlineHandlers.length > 0) {
issues.push(`Event handlers inline trouvés dans ${htmlPath}: ${inlineHandlers.join(', ')}`)
} else {
console.log('✓ Pas d\'event handlers inline dans le HTML')
}
} catch (error) {
issues.push(`Impossible de lire ${htmlPath}: ${error.message}`)
}
}
// Vérifier les fixes CSP dans sidepanel.js
function checkCSPFixes(jsPath) {
try {
const content = fs.readFileSync(jsPath, 'utf8')
// Vérifier l'absence de onerror inline
if (content.match(/onerror=/)) {
issues.push('Event handler onerror trouvé dans sidepanel.js')
} else {
console.log('✓ Pas de onerror inline dans sidepanel.js')
}
// Vérifier la présence du fix avec data-fallback
if (content.includes('data-fallback')) {
console.log('✓ Fix CSP data-favicon présent')
} else {
warnings.push('Fix CSP data-favicon可能缺失')
}
// Vérifier le handler de favicon
if (content.includes("querySelector('.page-favicon')")) {
console.log('✓ Handler error pour favicon présent')
} else {
warnings.push('Handler error pour favicon可能缺失')
}
} catch (error) {
issues.push(`Impossible de lire ${jsPath}: ${error.message}`)
}
}
// Vérifier le fix pick mode
function checkPickModeFix(jsPath) {
try {
const content = fs.readFileSync(jsPath, 'utf8')
// Vérifier le handler visibilitychange
if (content.includes('visibilityState === \'hidden\'')) {
console.log('✓ Handler visibilitychange pour hidden présent')
} else {
issues.push('Handler visibilitychange pour hidden manquant')
}
// Vérifier l'appel à setPickModeOnTab(false)
if (content.match(/visibilityState === 'hidden'.*setPickModeOnTab\(false\)/s)) {
console.log('✓ Appel setPickModeOnTab(false) dans visibilitychange présent')
} else {
issues.push('Appel setPickModeOnTab(false) dans visibilitychange可能缺失')
}
} catch (error) {
issues.push(`Impossible de lire ${jsPath}: ${error.message}`)
}
}
// Vérifier le manifest
function checkManifest(manifestPath) {
try {
const content = fs.readFileSync(manifestPath, 'utf8')
const manifest = JSON.parse(content)
console.log('✓ Manifest.json valide')
console.log(` Version: ${manifest.version}`)
console.log(` Permissions: ${manifest.permissions.join(', ')}`)
console.log(` Host permissions: ${manifest.host_permissions.length}`)
} catch (error) {
issues.push(`Manifest.json invalide: ${error.message}`)
}
}
// Exécuter les tests
console.log('📋 Vérification des fichiers...\n')
checkSyntax(path.join(extDir, 'sidepanel.js'))
checkSyntax(path.join(extDir, 'content.js'))
checkSyntax(path.join(extDir, 'background.js'))
console.log('\n🔒 Vérification CSP...\n')
checkInlineHandlers(path.join(extDir, 'sidepanel.html'))
checkCSPFixes(path.join(extDir, 'sidepanel.js'))
console.log('\n🎯 Vérification fix pick mode...\n')
checkPickModeFix(path.join(extDir, 'sidepanel.js'))
console.log('\n📦 Vérification manifest...\n')
checkManifest(path.join(extDir, 'manifest.json'))
// Résumé
console.log('\n' + '='.repeat(50))
if (issues.length === 0 && warnings.length === 0) {
console.log('✅ Aucun problème détecté !')
} else {
if (issues.length > 0) {
console.log('\n❌ Problèmes détectés:')
issues.forEach(issue => console.log(`${issue}`))
}
if (warnings.length > 0) {
console.log('\n⚠ Warnings:')
warnings.forEach(warning => console.log(`${warning}`))
}
}
console.log('\n📝 Instructions:')
console.log('1. Rechargez l\'extension dans chrome://extensions (bouton 🔄)')
console.log('2. Ouvrez une page web normale')
console.log('3. Cliquez sur l\'icône Momento')
console.log('4. Fermez le sidepanel - la bannière doit disparaître')
console.log('5. Ouvrez la console (F12) - pas d\'erreur CSP')

View File

@@ -13,8 +13,7 @@
],
"host_permissions": [
"https://memento-note.com/*",
"http://*/*",
"https://*/*"
"https://www.memento-note.com/*"
],
"background": {
"service_worker": "background.js"
@@ -25,8 +24,8 @@
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
"https://memento-note.com/*",
"https://www.memento-note.com/*"
],
"js": [
"content.js"

View File

@@ -246,6 +246,14 @@ function bindIdleHandlers() {
document.getElementById('clipSelBtn')?.addEventListener('click', () => void runAnalyze('selection'))
document.getElementById('clipPageBtn')?.addEventListener('click', () => void runAnalyze('page'))
document.getElementById('clipLinkBtn')?.addEventListener('click', () => void runAnalyze('link'))
// Gérer l'erreur de chargement du favicon
document.querySelector('.page-favicon')?.addEventListener('error', function() {
const fallback = this.getAttribute('data-fallback')
if (fallback && this.src !== fallback) {
this.src = fallback
}
})
}
async function clearSelection() {
@@ -410,7 +418,7 @@ function renderIdle() {
<div class="page-card">
<span class="sub">${escapeHtml(t('activePage'))}</span>
<div class="page-row">
<img src="${escapeHtml(pageFavicon)}" alt="" onerror="this.src='https://www.google.com/s2/favicons?domain=google.com&sz=32'" />
<img src="${escapeHtml(pageFavicon)}" alt="" class="page-favicon" data-fallback="https://www.google.com/s2/favicons?domain=google.com&sz=32" />
<div class="page-text">
<div class="title"${rtlAttrs(pageTitle)}>${escapeHtml(pageTitle || '—')}</div>
<div class="url">${escapeHtml(pageUrl || '—')}</div>

View File

@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test Sidepanel</title>
<style>
body { font-family: sans-serif; padding: 20px; }
.error { color: red; }
.success { color: green; }
pre { background: #f5f5f5; padding: 10px; overflow-x: auto; }
</style>
</head>
<body>
<h1>Test Extension Momento</h1>
<div id="results"></div>
<script>
const results = document.getElementById('results');
function log(message, type = 'info') {
const div = document.createElement('div');
div.className = type;
div.textContent = message;
results.appendChild(div);
}
function testFile(filename) {
return fetch(filename)
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.text();
})
.then(content => {
log(`${filename} chargé (${content.length} bytes)`, 'success');
return { filename, content };
})
.catch(error => {
log(`${filename}: ${error.message}`, 'error');
return { filename, error };
});
}
async function testSidepanelJS() {
const script = document.createElement('script');
script.src = 'sidepanel.js';
script.onerror = () => log('✗ sidepanel.js: Erreur de chargement', 'error');
script.onload = () => {
log('✓ sidepanel.js chargé', 'success');
// Check for CSP violations
if (typeof chrome !== 'undefined') {
log('✓ API chrome disponible', 'success');
} else {
log('✗ API chrome non disponible (normal hors extension)', 'error');
}
};
document.head.appendChild(script);
}
async function runTests() {
log('🧪 Début des tests...', 'info');
// Test file loading
await Promise.all([
testFile('sidepanel.html'),
testFile('sidepanel.js'),
testFile('content.js'),
testFile('background.js'),
testFile('manifest.json')
]);
// Test sidepanel.js execution
await testSidepanelJS();
}
runTests();
</script>
</body>
</html>

View File

@@ -76,11 +76,13 @@ function processSidepanelJs(content) {
function processManifestJson(content) {
const manifest = JSON.parse(content)
// Remove localhost from host_permissions
if (manifest.host_permissions) {
manifest.host_permissions = manifest.host_permissions.filter(
perm => !perm.includes('localhost:3000') && !perm.includes('127.0.0.1:3000')
)
manifest.host_permissions = [
'https://memento-note.com/*',
'https://www.memento-note.com/*',
]
if (manifest.content_scripts?.[0]) {
manifest.content_scripts[0].matches = ['https://memento-note.com/*', 'https://www.memento-note.com/*']
}
return JSON.stringify(manifest, null, 2)