diff --git a/src/session-monitor.js b/src/session-monitor.js index a815cb6..e3cbe8a 100644 --- a/src/session-monitor.js +++ b/src/session-monitor.js @@ -106,6 +106,10 @@ class SessionMonitor extends EventEmitter { */ clearCompleted(sessionKey) { this._completedSessions.delete(sessionKey); + // Also remove from _knownSessions so the next poll sees it as a new session + // and fires _onSessionAdded (which creates the new status box). + // Without this, isKnown=true suppresses _onSessionAdded even after clearCompleted. + this._knownSessions.delete(sessionKey); } /** diff --git a/src/watcher-manager.js b/src/watcher-manager.js index 02c1c9e..04103ed 100644 --- a/src/watcher-manager.js +++ b/src/watcher-manager.js @@ -287,8 +287,11 @@ async function startDaemon() { logger.info({ sessionKey }, 'Reactivating session — creating fresh status box'); } - // Check for existing post (restart recovery) - if (!postId) { + // Check for existing post (restart recovery — REST mode only). + // In plugin mode we always create a fresh post: the plugin manages its own + // KV store and the old post is already marked done. Reusing it would make + // the status box appear stuck at the old position in the thread. + if (!postId && !(usePlugin && pluginClient)) { const saved = savedOffsets[sessionKey]; // eslint-disable-line security/detect-object-injection if (saved) { // Try to find existing post in channel history @@ -300,7 +303,9 @@ async function startDaemon() { if (!postId) { try { if (usePlugin && pluginClient) { - // Plugin mode: create custom_livestatus post via plugin + // Plugin mode: always create a fresh custom_livestatus post. + // The plugin replaces any existing KV entry for this sessionKey so there + // is no risk of duplicate boxes. postId = await pluginClient.createSession(sessionKey, channelId, rootPostId, agentId); logger.info({ sessionKey, postId, channelId, mode: 'plugin' }, 'Created status box via plugin'); } else {