fix: stale sessions permanently ignored + CLI missing custom post type
Two bugs fixed: 1. Session monitor stale session bug: Sessions that were stale on first poll got added to _knownSessions but never re-checked, even after their transcript became active. Now stale sessions are tracked separately in _staleSessions and re-checked on every poll cycle. 2. CLI live-status tool: create/update commands were creating plain text posts without the custom_livestatus post type or plugin props. The Mattermost webapp plugin only renders posts with type=custom_livestatus. Now all CLI commands set the correct post type and livestatus props.
This commit is contained in:
@@ -46,6 +46,8 @@ class SessionMonitor extends EventEmitter {
|
||||
|
||||
// Map<sessionKey, sessionEntry>
|
||||
this._knownSessions = new Map();
|
||||
// Set<sessionKey> — sessions that were skipped as stale; re-check on next poll
|
||||
this._staleSessions = new Set();
|
||||
// Cache: "user:XXXX" -> channelId (resolved DM channels)
|
||||
this._dmChannelCache = new Map();
|
||||
this._pollTimer = null;
|
||||
@@ -175,6 +177,8 @@ class SessionMonitor extends EventEmitter {
|
||||
if (dmIdx >= 0 && parts[dmIdx + 1]) {
|
||||
return parts[dmIdx + 1]; // eslint-disable-line security/detect-object-injection
|
||||
}
|
||||
// agent:main:mattermost:direct:USER_ID — DM sessions use "direct" prefix
|
||||
// Channel ID must be resolved via API (returns null here; resolveChannelFromEntry handles it)
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -343,9 +347,9 @@ class SessionMonitor extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// Detect added sessions
|
||||
// Detect new or previously-stale sessions
|
||||
for (const [sessionKey, entry] of currentSessions) {
|
||||
if (!this._knownSessions.has(sessionKey)) {
|
||||
if (!this._knownSessions.has(sessionKey) || this._staleSessions.has(sessionKey)) {
|
||||
this._onSessionAdded(entry);
|
||||
}
|
||||
}
|
||||
@@ -354,6 +358,14 @@ class SessionMonitor extends EventEmitter {
|
||||
for (const [sessionKey] of this._knownSessions) {
|
||||
if (!currentSessions.has(sessionKey)) {
|
||||
this._onSessionRemoved(sessionKey);
|
||||
this._staleSessions.delete(sessionKey);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up stale entries for sessions no longer in sessions.json
|
||||
for (const sessionKey of this._staleSessions) {
|
||||
if (!currentSessions.has(sessionKey)) {
|
||||
this._staleSessions.delete(sessionKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,13 +386,16 @@ class SessionMonitor extends EventEmitter {
|
||||
}
|
||||
|
||||
// Skip stale sessions — only track if transcript was modified in last 5 minutes
|
||||
// This prevents creating status boxes for every old session in sessions.json
|
||||
// This prevents creating status boxes for every old session in sessions.json.
|
||||
// Stale sessions are tracked in _staleSessions and re-checked on every poll
|
||||
// so they get picked up as soon as the transcript becomes active again.
|
||||
try {
|
||||
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
||||
const stat = fs.statSync(transcriptFile);
|
||||
const ageMs = Date.now() - stat.mtimeMs;
|
||||
const STALE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes
|
||||
if (ageMs > STALE_THRESHOLD_MS) {
|
||||
this._staleSessions.add(sessionKey);
|
||||
if (this.logger) {
|
||||
this.logger.debug(
|
||||
{ sessionKey, ageS: Math.floor(ageMs / 1000) },
|
||||
@@ -390,7 +405,8 @@ class SessionMonitor extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
} catch (_e) {
|
||||
// File doesn't exist — skip silently
|
||||
// File doesn't exist — skip silently but track as stale for re-check
|
||||
this._staleSessions.add(sessionKey);
|
||||
if (this.logger) {
|
||||
this.logger.debug(
|
||||
{ sessionKey, transcriptFile },
|
||||
@@ -400,6 +416,9 @@ class SessionMonitor extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
// Session is fresh — remove from stale tracking
|
||||
this._staleSessions.delete(sessionKey);
|
||||
|
||||
// Sub-agents always pass through — they inherit parent channel via watcher-manager
|
||||
const isSubAgent = !!spawnedBy;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user