fix: index CLI-created Claude sessions into Web UI#93
fix: index CLI-created Claude sessions into Web UI#93t2ance wants to merge 1 commit intoOpenLAIR:mainfrom
Conversation
Sessions created via the `claude` CLI command were not visible in the Web UI because they were written directly to disk (.jsonl files) without being indexed into the session_metadata database. The Web UI only queries the database, so these sessions were invisible. Two changes: 1. On startup, reconcile all registered projects to index any existing CLI sessions into the database. 2. In the file watcher, when a new .jsonl is detected under ~/.claude/projects/, call reconcileClaudeSessionIndex() to index the session before broadcasting the project update. Fixes the CLI session portion of OpenLAIR#86. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Zhang-Henry
left a comment
There was a problem hiding this comment.
Code Review
Adds two hooks to index CLI-created Claude sessions: a startup reconcile loop across all projects, and accumulation of .jsonl file-watcher events into reconcileClaudeSessionIndex calls. The approach is sound and well-scoped. A few issues need attention.
Should Fix
1. Single reconcileClaudeSessionIndex failure aborts the entire batch
server/index.js (~L194-200): eventsToProcess is spliced off the global array before the loop. If any single call throws (transient DB lock, malformed JSONL), the exception propagates, getProjects() never runs, and the spliced events are permanently lost. Wrap the loop body in its own try/catch:
for (const { projectName, sessionId } of eventsToProcess) {
try {
await reconcileClaudeSessionIndex(projectName, sessionId);
} catch (err) {
console.error(`[WARN] Failed to reconcile session ${sessionId} for ${projectName}:`, err.message);
}
}2. Same issue in the startup reconcile loop
server/index.js (~L2999-3010): If reconciliation fails for project N, projects N+1 through end are never reconciled. Move try/catch inside the loop and log the failing project name. Also, the success log shows total project count even if some failed.
3. pendingClaudeSessionEvents not cleared on watcher reinit
If setupProjectsWatcher is ever called again (e.g., after a chokidar error), the module-level array retains events from the previous lifecycle and they will be replayed. Add pendingClaudeSessionEvents = []; alongside the projectsWatchers = [] reset.
Minor
projectNameis derived frompath.basename(path.dirname(filePath))without validation. If chokidar ever emits a path with..segments,path.join(homedir, '.claude', 'projects', '..')resolves outside the intended scope. Add a guard:if (!projectName || projectName === '..' || projectName === '.') continue;sessionIdis only checked foragent-prefix. Temp files like.#session.jsonlwould pass through. A basic alphanumeric/hyphen guard would be cleaner.console.error('[WARN] ...')should beconsole.warnfor consistency with the rest of the codebase (e.g., line 1979).
Positive
pendingClaudeSessionEvents.splice(0)atomically drains the array — correct pattern for concurrent accumulation.agent-file filtering matches the existing pattern inprojects.js.- Startup reconcile correctly calls without
targetSessionIdto trigger a full scan. project.nameguard is good defensive coding.- Change is appropriately scoped to
server/index.jswithout mutating the reconcile logic itself.
Address code review feedback from OpenLAIR#93: - Wrap reconcile loops in per-item try/catch to prevent single failure from aborting the batch - Clear pendingClaudeSessionEvents on watcher reinit - Add path traversal guard for projectName (reject "." and "..") - Filter temp files with alphanumeric/hyphen regex on sessionId - Use console.warn instead of console.error for warnings - Track reconciled count separately from total project count Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address code review feedback from OpenLAIR#93: - Wrap reconcile loops in per-item try/catch to prevent single failure from aborting the batch - Clear pendingClaudeSessionEvents on watcher reinit - Add path traversal guard for projectName (reject "." and "..") - Filter temp files with alphanumeric/hyphen regex on sessionId - Use console.warn instead of console.error for warnings - Track reconciled count separately from total project count Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address code review feedback from OpenLAIR#93: - Wrap reconcile loops in per-item try/catch to prevent single failure from aborting the batch - Clear pendingClaudeSessionEvents on watcher reinit - Add path traversal guard for projectName (reject "." and "..") - Filter temp files with alphanumeric/hyphen regex on sessionId - Use console.warn instead of console.error for warnings - Track reconciled count separately from total project count Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address code review feedback from OpenLAIR#93: - Wrap reconcile loops in per-item try/catch to prevent single failure from aborting the batch - Clear pendingClaudeSessionEvents on watcher reinit - Add path traversal guard for projectName (reject "." and "..") - Filter temp files with alphanumeric/hyphen regex on sessionId - Use console.warn instead of console.error for warnings - Track reconciled count separately from total project count Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Superseded by #142 — rebased on latest main with all review feedback addressed. |
Summary
claudeCLI were not visible in the Web UI because they were written directly to disk (.jsonlfiles) without being indexed into thesession_metadatadatabase table.jsonlchange events during the debounce window and callreconcileClaudeSessionIndex()for each before broadcasting the project updateFixes the CLI session portion of #86.
Root Cause
Web UI sessions are indexed immediately via
recordIndexedSession()inclaude-sdk.jswhen the first message arrives. CLI sessions bypass the dr-claw server entirely -- theclaudebinary writes.jsonldirectly to~/.claude/projects/. The file watcher detects these changes but only callsgetProjects(), which reads from the DB index and never parses.jsonlfiles. So CLI sessions remain invisible.Test plan
cd /path/to/project && claude)Generated with Claude Code