Skip to content

bug(monitor): computeProjectHash mismatches CC slug — assistant messages never fan out to channels when workdir has dotted segments #3286

Description

@OneStepAt4time

Summary

computeProjectHash (src/path-utils.ts) preserves . inside path segments, but Claude Code's project-directory slug replaces every . with -. Result: any workdir whose path includes a dotted segment (e.g. .claude, .local, .config, .git-worktrees) gets a project-hash that does NOT match the on-disk CC directory.

Downstream effect: discoverFromFilesystemFallback (session-transcripts.ts:496-531) looks in the wrong ~/.claude/projects/<hash>/ folder, never finds the JSONL, never sets session.jsonlPath. The monitor's readMessagesForMonitor reads zero entries → forwardMessage never runs → channels.message('message.assistant', ...) never fires.

Impact: assistant replies from Claude Code do not reach any notification channel (Telegram, Slack, Webhooks, email) and do not appear in /v1/sessions/:id/transcript for sessions whose workdir contains a dotted segment.

Reproduction

  1. AEGIS_TG_TOKEN=... AEGIS_TG_GROUP=... node dist/cli.js
  2. POST /v1/sessions { workDir: ".../<repo>/.claude/worktrees/x", prompt: "Reply: HELLO" }
  3. Session created, prompt delivered (promptDelivery.delivered=true), Claude writes the assistant reply to the JSONL.
  4. Telegram topic is created and shows 🟢 session-created, 👤 User …, ✅ killedno assistant message.
  5. GET /v1/sessions/:id/transcript returns messages: [].

Aegis computed slug vs reality:

Workdir computeProjectHash CC actual dir
/Users/x/Documents/aegis/.claude/worktrees/verify-tg -Users-x-Documents-aegis-.claude-worktrees-verify-tg -Users-x-Documents-aegis--claude-worktrees-verify-tg

The two differ by aegis-.claude vs aegis--claude.

Fix

In src/path-utils.ts, when sanitizing segments, also replace . with -:

.map((segment) => segment.replace(/:/g, '').replace(/\s+/g, '-').replace(/\./g, '-'))

Add a unit test asserting computeProjectHash('/home/me/.claude/repo') === '-home-me--claude-repo'.

Why this hasn't surfaced before

Likely most existing flows use claudeSessionId set via the hook (session.ts:699), which bypasses the filesystem-fallback path. Workflows that rely on the fallback (no hook, or pre-hook timing) and use a workdir with . segments are affected.

Phase / scope

Phase 3.5 — ACP backend migration. Surfacing this through Telegram channel verification; the same bug breaks any out-of-band consumer relying on forwardMessage.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2P4P4 — nice to have / backlogbackendbugSomething isn't workingcidocumentationImprovements or additions to documentationreleasedIncluded in a published releasetests

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions