fix: исправление 6 пунктов из ревью

Critical:
- bridge: AutoGenPort=false по умолчанию, не генерируем secret если пустой
  → extension и bridge совпадают на port 9786 и empty secret
- bridgeConfig: убрана авто-генерация secret, убран secret из BridgeInfo

High:
- extension/background.js + extension-firefox/background.js:
  все chrome.* listeners вынесены в global scope (не внутри onInstalled/onStartup)
  → MV3 service worker корректно перезапускается
- UI: acceptBrowserEvent вызывает AcceptBrowserEvent, attachBrowserEvent вызывает
  AttachBrowserEventToNode (к текущему selectedNode), а не DismissBrowserEvent
- watcher: при Create проверяется isUnderVault(absPath, vaultRoot) —
  если файл уже в vault, используется AddExternal вместо CopyIntoVault
  → нет дублирования файлов с timestamp-суффиксом

Medium:
- bridge.Event: добавлено поле DeviceID, handleEvents обогащает events из batch.DeviceID
  → device_id сохраняется в DB как chrome-*/firefox-*, а не evt_*
- config: FileWatcher изменён на *bool — nil означает default true,
  false = явно выключено → старые config.json без поля file_watcher получают true
This commit is contained in:
2026-06-07 00:15:34 +08:00
parent b676ac675a
commit 1cc0c407b1
9 changed files with 142 additions and 137 deletions
+5 -28
View File
@@ -44,13 +44,10 @@ func (a *App) startBridge(appCfg *config.AppConfig) {
return
}
// Save the actual port and secret back to config if auto-generated.
// Save the actual port back to config if auto-generated.
if bc.AutoGenPort {
bc.Port = port
}
if bc.Secret == "" {
bc.Secret = srv.Secret()
}
a.saveBridgeConfig(appCfg, bc)
a.mu.Lock()
@@ -58,20 +55,14 @@ func (a *App) startBridge(appCfg *config.AppConfig) {
a.mu.Unlock()
}
// bridgeConfig extracts bridge config from app config, generating defaults if needed.
// bridgeConfig extracts bridge config from app config.
func (a *App) bridgeConfig(appCfg *config.AppConfig) *config.BridgeConfig {
if appCfg != nil && appCfg.Vault.Bridge.Port != 0 {
bc := &appCfg.Vault.Bridge
// If secret is empty, generate one on first run
if bc.Secret == "" {
bc.Secret = bridge.GenerateSecret()
}
return bc
return &appCfg.Vault.Bridge
}
return &config.BridgeConfig{
Port: 9786,
AutoGenPort: true,
Secret: bridge.GenerateSecret(),
AutoGenPort: false,
}
}
@@ -100,20 +91,15 @@ func (a *App) BridgeInfo() map[string]interface{} {
if a.bridge != nil {
info["running"] = a.bridge.Running()
info["port"] = a.bridge.Port()
info["secret"] = a.bridge.Secret()
}
return info
}
// bridgeToBrowser converts a bridge.Event to a browser.Event.
func bridgeToBrowser(ev bridge.Event) browser.Event {
deviceID := ev.ID
if idx := indexOf(ev.ID, "_"); idx > 0 {
deviceID = ev.ID[:idx]
}
return browser.Event{
ID: ev.ID,
DeviceID: deviceID,
DeviceID: ev.DeviceID,
Type: ev.Type,
URL: ev.URL,
Title: ev.Title,
@@ -126,12 +112,3 @@ func bridgeToBrowser(ev bridge.Event) browser.Event {
Note: ev.Note,
}
}
func indexOf(s string, sub string) int {
for i := 0; i < len(s); i++ {
if string(s[i]) == sub {
return i
}
}
return -1
}
+2 -2
View File
@@ -237,8 +237,8 @@ func (a *App) initVault(vaultPath string) error {
// Determine if real-time watching is enabled.
// Priority: CLI --no-watcher > env VERSTAK_NO_WATCHER > config file > default (true)
fileWatcherEnabled := true
if appCfg != nil {
fileWatcherEnabled = appCfg.Vault.FileWatcher
if appCfg != nil && appCfg.Vault.FileWatcher != nil {
fileWatcherEnabled = *appCfg.Vault.FileWatcher
}
// Env override
if os.Getenv("VERSTAK_NO_WATCHER") == "1" {
+1 -1
View File
@@ -45,7 +45,7 @@ func (a *App) ToggleFileWatcher(enable bool) error {
if err != nil || cfg == nil {
return fmt.Errorf("config: %w", err)
}
cfg.Vault.FileWatcher = enable
cfg.Vault.FileWatcher = config.BoolPtr(enable)
if err := config.SaveAppConfig(cfg); err != nil {
return fmt.Errorf("save config: %w", err)
}