@hua-labs/tap 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../packages/tap-plugin/channels/tap-identity.ts","../packages/tap-plugin/channels/tap-utils.ts","../packages/tap-plugin/channels/tap-io.ts","../packages/tap-plugin/channels/tap-comms.ts","../packages/tap-plugin/channels/tap-claims.ts","../packages/tap-plugin/channels/tap-db.ts","../packages/tap-plugin/channels/tap-watcher.ts","../packages/tap-plugin/channels/tap-presence.ts","../packages/tap-plugin/channels/tap-poll-fallback.ts"],"sourcesContent":["const BROADCAST_RECIPIENTS = new Set([\"전체\", \"all\"]);\n\nexport const PLACEHOLDER_AGENT_VALUES = new Set([\n \"unknown\",\n \"unnamed\",\n \"<set-per-session>\",\n]);\n\nfunction trimAddress(value?: string | null): string {\n return value?.trim() ?? \"\";\n}\n\nexport function canonicalizeAgentId(value: string): string {\n return trimAddress(value).replace(/-/g, \"_\");\n}\n\nexport function isBroadcastRecipient(value: string): boolean {\n return BROADCAST_RECIPIENTS.has(trimAddress(value));\n}\n\nexport function isPlaceholderAgentValue(value?: string | null): boolean {\n const normalized = trimAddress(value);\n return !normalized || PLACEHOLDER_AGENT_VALUES.has(normalized);\n}\n\nexport function sameRoutingAddress(left: string, right: string): boolean {\n const normalizedLeft = trimAddress(left);\n const normalizedRight = trimAddress(right);\n if (!normalizedLeft || !normalizedRight) {\n return false;\n }\n\n if (\n isBroadcastRecipient(normalizedLeft) &&\n isBroadcastRecipient(normalizedRight)\n ) {\n return true;\n }\n\n return (\n normalizedLeft === normalizedRight ||\n canonicalizeAgentId(normalizedLeft) === canonicalizeAgentId(normalizedRight)\n );\n}\n\nexport function matchesAgentRecipient(\n recipient: string,\n agentId: string,\n agentName: string,\n): boolean {\n const normalizedRecipient = trimAddress(recipient);\n if (!normalizedRecipient) {\n return false;\n }\n\n return (\n isBroadcastRecipient(normalizedRecipient) ||\n sameRoutingAddress(normalizedRecipient, agentId) ||\n normalizedRecipient === trimAddress(agentName)\n );\n}\n\nexport function isOwnMessageAddress(\n sender: string,\n agentId: string,\n agentName: string,\n): boolean {\n const normalizedSender = trimAddress(sender);\n if (!normalizedSender) {\n return false;\n }\n\n return (\n sameRoutingAddress(normalizedSender, agentId) ||\n normalizedSender === trimAddress(agentName)\n );\n}\n\nexport function normalizeRecipientList(\n rawRecipients: unknown,\n exclude: string[] = [],\n): string[] | undefined {\n let recipients: string[] | undefined;\n if (rawRecipients == null) {\n recipients = undefined;\n } else if (typeof rawRecipients === \"string\") {\n const trimmed = trimAddress(rawRecipients);\n recipients = trimmed ? [trimmed] : undefined;\n } else if (Array.isArray(rawRecipients)) {\n const valid = rawRecipients\n .filter(\n (value): value is string =>\n typeof value === \"string\" && trimAddress(value).length > 0,\n )\n .map((value) => trimAddress(value));\n recipients = valid.length > 0 ? valid : undefined;\n } else {\n recipients = undefined;\n }\n\n if (!recipients) {\n return undefined;\n }\n\n const filtered: string[] = [];\n for (const recipient of recipients) {\n if (exclude.some((value) => sameRoutingAddress(value, recipient))) {\n continue;\n }\n if (filtered.some((value) => sameRoutingAddress(value, recipient))) {\n continue;\n }\n filtered.push(recipient);\n }\n\n return filtered.length > 0 ? filtered : undefined;\n}\n","/**\n * tap-comms shared utilities: types, config, parsing, helpers.\n */\nimport { existsSync, readFileSync, readdirSync, statSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport {\n canonicalizeAgentId as canonicalizeIdentityId,\n isPlaceholderAgentValue,\n matchesAgentRecipient,\n} from \"./tap-identity.js\";\n\n// ── Config ──────────────────────────────────────────────────────────────\n\nconst RAW_COMMS_DIR = process.env.TAP_COMMS_DIR;\nif (!RAW_COMMS_DIR) {\n console.error(\n \"[tap-comms] FATAL: TAP_COMMS_DIR not set. Set via env or .tap-config\",\n );\n process.exit(1);\n}\n\nexport const COMMS_DIR = resolve(RAW_COMMS_DIR);\nexport const INBOX_DIR = join(COMMS_DIR, \"inbox\");\nexport const REVIEWS_DIR = join(COMMS_DIR, \"reviews\");\nexport const FINDINGS_DIR = join(COMMS_DIR, \"findings\");\nexport const RECEIPTS_DIR = join(COMMS_DIR, \"receipts\");\nexport const RECEIPTS_PATH = join(RECEIPTS_DIR, \"receipts.json\");\nexport const RECEIPTS_LOCK = join(RECEIPTS_DIR, \".lock\");\nexport const HEARTBEATS_PATH = join(COMMS_DIR, \"heartbeats.json\");\nexport const HEARTBEATS_LOCK = join(COMMS_DIR, \".heartbeats.lock\");\nexport const ARCHIVE_DIR = join(COMMS_DIR, \"archive\");\nexport const DB_PATH = join(COMMS_DIR, \"tap.db\");\nexport const SERVER_START = Date.now();\n\n// ── Agent Identity ──────────────────────────────────────────────────────\n// id = immutable routing key (set once at startup or first tap_set_name)\n// name = session display label. Once a real name is confirmed, only\n// idempotent tap_set_name calls are allowed until an explicit rename flow exists.\n\ntype TapBootstrapInstance = {\n runtime?: string;\n installed?: boolean;\n agentName?: string | null;\n};\n\nfunction isConcreteIdentity(value: string | undefined): value is string {\n return !isPlaceholderAgentValue(value);\n}\n\nfunction normalizeAgentId(value: string): string {\n return canonicalizeIdentityId(value);\n}\n\nfunction loadStateInstances(): Record<string, TapBootstrapInstance> | null {\n const stateDir = process.env.TAP_STATE_DIR;\n if (!stateDir) return null;\n try {\n const statePath = join(stateDir, \"state.json\");\n if (!existsSync(statePath)) return null;\n const state = JSON.parse(readFileSync(statePath, \"utf-8\")) as {\n instances?: Record<string, TapBootstrapInstance>;\n };\n return state.instances ?? null;\n } catch {\n return null;\n }\n}\n\ntype StateBootstrapIdentity = {\n agentId: string;\n agentName: string | null;\n};\n\nfunction resolveSingleCodexBootstrap(): StateBootstrapIdentity | null {\n const instances = loadStateInstances();\n if (!instances) return null;\n\n const installedCodexInstances = Object.entries(instances).filter(\n ([, instance]) => instance?.runtime === \"codex\" && instance?.installed,\n );\n if (installedCodexInstances.length !== 1) return null;\n\n const [instanceId, instance] = installedCodexInstances[0];\n return {\n agentId: normalizeAgentId(instanceId),\n agentName:\n typeof instance.agentName === \"string\" &&\n !isPlaceholderAgentValue(instance.agentName)\n ? instance.agentName\n : null,\n };\n}\n\nfunction resolveInitialId(\n stateBootstrap: StateBootstrapIdentity | null,\n): string {\n const envId = process.env.TAP_AGENT_ID;\n if (isConcreteIdentity(envId)) return normalizeAgentId(envId);\n const envName = process.env.TAP_AGENT_NAME;\n if (isConcreteIdentity(envName)) return normalizeAgentId(envName);\n return stateBootstrap?.agentId ?? \"unknown\";\n}\n\n/** Try to read agentName from state.json for the current instance. */\nfunction resolveNameFromState(\n agentId: string,\n stateBootstrap: StateBootstrapIdentity | null,\n): string | null {\n if (agentId === \"unknown\") return null;\n if (stateBootstrap?.agentId === agentId && stateBootstrap.agentName) {\n return stateBootstrap.agentName;\n }\n try {\n const instances = loadStateInstances();\n if (!instances) return null;\n const instance =\n instances[agentId] ?? instances[agentId.replace(/_/g, \"-\")];\n return typeof instance?.agentName === \"string\" &&\n !isPlaceholderAgentValue(instance.agentName)\n ? instance.agentName\n : null;\n } catch {\n return null;\n }\n}\n\nconst stateBootstrap = resolveSingleCodexBootstrap();\nlet _agentId = resolveInitialId(stateBootstrap);\n// State takes priority over env — tap_set_name backwrites to state,\n// but managed MCP config env may still hold a stale name from tap add time.\nlet _agentName =\n resolveNameFromState(_agentId, stateBootstrap) ??\n (isConcreteIdentity(process.env.TAP_AGENT_NAME)\n ? process.env.TAP_AGENT_NAME\n : \"unknown\");\nlet _idLocked = _agentId !== \"unknown\";\n// M185: Name confirmation — once confirmed, only idempotent calls allowed.\n// Prevents subagents from overwriting parent's display name.\n// If booted with a real name (from state or env), consider it pre-confirmed.\nlet _nameConfirmed = !isPlaceholderAgentValue(_agentName);\n\nexport function getAgentId(): string {\n return _agentId;\n}\n\nexport function getAgentName(): string {\n return _agentName;\n}\n\nexport function resolveKnownInstanceId(\n agentId: string,\n displayName?: string | null,\n): string | null {\n const instances = loadStateInstances();\n if (!instances) return null;\n\n const candidates = [\n agentId,\n agentId.replace(/_/g, \"-\"),\n agentId.replace(/-/g, \"_\"),\n ];\n for (const candidate of candidates) {\n if (instances[candidate]?.installed) return candidate;\n }\n\n if (!displayName || isPlaceholderAgentValue(displayName)) return null;\n const matches = Object.entries(instances).filter(\n ([, instance]) => instance?.installed && instance.agentName === displayName,\n );\n return matches.length === 1 ? matches[0][0] : null;\n}\n\nexport function resolveCurrentInstanceId(): string | null {\n return resolveKnownInstanceId(_agentId, _agentName);\n}\n\nexport function buildHeartbeatConnectHash(\n instanceId: string | null | undefined,\n agentId: string,\n): string {\n return instanceId ? `instance:${instanceId}` : `session:${agentId}`;\n}\n\nexport function isNameConfirmed(): boolean {\n return _nameConfirmed;\n}\n\n/**\n * Demote agent name to \"unknown\" and reset confirmed state.\n * Used when bootstrap claim fails — allows tap_set_name recovery.\n */\nexport function demoteAgentName(): void {\n _agentName = \"unknown\";\n _nameConfirmed = false;\n}\n\nexport function setAgentName(name: string) {\n _agentName = name;\n _nameConfirmed = true;\n // First set_name also locks the id (backward compat: id = first name chosen)\n if (!_idLocked) {\n // Hyphens are reserved as filename delimiters — use underscores instead\n _agentId = canonicalizeIdentityId(name);\n _idLocked = true;\n }\n}\n\nexport type AgentNameClaimResult =\n | {\n ok: true;\n oldName: string;\n agentId: string;\n wasIdLocked: boolean;\n }\n | {\n ok: false;\n currentName: string;\n agentId: string;\n };\n\n// M185 scope: once a session already holds a real name, later same-process\n// callers can only repeat that same name. Placeholder boot first-claim remains\n// first-caller-wins until caller context exists (M193).\nexport function claimAgentName(name: string): AgentNameClaimResult {\n const oldName = _agentName;\n const wasIdLocked = _idLocked;\n if (_nameConfirmed && name !== oldName) {\n return {\n ok: false,\n currentName: oldName,\n agentId: _agentId,\n };\n }\n\n setAgentName(name);\n return {\n ok: true,\n oldName,\n agentId: _agentId,\n wasIdLocked,\n };\n}\n\nexport function isIdLocked(): boolean {\n return _idLocked;\n}\n\n// ── Types ───────────────────────────────────────────────────────────────\n\nexport type ChannelSource = \"inbox\" | \"reviews\" | \"findings\";\n\nexport type ParsedFilename = { from: string; to: string; subject: string };\n\nexport type ParsedFrontmatter = {\n from: string;\n from_name?: string;\n to: string;\n to_name?: string;\n subject: string;\n sent_at?: string;\n type?: string;\n};\n\nexport type TapUnreadItem = {\n source: ChannelSource;\n filename: string;\n path: string;\n from: string;\n to: string;\n subject: string;\n mtime: string;\n content?: string;\n};\n\nexport type HeartbeatSource = \"bridge-dispatch\" | \"mcp-direct\";\n\nexport type Heartbeat = {\n id?: string; // routing id (immutable) — absent in legacy entries\n agent: string; // display name (mutable)\n timestamp: string;\n lastActivity: string;\n joinedAt?: string; // ISO — set on first tap_set_name, preserved on rename\n status: \"active\" | \"idle\" | \"signing-off\";\n source?: HeartbeatSource;\n instanceId?: string | null;\n bridgePid?: number | null;\n connectHash?: string;\n};\n\nexport type HeartbeatStore = Record<string, Heartbeat>;\n\nexport type Receipt = { reader: string; timestamp: string };\nexport type ReceiptStore = Record<string, Receipt[]>;\n\n// ── Activity Tracking ───────────────────────────────────────────────────\n\nlet _lastActivityTime = new Date().toISOString();\n\nexport function getLastActivityTime(): string {\n return _lastActivityTime;\n}\n\nexport function updateActivityTime() {\n _lastActivityTime = new Date().toISOString();\n}\n\n// ── Utilities ───────────────────────────────────────────────────────────\n\nexport function debug(message: string) {\n console.error(`[tap-comms] ${message}`);\n}\n\nexport function stripBom(text: string): string {\n return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n}\n\n/**\n * Parse YAML frontmatter from message content.\n * Returns parsed fields or null if no valid frontmatter found.\n */\nexport function parseFrontmatter(content: string): ParsedFrontmatter | null {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---/);\n if (!match) return null;\n\n const fields: Record<string, string> = {};\n for (const line of match[1].split(\"\\n\")) {\n const kv = line.match(/^(\\w+):\\s*(.+)$/);\n if (kv) fields[kv[1]] = kv[2].trim();\n }\n\n if (!fields.from || !fields.to) return null;\n\n return {\n from: fields.from,\n from_name: fields.from_name,\n to: fields.to,\n to_name: fields.to_name,\n subject: fields.subject ?? \"\",\n sent_at: fields.sent_at,\n type: fields.type,\n };\n}\n\n/**\n * Strip frontmatter from content, returning only the body.\n */\nexport function stripFrontmatter(content: string): string {\n return content.replace(/^---\\r?\\n[\\s\\S]*?\\r?\\n---\\r?\\n*/, \"\");\n}\n\n/**\n * Parse message routing info: try frontmatter first, fall back to filename.\n */\nexport function parseMessageRoute(\n filename: string,\n content?: string,\n): ParsedFilename | null {\n if (content) {\n const fm = parseFrontmatter(content);\n if (fm) return { from: fm.from, to: fm.to, subject: fm.subject };\n }\n return parseFilename(filename);\n}\n\nexport function parseFilename(filename: string): ParsedFilename | null {\n // Format: YYYYMMDD-{from}-{to}-{subject}.md\n // from/to may contain hyphens (e.g. \"codex-1\"), so we split by \"-\" and\n // use a known-agent or structural heuristic: date(1) + from + to + subject(rest).\n // Strategy: strip date prefix, then split remainder into exactly 3+ segments\n // where from/to are single CJK chars or known multi-segment ids.\n const withoutExt = filename.replace(/\\.md$/, \"\");\n const dateMatch = withoutExt.match(/^(\\d{8})-(.+)$/);\n if (!dateMatch) return null;\n\n const rest = dateMatch[2];\n\n // Try CJK-aware split: CJK characters are single-char agent names\n // Match: {from}-{to}-{subject} where from/to can be CJK single chars\n const cjkMatch = rest.match(\n /^([\\u3131-\\uD79DA-Za-z][\\w]*?)-([\\u3131-\\uD79DA-Za-z][\\w]*?)-(.+)$/,\n );\n if (cjkMatch) {\n return { from: cjkMatch[1], to: cjkMatch[2], subject: cjkMatch[3] };\n }\n\n // Fallback: simple 3-part split (first two segments = from/to)\n const parts = rest.split(\"-\");\n if (parts.length >= 3) {\n return {\n from: parts[0] || \"?\",\n to: parts[1] || \"?\",\n subject: parts.slice(2).join(\"-\") || \"?\",\n };\n }\n\n return null;\n}\n\n/**\n * M204: Canonicalize agent ID — normalize hyphens to underscores.\n * Both `codex-1` and `codex_1` map to `codex_1`.\n */\nexport function canonicalizeAgentId(id: string): string {\n return canonicalizeIdentityId(id);\n}\n\nexport function isForMe(to: string): boolean {\n return matchesAgentRecipient(to, _agentId, _agentName);\n}\n\nexport function normalizeSources(value: unknown): ChannelSource[] {\n // Default: inbox + reviews only. Findings are record-keeping, not real-time\n // comms — request explicitly via sources: [\"findings\"] if needed.\n if (!Array.isArray(value) || value.length === 0) {\n return [\"inbox\", \"reviews\"];\n }\n\n const allowed = new Set<ChannelSource>([\"inbox\", \"reviews\", \"findings\"]);\n const normalized = value.filter(\n (entry): entry is ChannelSource =>\n typeof entry === \"string\" && allowed.has(entry as ChannelSource),\n );\n\n return normalized.length ? normalized : [\"inbox\", \"reviews\"];\n}\n\nexport function getLatestReviewDir(): string | null {\n if (!existsSync(REVIEWS_DIR)) return null;\n const gens = readdirSync(REVIEWS_DIR)\n .filter((entry) => entry.startsWith(\"gen\"))\n .sort();\n return gens.length ? join(REVIEWS_DIR, gens[gens.length - 1]) : null;\n}\n\nexport function getSourceDir(source: ChannelSource): string | null {\n if (source === \"inbox\") return INBOX_DIR;\n if (source === \"reviews\") return getLatestReviewDir();\n return FINDINGS_DIR;\n}\n\nexport function getSourceKey(source: ChannelSource, filename: string): string {\n return `${source}/${filename}`;\n}\n\nexport function getRecentSenders(): Set<string> {\n const senders = new Set<string>();\n if (!existsSync(INBOX_DIR)) return senders;\n\n const cutoff = Date.now() - 24 * 60 * 60 * 1000;\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n try {\n const mtime = statSync(join(INBOX_DIR, filename)).mtimeMs;\n if (mtime < cutoff) continue;\n } catch {\n continue;\n }\n const parsed = parseFilename(filename);\n if (parsed) senders.add(parsed.from);\n }\n return senders;\n}\n","/**\n * tap-comms file I/O: locks, receipts, heartbeats, unread scanning.\n */\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"fs\";\nimport { createHash } from \"crypto\";\nimport { join } from \"path\";\nimport {\n RECEIPTS_DIR,\n RECEIPTS_PATH,\n HEARTBEATS_PATH,\n stripBom,\n parseFilename,\n parseFrontmatter,\n stripFrontmatter,\n isForMe,\n getAgentId,\n getAgentName,\n getSourceDir,\n getSourceKey,\n normalizeSources,\n type ChannelSource,\n type TapUnreadItem,\n type ReceiptStore,\n type HeartbeatStore,\n} from \"./tap-utils.js\";\nimport { isOwnMessageAddress } from \"./tap-identity.js\";\n\n// ── State ───────────────────────────────────────────────────────────────\n\nexport const startupFiles = new Set<string>();\nexport const readFiles = new Set<string>();\n\n// ── Bridge Dedup ───────────────────────────────────────────────────────\n// Bridge writes processed markers at {bridgeStateDir}/processed/{sha1}.done.\n// bridgeStateDir = {repoRoot}/.tmp/codex-app-server-bridge-{name}/\n// Scan all bridge state dirs to find markers.\n\nconst REPO_ROOT = process.env.TAP_REPO_ROOT ?? null;\n\nconst BRIDGE_DIR_CACHE_TTL_MS = 30_000; // re-scan every 30s to pick up late-start bridges\nlet _bridgeProcessedDirs: string[] = [];\nlet _bridgeDirsCachedAt = 0;\n\nfunction getBridgeProcessedDirs(): string[] {\n const now = Date.now();\n if (now - _bridgeDirsCachedAt < BRIDGE_DIR_CACHE_TTL_MS) {\n return _bridgeProcessedDirs;\n }\n _bridgeDirsCachedAt = now;\n\n if (!REPO_ROOT) {\n _bridgeProcessedDirs = [];\n return _bridgeProcessedDirs;\n }\n const tmpDir = join(REPO_ROOT, \".tmp\");\n if (!existsSync(tmpDir)) {\n _bridgeProcessedDirs = [];\n return _bridgeProcessedDirs;\n }\n try {\n _bridgeProcessedDirs = readdirSync(tmpDir)\n .filter((d) => d.startsWith(\"codex-app-server-bridge\"))\n .map((d) => join(tmpDir, d, \"processed\"))\n .filter((p) => existsSync(p));\n } catch {\n _bridgeProcessedDirs = [];\n }\n return _bridgeProcessedDirs;\n}\n\nfunction isBridgeProcessed(filePath: string, mtimeMs: number): boolean {\n const dirs = getBridgeProcessedDirs();\n if (dirs.length === 0) return false;\n const markerId = createHash(\"sha1\")\n .update(`${filePath}|${mtimeMs}`)\n .digest(\"hex\");\n const markerFile = `${markerId}.done`;\n return dirs.some((dir) => existsSync(join(dir, markerFile)));\n}\n\n// ── Lock ────────────────────────────────────────────────────────────────\n\nexport function acquireLock(\n lockPath: string,\n retries = 3,\n delayMs = 100,\n): boolean {\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n writeFileSync(lockPath, String(process.pid), { flag: \"wx\" });\n return true;\n } catch {\n try {\n const age = Date.now() - statSync(lockPath).mtimeMs;\n if (age > 10_000) {\n unlinkSync(lockPath);\n continue;\n }\n } catch {}\n if (attempt < retries - 1) {\n const start = Date.now();\n while (Date.now() - start < delayMs) {}\n }\n }\n }\n return false;\n}\n\nexport function releaseLock(lockPath: string) {\n try {\n unlinkSync(lockPath);\n } catch {}\n}\n\n// ── Receipts ────────────────────────────────────────────────────────────\n\nexport function ensureReceiptsDir() {\n if (!existsSync(RECEIPTS_DIR)) mkdirSync(RECEIPTS_DIR, { recursive: true });\n}\n\nexport function loadReceipts(): ReceiptStore {\n try {\n return JSON.parse(readFileSync(RECEIPTS_PATH, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nexport function saveReceipts(store: ReceiptStore) {\n ensureReceiptsDir();\n const tmpPath = RECEIPTS_PATH + \".tmp\";\n writeFileSync(tmpPath, JSON.stringify(store, null, 2), \"utf-8\");\n renameSync(tmpPath, RECEIPTS_PATH);\n}\n\n// ── Heartbeats ──────────────────────────────────────────────────────────\n\nexport function loadHeartbeats(): HeartbeatStore {\n try {\n return JSON.parse(readFileSync(HEARTBEATS_PATH, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nexport function saveHeartbeats(store: HeartbeatStore) {\n const tmpPath = HEARTBEATS_PATH + \".tmp\";\n writeFileSync(tmpPath, JSON.stringify(store, null, 2), \"utf-8\");\n renameSync(tmpPath, HEARTBEATS_PATH);\n}\n\nexport function formatAgentLabel(\n agentIdOrName: string,\n displayName?: string | null,\n): string {\n const normalizedId = agentIdOrName.trim();\n const normalizedName = displayName?.trim();\n\n if (!normalizedId) {\n return normalizedName ?? agentIdOrName;\n }\n\n if (!normalizedName || normalizedName === normalizedId) {\n return normalizedId;\n }\n\n return `${normalizedName} [${normalizedId}]`;\n}\n\nexport function resolveAgentLabel(\n agentIdOrName: string,\n store: HeartbeatStore = loadHeartbeats(),\n): string {\n const normalized = agentIdOrName.trim();\n if (!normalized || normalized === \"전체\" || normalized === \"all\") {\n return agentIdOrName;\n }\n\n const byId = store[normalized];\n if (byId?.agent?.trim()) {\n return formatAgentLabel(normalized, byId.agent);\n }\n\n for (const [agentId, heartbeat] of Object.entries(store)) {\n if (heartbeat.agent?.trim() === normalized) {\n return formatAgentLabel(agentId, heartbeat.agent);\n }\n }\n\n return normalized;\n}\n\n// ── Startup ─────────────────────────────────────────────────────────────\n\nexport function seedStartupFiles(source: ChannelSource) {\n const dir = getSourceDir(source);\n if (!dir || !existsSync(dir)) return;\n\n for (const filename of readdirSync(dir)) {\n startupFiles.add(getSourceKey(source, filename));\n }\n}\n\n// ── Unread Items ────────────────────────────────────────────────────────\n\nexport function getUnreadItems(options?: {\n sources?: unknown;\n limit?: unknown;\n includeContent?: unknown;\n markRead?: unknown;\n since?: unknown;\n}): TapUnreadItem[] {\n const sources = normalizeSources(options?.sources);\n const includeContent = options?.includeContent !== false;\n const markRead = options?.markRead !== false;\n const sinceMs =\n typeof options?.since === \"string\" ? new Date(options.since).getTime() : 0;\n\n // Apply joinedAt filter: don't show messages from before agent joined\n // Look up by id first, fallback to name for backward compat\n const agentId = getAgentId();\n const agentName = getAgentName();\n let heartbeatStore: HeartbeatStore = {};\n let joinedAtMs = 0;\n if (agentId !== \"unknown\") {\n try {\n heartbeatStore = loadHeartbeats();\n const entry = heartbeatStore[agentId] ?? heartbeatStore[agentName];\n if (entry?.joinedAt) {\n joinedAtMs = new Date(entry.joinedAt).getTime();\n }\n } catch {\n // Non-critical: if we can't read, show all\n }\n }\n // Use the later of since and joinedAt\n const effectiveSinceMs = Math.max(sinceMs, joinedAtMs);\n\n const parsedLimit =\n typeof options?.limit === \"number\"\n ? options.limit\n : Number.parseInt(String(options?.limit ?? \"20\"), 10);\n const limit = Number.isFinite(parsedLimit)\n ? Math.max(1, Math.min(100, parsedLimit))\n : 20;\n\n const items: TapUnreadItem[] = [];\n\n for (const source of sources) {\n const dir = getSourceDir(source);\n if (!dir || !existsSync(dir)) continue;\n\n const filenames = readdirSync(dir)\n .filter((filename) => filename.endsWith(\".md\"))\n .sort();\n\n for (const filename of filenames) {\n const key = getSourceKey(source, filename);\n if (startupFiles.has(key) || readFiles.has(key)) continue;\n\n const fullPath = join(dir, filename);\n let mtime: number;\n try {\n mtime = statSync(fullPath).mtimeMs;\n } catch {\n continue;\n }\n if (effectiveSinceMs && mtime < effectiveSinceMs) continue;\n\n // Skip messages already delivered via bridge (dedup)\n if (isBridgeProcessed(fullPath, mtime)) {\n readFiles.add(key);\n continue;\n }\n\n let content: string;\n try {\n content = stripBom(readFileSync(fullPath, \"utf-8\"));\n } catch {\n continue;\n }\n\n let from: string = source;\n let to = \"all\";\n let subject = filename.replace(/\\.md$/, \"\");\n\n if (source === \"inbox\") {\n // Frontmatter-first routing (M202): try frontmatter, fall back to filename\n const fm = parseFrontmatter(content);\n const parsed = fm\n ? { from: fm.from, to: fm.to, subject: fm.subject }\n : parseFilename(filename);\n if (!parsed || !isForMe(parsed.to)) continue;\n if (isOwnMessageAddress(parsed.from, getAgentId(), getAgentName()))\n continue;\n from = resolveAgentLabel(fm?.from_name ?? parsed.from, heartbeatStore);\n to = resolveAgentLabel(fm?.to_name ?? parsed.to, heartbeatStore);\n subject = parsed.subject;\n // Strip frontmatter from displayed content\n if (fm && includeContent) {\n content = stripFrontmatter(content);\n }\n }\n\n const item: TapUnreadItem = {\n source,\n filename,\n path: `${source}/${filename}`,\n from,\n to,\n subject,\n mtime: new Date(mtime).toISOString(),\n };\n\n if (includeContent) {\n item.content = content;\n }\n\n items.push(item);\n if (markRead) {\n readFiles.add(key);\n }\n\n if (items.length >= limit) {\n return items;\n }\n }\n }\n\n return items;\n}\n","#!/usr/bin/env node\n/**\n * tap-comms: file-based real-time channel for tap multi-session orchestration.\n * Claude can receive fs.watch-driven channel notifications.\n * Other MCP clients can poll unread items via tap_list_unread.\n *\n * This is the thin orchestrator — tool definitions + handler routing.\n * Logic lives in tap-utils, tap-io, tap-db, tap-watcher.\n */\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport {\n isBroadcastRecipient,\n isPlaceholderAgentValue,\n normalizeRecipientList,\n} from \"./tap-identity.js\";\n\nimport {\n INBOX_DIR,\n ARCHIVE_DIR,\n RECEIPTS_LOCK,\n HEARTBEATS_LOCK,\n buildHeartbeatConnectHash,\n debug,\n getAgentId,\n getAgentName,\n claimAgentName,\n getRecentSenders,\n getLatestReviewDir,\n getLastActivityTime,\n resolveCurrentInstanceId,\n updateActivityTime,\n parseFilename,\n} from \"./tap-utils.js\";\nimport {\n claimName,\n renewClaimTTL,\n releaseClaim,\n resolveClaimInstanceId,\n} from \"./tap-claims.js\";\nimport {\n seedStartupFiles,\n getUnreadItems,\n acquireLock,\n releaseLock,\n ensureReceiptsDir,\n loadReceipts,\n saveReceipts,\n loadHeartbeats,\n saveHeartbeats,\n} from \"./tap-io.js\";\nimport {\n initDb,\n autoSyncOnStartup,\n dbInsertMessage,\n dbUpsertHeartbeat,\n dbInsertReceipt,\n dbGetStats,\n dbSyncAll,\n} from \"./tap-db.js\";\nimport { watchDir } from \"./tap-watcher.js\";\nimport { buildWhoAgents, resolvePreferredRecipient } from \"./tap-presence.js\";\nimport { readdirSync, renameSync, statSync, unlinkSync } from \"fs\";\n\n// ── Initialize ──────────────────────────────────────────────────────────\n\ninitDb();\nautoSyncOnStartup();\n\nseedStartupFiles(\"inbox\");\nseedStartupFiles(\"reviews\");\nseedStartupFiles(\"findings\");\n\n// ── Onboarding ─────────────────────────────────────────────────────────\n\nconst ONBOARDING_TEASER_LINES = 10;\n\nfunction loadOnboardingTeaser(): string {\n const commsDir = process.env.TAP_COMMS_DIR;\n if (!commsDir) return \"\";\n\n // Startup-time gating: skip teaser if agent already onboarded\n const stateDir = process.env.TAP_STATE_DIR;\n const agentId = getAgentId();\n if (stateDir && agentId !== \"unknown\") {\n try {\n const markerPath = join(stateDir, \"onboarded.json\");\n if (existsSync(markerPath)) {\n const store = JSON.parse(readFileSync(markerPath, \"utf-8\"));\n if (store[agentId]) return \"\"; // Already onboarded — skip teaser\n }\n } catch {\n // best-effort — serve teaser if marker unreadable\n }\n }\n\n try {\n const welcomePath = join(commsDir, \"onboarding\", \"welcome.md\");\n if (!existsSync(welcomePath)) return \"\";\n const content = readFileSync(welcomePath, \"utf-8\");\n const lines = content.split(\"\\n\").slice(0, ONBOARDING_TEASER_LINES);\n\n // Write marker on teaser serve — so next startup skips it\n if (stateDir && agentId !== \"unknown\") {\n try {\n const markerPath = join(stateDir, \"onboarded.json\");\n let store: Record<string, { onboardedAt: string }> = {};\n if (existsSync(markerPath)) {\n store = JSON.parse(readFileSync(markerPath, \"utf-8\"));\n }\n if (!store[agentId]) {\n store[agentId] = { onboardedAt: new Date().toISOString() };\n mkdirSync(stateDir, { recursive: true });\n writeFileSync(markerPath, JSON.stringify(store, null, 2), \"utf-8\");\n }\n } catch {\n // best-effort\n }\n }\n\n return (\n \"\\n\\n--- Onboarding ---\\n\" +\n lines.join(\"\\n\") +\n \"\\n(Use tap_onboard tool for full onboarding guide.)\"\n );\n } catch {\n return \"\";\n }\n}\n\n// ── MCP Server ──────────────────────────────────────────────────────────\n\nconst baseInstructions =\n 'You are connected to the tap-comms channel. Messages from other agents may arrive as <channel source=\"tap-comms\" from=\"X\" to=\"Y\" subject=\"Z\"> notifications. If your client does not surface Claude channel notifications, call tap_list_unread to pull pending inbox and review messages. Reply using the tap_reply tool to send messages back to other agents or the control tower.';\n\nconst mcp = new Server(\n { name: \"tap-comms\", version: \"0.2.2\" },\n {\n capabilities: {\n experimental: { \"claude/channel\": {} },\n tools: {},\n },\n instructions: baseInstructions + loadOnboardingTeaser(),\n },\n);\n\n// ── Tool Definitions ────────────────────────────────────────────────────\n\nmcp.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n {\n name: \"tap_set_name\",\n description:\n \"Set your agent name. Call this when you pick your name at session start.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n name: {\n type: \"string\" as const,\n description: \"Your chosen agent name.\",\n },\n },\n required: [\"name\"],\n },\n },\n {\n name: \"tap_reply\",\n description: \"Send a message to another tap agent via comms inbox.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n to: { type: \"string\" as const, description: \"Recipient agent name.\" },\n subject: {\n type: \"string\" as const,\n description: \"Message subject in kebab-case.\",\n },\n content: {\n type: \"string\" as const,\n description: \"Markdown message content.\",\n },\n cc: {\n description:\n \"Optional CC recipients. Each receives a copy of the message. Pass a single string or an array of strings.\",\n oneOf: [\n { type: \"string\" as const },\n {\n type: \"array\" as const,\n items: { type: \"string\" as const },\n },\n ],\n },\n },\n required: [\"to\", \"subject\", \"content\"],\n },\n },\n {\n name: \"tap_broadcast\",\n description:\n \"Broadcast a message to all agents. Shorthand for tap_reply with to='전체'.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n subject: {\n type: \"string\" as const,\n description: \"Message subject in kebab-case.\",\n },\n content: {\n type: \"string\" as const,\n description: \"Markdown message content.\",\n },\n },\n required: [\"subject\", \"content\"],\n },\n },\n {\n name: \"tap_list_unread\",\n description:\n \"Poll unread tap-comms items for clients that do not receive channel notifications.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n sources: {\n type: \"array\" as const,\n description:\n 'Optional source filter. Defaults to inbox, reviews. Add \"findings\" explicitly if needed.',\n items: {\n type: \"string\" as const,\n enum: [\"inbox\", \"reviews\", \"findings\"],\n },\n },\n limit: {\n type: \"number\" as const,\n description:\n \"Maximum number of unread items to return. Default 20.\",\n },\n includeContent: {\n type: \"boolean\" as const,\n description: \"Include full markdown content. Default true.\",\n },\n markRead: {\n type: \"boolean\" as const,\n description: \"Mark returned items as read. Default true.\",\n },\n since: {\n type: \"string\" as const,\n description:\n \"ISO timestamp. Only return files modified after this time.\",\n },\n },\n },\n },\n {\n name: \"tap_read_receipt\",\n description:\n \"Acknowledge that you read a message. Stores a read receipt so the sender can verify delivery.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n filename: {\n type: \"string\" as const,\n description: \"The inbox filename of the message you read.\",\n },\n },\n required: [\"filename\"],\n },\n },\n {\n name: \"tap_stats\",\n description:\n \"Show communication statistics: messages sent/received per agent, read receipts.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n hours: {\n type: \"number\" as const,\n description: \"Time window in hours. Default 24.\",\n },\n },\n },\n },\n {\n name: \"tap_heartbeat\",\n description:\n \"Send a heartbeat to signal this agent is alive. Call periodically or before/after major work.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n status: {\n type: \"string\" as const,\n enum: [\"active\", \"idle\", \"signing-off\"],\n description:\n \"Agent status. Default 'active'. Use 'signing-off' before session end.\",\n },\n },\n },\n },\n {\n name: \"tap_who\",\n description:\n \"List online agents based on recent heartbeats. Shows status, last heartbeat, and zombie detection.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n minutes: {\n type: \"number\" as const,\n description:\n \"Consider agents alive if heartbeat within this many minutes. Default 10.\",\n },\n },\n },\n },\n {\n name: \"tap_cleanup\",\n description:\n \"Archive inbox files older than N days. Moves them to archive/ directory.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n days: {\n type: \"number\" as const,\n description: \"Archive files older than this many days. Default 7.\",\n },\n dryRun: {\n type: \"boolean\" as const,\n description: \"Preview only, don't move files. Default false.\",\n },\n },\n },\n },\n {\n name: \"tap_db_sync\",\n description:\n \"Sync existing inbox/receipts/heartbeats files into the SQLite database.\",\n inputSchema: { type: \"object\" as const, properties: {} },\n },\n {\n name: \"tap_onboard\",\n description:\n \"Get the full onboarding guide for this project. Returns welcome.md + any additional onboarding docs from commsDir/onboarding/.\",\n inputSchema: { type: \"object\" as const, properties: {} },\n },\n ],\n}));\n\n// ── Activity Persistence ────────────────────────────────────────────────\n\nfunction prunePhantomHeartbeats(\n store: Record<string, { id?: string; [k: string]: unknown }>,\n): number {\n let removed = 0;\n for (const key of Object.keys(store)) {\n if (!store[key].id) {\n delete store[key];\n removed++;\n }\n }\n return removed;\n}\n\nfunction persistActivity(id: string, name: string): void {\n const locked = acquireLock(HEARTBEATS_LOCK);\n if (!locked) return; // Skip this cycle, retry next tool call\n try {\n const store = loadHeartbeats();\n // M210: Remove phantom entries (no id field) on every write cycle\n prunePhantomHeartbeats(store);\n const existing = store[id];\n const resolvedInstanceId =\n resolveCurrentInstanceId() ?? existing?.instanceId ?? null;\n const connectHash = buildHeartbeatConnectHash(resolvedInstanceId, id);\n const preserveBridgeSource =\n existing?.source === \"bridge-dispatch\" &&\n existing.connectHash === connectHash;\n store[id] = {\n id,\n agent: name,\n timestamp: existing?.timestamp ?? new Date().toISOString(),\n lastActivity: getLastActivityTime(),\n joinedAt: existing?.joinedAt,\n status: existing?.status ?? \"active\",\n source: preserveBridgeSource ? \"bridge-dispatch\" : \"mcp-direct\",\n instanceId: resolvedInstanceId,\n bridgePid: preserveBridgeSource ? (existing?.bridgePid ?? null) : null,\n connectHash,\n };\n saveHeartbeats(store);\n } catch {\n // Non-critical\n } finally {\n releaseLock(HEARTBEATS_LOCK);\n }\n}\n\n// ── Tool Handlers ───────────────────────────────────────────────────────\n\nmcp.setRequestHandler(CallToolRequestSchema, async (req) => {\n updateActivityTime();\n\n // Auto-persist activity to heartbeat store so tap_who can find us\n // Skip for tap_set_name — handled after name change below\n const currentId = getAgentId();\n const currentName = getAgentName();\n if (currentId !== \"unknown\" && req.params.name !== \"tap_set_name\") {\n persistActivity(currentId, currentName);\n }\n\n // ── tap_set_name ──────────────────────────────────────────────────\n if (req.params.name === \"tap_set_name\") {\n const { name } = req.params.arguments as { name: string };\n if (!name || !/^[A-Za-z0-9가-힣_]+$/.test(name)) {\n return {\n content: [\n {\n type: \"text\",\n text: `Rejected: \"${name}\" contains invalid characters. Agent names must match [A-Za-z0-9가-힣_] — no hyphens, spaces, or special characters.`,\n },\n ],\n };\n }\n // Step 1: Pre-check memory guard (read-only) — reject if already confirmed with different name\n const { isNameConfirmed: isConfirmed, getAgentName: currentName } =\n await import(\"./tap-utils.js\");\n if (isConfirmed() && currentName() !== name) {\n return {\n content: [\n {\n type: \"text\",\n text:\n `Rejected: Name already confirmed as \"${currentName()}\". ` +\n `tap_set_name can only be called once per session. ` +\n `Agent ID: ${getAgentId()} (immutable).`,\n },\n ],\n };\n }\n\n // Step 2: File claim — atomic cross-instance lock\n const claimInstanceId = resolveClaimInstanceId();\n const fileClaim = claimName(\n name,\n claimInstanceId,\n process.pid,\n \"mcp-direct\",\n );\n if (!fileClaim.success) {\n const conflict = fileClaim.conflictWith;\n return {\n content: [\n {\n type: \"text\",\n text:\n `Rejected: Name \"${name}\" is claimed by instance \"${conflict?.instanceId}\" (alive: ${conflict?.alive}). ` +\n `Agent ID: ${getAgentId()} (immutable).`,\n },\n ],\n };\n }\n\n // Step 3: Memory claim — only after file claim succeeds\n const claim = claimAgentName(name);\n if (!claim.ok) {\n // Should not happen (pre-check passed), but safety net\n releaseClaim(name, claimInstanceId, process.pid);\n return {\n content: [\n {\n type: \"text\",\n text:\n `Rejected: Name already confirmed as \"${claim.currentName}\". ` +\n `Agent ID: ${claim.agentId} (immutable).`,\n },\n ],\n };\n }\n\n const { oldName, agentId, wasIdLocked } = claim;\n\n const activeSenders = getRecentSenders();\n activeSenders.delete(oldName);\n const isDuplicate = activeSenders.has(name);\n debug(\n `name changed: ${oldName} -> ${name} (id: ${agentId}, locked: ${wasIdLocked})${isDuplicate ? \" (DUPLICATE WARNING)\" : \"\"}`,\n );\n\n const activeList = [...activeSenders]\n .filter((n) => n !== \"unnamed\" && n !== \"unknown\")\n .join(\", \");\n // Persist heartbeat under agent id (not name) for stable routing\n const now = new Date().toISOString();\n let priorJoinedAt: string | null = null; // M111: capture pre-write state\n let priorLastActivity: string | null = null;\n const locked = acquireLock(HEARTBEATS_LOCK);\n if (locked) {\n try {\n const store = loadHeartbeats();\n // Find existing entry by id or old name (migration from name-keyed)\n const oldEntry =\n store[agentId] ??\n (oldName !== \"unknown\" ? store[oldName] : undefined);\n\n // M111: capture pre-write state for tower notify dedupe\n priorJoinedAt = oldEntry?.joinedAt ?? null;\n priorLastActivity = oldEntry?.lastActivity ?? null;\n\n // Delete old name-keyed entry if migrating to id-keyed\n if (oldName !== \"unknown\" && oldName !== agentId) {\n delete store[oldName];\n }\n\n const resolvedInstanceId =\n resolveCurrentInstanceId() ?? oldEntry?.instanceId ?? null;\n const connectHash = buildHeartbeatConnectHash(\n resolvedInstanceId,\n agentId,\n );\n const preserveBridgeSource =\n oldEntry?.source === \"bridge-dispatch\" &&\n oldEntry.connectHash === connectHash;\n store[agentId] = {\n id: agentId,\n agent: name,\n timestamp: now,\n lastActivity: getLastActivityTime(),\n joinedAt: oldEntry?.joinedAt ?? now,\n status: \"active\",\n source: preserveBridgeSource ? \"bridge-dispatch\" : \"mcp-direct\",\n instanceId: resolvedInstanceId,\n bridgePid: preserveBridgeSource\n ? (oldEntry?.bridgePid ?? null)\n : null,\n connectHash,\n };\n\n // M162: Clean stale heartbeats with the same display name but\n // different agent ID. Prevents duplicate routing when a bridge\n // restarts with a new session ID but the same agent name.\n // Use lastActivity (updated on every tool call) rather than\n // timestamp (only set at tap_set_name time) to avoid removing\n // sessions that are still actively using tools.\n const STALE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes\n for (const [otherId, otherHb] of Object.entries(store)) {\n if (otherId === agentId) continue;\n if (otherHb.agent !== name) continue;\n const otherConnectHash =\n otherHb.connectHash ??\n buildHeartbeatConnectHash(otherHb.instanceId ?? null, otherId);\n if (otherConnectHash !== connectHash) continue;\n const freshestTs = Math.max(\n otherHb.lastActivity ? new Date(otherHb.lastActivity).getTime() : 0,\n otherHb.timestamp ? new Date(otherHb.timestamp).getTime() : 0,\n );\n if (Date.now() - freshestTs > STALE_THRESHOLD_MS) {\n delete store[otherId];\n }\n }\n\n saveHeartbeats(store);\n } catch {\n // Non-critical\n } finally {\n releaseLock(HEARTBEATS_LOCK);\n }\n }\n\n // Backwrite agentName to state.json so next session bootstraps with it\n const stateDir = process.env.TAP_STATE_DIR;\n if (stateDir) {\n try {\n const statePath = join(stateDir, \"state.json\");\n if (existsSync(statePath)) {\n const state = JSON.parse(readFileSync(statePath, \"utf-8\"));\n const instanceKey = agentId.replace(/_/g, \"-\");\n const instance =\n state.instances?.[agentId] ?? state.instances?.[instanceKey];\n if (instance) {\n instance.agentName = name;\n const tmp = `${statePath}.tmp.${process.pid}`;\n writeFileSync(tmp, JSON.stringify(state, null, 2), \"utf-8\");\n try {\n renameSync(tmp, statePath);\n } catch {\n // Retry once — Windows may hold file handle briefly\n try {\n renameSync(tmp, statePath);\n } catch {\n try {\n unlinkSync(tmp);\n } catch {\n /* best-effort cleanup */\n }\n }\n }\n debug(`backwrite agentName=\"${name}\" to state.json for ${agentId}`);\n }\n }\n } catch {\n // Non-critical — state backwrite is best-effort\n }\n }\n\n // M111: Notify tower on new agent join (first non-placeholder name)\n if (oldName === \"unknown\" || oldName === \"unnamed\") {\n try {\n // Read towerName from tap-config.json (TAP_REPO_ROOT is canonical source)\n const repoRoot = process.env.TAP_REPO_ROOT ?? \".\";\n let towerName: string | null = null;\n const cfgPath = join(repoRoot, \"tap-config.json\");\n if (existsSync(cfgPath)) {\n const cfg = JSON.parse(readFileSync(cfgPath, \"utf-8\"));\n towerName = cfg.towerName ?? null;\n }\n\n // Resolve runtime from state.json (works for all runtimes)\n let runtime = process.env.TAP_BRIDGE_RUNTIME ?? null;\n if (!runtime && stateDir) {\n try {\n const statePath = join(stateDir, \"state.json\");\n if (existsSync(statePath)) {\n const state = JSON.parse(readFileSync(statePath, \"utf-8\"));\n const instanceKey = agentId.replace(/_/g, \"-\");\n const inst =\n state.instances?.[agentId] ?? state.instances?.[instanceKey];\n runtime = inst?.runtime ?? null;\n }\n } catch {\n /* best-effort */\n }\n }\n\n if (towerName && towerName !== name && towerName !== agentId) {\n // Dedupe using pre-write heartbeat state (avoids self-skip on first join)\n const SKIP_WINDOW_MS = 10 * 60 * 1000;\n const STALE_WINDOW_MS = 30 * 60 * 1000;\n let shouldNotify = true;\n\n if (priorJoinedAt) {\n // Existing agent — check lastActivity freshness\n const activityTs = priorLastActivity ?? priorJoinedAt;\n const activityAge = Date.now() - new Date(activityTs).getTime();\n if (activityAge < SKIP_WINDOW_MS) {\n shouldNotify = false; // Recently active — skip\n } else if (activityAge < STALE_WINDOW_MS) {\n shouldNotify = false; // Active within window — skip\n }\n // > 30min since last activity → re-notify\n }\n // priorJoinedAt === null → truly new agent → notify\n\n if (shouldNotify) {\n const ts = new Date().toISOString().replace(/[:.]/g, \"-\");\n const notifyFilename = `${ts.slice(0, 10).replace(/-/g, \"\")}-tap-${towerName}-new-agent-${agentId}.md`;\n const notifyPath = join(INBOX_DIR, notifyFilename);\n writeFileSync(\n notifyPath,\n `[NEW] ${name} (${agentId}) joined. Runtime: ${runtime ?? \"unknown\"}.`,\n \"utf-8\",\n );\n debug(\n `tower notify: ${towerName} ← new agent ${name} (${runtime})`,\n );\n }\n }\n } catch {\n // Non-critical — tower notify is best-effort\n }\n }\n\n let text = `Name set: ${name} (was: ${oldName}). Messages to \"${name}\", \"${agentId}\", \"전체\", or \"all\" will be received.`;\n if (!wasIdLocked)\n text += `\\nAgent ID locked: ${agentId} (immutable for this session)`;\n if (isDuplicate)\n text += `\\n⚠️ WARNING: \"${name}\" was already used in the last 24h. Pick a different name to avoid confusion.`;\n if (activeList) text += `\\nRecent active names: ${activeList}`;\n return { content: [{ type: \"text\", text }] };\n }\n\n // ── tap_reply ─────────────────────────────────────────────────────\n if (req.params.name === \"tap_reply\") {\n const {\n to: rawTo,\n subject: rawSubject,\n content,\n cc: rawCc,\n } = req.params.arguments as {\n to: string;\n subject: string;\n content: string;\n cc?: string | string[];\n };\n\n // M142: Validate required fields\n const to = typeof rawTo === \"string\" ? rawTo.trim() : \"\";\n const subject = typeof rawSubject === \"string\" ? rawSubject.trim() : \"\";\n if (!to) {\n return {\n content: [\n {\n type: \"text\",\n text: 'Rejected: \"to\" is required and must be a non-empty string.',\n },\n ],\n };\n }\n if (!subject) {\n return {\n content: [\n {\n type: \"text\",\n text: 'Rejected: \"subject\" is required and must be a non-empty string.',\n },\n ],\n };\n }\n const cc = normalizeRecipientList(rawCc, [to]);\n\n const recipientWarnings: string[] = [];\n const store = loadHeartbeats();\n const knownAgents = new Set<string>();\n for (const [key, hb] of Object.entries(store)) {\n if (!isPlaceholderAgentValue(key)) knownAgents.add(key);\n if (!isPlaceholderAgentValue(hb.agent)) {\n knownAgents.add(hb.agent); // display name (exclude placeholders)\n }\n }\n const knownList = [...knownAgents]\n .filter((n) => n !== \"unknown\")\n .join(\", \");\n\n function resolveRecipient(recipient: string): {\n target: string;\n found: boolean;\n warning: string | null;\n } {\n const resolution = resolvePreferredRecipient(store, recipient);\n if (resolution.found) {\n return {\n target: resolution.target,\n found: true,\n warning: resolution.warning,\n };\n }\n\n return {\n target: recipient,\n found: false,\n warning:\n `⚠️ WARNING: \"${recipient}\" is not a known agent. ` +\n `Check spelling. Known: ${knownList}`,\n };\n }\n\n let resolvedTo = to;\n if (!isBroadcastRecipient(to)) {\n const resolution = resolveRecipient(to);\n if (!resolution.found) {\n if (resolution.warning) recipientWarnings.push(resolution.warning);\n } else {\n resolvedTo = resolution.target;\n if (resolution.warning) recipientWarnings.push(resolution.warning);\n }\n }\n\n if (cc?.length) {\n for (const recipient of cc) {\n if (isBroadcastRecipient(recipient)) continue;\n const resolution = resolveRecipient(recipient);\n if (resolution.warning) {\n recipientWarnings.push(\n resolution.warning.replace(`\"${recipient}\"`, `CC \"${recipient}\"`),\n );\n }\n }\n }\n\n const now = new Date();\n const date = now.toISOString().slice(0, 10).replace(/-/g, \"\");\n const fromId = getAgentId();\n const fromName = getAgentName();\n const filename = `${date}-${fromId}-${resolvedTo}-${subject}.md`;\n const filepath = join(INBOX_DIR, filename);\n const ccHeader = cc?.length ? `> CC: ${cc.join(\", \")}\\n\\n` : \"\";\n const frontmatter = [\n \"---\",\n \"type: inbox\",\n `from: ${fromId}`,\n `from_name: ${fromName}`,\n `to: ${resolvedTo}`,\n `to_name: ${to}`,\n `subject: ${subject}`,\n `sent_at: ${now.toISOString()}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n writeFileSync(filepath, frontmatter + ccHeader + content, \"utf-8\");\n dbInsertMessage(\n filename,\n fromName,\n resolvedTo,\n subject,\n \"inbox\",\n Date.now(),\n );\n\n const sent = [`Sent to ${to}: ${filename}`];\n if (cc?.length) {\n const writtenFiles = new Set<string>([filename]); // Track to prevent overwrite\n for (const recipient of cc) {\n try {\n const resolvedRecipient = isBroadcastRecipient(recipient)\n ? recipient\n : resolveRecipient(recipient).target;\n const ccFilename = `${date}-${fromId}-${resolvedRecipient}-${subject}.md`;\n // Skip if resolved filename matches primary or already written CC\n if (writtenFiles.has(ccFilename)) {\n sent.push(`CC to ${recipient}: skipped (resolves to same target)`);\n continue;\n }\n writtenFiles.add(ccFilename);\n const ccFrontmatter = [\n \"---\",\n \"type: inbox\",\n `from: ${fromId}`,\n `from_name: ${fromName}`,\n `to: ${resolvedRecipient}`,\n `to_name: ${recipient}`,\n `subject: ${subject}`,\n `sent_at: ${now.toISOString()}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n writeFileSync(\n join(INBOX_DIR, ccFilename),\n ccFrontmatter + `> CC from message to ${to}\\n\\n${content}`,\n \"utf-8\",\n );\n dbInsertMessage(\n ccFilename,\n fromName,\n resolvedRecipient,\n subject,\n \"inbox\",\n Date.now(),\n );\n sent.push(`CC to ${recipient}: ${ccFilename}`);\n } catch (err) {\n sent.push(\n `CC to ${recipient}: FAILED (${err instanceof Error ? err.message : String(err)})`,\n );\n }\n }\n }\n // Append warnings after delivery (still send — warning only, not blocking)\n sent.push(...recipientWarnings);\n return { content: [{ type: \"text\", text: sent.join(\"\\n\") }] };\n }\n\n // ── tap_broadcast ─────────────────────────────────────────────────\n if (req.params.name === \"tap_broadcast\") {\n const { subject, content } = req.params.arguments as {\n subject: string;\n content: string;\n };\n const now = new Date();\n const date = now.toISOString().slice(0, 10).replace(/-/g, \"\");\n const broadcastId = getAgentId();\n const broadcastName = getAgentName();\n const filename = `${date}-${broadcastId}-전체-${subject}.md`;\n const broadcastFrontmatter = [\n \"---\",\n \"type: inbox\",\n `from: ${broadcastId}`,\n `from_name: ${broadcastName}`,\n \"to: 전체\",\n `subject: ${subject}`,\n `sent_at: ${now.toISOString()}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n writeFileSync(\n join(INBOX_DIR, filename),\n broadcastFrontmatter + content,\n \"utf-8\",\n );\n dbInsertMessage(\n filename,\n broadcastName,\n \"전체\",\n subject,\n \"inbox\",\n Date.now(),\n );\n return { content: [{ type: \"text\", text: `Broadcast sent: ${filename}` }] };\n }\n\n // ── tap_list_unread ───────────────────────────────────────────────\n if (req.params.name === \"tap_list_unread\") {\n const unread = getUnreadItems((req.params.arguments as any) || {});\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n { agent: getAgentName(), count: unread.length, items: unread },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n // ── tap_read_receipt ──────────────────────────────────────────────\n if (req.params.name === \"tap_read_receipt\") {\n const { filename } = req.params.arguments as { filename: string };\n ensureReceiptsDir();\n if (!acquireLock(RECEIPTS_LOCK)) {\n return {\n content: [{ type: \"text\", text: \"Receipt store busy, try again.\" }],\n };\n }\n try {\n const store = loadReceipts();\n if (!store[filename]) store[filename] = [];\n const readerId = getAgentId();\n const already = store[filename].some((r) => r.reader === readerId);\n if (!already) {\n const ts = new Date().toISOString();\n store[filename].push({ reader: readerId, timestamp: ts });\n saveReceipts(store);\n dbInsertReceipt(filename, readerId, ts);\n }\n return {\n content: [\n {\n type: \"text\",\n text: already\n ? `Already acknowledged: ${filename}`\n : `Read receipt saved for: ${filename}`,\n },\n ],\n };\n } finally {\n releaseLock(RECEIPTS_LOCK);\n }\n }\n\n // ── M194: HUD formatter ──────────────────────────────────────────\n function buildHudLine(): string {\n const hbStore = loadHeartbeats();\n const agentCount = buildWhoAgents(hbStore, 10).filter(\n (agent) => agent.alive,\n ).length;\n\n // Unread count — use getUnreadItems with markRead=false for accurate semantics\n // (respects joinedAt, startupFiles, readFiles, isForMe)\n const unreadItems = getUnreadItems({\n sources: [\"inbox\"],\n limit: 100,\n includeContent: false,\n markRead: false,\n });\n // getUnreadItems clamps at 100 — display \"99+\" if at limit\n const unreadCount = unreadItems.length;\n const unreadDisplay = unreadCount >= 100 ? \"99+\" : String(unreadCount);\n\n // Status emoji\n const status = agentCount > 0 ? \"🟢\" : \"⚪\";\n\n return `[tap] ${status} ${agentCount} agents | 📨 ${unreadDisplay} unread`;\n }\n\n // ── tap_stats ─────────────────────────────────────────────────────\n if (req.params.name === \"tap_stats\") {\n const hours =\n typeof (req.params.arguments as any)?.hours === \"number\"\n ? (req.params.arguments as any).hours\n : 24;\n const cutoff = Date.now() - hours * 60 * 60 * 1000;\n\n const hud = buildHudLine();\n\n // DB fast path\n const dbResult = dbGetStats(cutoff);\n if (dbResult) {\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n { hours, ...dbResult, source: \"sqlite\", hud },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n // File fallback\n const sent: Record<string, number> = {};\n const received: Record<string, number> = {};\n let broadcasts = 0;\n if (existsSync(INBOX_DIR)) {\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n try {\n if (statSync(join(INBOX_DIR, filename)).mtimeMs < cutoff) continue;\n } catch {\n continue;\n }\n const parsed = parseFilename(filename);\n if (!parsed) continue;\n sent[parsed.from] = (sent[parsed.from] || 0) + 1;\n if (isBroadcastRecipient(parsed.to)) broadcasts++;\n else received[parsed.to] = (received[parsed.to] || 0) + 1;\n }\n }\n const receipts = loadReceipts();\n const cutoffISO = new Date(cutoff).toISOString();\n const receiptCount = Object.values(receipts).reduce(\n (sum, arr) => sum + arr.filter((r) => r.timestamp >= cutoffISO).length,\n 0,\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n hours,\n sent,\n received,\n broadcasts,\n totalReceipts: receiptCount,\n hud,\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n // ── tap_heartbeat ─────────────────────────────────────────────────\n if (req.params.name === \"tap_heartbeat\") {\n const status =\n ((req.params.arguments as any)?.status as\n | \"active\"\n | \"idle\"\n | \"signing-off\") || \"active\";\n const hbId = getAgentId();\n const hbName = getAgentName();\n if (!acquireLock(HEARTBEATS_LOCK)) {\n return {\n content: [{ type: \"text\", text: \"Heartbeat store busy, try again.\" }],\n };\n }\n try {\n const store = loadHeartbeats();\n const existing = store[hbId];\n const resolvedInstanceId =\n resolveCurrentInstanceId() ?? existing?.instanceId ?? null;\n const connectHash = buildHeartbeatConnectHash(resolvedInstanceId, hbId);\n const preserveBridgeSource =\n existing?.source === \"bridge-dispatch\" &&\n existing.connectHash === connectHash;\n store[hbId] = {\n id: hbId,\n agent: hbName,\n timestamp: new Date().toISOString(),\n lastActivity: getLastActivityTime(),\n joinedAt: existing?.joinedAt,\n status,\n source: preserveBridgeSource ? \"bridge-dispatch\" : \"mcp-direct\",\n instanceId: resolvedInstanceId,\n bridgePid: preserveBridgeSource ? (existing?.bridgePid ?? null) : null,\n connectHash,\n };\n saveHeartbeats(store);\n dbUpsertHeartbeat(hbId, status, getLastActivityTime());\n } finally {\n releaseLock(HEARTBEATS_LOCK);\n }\n\n // M221: Renew claim TTL on heartbeat, release on signing-off\n // Pass ownership (instanceId + pid) to prevent cross-instance interference\n if (hbName && hbName !== \"unknown\") {\n const hbInstanceId = resolveClaimInstanceId();\n if (status === \"signing-off\") {\n releaseClaim(hbName, hbInstanceId, process.pid);\n } else {\n renewClaimTTL(hbName, hbInstanceId, process.pid);\n }\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: `Heartbeat sent: ${hbName} [${hbId}] (${status})`,\n },\n ],\n };\n }\n\n // ── tap_who ───────────────────────────────────────────────────────\n if (req.params.name === \"tap_who\") {\n const minutes =\n typeof (req.params.arguments as any)?.minutes === \"number\"\n ? (req.params.arguments as any).minutes\n : 10;\n const store = loadHeartbeats();\n const agents = buildWhoAgents(store, minutes);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify({ onlineCount: agents.length, agents }, null, 2),\n },\n ],\n };\n }\n\n // ── tap_db_sync ───────────────────────────────────────────────────\n if (req.params.name === \"tap_db_sync\") {\n const result = dbSyncAll();\n if (!result)\n return {\n content: [{ type: \"text\", text: \"SQLite not available. Cannot sync.\" }],\n };\n return {\n content: [\n {\n type: \"text\",\n text: `DB sync complete: ${result.messages} messages, ${result.heartbeats} heartbeats, ${result.receipts} receipts`,\n },\n ],\n };\n }\n\n // ── tap_cleanup ───────────────────────────────────────────────────\n if (req.params.name === \"tap_cleanup\") {\n const days =\n typeof (req.params.arguments as any)?.days === \"number\"\n ? (req.params.arguments as any).days\n : 7;\n const dryRun = (req.params.arguments as any)?.dryRun === true;\n const cutoffDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000);\n const cutoffStr =\n cutoffDate.getFullYear().toString() +\n (cutoffDate.getMonth() + 1).toString().padStart(2, \"0\") +\n cutoffDate.getDate().toString().padStart(2, \"0\");\n const moved: string[] = [];\n if (!existsSync(ARCHIVE_DIR)) mkdirSync(ARCHIVE_DIR, { recursive: true });\n if (existsSync(INBOX_DIR)) {\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n // Parse date from filename: YYYYMMDD-from-to-subject.md\n const dateMatch = filename.match(/^(\\d{8})-/);\n if (!dateMatch) continue;\n if (dateMatch[1] >= cutoffStr) continue; // not old enough\n const filepath = join(INBOX_DIR, filename);\n if (!dryRun) renameSync(filepath, join(ARCHIVE_DIR, filename));\n moved.push(filename);\n }\n }\n return {\n content: [\n {\n type: \"text\",\n text: dryRun\n ? `[DRY RUN] Would archive ${moved.length} files older than ${days} days (filename date).`\n : `Archived ${moved.length} files older than ${days} days to archive/ (filename date).`,\n },\n ],\n };\n }\n\n // ── tap_onboard ──────────────────────────────────────────────────\n if (req.params.name === \"tap_onboard\") {\n const commsDir = process.env.TAP_COMMS_DIR;\n if (!commsDir) {\n return {\n content: [\n {\n type: \"text\",\n text: \"TAP_COMMS_DIR not set. Cannot load onboarding docs.\",\n },\n ],\n };\n }\n\n // Idempotent marker — agent-scoped onboarding tracker\n const stateDir = process.env.TAP_STATE_DIR;\n const agentId = getAgentId();\n let alreadyOnboarded = false;\n let markerStore: Record<string, { onboardedAt: string }> = {};\n const markerPath = stateDir ? join(stateDir, \"onboarded.json\") : null;\n if (markerPath) {\n try {\n if (existsSync(markerPath)) {\n markerStore = JSON.parse(readFileSync(markerPath, \"utf-8\"));\n if (markerStore[agentId]) {\n alreadyOnboarded = true;\n }\n }\n } catch {\n // best-effort\n }\n }\n\n const onboardingDir = join(commsDir, \"onboarding\");\n if (!existsSync(onboardingDir)) {\n return {\n content: [\n {\n type: \"text\",\n text: \"No onboarding directory found at \" + onboardingDir,\n },\n ],\n };\n }\n\n const docs: string[] = [];\n const allFiles = readdirSync(onboardingDir).filter((f: string) =>\n f.endsWith(\".md\"),\n );\n\n // welcome.md always first, then alphabetical\n const files = [\n ...allFiles.filter((f: string) => f === \"welcome.md\"),\n ...allFiles.filter((f: string) => f !== \"welcome.md\").sort(),\n ];\n\n for (const file of files) {\n try {\n const content = readFileSync(join(onboardingDir, file), \"utf-8\");\n docs.push(`# ${file}\\n\\n${content}`);\n } catch {\n docs.push(`# ${file}\\n\\n(failed to read)`);\n }\n }\n\n if (docs.length === 0) {\n return {\n content: [{ type: \"text\", text: \"Onboarding directory is empty.\" }],\n };\n }\n\n // Write agent-scoped onboarded marker\n if (markerPath && !alreadyOnboarded) {\n try {\n markerStore[agentId] = { onboardedAt: new Date().toISOString() };\n writeFileSync(\n markerPath,\n JSON.stringify(markerStore, null, 2),\n \"utf-8\",\n );\n } catch {\n // best-effort\n }\n }\n\n const prefix = alreadyOnboarded\n ? \"(You have already been onboarded. Showing docs again for reference.)\\n\\n\"\n : \"\";\n\n return {\n content: [{ type: \"text\", text: prefix + docs.join(\"\\n\\n---\\n\\n\") }],\n };\n }\n\n throw new Error(`unknown tool: ${req.params.name}`);\n});\n\n// ── Start ───────────────────────────────────────────────────────────────\n\nawait mcp.connect(new StdioServerTransport());\n\n// M221 hotfix: auto-claim bootstrapped name so persisted names are protected\n{\n const { isNameConfirmed, getAgentName: bootName } =\n await import(\"./tap-utils.js\");\n if (isNameConfirmed()) {\n const name = bootName();\n if (name && name !== \"unknown\") {\n const bootInstanceId = resolveClaimInstanceId();\n const bootClaim = claimName(\n name,\n bootInstanceId,\n process.pid,\n \"mcp-direct\",\n );\n if (bootClaim.success) {\n debug(\n `auto-claimed bootstrapped name: ${name} (instance: ${bootInstanceId})`,\n );\n } else {\n // Demote name so tap_set_name can recover with a different name\n const { demoteAgentName } = await import(\"./tap-utils.js\");\n demoteAgentName();\n debug(\n `WARNING: bootstrapped name \"${name}\" claimed by ${bootClaim.conflictWith?.instanceId ?? \"unknown\"} — demoted to unknown, use tap_set_name to pick a new name`,\n );\n }\n }\n }\n}\n\ndebug(`agent id: ${getAgentId()}, name: ${getAgentName()}`);\ndebug(`watching inbox: ${INBOX_DIR}`);\n\nwatchDir(INBOX_DIR, \"inbox\", mcp);\n\nconst latestReviewDir = getLatestReviewDir();\nif (latestReviewDir) {\n debug(`watching reviews: ${latestReviewDir}`);\n watchDir(latestReviewDir, \"reviews\", mcp);\n}\n\n// findings are record-keeping, not real-time comms — no watcher needed.\n// Agents read findings on-demand via tap_list_unread(sources: [\"findings\"]).\n\n// M93: Poll fallback catches messages missed by fs.watch (Windows race, watcher death, etc.)\nimport { startPollFallback } from \"./tap-poll-fallback.js\";\nstartPollFallback(mcp);\n\nprocess.on(\"SIGINT\", () => process.exit(0));\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n unlinkSync,\n readdirSync,\n openSync,\n closeSync,\n renameSync,\n statSync,\n constants,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { COMMS_DIR } from \"./tap-utils.js\";\n\n// ─── Types ─────────────────────────────────────────────────────\n\nexport type HeartbeatSource = \"bridge-dispatch\" | \"mcp-direct\";\n\nexport interface NameClaim {\n name: string;\n claimedBy: {\n instanceId: string;\n sessionPid: number;\n source: HeartbeatSource;\n };\n claimedAt: string;\n nonce: string;\n status: \"confirmed\" | \"released\";\n expiresAt: string | null;\n}\n\nexport interface NameClaimResult {\n success: boolean;\n claim: NameClaim | null;\n conflictWith: {\n instanceId: string;\n alive: boolean;\n lastActivity: string;\n } | null;\n}\n\n// ─── Constants ─────────────────────────────────────────────────\n\nconst CLAIMS_DIR = join(COMMS_DIR, \".claims\");\nconst CLAIM_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\n// ─── Helpers ───────────────────────────────────────────────────\n\nfunction ensureClaimsDir(): void {\n if (!existsSync(CLAIMS_DIR)) {\n mkdirSync(CLAIMS_DIR, { recursive: true });\n }\n}\n\nfunction claimFilePath(name: string): string {\n const safe = name.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n return join(CLAIMS_DIR, `${safe}.json`);\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Build a unique instanceId even when env vars are missing.\n * Falls back to PID-based identity so direct MCP sessions\n * never share the same \"unknown\" instanceId.\n */\nexport function resolveClaimInstanceId(): string {\n const envId = process.env.TAP_BRIDGE_INSTANCE_ID ?? process.env.TAP_AGENT_ID;\n if (envId && envId !== \"unknown\") return envId;\n // No managed identity — use PID to distinguish direct MCP sessions\n return `mcp-direct-${process.pid}`;\n}\n\n/**\n * Atomic create: uses O_EXCL to fail if file already exists.\n * Returns true if file was created, false if it already existed.\n */\nfunction atomicCreate(filePath: string, data: string): boolean {\n try {\n const fd = openSync(\n filePath,\n constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL,\n );\n writeFileSync(fd, data, \"utf-8\");\n closeSync(fd);\n return true;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") return false;\n throw err;\n }\n}\n\nfunction atomicOverwrite(filePath: string, data: string): void {\n const tmp = `${filePath}.tmp.${process.pid}.${Date.now()}`;\n writeFileSync(tmp, data, \"utf-8\");\n try {\n renameSync(tmp, filePath);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n /* best-effort cleanup */\n }\n throw err;\n }\n}\n\n// ─── Core ──────────────────────────────────────────────────────\n\nexport function checkClaim(name: string): NameClaim | null {\n const filePath = claimFilePath(name);\n if (!existsSync(filePath)) return null;\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as NameClaim;\n } catch {\n return null;\n }\n}\n\nexport function isClaimAlive(claim: NameClaim): boolean {\n if (claim.status === \"released\") return false;\n if (claim.expiresAt) {\n if (Date.now() > new Date(claim.expiresAt).getTime()) return false;\n }\n return isProcessAlive(claim.claimedBy.sessionPid);\n}\n\n/**\n * Acquire an exclusive lock file using O_EXCL.\n * Returns true if lock acquired, false if busy.\n * Stale locks (>30s) are force-removed.\n */\nfunction acquireClaimLock(name: string): boolean {\n ensureClaimsDir();\n const lockPath = claimFilePath(name) + \".lock\";\n // Remove stale locks older than 30s\n if (existsSync(lockPath)) {\n try {\n const { mtimeMs } = statSync(lockPath);\n if (Date.now() - mtimeMs > 30_000) {\n unlinkSync(lockPath);\n }\n } catch {\n /* ignore */\n }\n }\n return atomicCreate(lockPath, `${process.pid}\\n`);\n}\n\nfunction releaseClaimLock(name: string): void {\n const lockPath = claimFilePath(name) + \".lock\";\n try {\n unlinkSync(lockPath);\n } catch {\n /* ignore */\n }\n}\n\nexport function claimName(\n name: string,\n instanceId: string,\n pid: number,\n source: HeartbeatSource,\n): NameClaimResult {\n ensureClaimsDir();\n\n // Acquire exclusive lock — serializes all claim operations for this name\n if (!acquireClaimLock(name)) {\n // Lock busy — another process is claiming right now\n return {\n success: false,\n claim: null,\n conflictWith: {\n instanceId: \"lock-busy\",\n alive: true,\n lastActivity: new Date().toISOString(),\n },\n };\n }\n\n try {\n return claimNameLocked(name, instanceId, pid, source);\n } finally {\n releaseClaimLock(name);\n }\n}\n\n/**\n * Claim logic under exclusive lock — no race conditions.\n */\nfunction claimNameLocked(\n name: string,\n instanceId: string,\n pid: number,\n source: HeartbeatSource,\n): NameClaimResult {\n const filePath = claimFilePath(name);\n const claim = createClaim(name, instanceId, pid, source);\n const data = JSON.stringify(claim, null, 2) + \"\\n\";\n\n const existing = checkClaim(name);\n\n // No existing claim → create\n if (!existing) {\n atomicOverwrite(filePath, data);\n return { success: true, claim, conflictWith: null };\n }\n\n // Same instance + same PID → idempotent\n if (\n existing.claimedBy.instanceId === instanceId &&\n existing.claimedBy.sessionPid === pid\n ) {\n return { success: true, claim: existing, conflictWith: null };\n }\n\n // Same instance, different PID → restart reclaim only if previous claim is not alive\n if (existing.claimedBy.instanceId === instanceId) {\n if (isClaimAlive(existing)) {\n // Previous claim still alive (not expired AND PID running) — true conflict\n return {\n success: false,\n claim: null,\n conflictWith: {\n instanceId: existing.claimedBy.instanceId,\n alive: true,\n lastActivity: existing.claimedAt,\n },\n };\n }\n atomicOverwrite(filePath, data);\n return { success: true, claim, conflictWith: null };\n }\n\n // Different instance — check liveness\n if (!isClaimAlive(existing)) {\n // Dead claim — take over\n atomicOverwrite(filePath, data);\n return { success: true, claim, conflictWith: null };\n }\n\n // Alive conflict — reject\n return {\n success: false,\n claim: null,\n conflictWith: {\n instanceId: existing.claimedBy.instanceId,\n alive: true,\n lastActivity: existing.claimedAt,\n },\n };\n}\n\n/**\n * Release claim — under lock, only if caller owns it.\n */\nexport function releaseClaim(\n name: string,\n instanceId?: string,\n pid?: number,\n): boolean {\n if (!acquireClaimLock(name)) return false;\n try {\n return releaseClaimLocked(name, instanceId, pid);\n } finally {\n releaseClaimLock(name);\n }\n}\n\nfunction releaseClaimLocked(\n name: string,\n instanceId?: string,\n pid?: number,\n): boolean {\n const filePath = claimFilePath(name);\n if (!existsSync(filePath)) return false;\n\n if (instanceId || pid) {\n const claim = checkClaim(name);\n if (!claim) return false;\n if (instanceId && claim.claimedBy.instanceId !== instanceId) return false;\n if (pid && claim.claimedBy.sessionPid !== pid) return false;\n }\n\n try {\n unlinkSync(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Renew TTL — under lock, only if caller owns the claim.\n */\nexport function renewClaimTTL(\n name: string,\n instanceId?: string,\n pid?: number,\n): boolean {\n if (!acquireClaimLock(name)) return false;\n try {\n return renewClaimTTLLocked(name, instanceId, pid);\n } finally {\n releaseClaimLock(name);\n }\n}\n\nfunction renewClaimTTLLocked(\n name: string,\n instanceId?: string,\n pid?: number,\n): boolean {\n const claim = checkClaim(name);\n if (!claim || claim.status === \"released\") return false;\n\n if (instanceId && claim.claimedBy.instanceId !== instanceId) return false;\n if (pid && claim.claimedBy.sessionPid !== pid) return false;\n\n claim.expiresAt = new Date(Date.now() + CLAIM_TTL_MS).toISOString();\n const filePath = claimFilePath(name);\n atomicOverwrite(filePath, JSON.stringify(claim, null, 2) + \"\\n\");\n return true;\n}\n\nexport function expireStale(): string[] {\n ensureClaimsDir();\n const expired: string[] = [];\n\n for (const file of readdirSync(CLAIMS_DIR)) {\n if (!file.endsWith(\".json\")) continue;\n const filePath = join(CLAIMS_DIR, file);\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n const claim = JSON.parse(raw) as NameClaim;\n if (!isClaimAlive(claim)) {\n unlinkSync(filePath);\n expired.push(claim.name);\n }\n } catch {\n // Skip corrupted files\n }\n }\n\n return expired;\n}\n\n// ─── Internal ──────────────────────────────────────────────────\n\nfunction createClaim(\n name: string,\n instanceId: string,\n pid: number,\n source: HeartbeatSource,\n): NameClaim {\n return {\n name,\n claimedBy: { instanceId, sessionPid: pid, source },\n claimedAt: new Date().toISOString(),\n nonce: randomUUID(),\n status: \"confirmed\",\n expiresAt: new Date(Date.now() + CLAIM_TTL_MS).toISOString(),\n };\n}\n","/**\n * tap-comms optional SQLite cache layer.\n * Falls back gracefully if bun:sqlite is unavailable.\n */\nimport { existsSync, readFileSync, readdirSync, statSync } from \"fs\";\nimport { join } from \"path\";\nimport {\n DB_PATH,\n INBOX_DIR,\n RECEIPTS_DIR,\n debug,\n parseFilename,\n type ChannelSource,\n} from \"./tap-utils.js\";\n\n// ── DB Instance ─────────────────────────────────────────────────────────\n\n// bun:sqlite type stub — avoids TS2307 when not running in Bun\ninterface BunDatabase {\n exec(sql: string): void;\n run(sql: string, ...args: unknown[]): void;\n prepare(sql: string): {\n run(...args: unknown[]): void;\n all(...args: unknown[]): unknown[];\n get(...args: unknown[]): unknown;\n };\n close(): void;\n}\n\nlet db: BunDatabase | null = null;\n\nexport function getDb() {\n return db;\n}\n\n// ── Init ────────────────────────────────────────────────────────────────\n\nexport function initDb(): boolean {\n try {\n const { Database } = require(\"bun:sqlite\") as {\n Database: new (path: string, opts?: { create?: boolean }) => BunDatabase;\n };\n db = new Database(DB_PATH, { create: true });\n db.exec(\"PRAGMA journal_mode=WAL\");\n db.exec(\"PRAGMA busy_timeout=5000\");\n db.exec(`\n CREATE TABLE IF NOT EXISTS messages (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n filename TEXT UNIQUE NOT NULL,\n from_agent TEXT NOT NULL,\n to_agent TEXT NOT NULL,\n subject TEXT NOT NULL,\n source TEXT NOT NULL DEFAULT 'inbox',\n mtime REAL NOT NULL,\n created_at TEXT DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS idx_messages_to ON messages(to_agent);\n CREATE INDEX IF NOT EXISTS idx_messages_mtime ON messages(mtime);\n CREATE INDEX IF NOT EXISTS idx_messages_from ON messages(from_agent);\n\n CREATE TABLE IF NOT EXISTS heartbeats (\n agent TEXT PRIMARY KEY,\n status TEXT NOT NULL DEFAULT 'active',\n last_activity TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS receipts (\n filename TEXT NOT NULL,\n reader TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n PRIMARY KEY (filename, reader)\n );\n `);\n debug(\"SQLite initialized: \" + DB_PATH);\n return true;\n } catch (err) {\n debug(\"SQLite unavailable, using file-only mode: \" + String(err));\n db = null;\n return false;\n }\n}\n\n// ── Auto Sync ───────────────────────────────────────────────────────────\n\nexport function autoSyncOnStartup() {\n if (!db) return;\n\n try {\n // Sync inbox\n if (existsSync(INBOX_DIR)) {\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n const match = filename.match(/^\\d{8}-(.+?)-(.+?)-(.+)\\.md$/);\n if (!match) continue;\n try {\n const mtime = statSync(join(INBOX_DIR, filename)).mtimeMs;\n db.run(\n \"INSERT OR IGNORE INTO messages (filename, from_agent, to_agent, subject, source, mtime) VALUES (?, ?, ?, ?, ?, ?)\",\n [filename, match[1], match[2], match[3], \"inbox\", mtime],\n );\n } catch {}\n }\n }\n debug(\"auto-sync: inbox files imported into DB\");\n\n // Sync receipts\n const rcptPath = join(RECEIPTS_DIR, \"receipts.json\");\n if (existsSync(rcptPath)) {\n try {\n const rcptStore = JSON.parse(readFileSync(rcptPath, \"utf-8\"));\n for (const [fname, readers] of Object.entries(rcptStore)) {\n for (const r of readers as Array<{\n reader: string;\n timestamp: string;\n }>) {\n db.run(\n \"INSERT OR IGNORE INTO receipts (filename, reader, timestamp) VALUES (?, ?, ?)\",\n [fname, r.reader, r.timestamp],\n );\n }\n }\n debug(\"auto-sync: receipts imported into DB\");\n } catch {}\n }\n } catch {}\n}\n\n// ── Write Helpers ───────────────────────────────────────────────────────\n\nexport function dbInsertMessage(\n filename: string,\n from: string,\n to: string,\n subject: string,\n source: ChannelSource,\n mtimeMs: number,\n) {\n if (!db) return;\n try {\n db.run(\n \"INSERT OR IGNORE INTO messages (filename, from_agent, to_agent, subject, source, mtime) VALUES (?, ?, ?, ?, ?, ?)\",\n [filename, from, to, subject, source, mtimeMs],\n );\n } catch {}\n}\n\nexport function dbUpsertHeartbeat(\n agent: string,\n status: string,\n lastActivity: string,\n) {\n if (!db) return;\n try {\n db.run(\n `INSERT INTO heartbeats (agent, status, last_activity, updated_at)\n VALUES (?, ?, ?, datetime('now'))\n ON CONFLICT(agent) DO UPDATE SET\n status=excluded.status,\n last_activity=excluded.last_activity,\n updated_at=datetime('now')`,\n [agent, status, lastActivity],\n );\n } catch {}\n}\n\nexport function dbInsertReceipt(\n filename: string,\n reader: string,\n timestamp: string,\n) {\n if (!db) return;\n try {\n db.run(\n \"INSERT OR IGNORE INTO receipts (filename, reader, timestamp) VALUES (?, ?, ?)\",\n [filename, reader, timestamp],\n );\n } catch {}\n}\n\n// ── Query Helpers ───────────────────────────────────────────────────────\n\nexport function dbGetStats(cutoff: number): {\n sent: Record<string, number>;\n received: Record<string, number>;\n broadcasts: number;\n totalReceipts: number;\n} | null {\n if (!db) return null;\n try {\n const sentRows = db\n .prepare(\n \"SELECT from_agent, COUNT(*) as cnt FROM messages WHERE mtime >= ? AND source = 'inbox' GROUP BY from_agent\",\n )\n .all(cutoff) as Array<{ from_agent: string; cnt: number }>;\n const receivedRows = db\n .prepare(\n \"SELECT to_agent, COUNT(*) as cnt FROM messages WHERE mtime >= ? AND source = 'inbox' AND to_agent NOT IN ('전체','all') GROUP BY to_agent\",\n )\n .all(cutoff) as Array<{ to_agent: string; cnt: number }>;\n const broadcastRow = db\n .prepare(\n \"SELECT COUNT(*) as cnt FROM messages WHERE mtime >= ? AND source = 'inbox' AND to_agent IN ('전체','all')\",\n )\n .get(cutoff) as { cnt: number } | null;\n const cutoffISO = new Date(cutoff).toISOString();\n const receiptRow = db\n .prepare(\"SELECT COUNT(*) as cnt FROM receipts WHERE timestamp >= ?\")\n .get(cutoffISO) as { cnt: number } | null;\n\n const sent: Record<string, number> = {};\n for (const r of sentRows) sent[r.from_agent] = r.cnt;\n const received: Record<string, number> = {};\n for (const r of receivedRows) received[r.to_agent] = r.cnt;\n\n return {\n sent,\n received,\n broadcasts: broadcastRow?.cnt ?? 0,\n totalReceipts: receiptRow?.cnt ?? 0,\n };\n } catch {\n return null;\n }\n}\n\nexport function dbSyncAll(): {\n messages: number;\n heartbeats: number;\n receipts: number;\n} | null {\n if (!db) return null;\n\n let msgCount = 0;\n let hbCount = 0;\n let rcptCount = 0;\n\n // Sync inbox\n if (existsSync(INBOX_DIR)) {\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n const parsed = parseFilename(filename);\n if (!parsed) continue;\n try {\n const mtime = statSync(join(INBOX_DIR, filename)).mtimeMs;\n dbInsertMessage(\n filename,\n parsed.from,\n parsed.to,\n parsed.subject,\n \"inbox\",\n mtime,\n );\n msgCount++;\n } catch {}\n }\n }\n\n // Sync heartbeats\n try {\n const { loadHeartbeats } = require(\"./tap-io.js\");\n const hbStore = loadHeartbeats();\n for (const [agent, hb] of Object.entries(hbStore) as Array<[string, any]>) {\n dbUpsertHeartbeat(agent, hb.status, hb.lastActivity);\n hbCount++;\n }\n } catch {}\n\n // Sync receipts\n try {\n const { loadReceipts } = require(\"./tap-io.js\");\n const rcptStore = loadReceipts();\n for (const [filename, readers] of Object.entries(rcptStore) as Array<\n [string, any]\n >) {\n for (const r of readers) {\n dbInsertReceipt(filename, r.reader, r.timestamp);\n rcptCount++;\n }\n }\n } catch {}\n\n return { messages: msgCount, heartbeats: hbCount, receipts: rcptCount };\n}\n","/**\n * tap-comms fs.watch watcher: real-time channel push notifications.\n */\nimport { existsSync, readFileSync, statSync, watch, type FSWatcher } from \"fs\";\nimport { join } from \"path\";\nimport type { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n SERVER_START,\n stripBom,\n parseFilename,\n parseFrontmatter,\n isForMe,\n getAgentId,\n getAgentName,\n getSourceKey,\n debug,\n type ChannelSource,\n} from \"./tap-utils.js\";\nimport { dbInsertMessage } from \"./tap-db.js\";\nimport { readFiles, resolveAgentLabel } from \"./tap-io.js\";\nimport { isOwnMessageAddress } from \"./tap-identity.js\";\n\n// ── State ───────────────────────────────────────────────────────────────\n\nconst notifiedFiles = new Set<string>();\nconst recentEvents = new Map<string, number>();\nconst inFlightFiles = new Set<string>();\nconst DEBOUNCE_MS = 200;\nconst MAX_READY_ATTEMPTS = 6;\nconst READY_RETRY_MS = 40;\nconst WATCH_RESTART_MS = 1_000;\nconst RECENT_EVENT_TTL_MS = 5 * 60 * 1000;\nconst RECENT_EVENT_CLEANUP_MS = 60 * 1000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetryableFsError(error: unknown): boolean {\n const code =\n error && typeof error === \"object\" && \"code\" in error\n ? String((error as NodeJS.ErrnoException).code ?? \"\")\n : \"\";\n return (\n code === \"ENOENT\" ||\n code === \"EBUSY\" ||\n code === \"EPERM\" ||\n code === \"EACCES\"\n );\n}\n\nasync function waitForFileReady(\n filepath: string,\n): Promise<{ content: string; mtime: number } | \"stale\" | null> {\n for (let attempt = 0; attempt < MAX_READY_ATTEMPTS; attempt++) {\n try {\n const mtime = statSync(filepath).mtimeMs;\n if (mtime < SERVER_START - 5000) return \"stale\";\n const content = stripBom(readFileSync(filepath, \"utf-8\"));\n return { content, mtime };\n } catch (error) {\n if (attempt === MAX_READY_ATTEMPTS - 1 || !isRetryableFsError(error)) {\n debug(\n `watch read failed [${filepath}]: ${error instanceof Error ? error.message : String(error)}`,\n );\n return null;\n }\n await sleep(READY_RETRY_MS * (attempt + 1));\n }\n }\n\n return null;\n}\n\nfunction isOwnMessageArtifact(\n source: ChannelSource,\n filename: string,\n parsed: ReturnType<typeof parseFilename>,\n): boolean {\n const agentId = getAgentId();\n const agentName = getAgentName();\n\n if (parsed && isOwnMessageAddress(parsed.from, agentId, agentName)) {\n return true;\n }\n\n if (source === \"reviews\") {\n return (\n filename.endsWith(`-${agentId}.md`) ||\n filename.endsWith(`-${agentName}.md`)\n );\n }\n\n return false;\n}\n\nfunction cleanupRecentEvents(now: number = Date.now()) {\n const cutoff = now - RECENT_EVENT_TTL_MS;\n for (const [key, ts] of recentEvents) {\n if (ts < cutoff) recentEvents.delete(key);\n }\n}\n\nconst recentEventsCleanupTimer = setInterval(() => {\n cleanupRecentEvents();\n}, RECENT_EVENT_CLEANUP_MS);\nrecentEventsCleanupTimer.unref?.();\n\n// @internal test helper\nexport function resetWatcherStateForTests() {\n notifiedFiles.clear();\n recentEvents.clear();\n inFlightFiles.clear();\n}\n\n// @internal test helper\nexport async function processWatchFile(\n dir: string,\n source: ChannelSource,\n filename: string,\n mcp: Pick<Server, \"notification\">,\n): Promise<boolean> {\n const key = getSourceKey(source, filename);\n // Skip if already notified (watcher), in-flight, or read via tap_list_unread\n if (notifiedFiles.has(key) || inFlightFiles.has(key) || readFiles.has(key))\n return false;\n\n inFlightFiles.add(key);\n\n try {\n const filepath = join(dir, filename);\n const file = await waitForFileReady(filepath);\n if (file === \"stale\") {\n notifiedFiles.add(key);\n return false;\n }\n if (!file) return false;\n\n // M204: Frontmatter-first routing (matches tap-io getUnreadItems)\n let parsed: ReturnType<typeof parseFilename> = null;\n if (source === \"inbox\") {\n const fm = parseFrontmatter(file.content);\n parsed = fm\n ? { from: fm.from, to: fm.to, subject: fm.subject }\n : parseFilename(filename);\n } else {\n parsed = parseFilename(filename);\n }\n\n if (source === \"inbox\" && (!parsed || !isForMe(parsed.to))) return false;\n if (isOwnMessageArtifact(source, filename, parsed)) return false;\n\n const rawFrom = parsed?.from || source;\n const rawTo = parsed?.to || \"all\";\n const from = parsed ? resolveAgentLabel(parsed.from) : source;\n const to = parsed ? resolveAgentLabel(parsed.to) : \"all\";\n const subject = parsed?.subject || filename.replace(/\\.md$/, \"\");\n\n dbInsertMessage(filename, rawFrom, rawTo, subject, source, Date.now());\n debug(`sending notification [${source}]: from=${from} to=${to}`);\n await mcp.notification({\n method: \"notifications/claude/channel\",\n params: {\n content: file.content,\n meta: { from, to, subject, filename, source },\n },\n });\n notifiedFiles.add(key);\n return true;\n } finally {\n inFlightFiles.delete(key);\n }\n}\n\n// ── Watch ───────────────────────────────────────────────────────────────\n\nexport function watchDir(dir: string, source: ChannelSource, mcp: Server) {\n if (!existsSync(dir)) return;\n\n let watcher: FSWatcher | null = null;\n let restartTimer: NodeJS.Timeout | null = null;\n\n const scheduleRestart = (reason: string) => {\n if (restartTimer) return;\n debug(`fs.watch restart scheduled [${source}]: ${reason}`);\n restartTimer = setTimeout(() => {\n restartTimer = null;\n if (!existsSync(dir)) {\n debug(`fs.watch restart skipped [${source}]: missing ${dir}`);\n return;\n }\n startWatcher();\n }, WATCH_RESTART_MS);\n restartTimer.unref();\n };\n\n const disposeWatcher = () => {\n if (!watcher) return;\n watcher.removeAllListeners();\n try {\n watcher.close();\n } catch {\n // Best-effort cleanup only.\n }\n watcher = null;\n };\n\n const startWatcher = () => {\n disposeWatcher();\n\n try {\n watcher = watch(dir, (eventType, filename) => {\n debug(`fs.watch [${source}]: ${eventType} ${filename}`);\n if (!filename || !filename.endsWith(\".md\")) return;\n\n const key = getSourceKey(source, filename);\n const now = Date.now();\n cleanupRecentEvents(now);\n const lastSeen = recentEvents.get(key);\n if (lastSeen && now - lastSeen < DEBOUNCE_MS) return;\n recentEvents.set(key, now);\n\n void processWatchFile(dir, source, filename, mcp).catch((error) => {\n debug(\n `watch processing failed [${source}/${filename}]: ${error instanceof Error ? error.message : String(error)}`,\n );\n });\n });\n\n watcher.on(\"error\", (error) => {\n debug(\n `fs.watch error [${source}]: ${error instanceof Error ? error.message : String(error)}`,\n );\n scheduleRestart(\"error\");\n });\n\n watcher.on(\"close\", () => {\n debug(`fs.watch closed [${source}]`);\n scheduleRestart(\"close\");\n });\n\n debug(`fs.watch active [${source}]: ${dir}`);\n } catch (error) {\n debug(\n `fs.watch start failed [${source}]: ${error instanceof Error ? error.message : String(error)}`,\n );\n scheduleRestart(\"start-failed\");\n }\n };\n\n startWatcher();\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n buildHeartbeatConnectHash,\n resolveKnownInstanceId,\n type Heartbeat,\n type HeartbeatSource,\n} from \"./tap-utils.js\";\n\ntype BridgeStateFile = {\n pid?: number;\n runtimeStateDir?: string | null;\n};\n\ntype RuntimeHeartbeat = {\n connected?: boolean;\n initialized?: boolean;\n threadId?: string | null;\n activeTurnId?: string | null;\n idleSince?: string | null;\n turnState?: \"active\" | \"idle\" | \"waiting-approval\" | \"disconnected\" | null;\n};\n\ntype RuntimeThreadState = {\n threadId?: string | null;\n};\n\nexport interface TapWhoAgent {\n id: string;\n agent: string;\n status: string;\n lastHeartbeat: string;\n lastActivity: string;\n alive: boolean;\n source: HeartbeatSource;\n instanceId: string | null;\n connectHash: string;\n presence: \"bridge-live\" | \"bridge-stale\" | \"mcp-only\";\n lifecycle:\n | \"ready\"\n | \"initializing\"\n | \"degraded-no-thread\"\n | \"bridge-stale\"\n | null;\n session:\n | \"initializing\"\n | \"active\"\n | \"idle\"\n | \"waiting-approval\"\n | \"disconnected\"\n | null;\n idleSeconds: number | null;\n}\n\ntype TapPresenceCandidate = TapWhoAgent & {\n displayName: string | null;\n lastActivityMs: number;\n};\n\nexport interface TapRecipientResolution {\n target: string;\n found: boolean;\n ambiguous: boolean;\n candidates: string[];\n warning: string | null;\n}\n\nfunction parseJsonFile<T>(filePath: string): T | null {\n if (!existsSync(filePath)) return null;\n try {\n return JSON.parse(readFileSync(filePath, \"utf-8\")) as T;\n } catch {\n return null;\n }\n}\n\nfunction formatAgentLabel(\n agentIdOrName: string,\n displayName?: string | null,\n): string {\n const normalizedId = agentIdOrName.trim();\n const normalizedName = displayName?.trim();\n\n if (!normalizedId) {\n return normalizedName ?? agentIdOrName;\n }\n\n if (!normalizedName || normalizedName === normalizedId) {\n return normalizedId;\n }\n\n return `${normalizedName} [${normalizedId}]`;\n}\n\nfunction isProcessAlive(pid: number | null | undefined): boolean {\n if (pid == null || !Number.isFinite(pid)) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction parseIsoAgeSeconds(value: string | null | undefined): number | null {\n if (!value) return null;\n const timestamp = new Date(value).getTime();\n if (Number.isNaN(timestamp)) return null;\n return Math.max(0, Math.floor((Date.now() - timestamp) / 1000));\n}\n\nfunction getActivityMs(heartbeat: Heartbeat): number {\n return new Date(heartbeat.lastActivity ?? heartbeat.timestamp ?? 0).getTime();\n}\n\nfunction resolveHeartbeatSource(heartbeat: Heartbeat): HeartbeatSource {\n return heartbeat.source === \"bridge-dispatch\" ? \"bridge-dispatch\" : \"mcp-direct\";\n}\n\nfunction resolveBridgeStatus(\n stateDir: string,\n instanceId: string | null,\n): {\n presence: \"bridge-live\" | \"bridge-stale\" | \"mcp-only\";\n lifecycle:\n | \"ready\"\n | \"initializing\"\n | \"degraded-no-thread\"\n | \"bridge-stale\"\n | null;\n session:\n | \"initializing\"\n | \"active\"\n | \"idle\"\n | \"waiting-approval\"\n | \"disconnected\"\n | null;\n idleSince: string | null;\n} {\n if (!instanceId) {\n return {\n presence: \"mcp-only\",\n lifecycle: null,\n session: null,\n idleSince: null,\n };\n }\n\n const bridgeState = parseJsonFile<BridgeStateFile>(\n join(stateDir, \"pids\", `bridge-${instanceId}.json`),\n );\n if (!bridgeState) {\n return {\n presence: \"mcp-only\",\n lifecycle: null,\n session: null,\n idleSince: null,\n };\n }\n\n if (!isProcessAlive(bridgeState.pid)) {\n return {\n presence: \"bridge-stale\",\n lifecycle: \"bridge-stale\",\n session: null,\n idleSince: null,\n };\n }\n\n const runtimeHeartbeat = bridgeState.runtimeStateDir\n ? parseJsonFile<RuntimeHeartbeat>(\n join(bridgeState.runtimeStateDir, \"heartbeat.json\"),\n )\n : null;\n const savedThread = bridgeState.runtimeStateDir\n ? parseJsonFile<RuntimeThreadState>(\n join(bridgeState.runtimeStateDir, \"thread.json\"),\n )\n : null;\n\n if (!runtimeHeartbeat || runtimeHeartbeat.initialized === false) {\n return {\n presence: \"bridge-live\",\n lifecycle: \"initializing\",\n session: \"initializing\",\n idleSince: null,\n };\n }\n\n const lifecycle =\n runtimeHeartbeat.threadId && runtimeHeartbeat.connected !== false\n ? \"ready\"\n : \"degraded-no-thread\";\n\n const session =\n runtimeHeartbeat.activeTurnId || runtimeHeartbeat.turnState === \"active\"\n ? \"active\"\n : runtimeHeartbeat.turnState === \"waiting-approval\"\n ? \"waiting-approval\"\n : runtimeHeartbeat.turnState === \"disconnected\" ||\n runtimeHeartbeat.connected === false\n ? \"disconnected\"\n : \"idle\";\n\n const idleSince =\n session === \"idle\" || session === \"waiting-approval\"\n ? (runtimeHeartbeat.idleSince ?? null)\n : null;\n\n return {\n presence: \"bridge-live\",\n lifecycle:\n lifecycle === \"degraded-no-thread\" && !savedThread?.threadId\n ? \"degraded-no-thread\"\n : lifecycle,\n session,\n idleSince,\n };\n}\n\nconst PRESENCE_PRIORITY: Record<TapWhoAgent[\"presence\"], number> = {\n \"bridge-live\": 3,\n \"mcp-only\": 2,\n \"bridge-stale\": 1,\n};\n\nconst SOURCE_PRIORITY: Record<HeartbeatSource, number> = {\n \"bridge-dispatch\": 2,\n \"mcp-direct\": 1,\n};\n\nfunction compareCandidates(a: TapPresenceCandidate, b: TapPresenceCandidate): number {\n const presenceDelta = PRESENCE_PRIORITY[b.presence] - PRESENCE_PRIORITY[a.presence];\n if (presenceDelta !== 0) return presenceDelta;\n\n const sourceDelta = SOURCE_PRIORITY[b.source] - SOURCE_PRIORITY[a.source];\n if (sourceDelta !== 0) return sourceDelta;\n\n if (a.alive !== b.alive) return a.alive ? -1 : 1;\n if (a.lastActivityMs !== b.lastActivityMs) {\n return b.lastActivityMs - a.lastActivityMs;\n }\n return a.id.localeCompare(b.id);\n}\n\nfunction dedupeByConnectHash(\n candidates: TapPresenceCandidate[],\n): TapPresenceCandidate[] {\n const deduped = new Map<string, TapPresenceCandidate>();\n for (const candidate of candidates) {\n const existing = deduped.get(candidate.connectHash);\n if (!existing || compareCandidates(candidate, existing) < 0) {\n deduped.set(candidate.connectHash, candidate);\n }\n }\n return [...deduped.values()].sort(compareCandidates);\n}\n\nexport function buildPresenceCandidates(\n store: Record<string, Heartbeat>,\n minutes?: number | null,\n): TapPresenceCandidate[] {\n const cutoff = minutes == null ? null : Date.now() - minutes * 60 * 1000;\n const stateDir = process.env.TAP_STATE_DIR;\n const agents: TapPresenceCandidate[] = [];\n\n for (const [agentId, heartbeat] of Object.entries(store)) {\n if (!heartbeat.id) continue;\n\n const lastActivityMs = getActivityMs(heartbeat);\n if (!Number.isFinite(lastActivityMs)) continue;\n if (cutoff != null && lastActivityMs < cutoff) continue;\n\n const displayName = heartbeat.agent ?? null;\n const instanceId =\n heartbeat.instanceId ?? resolveKnownInstanceId(agentId, displayName);\n const source = resolveHeartbeatSource(heartbeat);\n const connectHash =\n heartbeat.connectHash ?? buildHeartbeatConnectHash(instanceId, agentId);\n const bridge =\n stateDir != null\n ? resolveBridgeStatus(stateDir, instanceId)\n : {\n presence: \"mcp-only\" as const,\n lifecycle: null,\n session: null,\n idleSince: null,\n };\n const idleBasis =\n bridge.idleSince ??\n heartbeat.lastActivity ??\n heartbeat.timestamp ??\n null;\n\n agents.push({\n id: agentId,\n agent: formatAgentLabel(agentId, displayName),\n status: heartbeat.status ?? \"active\",\n lastHeartbeat: heartbeat.timestamp ?? \"\",\n lastActivity: heartbeat.lastActivity ?? heartbeat.timestamp ?? \"\",\n alive: heartbeat.status !== \"signing-off\",\n source,\n instanceId,\n connectHash,\n presence: bridge.presence,\n lifecycle: bridge.lifecycle,\n session: bridge.session,\n idleSeconds: parseIsoAgeSeconds(idleBasis),\n displayName,\n lastActivityMs,\n });\n }\n\n return agents.sort(compareCandidates);\n}\n\nexport function buildWhoAgents(\n store: Record<string, Heartbeat>,\n minutes: number,\n): TapWhoAgent[] {\n return dedupeByConnectHash(buildPresenceCandidates(store, minutes));\n}\n\nexport function resolvePreferredRecipient(\n store: Record<string, Heartbeat>,\n recipient: string,\n): TapRecipientResolution {\n const allCandidates = buildPresenceCandidates(store, null);\n const exactId = allCandidates.find((candidate) => candidate.id === recipient);\n if (exactId) {\n return {\n target: exactId.id,\n found: true,\n ambiguous: false,\n candidates: [exactId.id],\n warning: null,\n };\n }\n\n const deduped = dedupeByConnectHash(allCandidates);\n const nameMatches = deduped.filter(\n (candidate) => candidate.displayName === recipient,\n );\n if (nameMatches.length === 1) {\n return {\n target: nameMatches[0].id,\n found: true,\n ambiguous: false,\n candidates: [nameMatches[0].id],\n warning: null,\n };\n }\n\n if (nameMatches.length > 1) {\n const sorted = [...nameMatches].sort(compareCandidates);\n const winner = sorted[0];\n const candidateIds = sorted.map((candidate) => candidate.id);\n return {\n target: winner.id,\n found: true,\n ambiguous: true,\n candidates: candidateIds,\n warning:\n `⚠️ Routed \"${recipient}\" → \"${winner.id}\" ` +\n `(${winner.presence}/${winner.source}, preferred of ${candidateIds.join(\", \")}).`,\n };\n }\n\n return {\n target: recipient,\n found: false,\n ambiguous: false,\n candidates: [],\n warning: null,\n };\n}\n\n/**\n * Build a Map<heartbeatKey, PresenceLevel> for routing disambiguation.\n * Unlike buildWhoAgents, returns raw key→presence without label formatting.\n */\nexport function resolvePresenceMap(\n store: Record<string, Heartbeat>,\n): Map<string, \"bridge-live\" | \"bridge-stale\" | \"mcp-only\"> {\n const result = new Map<string, \"bridge-live\" | \"bridge-stale\" | \"mcp-only\">();\n\n for (const candidate of buildPresenceCandidates(store, null)) {\n result.set(candidate.id, candidate.presence);\n }\n\n return result;\n}\n","/**\n * tap-comms polling fallback: catches messages missed by fs.watch push.\n *\n * Runs periodically alongside the watcher. Scans inbox/reviews for files\n * that arrived after server start but were never pushed via channel\n * notification (e.g. due to fs.watch missing events on Windows).\n *\n * M93: Auto-poll fallback for push reliability.\n */\nimport { existsSync, readdirSync, statSync } from \"fs\";\nimport type { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n SERVER_START,\n getSourceDir,\n debug,\n type ChannelSource,\n} from \"./tap-utils.js\";\nimport { processWatchFile } from \"./tap-watcher.js\";\n\n// ── Config ──────────────────────────────────────────────────────────────\n\n// Windows fs.watch is unreliable for cross-process file creation; poll faster.\nconst POLL_INTERVAL_MS = process.platform === \"win32\" ? 10_000 : 30_000;\nconst POLL_SOURCES: ChannelSource[] = [\"inbox\", \"reviews\"];\n\n// ── Stats ───────────────────────────────────────────────────────────────\n\nlet recoveredCount = 0;\nlet pollCycles = 0;\n\nexport function getPollStats() {\n return { pollCycles, recoveredCount };\n}\n\n// ── Poll ────────────────────────────────────────────────────────────────\n\nasync function pollOnce(mcp: Server): Promise<number> {\n let recovered = 0;\n\n for (const source of POLL_SOURCES) {\n const dir = getSourceDir(source);\n if (!dir || !existsSync(dir)) continue;\n\n let filenames: string[];\n try {\n filenames = readdirSync(dir).filter((f) => f.endsWith(\".md\"));\n } catch {\n continue;\n }\n\n for (const filename of filenames) {\n // Quick pre-filter: only check files newer than server start\n const filepath = `${dir}/${filename}`;\n try {\n const mtime = statSync(filepath).mtimeMs;\n if (mtime < SERVER_START - 5000) continue;\n } catch {\n continue;\n }\n\n // processWatchFile handles notifiedFiles/inFlightFiles dedup internally.\n // If already notified, it returns false immediately (cheap).\n try {\n const sent = await processWatchFile(dir, source, filename, mcp);\n if (sent) {\n recovered++;\n debug(`poll-fallback recovered [${source}]: ${filename}`);\n }\n } catch {\n // Non-critical — skip this file\n }\n }\n }\n\n return recovered;\n}\n\n// ── Start ───────────────────────────────────────────────────────────────\n\nexport function startPollFallback(mcp: Server) {\n debug(`poll-fallback: starting (interval=${POLL_INTERVAL_MS}ms)`);\n\n const timer = setInterval(async () => {\n pollCycles++;\n try {\n const count = await pollOnce(mcp);\n if (count > 0) {\n recoveredCount += count;\n debug(\n `poll-fallback: recovered ${count} missed message(s) (total: ${recoveredCount})`,\n );\n }\n } catch (error) {\n debug(\n `poll-fallback error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }, POLL_INTERVAL_MS);\n timer.unref();\n\n // Run first poll after a short delay (let watcher settle first)\n setTimeout(async () => {\n pollCycles++;\n try {\n const count = await pollOnce(mcp);\n if (count > 0) {\n recoveredCount += count;\n debug(`poll-fallback (initial): recovered ${count} missed message(s)`);\n }\n } catch {\n // Non-critical\n }\n }, 5_000).unref();\n}\n"],"mappings":"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","names":["canonicalizeAgentId","instance","stateBootstrap","existsSync","mkdirSync","readFileSync","readdirSync","renameSync","statSync","unlinkSync","writeFileSync","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","existsSync","readFileSync","readdirSync","statSync","join","existsSync","readFileSync","readdirSync","statSync","join","existsSync","readdirSync","statSync","join","readFileSync","loadHeartbeats","loadReceipts","existsSync","readFileSync","statSync","join","resolve","statSync","readFileSync","mcp","join","existsSync","existsSync","readFileSync","join","formatAgentLabel","isProcessAlive","readdirSync","renameSync","statSync","unlinkSync","existsSync","readdirSync","statSync","mcp","existsSync","readdirSync","statSync","join","existsSync","readFileSync","mkdirSync","writeFileSync","currentName","renameSync","unlinkSync","resolveRecipient","readdirSync","statSync","isNameConfirmed","demoteAgentName"]}
1
+ {"version":3,"sources":["../packages/tap-plugin/channels/tap-identity.ts","../packages/tap-plugin/channels/tap-utils.ts","../packages/tap-plugin/channels/tap-io.ts","../packages/tap-plugin/channels/tap-comms.ts","../packages/tap-plugin/channels/tap-peer-dm-rate-limit.ts","../packages/tap-plugin/channels/tap-claims.ts","../packages/tap-plugin/channels/tap-db.ts","../packages/tap-plugin/channels/tap-watcher.ts","../packages/tap-plugin/channels/tap-presence.ts","../packages/tap-plugin/channels/tap-poll-fallback.ts"],"sourcesContent":["const BROADCAST_RECIPIENTS = new Set([\"전체\", \"all\"]);\n\nexport const PLACEHOLDER_AGENT_VALUES = new Set([\n \"unknown\",\n \"unnamed\",\n \"<set-per-session>\",\n]);\n\nfunction trimAddress(value?: string | null): string {\n return value?.trim() ?? \"\";\n}\n\nexport function canonicalizeAgentId(value: string): string {\n return trimAddress(value).replace(/-/g, \"_\");\n}\n\nexport function isBroadcastRecipient(value: string): boolean {\n return BROADCAST_RECIPIENTS.has(trimAddress(value));\n}\n\nexport function isPlaceholderAgentValue(value?: string | null): boolean {\n const normalized = trimAddress(value);\n return !normalized || PLACEHOLDER_AGENT_VALUES.has(normalized);\n}\n\nexport function sameRoutingAddress(left: string, right: string): boolean {\n const normalizedLeft = trimAddress(left);\n const normalizedRight = trimAddress(right);\n if (!normalizedLeft || !normalizedRight) {\n return false;\n }\n\n if (\n isBroadcastRecipient(normalizedLeft) &&\n isBroadcastRecipient(normalizedRight)\n ) {\n return true;\n }\n\n return (\n normalizedLeft === normalizedRight ||\n canonicalizeAgentId(normalizedLeft) === canonicalizeAgentId(normalizedRight)\n );\n}\n\nexport function matchesAgentRecipient(\n recipient: string,\n agentId: string,\n agentName: string,\n): boolean {\n const normalizedRecipient = trimAddress(recipient);\n if (!normalizedRecipient) {\n return false;\n }\n\n return (\n isBroadcastRecipient(normalizedRecipient) ||\n sameRoutingAddress(normalizedRecipient, agentId) ||\n normalizedRecipient === trimAddress(agentName)\n );\n}\n\nexport function isOwnMessageAddress(\n sender: string,\n agentId: string,\n agentName: string,\n): boolean {\n const normalizedSender = trimAddress(sender);\n if (!normalizedSender) {\n return false;\n }\n\n return (\n sameRoutingAddress(normalizedSender, agentId) ||\n normalizedSender === trimAddress(agentName)\n );\n}\n\nexport function normalizeRecipientList(\n rawRecipients: unknown,\n exclude: string[] = [],\n): string[] | undefined {\n let recipients: string[] | undefined;\n if (rawRecipients == null) {\n recipients = undefined;\n } else if (typeof rawRecipients === \"string\") {\n const trimmed = trimAddress(rawRecipients);\n recipients = trimmed ? [trimmed] : undefined;\n } else if (Array.isArray(rawRecipients)) {\n const valid = rawRecipients\n .filter(\n (value): value is string =>\n typeof value === \"string\" && trimAddress(value).length > 0,\n )\n .map((value) => trimAddress(value));\n recipients = valid.length > 0 ? valid : undefined;\n } else {\n recipients = undefined;\n }\n\n if (!recipients) {\n return undefined;\n }\n\n const filtered: string[] = [];\n for (const recipient of recipients) {\n if (exclude.some((value) => sameRoutingAddress(value, recipient))) {\n continue;\n }\n if (filtered.some((value) => sameRoutingAddress(value, recipient))) {\n continue;\n }\n filtered.push(recipient);\n }\n\n return filtered.length > 0 ? filtered : undefined;\n}\n","/**\n * tap-comms shared utilities: types, config, parsing, helpers.\n */\nimport { existsSync, readFileSync, readdirSync, statSync } from \"fs\";\nimport { basename, join, resolve } from \"path\";\nimport {\n canonicalizeAgentId as canonicalizeIdentityId,\n isPlaceholderAgentValue,\n matchesAgentRecipient,\n} from \"./tap-identity.js\";\n\n// ── Config ──────────────────────────────────────────────────────────────\n\nconst RAW_COMMS_DIR = process.env.TAP_COMMS_DIR;\nif (!RAW_COMMS_DIR) {\n console.error(\n \"[tap-comms] FATAL: TAP_COMMS_DIR not set. Set via env or .tap-config\",\n );\n process.exit(1);\n}\n\nexport const COMMS_DIR = resolve(RAW_COMMS_DIR);\nexport const INBOX_DIR = join(COMMS_DIR, \"inbox\");\nexport const REVIEWS_DIR = join(COMMS_DIR, \"reviews\");\nexport const FINDINGS_DIR = join(COMMS_DIR, \"findings\");\nexport const RECEIPTS_DIR = join(COMMS_DIR, \"receipts\");\nexport const RECEIPTS_PATH = join(RECEIPTS_DIR, \"receipts.json\");\nexport const RECEIPTS_LOCK = join(RECEIPTS_DIR, \".lock\");\nexport const HEARTBEATS_PATH = join(COMMS_DIR, \"heartbeats.json\");\nexport const HEARTBEATS_LOCK = join(COMMS_DIR, \".heartbeats.lock\");\nexport const ARCHIVE_DIR = join(COMMS_DIR, \"archive\");\nexport const DB_PATH = join(COMMS_DIR, \"tap.db\");\nexport const SERVER_START = Date.now();\n\n// ── Agent Identity ──────────────────────────────────────────────────────\n// id = immutable routing key (set once at startup or first tap_set_name)\n// name = session display label. Once a real name is confirmed, only\n// idempotent tap_set_name calls are allowed until an explicit rename flow exists.\n\nexport type TapBootstrapInstance = {\n runtime?: string;\n installed?: boolean;\n agentName?: string | null;\n bridgeMode?: string;\n};\n\nfunction isConcreteIdentity(value: string | undefined): value is string {\n return !isPlaceholderAgentValue(value);\n}\n\nfunction normalizeAgentId(value: string): string {\n return canonicalizeIdentityId(value);\n}\n\nexport function loadStateInstances(): Record<string, TapBootstrapInstance> | null {\n const stateDir = process.env.TAP_STATE_DIR;\n if (!stateDir) return null;\n try {\n const statePath = join(stateDir, \"state.json\");\n if (!existsSync(statePath)) return null;\n const state = JSON.parse(readFileSync(statePath, \"utf-8\")) as {\n instances?: Record<string, TapBootstrapInstance>;\n };\n return state.instances ?? null;\n } catch {\n return null;\n }\n}\n\ntype StateBootstrapIdentity = {\n agentId: string;\n agentName: string | null;\n};\n\nconst BRIDGE_RUNTIME_STATE_DIR_PREFIX = \"codex-app-server-bridge-\";\n\nexport type AgentIdentitySnapshot = {\n agentId: string;\n agentName: string;\n idLocked: boolean;\n nameConfirmed: boolean;\n runtimeEnv: {\n bridgeInstanceId: string | null;\n agentId: string | null;\n agentName: string | null;\n codexTapAgentName: string | null;\n commsDir: string | null;\n stateDir: string | null;\n runtimeStateDir: string | null;\n repoRoot: string | null;\n };\n bootstrap: StateBootstrapIdentity | null;\n resolvedCurrentInstanceId: string | null;\n};\n\nfunction resolveSingleCodexBootstrap(): StateBootstrapIdentity | null {\n const instances = loadStateInstances();\n if (!instances) return null;\n\n const installedCodexInstances = Object.entries(instances).filter(\n ([, instance]) => instance?.runtime === \"codex\" && instance?.installed,\n );\n if (installedCodexInstances.length !== 1) return null;\n\n const [instanceId, instance] = installedCodexInstances[0];\n return {\n agentId: normalizeAgentId(instanceId),\n agentName:\n typeof instance.agentName === \"string\" &&\n !isPlaceholderAgentValue(instance.agentName)\n ? instance.agentName\n : null,\n };\n}\n\nfunction resolveRuntimeInstanceId(): string | null {\n const bridgeInstanceId = process.env.TAP_BRIDGE_INSTANCE_ID;\n if (isConcreteIdentity(bridgeInstanceId)) {\n return normalizeAgentId(bridgeInstanceId);\n }\n const envId = process.env.TAP_AGENT_ID;\n if (isConcreteIdentity(envId)) {\n return normalizeAgentId(envId);\n }\n return null;\n}\n\nfunction resolveRuntimeStateDir(): string | null {\n const runtimeStateDir = process.env.TAP_RUNTIME_STATE_DIR;\n if (!runtimeStateDir) return null;\n return resolve(runtimeStateDir);\n}\n\nfunction resolveRuntimeStateInstanceId(): string | null {\n const runtimeStateDir = resolveRuntimeStateDir();\n if (!runtimeStateDir) return null;\n\n const dirName = basename(runtimeStateDir);\n if (!dirName.startsWith(BRIDGE_RUNTIME_STATE_DIR_PREFIX)) {\n return null;\n }\n\n const instanceId = dirName\n .slice(BRIDGE_RUNTIME_STATE_DIR_PREFIX.length)\n .trim();\n if (!instanceId) return null;\n return normalizeAgentId(instanceId);\n}\n\nfunction resolveRuntimeStateDisplayName(): string | null {\n const runtimeStateDir = resolveRuntimeStateDir();\n if (!runtimeStateDir) return null;\n\n try {\n const heartbeatPath = join(runtimeStateDir, \"heartbeat.json\");\n if (existsSync(heartbeatPath)) {\n const heartbeat = JSON.parse(readFileSync(heartbeatPath, \"utf-8\")) as {\n agent?: string | null;\n };\n const heartbeatAgent = heartbeat.agent ?? undefined;\n if (isConcreteIdentity(heartbeatAgent)) {\n return heartbeatAgent;\n }\n }\n } catch {\n // Fall through to the persisted agent-name hint below.\n }\n\n try {\n const agentNamePath = join(runtimeStateDir, \"agent-name.txt\");\n if (!existsSync(agentNamePath)) return null;\n const agentName = readFileSync(agentNamePath, \"utf-8\").trim();\n return isConcreteIdentity(agentName) ? agentName : null;\n } catch {\n return null;\n }\n}\n\nfunction resolveRuntimeDisplayName(): string | null {\n const envName = process.env.TAP_AGENT_NAME;\n if (isConcreteIdentity(envName)) return envName;\n const codexName = process.env.CODEX_TAP_AGENT_NAME;\n if (isConcreteIdentity(codexName)) return codexName;\n const runtimeName = resolveRuntimeStateDisplayName();\n if (runtimeName) return runtimeName;\n return null;\n}\n\nfunction resolveInitialId(\n stateBootstrap: StateBootstrapIdentity | null,\n): string {\n const runtimeInstanceId = resolveRuntimeInstanceId();\n if (runtimeInstanceId) return runtimeInstanceId;\n const runtimeStateInstanceId = resolveRuntimeStateInstanceId();\n if (runtimeStateInstanceId) return runtimeStateInstanceId;\n const envName = process.env.TAP_AGENT_NAME;\n if (isConcreteIdentity(envName)) return normalizeAgentId(envName);\n return stateBootstrap?.agentId ?? \"unknown\";\n}\n\n/** Try to read agentName from state.json for the current instance. */\nfunction resolveNameFromState(\n agentId: string,\n stateBootstrap: StateBootstrapIdentity | null,\n): string | null {\n if (agentId === \"unknown\") return null;\n if (stateBootstrap?.agentId === agentId && stateBootstrap.agentName) {\n return stateBootstrap.agentName;\n }\n try {\n const instances = loadStateInstances();\n if (!instances) return null;\n const instance =\n instances[agentId] ?? instances[agentId.replace(/_/g, \"-\")];\n return typeof instance?.agentName === \"string\" &&\n !isPlaceholderAgentValue(instance.agentName)\n ? instance.agentName\n : null;\n } catch {\n return null;\n }\n}\n\nconst stateBootstrap = resolveSingleCodexBootstrap();\nlet _agentId = resolveInitialId(stateBootstrap);\n// State takes priority over env — tap_set_name backwrites to state,\n// but managed MCP config env may still hold a stale name from tap add time.\nlet _agentName =\n resolveNameFromState(_agentId, stateBootstrap) ??\n resolveRuntimeDisplayName() ??\n \"unknown\";\nlet _idLocked = _agentId !== \"unknown\";\n// M185: Name confirmation — once confirmed, only idempotent calls allowed.\n// Prevents subagents from overwriting parent's display name.\n// If booted with a real name (from state or env), consider it pre-confirmed.\nlet _nameConfirmed = !isPlaceholderAgentValue(_agentName);\n\nfunction refreshUnknownIdentity(): void {\n if (_idLocked) return;\n\n const nextBootstrap = resolveSingleCodexBootstrap();\n const nextId = resolveInitialId(nextBootstrap);\n if (nextId === \"unknown\") return;\n\n _agentId = nextId;\n _idLocked = true;\n\n const nextName =\n resolveNameFromState(nextId, nextBootstrap) ?? resolveRuntimeDisplayName();\n if (nextName && !isPlaceholderAgentValue(nextName)) {\n _agentName = nextName;\n _nameConfirmed = true;\n }\n}\n\nexport function getAgentId(): string {\n refreshUnknownIdentity();\n return _agentId;\n}\n\nexport function getAgentName(): string {\n refreshUnknownIdentity();\n return _agentName;\n}\n\nexport function resolveKnownInstanceId(\n agentId: string,\n displayName?: string | null,\n): string | null {\n const instances = loadStateInstances();\n if (!instances) return null;\n\n const candidates = [\n agentId,\n agentId.replace(/_/g, \"-\"),\n agentId.replace(/-/g, \"_\"),\n ];\n for (const candidate of candidates) {\n if (instances[candidate]?.installed) return candidate;\n }\n\n if (!displayName || isPlaceholderAgentValue(displayName)) return null;\n const matches = Object.entries(instances).filter(\n ([, instance]) => instance?.installed && instance.agentName === displayName,\n );\n return matches.length === 1 ? matches[0][0] : null;\n}\n\nexport function resolveCurrentInstanceId(): string | null {\n refreshUnknownIdentity();\n return resolveKnownInstanceId(_agentId, _agentName);\n}\n\nexport function getAgentIdentitySnapshot(): AgentIdentitySnapshot {\n refreshUnknownIdentity();\n const bootstrap = resolveSingleCodexBootstrap();\n return {\n agentId: _agentId,\n agentName: _agentName,\n idLocked: _idLocked,\n nameConfirmed: _nameConfirmed,\n runtimeEnv: {\n bridgeInstanceId: process.env.TAP_BRIDGE_INSTANCE_ID ?? null,\n agentId: process.env.TAP_AGENT_ID ?? null,\n agentName: process.env.TAP_AGENT_NAME ?? null,\n codexTapAgentName: process.env.CODEX_TAP_AGENT_NAME ?? null,\n commsDir: process.env.TAP_COMMS_DIR ?? null,\n stateDir: process.env.TAP_STATE_DIR ?? null,\n runtimeStateDir: process.env.TAP_RUNTIME_STATE_DIR ?? null,\n repoRoot: process.env.TAP_REPO_ROOT ?? null,\n },\n bootstrap,\n resolvedCurrentInstanceId: resolveKnownInstanceId(_agentId, _agentName),\n };\n}\n\nexport function buildHeartbeatConnectHash(\n instanceId: string | null | undefined,\n agentId: string,\n): string {\n return instanceId ? `instance:${instanceId}` : `session:${agentId}`;\n}\n\nexport function isNameConfirmed(): boolean {\n return _nameConfirmed;\n}\n\n/**\n * Demote agent name to \"unknown\" and reset confirmed state.\n * Used when bootstrap claim fails — allows tap_set_name recovery.\n */\nexport function demoteAgentName(): void {\n _agentName = \"unknown\";\n _nameConfirmed = false;\n}\n\nexport function setAgentName(name: string) {\n _agentName = name;\n _nameConfirmed = true;\n // First set_name also locks the id (backward compat: id = first name chosen)\n if (!_idLocked) {\n // Hyphens are reserved as filename delimiters — use underscores instead\n _agentId = canonicalizeIdentityId(name);\n _idLocked = true;\n }\n}\n\nexport type AgentNameClaimResult =\n | {\n ok: true;\n oldName: string;\n agentId: string;\n wasIdLocked: boolean;\n }\n | {\n ok: false;\n currentName: string;\n agentId: string;\n };\n\n// M185 scope: once a session already holds a real name, later same-process\n// callers can only repeat that same name. Placeholder boot first-claim remains\n// first-caller-wins until caller context exists (M193).\nexport function claimAgentName(name: string): AgentNameClaimResult {\n const oldName = _agentName;\n const wasIdLocked = _idLocked;\n if (_nameConfirmed && name !== oldName) {\n return {\n ok: false,\n currentName: oldName,\n agentId: _agentId,\n };\n }\n\n setAgentName(name);\n return {\n ok: true,\n oldName,\n agentId: _agentId,\n wasIdLocked,\n };\n}\n\nexport function isIdLocked(): boolean {\n return _idLocked;\n}\n\n// ── Types ───────────────────────────────────────────────────────────────\n\nexport type ChannelSource = \"inbox\" | \"reviews\" | \"findings\";\n\nexport type ParsedFilename = { from: string; to: string; subject: string };\n\nexport type ParsedFrontmatter = {\n from: string;\n from_name?: string;\n to: string;\n to_name?: string;\n subject: string;\n sent_at?: string;\n type?: string;\n};\n\nexport type TapUnreadItem = {\n source: ChannelSource;\n filename: string;\n path: string;\n from: string;\n to: string;\n subject: string;\n mtime: string;\n content?: string;\n};\n\nexport type HeartbeatSource = \"bridge-dispatch\" | \"mcp-direct\";\n\nexport type Heartbeat = {\n id?: string; // routing id (immutable) — absent in legacy entries\n agent: string; // display name (mutable)\n timestamp: string;\n lastActivity: string;\n joinedAt?: string; // ISO — set on first tap_set_name, preserved on rename\n status: \"active\" | \"idle\" | \"signing-off\";\n source?: HeartbeatSource;\n instanceId?: string | null;\n bridgePid?: number | null;\n connectHash?: string;\n};\n\nexport type HeartbeatStore = Record<string, Heartbeat>;\n\nexport type Receipt = { reader: string; timestamp: string };\nexport type ReceiptStore = Record<string, Receipt[]>;\n\n// ── Activity Tracking ───────────────────────────────────────────────────\n\nlet _lastActivityTime = new Date().toISOString();\n\nexport function getLastActivityTime(): string {\n return _lastActivityTime;\n}\n\nexport function updateActivityTime() {\n _lastActivityTime = new Date().toISOString();\n}\n\n// ── Utilities ───────────────────────────────────────────────────────────\n\nexport function debug(message: string) {\n console.error(`[tap-comms] ${message}`);\n}\n\nexport function stripBom(text: string): string {\n return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n}\n\n/**\n * Parse YAML frontmatter from message content.\n * Returns parsed fields or null if no valid frontmatter found.\n */\nexport function parseFrontmatter(content: string): ParsedFrontmatter | null {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---/);\n if (!match) return null;\n\n const fields: Record<string, string> = {};\n for (const line of match[1].split(\"\\n\")) {\n const kv = line.match(/^(\\w+):\\s*(.+)$/);\n if (kv) fields[kv[1]] = kv[2].trim();\n }\n\n if (!fields.from || !fields.to) return null;\n\n return {\n from: fields.from,\n from_name: fields.from_name,\n to: fields.to,\n to_name: fields.to_name,\n subject: fields.subject ?? \"\",\n sent_at: fields.sent_at,\n type: fields.type,\n };\n}\n\n/**\n * Strip frontmatter from content, returning only the body.\n */\nexport function stripFrontmatter(content: string): string {\n return content.replace(/^---\\r?\\n[\\s\\S]*?\\r?\\n---\\r?\\n*/, \"\");\n}\n\n/**\n * Parse message routing info: try frontmatter first, fall back to filename.\n */\nexport function parseMessageRoute(\n filename: string,\n content?: string,\n): ParsedFilename | null {\n if (content) {\n const fm = parseFrontmatter(content);\n if (fm) return { from: fm.from, to: fm.to, subject: fm.subject };\n }\n return parseFilename(filename);\n}\n\nexport function parseFilename(filename: string): ParsedFilename | null {\n // Format: YYYYMMDD-{from}-{to}-{subject}.md\n // from/to may contain hyphens (e.g. \"codex-1\"), so we split by \"-\" and\n // use a known-agent or structural heuristic: date(1) + from + to + subject(rest).\n // Strategy: strip date prefix, then split remainder into exactly 3+ segments\n // where from/to are single CJK chars or known multi-segment ids.\n const withoutExt = filename.replace(/\\.md$/, \"\");\n const dateMatch = withoutExt.match(/^(\\d{8})-(.+)$/);\n if (!dateMatch) return null;\n\n const rest = dateMatch[2];\n\n // Try CJK-aware split: CJK characters are single-char agent names\n // Match: {from}-{to}-{subject} where from/to can be CJK single chars\n const cjkMatch = rest.match(\n /^([\\u3131-\\uD79DA-Za-z][\\w]*?)-([\\u3131-\\uD79DA-Za-z][\\w]*?)-(.+)$/,\n );\n if (cjkMatch) {\n return { from: cjkMatch[1], to: cjkMatch[2], subject: cjkMatch[3] };\n }\n\n // Fallback: simple 3-part split (first two segments = from/to)\n const parts = rest.split(\"-\");\n if (parts.length >= 3) {\n return {\n from: parts[0] || \"?\",\n to: parts[1] || \"?\",\n subject: parts.slice(2).join(\"-\") || \"?\",\n };\n }\n\n return null;\n}\n\n/**\n * M204: Canonicalize agent ID — normalize hyphens to underscores.\n * Both `codex-1` and `codex_1` map to `codex_1`.\n */\nexport function canonicalizeAgentId(id: string): string {\n return canonicalizeIdentityId(id);\n}\n\nexport function isForMe(to: string): boolean {\n refreshUnknownIdentity();\n return matchesAgentRecipient(to, _agentId, _agentName);\n}\n\nexport function normalizeSources(value: unknown): ChannelSource[] {\n // Default: inbox + reviews only. Findings are record-keeping, not real-time\n // comms — request explicitly via sources: [\"findings\"] if needed.\n if (!Array.isArray(value) || value.length === 0) {\n return [\"inbox\", \"reviews\"];\n }\n\n const allowed = new Set<ChannelSource>([\"inbox\", \"reviews\", \"findings\"]);\n const normalized = value.filter(\n (entry): entry is ChannelSource =>\n typeof entry === \"string\" && allowed.has(entry as ChannelSource),\n );\n\n return normalized.length ? normalized : [\"inbox\", \"reviews\"];\n}\n\nexport function getLatestReviewDir(): string | null {\n if (!existsSync(REVIEWS_DIR)) return null;\n const gens = readdirSync(REVIEWS_DIR)\n .filter((entry) => entry.startsWith(\"gen\"))\n .sort();\n return gens.length ? join(REVIEWS_DIR, gens[gens.length - 1]) : null;\n}\n\nexport function getSourceDir(source: ChannelSource): string | null {\n if (source === \"inbox\") return INBOX_DIR;\n if (source === \"reviews\") return getLatestReviewDir();\n return FINDINGS_DIR;\n}\n\nexport function getSourceKey(source: ChannelSource, filename: string): string {\n return `${source}/${filename}`;\n}\n\nexport function getRecentSenders(): Set<string> {\n const senders = new Set<string>();\n if (!existsSync(INBOX_DIR)) return senders;\n\n const cutoff = Date.now() - 24 * 60 * 60 * 1000;\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n try {\n const mtime = statSync(join(INBOX_DIR, filename)).mtimeMs;\n if (mtime < cutoff) continue;\n } catch {\n continue;\n }\n const parsed = parseFilename(filename);\n if (parsed) senders.add(parsed.from);\n }\n return senders;\n}\n","/**\n * tap-comms file I/O: locks, receipts, heartbeats, unread scanning.\n */\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"fs\";\nimport { createHash } from \"crypto\";\nimport { join } from \"path\";\nimport {\n RECEIPTS_DIR,\n RECEIPTS_PATH,\n HEARTBEATS_PATH,\n stripBom,\n parseFilename,\n parseFrontmatter,\n stripFrontmatter,\n isForMe,\n getAgentId,\n getAgentName,\n getSourceDir,\n getSourceKey,\n normalizeSources,\n type ChannelSource,\n type TapUnreadItem,\n type ReceiptStore,\n type HeartbeatStore,\n} from \"./tap-utils.js\";\nimport { isOwnMessageAddress } from \"./tap-identity.js\";\n\n// ── State ───────────────────────────────────────────────────────────────\n\nexport const startupFiles = new Set<string>();\nexport const readFiles = new Set<string>();\n\n// ── Bridge Dedup ───────────────────────────────────────────────────────\n// Bridge writes processed markers at {bridgeStateDir}/processed/{sha1}.done.\n// bridgeStateDir = {repoRoot}/.tmp/codex-app-server-bridge-{name}/\n// Scan all bridge state dirs to find markers.\n\nconst REPO_ROOT = process.env.TAP_REPO_ROOT ?? null;\n\nconst BRIDGE_DIR_CACHE_TTL_MS = 30_000; // re-scan every 30s to pick up late-start bridges\nlet _bridgeProcessedDirs: string[] = [];\nlet _bridgeDirsCachedAt = 0;\n\nfunction getBridgeProcessedDirs(): string[] {\n const now = Date.now();\n if (now - _bridgeDirsCachedAt < BRIDGE_DIR_CACHE_TTL_MS) {\n return _bridgeProcessedDirs;\n }\n _bridgeDirsCachedAt = now;\n\n if (!REPO_ROOT) {\n _bridgeProcessedDirs = [];\n return _bridgeProcessedDirs;\n }\n const tmpDir = join(REPO_ROOT, \".tmp\");\n if (!existsSync(tmpDir)) {\n _bridgeProcessedDirs = [];\n return _bridgeProcessedDirs;\n }\n try {\n _bridgeProcessedDirs = readdirSync(tmpDir)\n .filter((d) => d.startsWith(\"codex-app-server-bridge\"))\n .map((d) => join(tmpDir, d, \"processed\"))\n .filter((p) => existsSync(p));\n } catch {\n _bridgeProcessedDirs = [];\n }\n return _bridgeProcessedDirs;\n}\n\nfunction isBridgeProcessed(filePath: string, mtimeMs: number): boolean {\n const dirs = getBridgeProcessedDirs();\n if (dirs.length === 0) return false;\n const markerId = createHash(\"sha1\")\n .update(`${filePath}|${mtimeMs}`)\n .digest(\"hex\");\n const markerFile = `${markerId}.done`;\n return dirs.some((dir) => existsSync(join(dir, markerFile)));\n}\n\n// ── Lock ────────────────────────────────────────────────────────────────\n\nexport function acquireLock(\n lockPath: string,\n retries = 3,\n delayMs = 100,\n): boolean {\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n writeFileSync(lockPath, String(process.pid), { flag: \"wx\" });\n return true;\n } catch {\n try {\n const age = Date.now() - statSync(lockPath).mtimeMs;\n if (age > 10_000) {\n unlinkSync(lockPath);\n continue;\n }\n } catch {}\n if (attempt < retries - 1) {\n const start = Date.now();\n while (Date.now() - start < delayMs) {}\n }\n }\n }\n return false;\n}\n\nexport function releaseLock(lockPath: string) {\n try {\n unlinkSync(lockPath);\n } catch {}\n}\n\n// ── Receipts ────────────────────────────────────────────────────────────\n\nexport function ensureReceiptsDir() {\n if (!existsSync(RECEIPTS_DIR)) mkdirSync(RECEIPTS_DIR, { recursive: true });\n}\n\nexport function loadReceipts(): ReceiptStore {\n try {\n return JSON.parse(readFileSync(RECEIPTS_PATH, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nexport function saveReceipts(store: ReceiptStore) {\n ensureReceiptsDir();\n const tmpPath = RECEIPTS_PATH + \".tmp\";\n writeFileSync(tmpPath, JSON.stringify(store, null, 2), \"utf-8\");\n renameSync(tmpPath, RECEIPTS_PATH);\n}\n\n// ── Heartbeats ──────────────────────────────────────────────────────────\n\nexport function loadHeartbeats(): HeartbeatStore {\n try {\n return JSON.parse(readFileSync(HEARTBEATS_PATH, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nexport function saveHeartbeats(store: HeartbeatStore) {\n const tmpPath = HEARTBEATS_PATH + \".tmp\";\n writeFileSync(tmpPath, JSON.stringify(store, null, 2), \"utf-8\");\n renameSync(tmpPath, HEARTBEATS_PATH);\n}\n\nexport function formatAgentLabel(\n agentIdOrName: string,\n displayName?: string | null,\n): string {\n const normalizedId = agentIdOrName.trim();\n const normalizedName = displayName?.trim();\n\n if (!normalizedId) {\n return normalizedName ?? agentIdOrName;\n }\n\n if (!normalizedName || normalizedName === normalizedId) {\n return normalizedId;\n }\n\n return `${normalizedName} [${normalizedId}]`;\n}\n\nexport function resolveAgentLabel(\n agentIdOrName: string,\n store: HeartbeatStore = loadHeartbeats(),\n): string {\n const normalized = agentIdOrName.trim();\n if (!normalized || normalized === \"전체\" || normalized === \"all\") {\n return agentIdOrName;\n }\n\n const byId = store[normalized];\n if (byId?.agent?.trim()) {\n return formatAgentLabel(normalized, byId.agent);\n }\n\n for (const [agentId, heartbeat] of Object.entries(store)) {\n if (heartbeat.agent?.trim() === normalized) {\n return formatAgentLabel(agentId, heartbeat.agent);\n }\n }\n\n return normalized;\n}\n\n// ── Startup ─────────────────────────────────────────────────────────────\n\nexport function seedStartupFiles(source: ChannelSource) {\n const dir = getSourceDir(source);\n if (!dir || !existsSync(dir)) return;\n\n for (const filename of readdirSync(dir)) {\n startupFiles.add(getSourceKey(source, filename));\n }\n}\n\n// ── Unread Items ────────────────────────────────────────────────────────\n\nexport function getUnreadItems(options?: {\n sources?: unknown;\n limit?: unknown;\n includeContent?: unknown;\n markRead?: unknown;\n since?: unknown;\n}): TapUnreadItem[] {\n const sources = normalizeSources(options?.sources);\n const includeContent = options?.includeContent !== false;\n const markRead = options?.markRead !== false;\n const sinceMs =\n typeof options?.since === \"string\" ? new Date(options.since).getTime() : 0;\n\n // Apply joinedAt filter: don't show messages from before agent joined\n // Look up by id first, fallback to name for backward compat\n const agentId = getAgentId();\n const agentName = getAgentName();\n let heartbeatStore: HeartbeatStore = {};\n let joinedAtMs = 0;\n if (agentId !== \"unknown\") {\n try {\n heartbeatStore = loadHeartbeats();\n const entry = heartbeatStore[agentId] ?? heartbeatStore[agentName];\n if (entry?.joinedAt) {\n joinedAtMs = new Date(entry.joinedAt).getTime();\n }\n } catch {\n // Non-critical: if we can't read, show all\n }\n }\n // Use the later of since and joinedAt\n const effectiveSinceMs = Math.max(sinceMs, joinedAtMs);\n\n const parsedLimit =\n typeof options?.limit === \"number\"\n ? options.limit\n : Number.parseInt(String(options?.limit ?? \"20\"), 10);\n const limit = Number.isFinite(parsedLimit)\n ? Math.max(1, Math.min(100, parsedLimit))\n : 20;\n\n const items: TapUnreadItem[] = [];\n\n for (const source of sources) {\n const dir = getSourceDir(source);\n if (!dir || !existsSync(dir)) continue;\n\n const filenames = readdirSync(dir)\n .filter((filename) => filename.endsWith(\".md\"))\n .sort();\n\n for (const filename of filenames) {\n const key = getSourceKey(source, filename);\n if (startupFiles.has(key) || readFiles.has(key)) continue;\n\n const fullPath = join(dir, filename);\n let mtime: number;\n try {\n mtime = statSync(fullPath).mtimeMs;\n } catch {\n continue;\n }\n if (effectiveSinceMs && mtime < effectiveSinceMs) continue;\n\n // Skip messages already delivered via bridge (dedup)\n if (isBridgeProcessed(fullPath, mtime)) {\n readFiles.add(key);\n continue;\n }\n\n let content: string;\n try {\n content = stripBom(readFileSync(fullPath, \"utf-8\"));\n } catch {\n continue;\n }\n\n let from: string = source;\n let to = \"all\";\n let subject = filename.replace(/\\.md$/, \"\");\n\n if (source === \"inbox\") {\n // Frontmatter-first routing (M202): try frontmatter, fall back to filename\n const fm = parseFrontmatter(content);\n const parsed = fm\n ? { from: fm.from, to: fm.to, subject: fm.subject }\n : parseFilename(filename);\n if (!parsed || !isForMe(parsed.to)) continue;\n if (isOwnMessageAddress(parsed.from, getAgentId(), getAgentName()))\n continue;\n from = resolveAgentLabel(fm?.from_name ?? parsed.from, heartbeatStore);\n to = resolveAgentLabel(fm?.to_name ?? parsed.to, heartbeatStore);\n subject = parsed.subject;\n // Strip frontmatter from displayed content\n if (fm && includeContent) {\n content = stripFrontmatter(content);\n }\n }\n\n const item: TapUnreadItem = {\n source,\n filename,\n path: `${source}/${filename}`,\n from,\n to,\n subject,\n mtime: new Date(mtime).toISOString(),\n };\n\n if (includeContent) {\n item.content = content;\n }\n\n items.push(item);\n if (markRead) {\n readFiles.add(key);\n }\n\n if (items.length >= limit) {\n return items;\n }\n }\n }\n\n return items;\n}\n","#!/usr/bin/env node\n/**\n * tap-comms: file-based real-time channel for tap multi-session orchestration.\n * Claude can receive fs.watch-driven channel notifications.\n * Other MCP clients can poll unread items via tap_list_unread.\n *\n * This is the thin orchestrator — tool definitions + handler routing.\n * Logic lives in tap-utils, tap-io, tap-db, tap-watcher.\n */\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport {\n isBroadcastRecipient,\n isPlaceholderAgentValue,\n normalizeRecipientList,\n} from \"./tap-identity.js\";\nimport {\n checkPeerDmRateLimit,\n recordPeerDm,\n type PeerDmHistoryStore,\n type PeerDmRoute,\n} from \"./tap-peer-dm-rate-limit.js\";\n\nimport {\n INBOX_DIR,\n ARCHIVE_DIR,\n RECEIPTS_LOCK,\n HEARTBEATS_LOCK,\n buildHeartbeatConnectHash,\n debug,\n getAgentId,\n getAgentName,\n getAgentIdentitySnapshot,\n claimAgentName,\n getRecentSenders,\n getLatestReviewDir,\n getLastActivityTime,\n resolveCurrentInstanceId,\n updateActivityTime,\n parseFilename,\n} from \"./tap-utils.js\";\nimport {\n claimName,\n renewClaimTTL,\n releaseClaim,\n resolveClaimInstanceId,\n} from \"./tap-claims.js\";\nimport {\n seedStartupFiles,\n getUnreadItems,\n acquireLock,\n releaseLock,\n ensureReceiptsDir,\n loadReceipts,\n saveReceipts,\n loadHeartbeats,\n saveHeartbeats,\n} from \"./tap-io.js\";\nimport {\n initDb,\n autoSyncOnStartup,\n dbInsertMessage,\n dbUpsertHeartbeat,\n dbInsertReceipt,\n dbGetStats,\n dbSyncAll,\n} from \"./tap-db.js\";\nimport { watchDir } from \"./tap-watcher.js\";\nimport { buildWhoAgents, resolvePreferredRecipient } from \"./tap-presence.js\";\nimport { readdirSync, renameSync, statSync, unlinkSync } from \"fs\";\n\n// ── Initialize ──────────────────────────────────────────────────────────\n\ninitDb();\nautoSyncOnStartup();\n\nseedStartupFiles(\"inbox\");\nseedStartupFiles(\"reviews\");\nseedStartupFiles(\"findings\");\n\n// ── Onboarding ─────────────────────────────────────────────────────────\n\nconst ONBOARDING_TEASER_LINES = 10;\nconst peerDmHistory: PeerDmHistoryStore = new Map();\n\nfunction loadTowerNameFromConfig(): string | null {\n const repoRoot = process.env.TAP_REPO_ROOT ?? \".\";\n try {\n const cfgPath = join(repoRoot, \"tap-config.json\");\n if (!existsSync(cfgPath)) return null;\n const cfg = JSON.parse(readFileSync(cfgPath, \"utf-8\")) as {\n towerName?: string | null;\n };\n return cfg.towerName?.trim() || null;\n } catch {\n return null;\n }\n}\n\nfunction loadOnboardingTeaser(): string {\n const commsDir = process.env.TAP_COMMS_DIR;\n if (!commsDir) return \"\";\n\n // Startup-time gating: skip teaser if agent already onboarded\n const stateDir = process.env.TAP_STATE_DIR;\n const agentId = getAgentId();\n if (stateDir && agentId !== \"unknown\") {\n try {\n const markerPath = join(stateDir, \"onboarded.json\");\n if (existsSync(markerPath)) {\n const store = JSON.parse(readFileSync(markerPath, \"utf-8\"));\n if (store[agentId]) return \"\"; // Already onboarded — skip teaser\n }\n } catch {\n // best-effort — serve teaser if marker unreadable\n }\n }\n\n try {\n const welcomePath = join(commsDir, \"onboarding\", \"welcome.md\");\n if (!existsSync(welcomePath)) return \"\";\n const content = readFileSync(welcomePath, \"utf-8\");\n const lines = content.split(\"\\n\").slice(0, ONBOARDING_TEASER_LINES);\n\n // Write marker on teaser serve — so next startup skips it\n if (stateDir && agentId !== \"unknown\") {\n try {\n const markerPath = join(stateDir, \"onboarded.json\");\n let store: Record<string, { onboardedAt: string }> = {};\n if (existsSync(markerPath)) {\n store = JSON.parse(readFileSync(markerPath, \"utf-8\"));\n }\n if (!store[agentId]) {\n store[agentId] = { onboardedAt: new Date().toISOString() };\n mkdirSync(stateDir, { recursive: true });\n writeFileSync(markerPath, JSON.stringify(store, null, 2), \"utf-8\");\n }\n } catch {\n // best-effort\n }\n }\n\n return (\n \"\\n\\n--- Onboarding ---\\n\" +\n lines.join(\"\\n\") +\n \"\\n(Use tap_onboard tool for full onboarding guide.)\"\n );\n } catch {\n return \"\";\n }\n}\n\n// ── MCP Server ──────────────────────────────────────────────────────────\n\nconst baseInstructions =\n 'You are connected to the tap-comms channel. Messages from other agents may arrive as <channel source=\"tap-comms\" from=\"X\" to=\"Y\" subject=\"Z\"> notifications. If your client does not surface Claude channel notifications, call tap_list_unread to pull pending inbox and review messages. Reply using the tap_reply tool to send messages back to other agents or the control tower.';\n\nconst mcp = new Server(\n { name: \"tap-comms\", version: \"0.2.2\" },\n {\n capabilities: {\n experimental: { \"claude/channel\": {} },\n tools: {},\n },\n instructions: baseInstructions + loadOnboardingTeaser(),\n },\n);\n\n// ── Tool Definitions ────────────────────────────────────────────────────\n\nmcp.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n {\n name: \"tap_set_name\",\n description:\n \"Set your agent name. Call this when you pick your name at session start.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n name: {\n type: \"string\" as const,\n description: \"Your chosen agent name.\",\n },\n },\n required: [\"name\"],\n },\n },\n {\n name: \"tap_reply\",\n description: \"Send a message to another tap agent via comms inbox.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n to: { type: \"string\" as const, description: \"Recipient agent name.\" },\n subject: {\n type: \"string\" as const,\n description: \"Message subject in kebab-case.\",\n },\n content: {\n type: \"string\" as const,\n description: \"Markdown message content.\",\n },\n cc: {\n description:\n \"Optional CC recipients. Each receives a copy of the message. Pass a single string or an array of strings.\",\n oneOf: [\n { type: \"string\" as const },\n {\n type: \"array\" as const,\n items: { type: \"string\" as const },\n },\n ],\n },\n },\n required: [\"to\", \"subject\", \"content\"],\n },\n },\n {\n name: \"tap_broadcast\",\n description:\n \"Broadcast a message to all agents. Shorthand for tap_reply with to='전체'.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n subject: {\n type: \"string\" as const,\n description: \"Message subject in kebab-case.\",\n },\n content: {\n type: \"string\" as const,\n description: \"Markdown message content.\",\n },\n },\n required: [\"subject\", \"content\"],\n },\n },\n {\n name: \"tap_list_unread\",\n description:\n \"Poll unread tap-comms items for clients that do not receive channel notifications.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n sources: {\n type: \"array\" as const,\n description:\n 'Optional source filter. Defaults to inbox, reviews. Add \"findings\" explicitly if needed.',\n items: {\n type: \"string\" as const,\n enum: [\"inbox\", \"reviews\", \"findings\"],\n },\n },\n limit: {\n type: \"number\" as const,\n description:\n \"Maximum number of unread items to return. Default 20.\",\n },\n includeContent: {\n type: \"boolean\" as const,\n description: \"Include full markdown content. Default true.\",\n },\n markRead: {\n type: \"boolean\" as const,\n description: \"Mark returned items as read. Default true.\",\n },\n since: {\n type: \"string\" as const,\n description:\n \"ISO timestamp. Only return files modified after this time.\",\n },\n },\n },\n },\n {\n name: \"tap_read_receipt\",\n description:\n \"Acknowledge that you read a message. Stores a read receipt so the sender can verify delivery.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n filename: {\n type: \"string\" as const,\n description: \"The inbox filename of the message you read.\",\n },\n },\n required: [\"filename\"],\n },\n },\n {\n name: \"tap_stats\",\n description:\n \"Show communication statistics: messages sent/received per agent, read receipts.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n hours: {\n type: \"number\" as const,\n description: \"Time window in hours. Default 24.\",\n },\n },\n },\n },\n {\n name: \"tap_heartbeat\",\n description:\n \"Send a heartbeat to signal this agent is alive. Call periodically or before/after major work.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n status: {\n type: \"string\" as const,\n enum: [\"active\", \"idle\", \"signing-off\"],\n description:\n \"Agent status. Default 'active'. Use 'signing-off' before session end.\",\n },\n },\n },\n },\n {\n name: \"tap_who\",\n description:\n \"List online agents based on recent heartbeats. Shows status, last heartbeat, and zombie detection.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n minutes: {\n type: \"number\" as const,\n description:\n \"Consider agents alive if heartbeat within this many minutes. Default 10.\",\n },\n },\n },\n },\n {\n name: \"tap_cleanup\",\n description:\n \"Archive inbox files older than N days. Moves them to archive/ directory.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n days: {\n type: \"number\" as const,\n description: \"Archive files older than this many days. Default 7.\",\n },\n dryRun: {\n type: \"boolean\" as const,\n description: \"Preview only, don't move files. Default false.\",\n },\n },\n },\n },\n {\n name: \"tap_db_sync\",\n description:\n \"Sync existing inbox/receipts/heartbeats files into the SQLite database.\",\n inputSchema: { type: \"object\" as const, properties: {} },\n },\n {\n name: \"tap_onboard\",\n description:\n \"Get the full onboarding guide for this project. Returns welcome.md + any additional onboarding docs from commsDir/onboarding/.\",\n inputSchema: { type: \"object\" as const, properties: {} },\n },\n {\n name: \"tap_identity_probe\",\n description:\n \"Dump the current MCP-side identity/runtime env snapshot seen by tap tools.\",\n inputSchema: { type: \"object\" as const, properties: {} },\n },\n ],\n}));\n\n// ── Activity Persistence ────────────────────────────────────────────────\n\nfunction prunePhantomHeartbeats(\n store: Record<string, { id?: string; [k: string]: unknown }>,\n): number {\n let removed = 0;\n for (const key of Object.keys(store)) {\n if (!store[key].id) {\n delete store[key];\n removed++;\n }\n }\n return removed;\n}\n\nfunction persistActivity(id: string, name: string): void {\n const locked = acquireLock(HEARTBEATS_LOCK);\n if (!locked) return; // Skip this cycle, retry next tool call\n try {\n const store = loadHeartbeats();\n // M210: Remove phantom entries (no id field) on every write cycle\n prunePhantomHeartbeats(store);\n const existing = store[id];\n const resolvedInstanceId =\n resolveCurrentInstanceId() ?? existing?.instanceId ?? null;\n const connectHash = buildHeartbeatConnectHash(resolvedInstanceId, id);\n const preserveBridgeSource =\n existing?.source === \"bridge-dispatch\" &&\n existing.connectHash === connectHash;\n store[id] = {\n id,\n agent: name,\n timestamp: existing?.timestamp ?? new Date().toISOString(),\n lastActivity: getLastActivityTime(),\n joinedAt: existing?.joinedAt,\n status: existing?.status ?? \"active\",\n source: preserveBridgeSource ? \"bridge-dispatch\" : \"mcp-direct\",\n instanceId: resolvedInstanceId,\n bridgePid: preserveBridgeSource ? (existing?.bridgePid ?? null) : null,\n connectHash,\n };\n saveHeartbeats(store);\n } catch {\n // Non-critical\n } finally {\n releaseLock(HEARTBEATS_LOCK);\n }\n}\n\n// ── Tool Handlers ───────────────────────────────────────────────────────\n\nmcp.setRequestHandler(CallToolRequestSchema, async (req) => {\n updateActivityTime();\n\n // Auto-persist activity to heartbeat store so tap_who can find us\n // Skip for tap_set_name — handled after name change below\n const currentId = getAgentId();\n const currentName = getAgentName();\n if (currentId !== \"unknown\" && req.params.name !== \"tap_set_name\") {\n persistActivity(currentId, currentName);\n }\n\n // ── tap_set_name ──────────────────────────────────────────────────\n if (req.params.name === \"tap_set_name\") {\n const { name } = req.params.arguments as { name: string };\n if (!name || !/^[A-Za-z0-9가-힣_]+$/.test(name)) {\n return {\n content: [\n {\n type: \"text\",\n text: `Rejected: \"${name}\" contains invalid characters. Agent names must match [A-Za-z0-9가-힣_] — no hyphens, spaces, or special characters.`,\n },\n ],\n };\n }\n // Step 1: Pre-check memory guard (read-only) — reject if already confirmed with different name\n const { isNameConfirmed: isConfirmed, getAgentName: currentName } =\n await import(\"./tap-utils.js\");\n if (isConfirmed() && currentName() !== name) {\n return {\n content: [\n {\n type: \"text\",\n text:\n `Rejected: Name already confirmed as \"${currentName()}\". ` +\n `tap_set_name can only be called once per session. ` +\n `Agent ID: ${getAgentId()} (immutable).`,\n },\n ],\n };\n }\n\n // Step 2: File claim — atomic cross-instance lock\n const claimInstanceId = resolveClaimInstanceId();\n const fileClaim = claimName(\n name,\n claimInstanceId,\n process.pid,\n \"mcp-direct\",\n );\n if (!fileClaim.success) {\n const conflict = fileClaim.conflictWith;\n return {\n content: [\n {\n type: \"text\",\n text:\n `Rejected: Name \"${name}\" is claimed by instance \"${conflict?.instanceId}\" (alive: ${conflict?.alive}). ` +\n `Agent ID: ${getAgentId()} (immutable).`,\n },\n ],\n };\n }\n\n // Step 3: Memory claim — only after file claim succeeds\n const claim = claimAgentName(name);\n if (!claim.ok) {\n // Should not happen (pre-check passed), but safety net\n releaseClaim(name, claimInstanceId, process.pid);\n return {\n content: [\n {\n type: \"text\",\n text:\n `Rejected: Name already confirmed as \"${claim.currentName}\". ` +\n `Agent ID: ${claim.agentId} (immutable).`,\n },\n ],\n };\n }\n\n const { oldName, agentId, wasIdLocked } = claim;\n\n const activeSenders = getRecentSenders();\n activeSenders.delete(oldName);\n const isDuplicate = activeSenders.has(name);\n debug(\n `name changed: ${oldName} -> ${name} (id: ${agentId}, locked: ${wasIdLocked})${isDuplicate ? \" (DUPLICATE WARNING)\" : \"\"}`,\n );\n\n const activeList = [...activeSenders]\n .filter((n) => n !== \"unnamed\" && n !== \"unknown\")\n .join(\", \");\n // Persist heartbeat under agent id (not name) for stable routing\n const now = new Date().toISOString();\n let priorJoinedAt: string | null = null; // M111: capture pre-write state\n let priorLastActivity: string | null = null;\n const locked = acquireLock(HEARTBEATS_LOCK);\n if (locked) {\n try {\n const store = loadHeartbeats();\n // Find existing entry by id or old name (migration from name-keyed)\n const oldEntry =\n store[agentId] ??\n (oldName !== \"unknown\" ? store[oldName] : undefined);\n\n // M111: capture pre-write state for tower notify dedupe\n priorJoinedAt = oldEntry?.joinedAt ?? null;\n priorLastActivity = oldEntry?.lastActivity ?? null;\n\n // Delete old name-keyed entry if migrating to id-keyed\n if (oldName !== \"unknown\" && oldName !== agentId) {\n delete store[oldName];\n }\n\n const resolvedInstanceId =\n resolveCurrentInstanceId() ?? oldEntry?.instanceId ?? null;\n const connectHash = buildHeartbeatConnectHash(\n resolvedInstanceId,\n agentId,\n );\n const preserveBridgeSource =\n oldEntry?.source === \"bridge-dispatch\" &&\n oldEntry.connectHash === connectHash;\n store[agentId] = {\n id: agentId,\n agent: name,\n timestamp: now,\n lastActivity: getLastActivityTime(),\n joinedAt: oldEntry?.joinedAt ?? now,\n status: \"active\",\n source: preserveBridgeSource ? \"bridge-dispatch\" : \"mcp-direct\",\n instanceId: resolvedInstanceId,\n bridgePid: preserveBridgeSource\n ? (oldEntry?.bridgePid ?? null)\n : null,\n connectHash,\n };\n\n // M162: Clean stale heartbeats with the same display name but\n // different agent ID. Prevents duplicate routing when a bridge\n // restarts with a new session ID but the same agent name.\n // Use lastActivity (updated on every tool call) rather than\n // timestamp (only set at tap_set_name time) to avoid removing\n // sessions that are still actively using tools.\n const STALE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes\n for (const [otherId, otherHb] of Object.entries(store)) {\n if (otherId === agentId) continue;\n if (otherHb.agent !== name) continue;\n const otherConnectHash =\n otherHb.connectHash ??\n buildHeartbeatConnectHash(otherHb.instanceId ?? null, otherId);\n if (otherConnectHash !== connectHash) continue;\n const freshestTs = Math.max(\n otherHb.lastActivity ? new Date(otherHb.lastActivity).getTime() : 0,\n otherHb.timestamp ? new Date(otherHb.timestamp).getTime() : 0,\n );\n if (Date.now() - freshestTs > STALE_THRESHOLD_MS) {\n delete store[otherId];\n }\n }\n\n saveHeartbeats(store);\n } catch {\n // Non-critical\n } finally {\n releaseLock(HEARTBEATS_LOCK);\n }\n }\n\n // Backwrite agentName to state.json so next session bootstraps with it\n const stateDir = process.env.TAP_STATE_DIR;\n if (stateDir) {\n try {\n const statePath = join(stateDir, \"state.json\");\n if (existsSync(statePath)) {\n const state = JSON.parse(readFileSync(statePath, \"utf-8\"));\n const instanceKey = agentId.replace(/_/g, \"-\");\n const instance =\n state.instances?.[agentId] ?? state.instances?.[instanceKey];\n if (instance) {\n instance.agentName = name;\n const tmp = `${statePath}.tmp.${process.pid}`;\n writeFileSync(tmp, JSON.stringify(state, null, 2), \"utf-8\");\n try {\n renameSync(tmp, statePath);\n } catch {\n // Retry once — Windows may hold file handle briefly\n try {\n renameSync(tmp, statePath);\n } catch {\n try {\n unlinkSync(tmp);\n } catch {\n /* best-effort cleanup */\n }\n }\n }\n debug(`backwrite agentName=\"${name}\" to state.json for ${agentId}`);\n }\n }\n } catch {\n // Non-critical — state backwrite is best-effort\n }\n }\n\n // M111: Notify tower on new agent join (first non-placeholder name)\n if (oldName === \"unknown\" || oldName === \"unnamed\") {\n try {\n const towerName = loadTowerNameFromConfig();\n\n // Resolve runtime from state.json (works for all runtimes)\n let runtime = process.env.TAP_BRIDGE_RUNTIME ?? null;\n if (!runtime && stateDir) {\n try {\n const statePath = join(stateDir, \"state.json\");\n if (existsSync(statePath)) {\n const state = JSON.parse(readFileSync(statePath, \"utf-8\"));\n const instanceKey = agentId.replace(/_/g, \"-\");\n const inst =\n state.instances?.[agentId] ?? state.instances?.[instanceKey];\n runtime = inst?.runtime ?? null;\n }\n } catch {\n /* best-effort */\n }\n }\n\n if (towerName && towerName !== name && towerName !== agentId) {\n // Dedupe using pre-write heartbeat state (avoids self-skip on first join)\n const SKIP_WINDOW_MS = 10 * 60 * 1000;\n const STALE_WINDOW_MS = 30 * 60 * 1000;\n let shouldNotify = true;\n\n if (priorJoinedAt) {\n // Existing agent — check lastActivity freshness\n const activityTs = priorLastActivity ?? priorJoinedAt;\n const activityAge = Date.now() - new Date(activityTs).getTime();\n if (activityAge < SKIP_WINDOW_MS) {\n shouldNotify = false; // Recently active — skip\n } else if (activityAge < STALE_WINDOW_MS) {\n shouldNotify = false; // Active within window — skip\n }\n // > 30min since last activity → re-notify\n }\n // priorJoinedAt === null → truly new agent → notify\n\n if (shouldNotify) {\n const ts = new Date().toISOString().replace(/[:.]/g, \"-\");\n const notifyFilename = `${ts.slice(0, 10).replace(/-/g, \"\")}-tap-${towerName}-new-agent-${agentId}.md`;\n const notifyPath = join(INBOX_DIR, notifyFilename);\n writeFileSync(\n notifyPath,\n `[NEW] ${name} (${agentId}) joined. Runtime: ${runtime ?? \"unknown\"}.`,\n \"utf-8\",\n );\n debug(\n `tower notify: ${towerName} ← new agent ${name} (${runtime})`,\n );\n }\n }\n } catch {\n // Non-critical — tower notify is best-effort\n }\n }\n\n let text = `Name set: ${name} (was: ${oldName}). Messages to \"${name}\", \"${agentId}\", \"전체\", or \"all\" will be received.`;\n if (!wasIdLocked)\n text += `\\nAgent ID locked: ${agentId} (immutable for this session)`;\n if (isDuplicate)\n text += `\\n⚠️ WARNING: \"${name}\" was already used in the last 24h. Pick a different name to avoid confusion.`;\n if (activeList) text += `\\nRecent active names: ${activeList}`;\n return { content: [{ type: \"text\", text }] };\n }\n\n // ── tap_reply ─────────────────────────────────────────────────────\n if (req.params.name === \"tap_reply\") {\n const {\n to: rawTo,\n subject: rawSubject,\n content,\n cc: rawCc,\n } = req.params.arguments as {\n to: string;\n subject: string;\n content: string;\n cc?: string | string[];\n };\n\n // M142: Validate required fields\n const to = typeof rawTo === \"string\" ? rawTo.trim() : \"\";\n const subject = typeof rawSubject === \"string\" ? rawSubject.trim() : \"\";\n if (!to) {\n return {\n content: [\n {\n type: \"text\",\n text: 'Rejected: \"to\" is required and must be a non-empty string.',\n },\n ],\n };\n }\n if (!subject) {\n return {\n content: [\n {\n type: \"text\",\n text: 'Rejected: \"subject\" is required and must be a non-empty string.',\n },\n ],\n };\n }\n const cc = normalizeRecipientList(rawCc, [to]);\n\n const recipientWarnings: string[] = [];\n const towerName = loadTowerNameFromConfig();\n const store = loadHeartbeats();\n const resolvedTowerId = towerName\n ? resolvePreferredRecipient(store, towerName).target\n : null;\n const knownAgents = new Set<string>();\n for (const [key, hb] of Object.entries(store)) {\n if (!isPlaceholderAgentValue(key)) knownAgents.add(key);\n if (!isPlaceholderAgentValue(hb.agent)) {\n knownAgents.add(hb.agent); // display name (exclude placeholders)\n }\n }\n const knownList = [...knownAgents]\n .filter((n) => n !== \"unknown\")\n .join(\", \");\n\n function resolveRecipient(recipient: string): {\n target: string;\n found: boolean;\n warning: string | null;\n } {\n const resolution = resolvePreferredRecipient(store, recipient);\n if (resolution.found) {\n return {\n target: resolution.target,\n found: true,\n warning: resolution.warning,\n };\n }\n\n return {\n target: recipient,\n found: false,\n warning:\n `⚠️ WARNING: \"${recipient}\" is not a known agent. ` +\n `Check spelling. Known: ${knownList}`,\n };\n }\n\n let resolvedTo = to;\n if (!isBroadcastRecipient(to)) {\n const resolution = resolveRecipient(to);\n if (!resolution.found) {\n if (resolution.warning) recipientWarnings.push(resolution.warning);\n } else {\n resolvedTo = resolution.target;\n if (resolution.warning) recipientWarnings.push(resolution.warning);\n }\n }\n\n if (cc?.length) {\n for (const recipient of cc) {\n if (isBroadcastRecipient(recipient)) continue;\n const resolution = resolveRecipient(recipient);\n if (resolution.warning) {\n recipientWarnings.push(\n resolution.warning.replace(`\"${recipient}\"`, `CC \"${recipient}\"`),\n );\n }\n }\n }\n\n const resolvedCc = cc?.map((recipient) => ({\n original: recipient,\n resolved: isBroadcastRecipient(recipient)\n ? recipient\n : resolveRecipient(recipient).target,\n }));\n\n const now = new Date();\n const nowMs = now.getTime();\n const date = now.toISOString().slice(0, 10).replace(/-/g, \"\");\n const fromId = getAgentId();\n const fromName = getAgentName();\n const rateLimitRoutes = new Map<string, PeerDmRoute>();\n const primaryRoute: PeerDmRoute = {\n fromId,\n fromName,\n to,\n resolvedTo,\n towerName,\n towerId: resolvedTowerId,\n };\n const primaryCheck = checkPeerDmRateLimit(peerDmHistory, primaryRoute, nowMs);\n if (!primaryCheck.exempt && primaryCheck.key) {\n rateLimitRoutes.set(primaryCheck.key, primaryRoute);\n }\n\n for (const recipient of resolvedCc ?? []) {\n const route: PeerDmRoute = {\n fromId,\n fromName,\n to: recipient.original,\n resolvedTo: recipient.resolved,\n towerName,\n towerId: resolvedTowerId,\n };\n const check = checkPeerDmRateLimit(peerDmHistory, route, nowMs);\n if (check.exempt || !check.key) continue;\n rateLimitRoutes.set(check.key, route);\n }\n\n for (const route of rateLimitRoutes.values()) {\n const check = checkPeerDmRateLimit(peerDmHistory, route, nowMs);\n if (!check.allowed) {\n return {\n content: [\n {\n type: \"text\",\n text:\n `Rate limited: too many messages between ${fromId}→${check.target}. ` +\n \"Route through tower instead.\",\n },\n ],\n };\n }\n }\n\n for (const route of rateLimitRoutes.values()) {\n recordPeerDm(peerDmHistory, route, nowMs);\n }\n\n const filename = `${date}-${fromId}-${resolvedTo}-${subject}.md`;\n const filepath = join(INBOX_DIR, filename);\n const ccHeader = cc?.length ? `> CC: ${cc.join(\", \")}\\n\\n` : \"\";\n const frontmatter = [\n \"---\",\n \"type: inbox\",\n `from: ${fromId}`,\n `from_name: ${fromName}`,\n `to: ${resolvedTo}`,\n `to_name: ${to}`,\n `subject: ${subject}`,\n `sent_at: ${now.toISOString()}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n writeFileSync(filepath, frontmatter + ccHeader + content, \"utf-8\");\n dbInsertMessage(\n filename,\n fromName,\n resolvedTo,\n subject,\n \"inbox\",\n Date.now(),\n );\n\n const sent = [`Sent to ${to}: ${filename}`];\n if (cc?.length) {\n const writtenFiles = new Set<string>([filename]); // Track to prevent overwrite\n for (const recipient of resolvedCc ?? []) {\n try {\n const resolvedRecipient = recipient.resolved;\n const ccFilename = `${date}-${fromId}-${resolvedRecipient}-${subject}.md`;\n // Skip if resolved filename matches primary or already written CC\n if (writtenFiles.has(ccFilename)) {\n sent.push(\n `CC to ${recipient.original}: skipped (resolves to same target)`,\n );\n continue;\n }\n writtenFiles.add(ccFilename);\n const ccFrontmatter = [\n \"---\",\n \"type: inbox\",\n `from: ${fromId}`,\n `from_name: ${fromName}`,\n `to: ${resolvedRecipient}`,\n `to_name: ${recipient.original}`,\n `subject: ${subject}`,\n `sent_at: ${now.toISOString()}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n writeFileSync(\n join(INBOX_DIR, ccFilename),\n ccFrontmatter + `> CC from message to ${to}\\n\\n${content}`,\n \"utf-8\",\n );\n dbInsertMessage(\n ccFilename,\n fromName,\n resolvedRecipient,\n subject,\n \"inbox\",\n Date.now(),\n );\n sent.push(`CC to ${recipient.original}: ${ccFilename}`);\n } catch (err) {\n sent.push(\n `CC to ${recipient.original}: FAILED (${err instanceof Error ? err.message : String(err)})`,\n );\n }\n }\n }\n // Append warnings after delivery (still send — warning only, not blocking)\n sent.push(...recipientWarnings);\n return { content: [{ type: \"text\", text: sent.join(\"\\n\") }] };\n }\n\n // ── tap_broadcast ─────────────────────────────────────────────────\n if (req.params.name === \"tap_broadcast\") {\n const { subject, content } = req.params.arguments as {\n subject: string;\n content: string;\n };\n const now = new Date();\n const date = now.toISOString().slice(0, 10).replace(/-/g, \"\");\n const broadcastId = getAgentId();\n const broadcastName = getAgentName();\n const filename = `${date}-${broadcastId}-전체-${subject}.md`;\n const broadcastFrontmatter = [\n \"---\",\n \"type: inbox\",\n `from: ${broadcastId}`,\n `from_name: ${broadcastName}`,\n \"to: 전체\",\n `subject: ${subject}`,\n `sent_at: ${now.toISOString()}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n writeFileSync(\n join(INBOX_DIR, filename),\n broadcastFrontmatter + content,\n \"utf-8\",\n );\n dbInsertMessage(\n filename,\n broadcastName,\n \"전체\",\n subject,\n \"inbox\",\n Date.now(),\n );\n return { content: [{ type: \"text\", text: `Broadcast sent: ${filename}` }] };\n }\n\n // ── tap_list_unread ───────────────────────────────────────────────\n if (req.params.name === \"tap_list_unread\") {\n const unread = getUnreadItems((req.params.arguments as any) || {});\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n { agent: getAgentName(), count: unread.length, items: unread },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n // ── tap_read_receipt ──────────────────────────────────────────────\n if (req.params.name === \"tap_read_receipt\") {\n const { filename } = req.params.arguments as { filename: string };\n ensureReceiptsDir();\n if (!acquireLock(RECEIPTS_LOCK)) {\n return {\n content: [{ type: \"text\", text: \"Receipt store busy, try again.\" }],\n };\n }\n try {\n const store = loadReceipts();\n if (!store[filename]) store[filename] = [];\n const readerId = getAgentId();\n const already = store[filename].some((r) => r.reader === readerId);\n if (!already) {\n const ts = new Date().toISOString();\n store[filename].push({ reader: readerId, timestamp: ts });\n saveReceipts(store);\n dbInsertReceipt(filename, readerId, ts);\n }\n return {\n content: [\n {\n type: \"text\",\n text: already\n ? `Already acknowledged: ${filename}`\n : `Read receipt saved for: ${filename}`,\n },\n ],\n };\n } finally {\n releaseLock(RECEIPTS_LOCK);\n }\n }\n\n // ── M194: HUD formatter ──────────────────────────────────────────\n function buildHudLine(): string {\n const hbStore = loadHeartbeats();\n const agentCount = buildWhoAgents(hbStore, 10).filter(\n (agent) => agent.alive,\n ).length;\n\n // Unread count — use getUnreadItems with markRead=false for accurate semantics\n // (respects joinedAt, startupFiles, readFiles, isForMe)\n const unreadItems = getUnreadItems({\n sources: [\"inbox\"],\n limit: 100,\n includeContent: false,\n markRead: false,\n });\n // getUnreadItems clamps at 100 — display \"99+\" if at limit\n const unreadCount = unreadItems.length;\n const unreadDisplay = unreadCount >= 100 ? \"99+\" : String(unreadCount);\n\n // Status emoji\n const status = agentCount > 0 ? \"🟢\" : \"⚪\";\n\n return `[tap] ${status} ${agentCount} agents | 📨 ${unreadDisplay} unread`;\n }\n\n // ── tap_stats ─────────────────────────────────────────────────────\n if (req.params.name === \"tap_stats\") {\n const hours =\n typeof (req.params.arguments as any)?.hours === \"number\"\n ? (req.params.arguments as any).hours\n : 24;\n const cutoff = Date.now() - hours * 60 * 60 * 1000;\n\n const hud = buildHudLine();\n\n // DB fast path\n const dbResult = dbGetStats(cutoff);\n if (dbResult) {\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n { hours, ...dbResult, source: \"sqlite\", hud },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n // File fallback\n const sent: Record<string, number> = {};\n const received: Record<string, number> = {};\n let broadcasts = 0;\n if (existsSync(INBOX_DIR)) {\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n try {\n if (statSync(join(INBOX_DIR, filename)).mtimeMs < cutoff) continue;\n } catch {\n continue;\n }\n const parsed = parseFilename(filename);\n if (!parsed) continue;\n sent[parsed.from] = (sent[parsed.from] || 0) + 1;\n if (isBroadcastRecipient(parsed.to)) broadcasts++;\n else received[parsed.to] = (received[parsed.to] || 0) + 1;\n }\n }\n const receipts = loadReceipts();\n const cutoffISO = new Date(cutoff).toISOString();\n const receiptCount = Object.values(receipts).reduce(\n (sum, arr) => sum + arr.filter((r) => r.timestamp >= cutoffISO).length,\n 0,\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n hours,\n sent,\n received,\n broadcasts,\n totalReceipts: receiptCount,\n hud,\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n // ── tap_heartbeat ─────────────────────────────────────────────────\n if (req.params.name === \"tap_heartbeat\") {\n const status =\n ((req.params.arguments as any)?.status as\n | \"active\"\n | \"idle\"\n | \"signing-off\") || \"active\";\n const hbId = getAgentId();\n const hbName = getAgentName();\n if (!acquireLock(HEARTBEATS_LOCK)) {\n return {\n content: [{ type: \"text\", text: \"Heartbeat store busy, try again.\" }],\n };\n }\n try {\n const store = loadHeartbeats();\n const existing = store[hbId];\n const resolvedInstanceId =\n resolveCurrentInstanceId() ?? existing?.instanceId ?? null;\n const connectHash = buildHeartbeatConnectHash(resolvedInstanceId, hbId);\n const preserveBridgeSource =\n existing?.source === \"bridge-dispatch\" &&\n existing.connectHash === connectHash;\n store[hbId] = {\n id: hbId,\n agent: hbName,\n timestamp: new Date().toISOString(),\n lastActivity: getLastActivityTime(),\n joinedAt: existing?.joinedAt,\n status,\n source: preserveBridgeSource ? \"bridge-dispatch\" : \"mcp-direct\",\n instanceId: resolvedInstanceId,\n bridgePid: preserveBridgeSource ? (existing?.bridgePid ?? null) : null,\n connectHash,\n };\n saveHeartbeats(store);\n dbUpsertHeartbeat(hbId, status, getLastActivityTime());\n } finally {\n releaseLock(HEARTBEATS_LOCK);\n }\n\n // M221: Renew claim TTL on heartbeat, release on signing-off\n // Pass ownership (instanceId + pid) to prevent cross-instance interference\n if (hbName && hbName !== \"unknown\") {\n const hbInstanceId = resolveClaimInstanceId();\n if (status === \"signing-off\") {\n releaseClaim(hbName, hbInstanceId, process.pid);\n } else {\n renewClaimTTL(hbName, hbInstanceId, process.pid);\n }\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: `Heartbeat sent: ${hbName} [${hbId}] (${status})`,\n },\n ],\n };\n }\n\n // ── tap_who ───────────────────────────────────────────────────────\n if (req.params.name === \"tap_who\") {\n const minutes =\n typeof (req.params.arguments as any)?.minutes === \"number\"\n ? (req.params.arguments as any).minutes\n : 10;\n const store = loadHeartbeats();\n const agents = buildWhoAgents(store, minutes);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify({ onlineCount: agents.length, agents }, null, 2),\n },\n ],\n };\n }\n\n // ── tap_db_sync ───────────────────────────────────────────────────\n if (req.params.name === \"tap_db_sync\") {\n const result = dbSyncAll();\n if (!result)\n return {\n content: [{ type: \"text\", text: \"SQLite not available. Cannot sync.\" }],\n };\n return {\n content: [\n {\n type: \"text\",\n text: `DB sync complete: ${result.messages} messages, ${result.heartbeats} heartbeats, ${result.receipts} receipts`,\n },\n ],\n };\n }\n\n // ── tap_cleanup ───────────────────────────────────────────────────\n if (req.params.name === \"tap_cleanup\") {\n const days =\n typeof (req.params.arguments as any)?.days === \"number\"\n ? (req.params.arguments as any).days\n : 7;\n const dryRun = (req.params.arguments as any)?.dryRun === true;\n const cutoffDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000);\n const cutoffStr =\n cutoffDate.getFullYear().toString() +\n (cutoffDate.getMonth() + 1).toString().padStart(2, \"0\") +\n cutoffDate.getDate().toString().padStart(2, \"0\");\n const moved: string[] = [];\n if (!existsSync(ARCHIVE_DIR)) mkdirSync(ARCHIVE_DIR, { recursive: true });\n if (existsSync(INBOX_DIR)) {\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n // Parse date from filename: YYYYMMDD-from-to-subject.md\n const dateMatch = filename.match(/^(\\d{8})-/);\n if (!dateMatch) continue;\n if (dateMatch[1] >= cutoffStr) continue; // not old enough\n const filepath = join(INBOX_DIR, filename);\n if (!dryRun) renameSync(filepath, join(ARCHIVE_DIR, filename));\n moved.push(filename);\n }\n }\n return {\n content: [\n {\n type: \"text\",\n text: dryRun\n ? `[DRY RUN] Would archive ${moved.length} files older than ${days} days (filename date).`\n : `Archived ${moved.length} files older than ${days} days to archive/ (filename date).`,\n },\n ],\n };\n }\n\n // ── tap_onboard ──────────────────────────────────────────────────\n if (req.params.name === \"tap_onboard\") {\n const commsDir = process.env.TAP_COMMS_DIR;\n if (!commsDir) {\n return {\n content: [\n {\n type: \"text\",\n text: \"TAP_COMMS_DIR not set. Cannot load onboarding docs.\",\n },\n ],\n };\n }\n\n // Idempotent marker — agent-scoped onboarding tracker\n const stateDir = process.env.TAP_STATE_DIR;\n const agentId = getAgentId();\n let alreadyOnboarded = false;\n let markerStore: Record<string, { onboardedAt: string }> = {};\n const markerPath = stateDir ? join(stateDir, \"onboarded.json\") : null;\n if (markerPath) {\n try {\n if (existsSync(markerPath)) {\n markerStore = JSON.parse(readFileSync(markerPath, \"utf-8\"));\n if (markerStore[agentId]) {\n alreadyOnboarded = true;\n }\n }\n } catch {\n // best-effort\n }\n }\n\n const onboardingDir = join(commsDir, \"onboarding\");\n if (!existsSync(onboardingDir)) {\n return {\n content: [\n {\n type: \"text\",\n text: \"No onboarding directory found at \" + onboardingDir,\n },\n ],\n };\n }\n\n const docs: string[] = [];\n const allFiles = readdirSync(onboardingDir).filter((f: string) =>\n f.endsWith(\".md\"),\n );\n\n // welcome.md always first, then alphabetical\n const files = [\n ...allFiles.filter((f: string) => f === \"welcome.md\"),\n ...allFiles.filter((f: string) => f !== \"welcome.md\").sort(),\n ];\n\n for (const file of files) {\n try {\n const content = readFileSync(join(onboardingDir, file), \"utf-8\");\n docs.push(`# ${file}\\n\\n${content}`);\n } catch {\n docs.push(`# ${file}\\n\\n(failed to read)`);\n }\n }\n\n if (docs.length === 0) {\n return {\n content: [{ type: \"text\", text: \"Onboarding directory is empty.\" }],\n };\n }\n\n // Write agent-scoped onboarded marker\n if (markerPath && !alreadyOnboarded) {\n try {\n markerStore[agentId] = { onboardedAt: new Date().toISOString() };\n writeFileSync(\n markerPath,\n JSON.stringify(markerStore, null, 2),\n \"utf-8\",\n );\n } catch {\n // best-effort\n }\n }\n\n const prefix = alreadyOnboarded\n ? \"(You have already been onboarded. Showing docs again for reference.)\\n\\n\"\n : \"\";\n\n return {\n content: [{ type: \"text\", text: prefix + docs.join(\"\\n\\n---\\n\\n\") }],\n };\n }\n\n // ── tap_identity_probe ──────────────────────────────────────────\n if (req.params.name === \"tap_identity_probe\") {\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(getAgentIdentitySnapshot(), null, 2),\n },\n ],\n };\n }\n\n throw new Error(`unknown tool: ${req.params.name}`);\n});\n\n// ── Start ───────────────────────────────────────────────────────────────\n\nawait mcp.connect(new StdioServerTransport());\n\n// M221 hotfix: auto-claim bootstrapped name so persisted names are protected\n{\n const { isNameConfirmed, getAgentName: bootName } =\n await import(\"./tap-utils.js\");\n if (isNameConfirmed()) {\n const name = bootName();\n if (name && name !== \"unknown\") {\n const bootInstanceId = resolveClaimInstanceId();\n const bootClaim = claimName(\n name,\n bootInstanceId,\n process.pid,\n \"mcp-direct\",\n );\n if (bootClaim.success) {\n debug(\n `auto-claimed bootstrapped name: ${name} (instance: ${bootInstanceId})`,\n );\n } else {\n // Demote name so tap_set_name can recover with a different name\n const { demoteAgentName } = await import(\"./tap-utils.js\");\n demoteAgentName();\n debug(\n `WARNING: bootstrapped name \"${name}\" claimed by ${bootClaim.conflictWith?.instanceId ?? \"unknown\"} — demoted to unknown, use tap_set_name to pick a new name`,\n );\n }\n }\n }\n}\n\ndebug(`agent id: ${getAgentId()}, name: ${getAgentName()}`);\ndebug(`watching inbox: ${INBOX_DIR}`);\n\nwatchDir(INBOX_DIR, \"inbox\", mcp);\n\nconst latestReviewDir = getLatestReviewDir();\nif (latestReviewDir) {\n debug(`watching reviews: ${latestReviewDir}`);\n watchDir(latestReviewDir, \"reviews\", mcp);\n}\n\n// findings are record-keeping, not real-time comms — no watcher needed.\n// Agents read findings on-demand via tap_list_unread(sources: [\"findings\"]).\n\n// M93: Poll fallback catches messages missed by fs.watch (Windows race, watcher death, etc.)\nimport { startPollFallback } from \"./tap-poll-fallback.js\";\nstartPollFallback(mcp);\n\nprocess.on(\"SIGINT\", () => process.exit(0));\n","import {\n canonicalizeAgentId,\n isBroadcastRecipient,\n sameRoutingAddress,\n} from \"./tap-identity.js\";\n\nexport const PEER_DM_WINDOW_MS = 5 * 60 * 1000;\nexport const PEER_DM_MAX_MESSAGES = 3;\n\nexport type PeerDmHistoryStore = Map<string, number[]>;\n\nexport type PeerDmRoute = {\n fromId: string;\n fromName?: string | null;\n to: string;\n resolvedTo?: string | null;\n towerName?: string | null;\n towerId?: string | null;\n};\n\nexport type PeerDmRateLimitCheck = {\n allowed: boolean;\n exempt: boolean;\n key: string | null;\n target: string;\n recentCount: number;\n};\n\nfunction normalizeAddress(value?: string | null): string {\n return value?.trim() ?? \"\";\n}\n\nfunction matchesTowerAddress(\n value: string | null | undefined,\n towerName: string | null | undefined,\n towerId: string | null | undefined,\n): boolean {\n const normalizedValue = normalizeAddress(value);\n const normalizedTower = normalizeAddress(towerName);\n const normalizedTowerId = normalizeAddress(towerId);\n if (!normalizedValue) return false;\n return (\n (!!normalizedTower &&\n (normalizedValue === normalizedTower ||\n sameRoutingAddress(normalizedValue, normalizedTower))) ||\n (!!normalizedTowerId &&\n (normalizedValue === normalizedTowerId ||\n sameRoutingAddress(normalizedValue, normalizedTowerId)))\n );\n}\n\nfunction resolveTargetAddress(route: PeerDmRoute): string {\n const candidate = normalizeAddress(route.resolvedTo) || normalizeAddress(route.to);\n return isBroadcastRecipient(candidate)\n ? \"broadcast\"\n : canonicalizeAgentId(candidate);\n}\n\nexport function isPeerDmRateLimitExempt(route: PeerDmRoute): boolean {\n if (\n isBroadcastRecipient(normalizeAddress(route.to)) ||\n isBroadcastRecipient(normalizeAddress(route.resolvedTo))\n ) {\n return true;\n }\n\n const towerName = normalizeAddress(route.towerName);\n const towerId = normalizeAddress(route.towerId);\n if (!towerName && !towerId) return false;\n\n return (\n matchesTowerAddress(route.fromId, towerName, towerId) ||\n matchesTowerAddress(route.fromName, towerName, towerId) ||\n matchesTowerAddress(route.to, towerName, towerId) ||\n matchesTowerAddress(route.resolvedTo, towerName, towerId)\n );\n}\n\nfunction pruneHistory(\n entries: number[] | undefined,\n nowMs: number,\n windowMs: number,\n): number[] {\n if (!entries?.length) return [];\n return entries.filter((timestamp) => nowMs - timestamp <= windowMs);\n}\n\nexport function getPeerDmRateLimitKey(route: PeerDmRoute): string | null {\n if (isPeerDmRateLimitExempt(route)) {\n return null;\n }\n\n const from = canonicalizeAgentId(normalizeAddress(route.fromId));\n const to = resolveTargetAddress(route);\n if (!from || !to || to === \"broadcast\") {\n return null;\n }\n\n return `${from}->${to}`;\n}\n\nexport function checkPeerDmRateLimit(\n store: PeerDmHistoryStore,\n route: PeerDmRoute,\n nowMs = Date.now(),\n maxMessages = PEER_DM_MAX_MESSAGES,\n windowMs = PEER_DM_WINDOW_MS,\n): PeerDmRateLimitCheck {\n const key = getPeerDmRateLimitKey(route);\n const target = resolveTargetAddress(route);\n if (!key) {\n return {\n allowed: true,\n exempt: true,\n key: null,\n target,\n recentCount: 0,\n };\n }\n\n const recent = pruneHistory(store.get(key), nowMs, windowMs);\n return {\n allowed: recent.length < maxMessages,\n exempt: false,\n key,\n target,\n recentCount: recent.length,\n };\n}\n\nexport function recordPeerDm(\n store: PeerDmHistoryStore,\n route: PeerDmRoute,\n nowMs = Date.now(),\n windowMs = PEER_DM_WINDOW_MS,\n): void {\n const key = getPeerDmRateLimitKey(route);\n if (!key) return;\n\n const recent = pruneHistory(store.get(key), nowMs, windowMs);\n recent.push(nowMs);\n store.set(key, recent);\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n unlinkSync,\n readdirSync,\n openSync,\n closeSync,\n renameSync,\n statSync,\n constants,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { COMMS_DIR } from \"./tap-utils.js\";\n\n// ─── Types ─────────────────────────────────────────────────────\n\nexport type HeartbeatSource = \"bridge-dispatch\" | \"mcp-direct\";\n\nexport interface NameClaim {\n name: string;\n claimedBy: {\n instanceId: string;\n sessionPid: number;\n source: HeartbeatSource;\n };\n claimedAt: string;\n nonce: string;\n status: \"confirmed\" | \"released\";\n expiresAt: string | null;\n}\n\nexport interface NameClaimResult {\n success: boolean;\n claim: NameClaim | null;\n conflictWith: {\n instanceId: string;\n alive: boolean;\n lastActivity: string;\n } | null;\n}\n\n// ─── Constants ─────────────────────────────────────────────────\n\nconst CLAIMS_DIR = join(COMMS_DIR, \".claims\");\nconst CLAIM_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\n// ─── Helpers ───────────────────────────────────────────────────\n\nfunction ensureClaimsDir(): void {\n if (!existsSync(CLAIMS_DIR)) {\n mkdirSync(CLAIMS_DIR, { recursive: true });\n }\n}\n\nfunction claimFilePath(name: string): string {\n const safe = name.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n return join(CLAIMS_DIR, `${safe}.json`);\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Build a unique instanceId even when env vars are missing.\n * Falls back to PID-based identity so direct MCP sessions\n * never share the same \"unknown\" instanceId.\n */\nexport function resolveClaimInstanceId(): string {\n const envId = process.env.TAP_BRIDGE_INSTANCE_ID ?? process.env.TAP_AGENT_ID;\n if (envId && envId !== \"unknown\") return envId;\n // No managed identity — use PID to distinguish direct MCP sessions\n return `mcp-direct-${process.pid}`;\n}\n\n/**\n * Atomic create: uses O_EXCL to fail if file already exists.\n * Returns true if file was created, false if it already existed.\n */\nfunction atomicCreate(filePath: string, data: string): boolean {\n try {\n const fd = openSync(\n filePath,\n constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL,\n );\n writeFileSync(fd, data, \"utf-8\");\n closeSync(fd);\n return true;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") return false;\n throw err;\n }\n}\n\nfunction atomicOverwrite(filePath: string, data: string): void {\n const tmp = `${filePath}.tmp.${process.pid}.${Date.now()}`;\n writeFileSync(tmp, data, \"utf-8\");\n try {\n renameSync(tmp, filePath);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n /* best-effort cleanup */\n }\n throw err;\n }\n}\n\n// ─── Core ──────────────────────────────────────────────────────\n\nexport function checkClaim(name: string): NameClaim | null {\n const filePath = claimFilePath(name);\n if (!existsSync(filePath)) return null;\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as NameClaim;\n } catch {\n return null;\n }\n}\n\nexport function isClaimAlive(claim: NameClaim): boolean {\n if (claim.status === \"released\") return false;\n if (claim.expiresAt) {\n if (Date.now() > new Date(claim.expiresAt).getTime()) return false;\n }\n return isProcessAlive(claim.claimedBy.sessionPid);\n}\n\n/**\n * Acquire an exclusive lock file using O_EXCL.\n * Returns true if lock acquired, false if busy.\n * Stale locks (>30s) are force-removed.\n */\nfunction acquireClaimLock(name: string): boolean {\n ensureClaimsDir();\n const lockPath = claimFilePath(name) + \".lock\";\n // Remove stale locks older than 30s\n if (existsSync(lockPath)) {\n try {\n const { mtimeMs } = statSync(lockPath);\n if (Date.now() - mtimeMs > 30_000) {\n unlinkSync(lockPath);\n }\n } catch {\n /* ignore */\n }\n }\n return atomicCreate(lockPath, `${process.pid}\\n`);\n}\n\nfunction releaseClaimLock(name: string): void {\n const lockPath = claimFilePath(name) + \".lock\";\n try {\n unlinkSync(lockPath);\n } catch {\n /* ignore */\n }\n}\n\nexport function claimName(\n name: string,\n instanceId: string,\n pid: number,\n source: HeartbeatSource,\n): NameClaimResult {\n ensureClaimsDir();\n\n // Acquire exclusive lock — serializes all claim operations for this name\n if (!acquireClaimLock(name)) {\n // Lock busy — another process is claiming right now\n return {\n success: false,\n claim: null,\n conflictWith: {\n instanceId: \"lock-busy\",\n alive: true,\n lastActivity: new Date().toISOString(),\n },\n };\n }\n\n try {\n return claimNameLocked(name, instanceId, pid, source);\n } finally {\n releaseClaimLock(name);\n }\n}\n\n/**\n * Claim logic under exclusive lock — no race conditions.\n */\nfunction claimNameLocked(\n name: string,\n instanceId: string,\n pid: number,\n source: HeartbeatSource,\n): NameClaimResult {\n const filePath = claimFilePath(name);\n const claim = createClaim(name, instanceId, pid, source);\n const data = JSON.stringify(claim, null, 2) + \"\\n\";\n\n const existing = checkClaim(name);\n\n // No existing claim → create\n if (!existing) {\n atomicOverwrite(filePath, data);\n return { success: true, claim, conflictWith: null };\n }\n\n // Same instance + same PID → idempotent\n if (\n existing.claimedBy.instanceId === instanceId &&\n existing.claimedBy.sessionPid === pid\n ) {\n return { success: true, claim: existing, conflictWith: null };\n }\n\n // Same instance, different PID → restart reclaim only if previous claim is not alive\n if (existing.claimedBy.instanceId === instanceId) {\n if (isClaimAlive(existing)) {\n // Previous claim still alive (not expired AND PID running) — true conflict\n return {\n success: false,\n claim: null,\n conflictWith: {\n instanceId: existing.claimedBy.instanceId,\n alive: true,\n lastActivity: existing.claimedAt,\n },\n };\n }\n atomicOverwrite(filePath, data);\n return { success: true, claim, conflictWith: null };\n }\n\n // Different instance — check liveness\n if (!isClaimAlive(existing)) {\n // Dead claim — take over\n atomicOverwrite(filePath, data);\n return { success: true, claim, conflictWith: null };\n }\n\n // Alive conflict — reject\n return {\n success: false,\n claim: null,\n conflictWith: {\n instanceId: existing.claimedBy.instanceId,\n alive: true,\n lastActivity: existing.claimedAt,\n },\n };\n}\n\n/**\n * Release claim — under lock, only if caller owns it.\n */\nexport function releaseClaim(\n name: string,\n instanceId?: string,\n pid?: number,\n): boolean {\n if (!acquireClaimLock(name)) return false;\n try {\n return releaseClaimLocked(name, instanceId, pid);\n } finally {\n releaseClaimLock(name);\n }\n}\n\nfunction releaseClaimLocked(\n name: string,\n instanceId?: string,\n pid?: number,\n): boolean {\n const filePath = claimFilePath(name);\n if (!existsSync(filePath)) return false;\n\n if (instanceId || pid) {\n const claim = checkClaim(name);\n if (!claim) return false;\n if (instanceId && claim.claimedBy.instanceId !== instanceId) return false;\n if (pid && claim.claimedBy.sessionPid !== pid) return false;\n }\n\n try {\n unlinkSync(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Renew TTL — under lock, only if caller owns the claim.\n */\nexport function renewClaimTTL(\n name: string,\n instanceId?: string,\n pid?: number,\n): boolean {\n if (!acquireClaimLock(name)) return false;\n try {\n return renewClaimTTLLocked(name, instanceId, pid);\n } finally {\n releaseClaimLock(name);\n }\n}\n\nfunction renewClaimTTLLocked(\n name: string,\n instanceId?: string,\n pid?: number,\n): boolean {\n const claim = checkClaim(name);\n if (!claim || claim.status === \"released\") return false;\n\n if (instanceId && claim.claimedBy.instanceId !== instanceId) return false;\n if (pid && claim.claimedBy.sessionPid !== pid) return false;\n\n claim.expiresAt = new Date(Date.now() + CLAIM_TTL_MS).toISOString();\n const filePath = claimFilePath(name);\n atomicOverwrite(filePath, JSON.stringify(claim, null, 2) + \"\\n\");\n return true;\n}\n\nexport function expireStale(): string[] {\n ensureClaimsDir();\n const expired: string[] = [];\n\n for (const file of readdirSync(CLAIMS_DIR)) {\n if (!file.endsWith(\".json\")) continue;\n const filePath = join(CLAIMS_DIR, file);\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n const claim = JSON.parse(raw) as NameClaim;\n if (!isClaimAlive(claim)) {\n unlinkSync(filePath);\n expired.push(claim.name);\n }\n } catch {\n // Skip corrupted files\n }\n }\n\n return expired;\n}\n\n// ─── Internal ──────────────────────────────────────────────────\n\nfunction createClaim(\n name: string,\n instanceId: string,\n pid: number,\n source: HeartbeatSource,\n): NameClaim {\n return {\n name,\n claimedBy: { instanceId, sessionPid: pid, source },\n claimedAt: new Date().toISOString(),\n nonce: randomUUID(),\n status: \"confirmed\",\n expiresAt: new Date(Date.now() + CLAIM_TTL_MS).toISOString(),\n };\n}\n","/**\n * tap-comms optional SQLite cache layer.\n * Falls back gracefully if bun:sqlite is unavailable.\n */\nimport { existsSync, readFileSync, readdirSync, statSync } from \"fs\";\nimport { join } from \"path\";\nimport {\n DB_PATH,\n INBOX_DIR,\n RECEIPTS_DIR,\n debug,\n parseFilename,\n type ChannelSource,\n} from \"./tap-utils.js\";\n\n// ── DB Instance ─────────────────────────────────────────────────────────\n\n// bun:sqlite type stub — avoids TS2307 when not running in Bun\ninterface BunDatabase {\n exec(sql: string): void;\n run(sql: string, ...args: unknown[]): void;\n prepare(sql: string): {\n run(...args: unknown[]): void;\n all(...args: unknown[]): unknown[];\n get(...args: unknown[]): unknown;\n };\n close(): void;\n}\n\nlet db: BunDatabase | null = null;\n\nexport function getDb() {\n return db;\n}\n\n// ── Init ────────────────────────────────────────────────────────────────\n\nexport function initDb(): boolean {\n try {\n const { Database } = require(\"bun:sqlite\") as {\n Database: new (path: string, opts?: { create?: boolean }) => BunDatabase;\n };\n db = new Database(DB_PATH, { create: true });\n db.exec(\"PRAGMA journal_mode=WAL\");\n db.exec(\"PRAGMA busy_timeout=5000\");\n db.exec(`\n CREATE TABLE IF NOT EXISTS messages (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n filename TEXT UNIQUE NOT NULL,\n from_agent TEXT NOT NULL,\n to_agent TEXT NOT NULL,\n subject TEXT NOT NULL,\n source TEXT NOT NULL DEFAULT 'inbox',\n mtime REAL NOT NULL,\n created_at TEXT DEFAULT (datetime('now'))\n );\n CREATE INDEX IF NOT EXISTS idx_messages_to ON messages(to_agent);\n CREATE INDEX IF NOT EXISTS idx_messages_mtime ON messages(mtime);\n CREATE INDEX IF NOT EXISTS idx_messages_from ON messages(from_agent);\n\n CREATE TABLE IF NOT EXISTS heartbeats (\n agent TEXT PRIMARY KEY,\n status TEXT NOT NULL DEFAULT 'active',\n last_activity TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS receipts (\n filename TEXT NOT NULL,\n reader TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n PRIMARY KEY (filename, reader)\n );\n `);\n debug(\"SQLite initialized: \" + DB_PATH);\n return true;\n } catch (err) {\n debug(\"SQLite unavailable, using file-only mode: \" + String(err));\n db = null;\n return false;\n }\n}\n\n// ── Auto Sync ───────────────────────────────────────────────────────────\n\nexport function autoSyncOnStartup() {\n if (!db) return;\n\n try {\n // Sync inbox\n if (existsSync(INBOX_DIR)) {\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n const match = filename.match(/^\\d{8}-(.+?)-(.+?)-(.+)\\.md$/);\n if (!match) continue;\n try {\n const mtime = statSync(join(INBOX_DIR, filename)).mtimeMs;\n db.run(\n \"INSERT OR IGNORE INTO messages (filename, from_agent, to_agent, subject, source, mtime) VALUES (?, ?, ?, ?, ?, ?)\",\n [filename, match[1], match[2], match[3], \"inbox\", mtime],\n );\n } catch {}\n }\n }\n debug(\"auto-sync: inbox files imported into DB\");\n\n // Sync receipts\n const rcptPath = join(RECEIPTS_DIR, \"receipts.json\");\n if (existsSync(rcptPath)) {\n try {\n const rcptStore = JSON.parse(readFileSync(rcptPath, \"utf-8\"));\n for (const [fname, readers] of Object.entries(rcptStore)) {\n for (const r of readers as Array<{\n reader: string;\n timestamp: string;\n }>) {\n db.run(\n \"INSERT OR IGNORE INTO receipts (filename, reader, timestamp) VALUES (?, ?, ?)\",\n [fname, r.reader, r.timestamp],\n );\n }\n }\n debug(\"auto-sync: receipts imported into DB\");\n } catch {}\n }\n } catch {}\n}\n\n// ── Write Helpers ───────────────────────────────────────────────────────\n\nexport function dbInsertMessage(\n filename: string,\n from: string,\n to: string,\n subject: string,\n source: ChannelSource,\n mtimeMs: number,\n) {\n if (!db) return;\n try {\n db.run(\n \"INSERT OR IGNORE INTO messages (filename, from_agent, to_agent, subject, source, mtime) VALUES (?, ?, ?, ?, ?, ?)\",\n [filename, from, to, subject, source, mtimeMs],\n );\n } catch {}\n}\n\nexport function dbUpsertHeartbeat(\n agent: string,\n status: string,\n lastActivity: string,\n) {\n if (!db) return;\n try {\n db.run(\n `INSERT INTO heartbeats (agent, status, last_activity, updated_at)\n VALUES (?, ?, ?, datetime('now'))\n ON CONFLICT(agent) DO UPDATE SET\n status=excluded.status,\n last_activity=excluded.last_activity,\n updated_at=datetime('now')`,\n [agent, status, lastActivity],\n );\n } catch {}\n}\n\nexport function dbInsertReceipt(\n filename: string,\n reader: string,\n timestamp: string,\n) {\n if (!db) return;\n try {\n db.run(\n \"INSERT OR IGNORE INTO receipts (filename, reader, timestamp) VALUES (?, ?, ?)\",\n [filename, reader, timestamp],\n );\n } catch {}\n}\n\n// ── Query Helpers ───────────────────────────────────────────────────────\n\nexport function dbGetStats(cutoff: number): {\n sent: Record<string, number>;\n received: Record<string, number>;\n broadcasts: number;\n totalReceipts: number;\n} | null {\n if (!db) return null;\n try {\n const sentRows = db\n .prepare(\n \"SELECT from_agent, COUNT(*) as cnt FROM messages WHERE mtime >= ? AND source = 'inbox' GROUP BY from_agent\",\n )\n .all(cutoff) as Array<{ from_agent: string; cnt: number }>;\n const receivedRows = db\n .prepare(\n \"SELECT to_agent, COUNT(*) as cnt FROM messages WHERE mtime >= ? AND source = 'inbox' AND to_agent NOT IN ('전체','all') GROUP BY to_agent\",\n )\n .all(cutoff) as Array<{ to_agent: string; cnt: number }>;\n const broadcastRow = db\n .prepare(\n \"SELECT COUNT(*) as cnt FROM messages WHERE mtime >= ? AND source = 'inbox' AND to_agent IN ('전체','all')\",\n )\n .get(cutoff) as { cnt: number } | null;\n const cutoffISO = new Date(cutoff).toISOString();\n const receiptRow = db\n .prepare(\"SELECT COUNT(*) as cnt FROM receipts WHERE timestamp >= ?\")\n .get(cutoffISO) as { cnt: number } | null;\n\n const sent: Record<string, number> = {};\n for (const r of sentRows) sent[r.from_agent] = r.cnt;\n const received: Record<string, number> = {};\n for (const r of receivedRows) received[r.to_agent] = r.cnt;\n\n return {\n sent,\n received,\n broadcasts: broadcastRow?.cnt ?? 0,\n totalReceipts: receiptRow?.cnt ?? 0,\n };\n } catch {\n return null;\n }\n}\n\nexport function dbSyncAll(): {\n messages: number;\n heartbeats: number;\n receipts: number;\n} | null {\n if (!db) return null;\n\n let msgCount = 0;\n let hbCount = 0;\n let rcptCount = 0;\n\n // Sync inbox\n if (existsSync(INBOX_DIR)) {\n for (const filename of readdirSync(INBOX_DIR)) {\n if (!filename.endsWith(\".md\")) continue;\n const parsed = parseFilename(filename);\n if (!parsed) continue;\n try {\n const mtime = statSync(join(INBOX_DIR, filename)).mtimeMs;\n dbInsertMessage(\n filename,\n parsed.from,\n parsed.to,\n parsed.subject,\n \"inbox\",\n mtime,\n );\n msgCount++;\n } catch {}\n }\n }\n\n // Sync heartbeats\n try {\n const { loadHeartbeats } = require(\"./tap-io.js\");\n const hbStore = loadHeartbeats();\n for (const [agent, hb] of Object.entries(hbStore) as Array<[string, any]>) {\n dbUpsertHeartbeat(agent, hb.status, hb.lastActivity);\n hbCount++;\n }\n } catch {}\n\n // Sync receipts\n try {\n const { loadReceipts } = require(\"./tap-io.js\");\n const rcptStore = loadReceipts();\n for (const [filename, readers] of Object.entries(rcptStore) as Array<\n [string, any]\n >) {\n for (const r of readers) {\n dbInsertReceipt(filename, r.reader, r.timestamp);\n rcptCount++;\n }\n }\n } catch {}\n\n return { messages: msgCount, heartbeats: hbCount, receipts: rcptCount };\n}\n","/**\n * tap-comms fs.watch watcher: real-time channel push notifications.\n */\nimport { existsSync, readFileSync, statSync, watch, type FSWatcher } from \"fs\";\nimport { join } from \"path\";\nimport type { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n SERVER_START,\n stripBom,\n parseFilename,\n parseFrontmatter,\n isForMe,\n getAgentId,\n getAgentName,\n getSourceKey,\n debug,\n type ChannelSource,\n} from \"./tap-utils.js\";\nimport { dbInsertMessage } from \"./tap-db.js\";\nimport { readFiles, resolveAgentLabel } from \"./tap-io.js\";\nimport { isOwnMessageAddress } from \"./tap-identity.js\";\n\n// ── State ───────────────────────────────────────────────────────────────\n\nconst notifiedFiles = new Set<string>();\nconst recentEvents = new Map<string, number>();\nconst inFlightFiles = new Set<string>();\nconst DEBOUNCE_MS = 200;\nconst MAX_READY_ATTEMPTS = 6;\nconst READY_RETRY_MS = 40;\nconst WATCH_RESTART_MS = 1_000;\nconst RECENT_EVENT_TTL_MS = 5 * 60 * 1000;\nconst RECENT_EVENT_CLEANUP_MS = 60 * 1000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetryableFsError(error: unknown): boolean {\n const code =\n error && typeof error === \"object\" && \"code\" in error\n ? String((error as NodeJS.ErrnoException).code ?? \"\")\n : \"\";\n return (\n code === \"ENOENT\" ||\n code === \"EBUSY\" ||\n code === \"EPERM\" ||\n code === \"EACCES\"\n );\n}\n\nasync function waitForFileReady(\n filepath: string,\n): Promise<{ content: string; mtime: number } | \"stale\" | null> {\n for (let attempt = 0; attempt < MAX_READY_ATTEMPTS; attempt++) {\n try {\n const mtime = statSync(filepath).mtimeMs;\n if (mtime < SERVER_START - 5000) return \"stale\";\n const content = stripBom(readFileSync(filepath, \"utf-8\"));\n return { content, mtime };\n } catch (error) {\n if (attempt === MAX_READY_ATTEMPTS - 1 || !isRetryableFsError(error)) {\n debug(\n `watch read failed [${filepath}]: ${error instanceof Error ? error.message : String(error)}`,\n );\n return null;\n }\n await sleep(READY_RETRY_MS * (attempt + 1));\n }\n }\n\n return null;\n}\n\nfunction isOwnMessageArtifact(\n source: ChannelSource,\n filename: string,\n parsed: ReturnType<typeof parseFilename>,\n): boolean {\n const agentId = getAgentId();\n const agentName = getAgentName();\n\n if (parsed && isOwnMessageAddress(parsed.from, agentId, agentName)) {\n return true;\n }\n\n if (source === \"reviews\") {\n return (\n filename.endsWith(`-${agentId}.md`) ||\n filename.endsWith(`-${agentName}.md`)\n );\n }\n\n return false;\n}\n\nfunction cleanupRecentEvents(now: number = Date.now()) {\n const cutoff = now - RECENT_EVENT_TTL_MS;\n for (const [key, ts] of recentEvents) {\n if (ts < cutoff) recentEvents.delete(key);\n }\n}\n\nconst recentEventsCleanupTimer = setInterval(() => {\n cleanupRecentEvents();\n}, RECENT_EVENT_CLEANUP_MS);\nrecentEventsCleanupTimer.unref?.();\n\n// @internal test helper\nexport function resetWatcherStateForTests() {\n notifiedFiles.clear();\n recentEvents.clear();\n inFlightFiles.clear();\n}\n\n// @internal test helper\nexport async function processWatchFile(\n dir: string,\n source: ChannelSource,\n filename: string,\n mcp: Pick<Server, \"notification\">,\n): Promise<boolean> {\n const key = getSourceKey(source, filename);\n // Skip if already notified (watcher), in-flight, or read via tap_list_unread\n if (notifiedFiles.has(key) || inFlightFiles.has(key) || readFiles.has(key))\n return false;\n\n inFlightFiles.add(key);\n\n try {\n const filepath = join(dir, filename);\n const file = await waitForFileReady(filepath);\n if (file === \"stale\") {\n notifiedFiles.add(key);\n return false;\n }\n if (!file) return false;\n\n // M204: Frontmatter-first routing (matches tap-io getUnreadItems)\n let parsed: ReturnType<typeof parseFilename> = null;\n if (source === \"inbox\") {\n const fm = parseFrontmatter(file.content);\n parsed = fm\n ? { from: fm.from, to: fm.to, subject: fm.subject }\n : parseFilename(filename);\n } else {\n parsed = parseFilename(filename);\n }\n\n if (source === \"inbox\" && (!parsed || !isForMe(parsed.to))) return false;\n if (isOwnMessageArtifact(source, filename, parsed)) return false;\n\n const rawFrom = parsed?.from || source;\n const rawTo = parsed?.to || \"all\";\n const from = parsed ? resolveAgentLabel(parsed.from) : source;\n const to = parsed ? resolveAgentLabel(parsed.to) : \"all\";\n const subject = parsed?.subject || filename.replace(/\\.md$/, \"\");\n\n dbInsertMessage(filename, rawFrom, rawTo, subject, source, Date.now());\n debug(`sending notification [${source}]: from=${from} to=${to}`);\n await mcp.notification({\n method: \"notifications/claude/channel\",\n params: {\n content: file.content,\n meta: { from, to, subject, filename, source },\n },\n });\n notifiedFiles.add(key);\n return true;\n } finally {\n inFlightFiles.delete(key);\n }\n}\n\n// ── Watch ───────────────────────────────────────────────────────────────\n\nexport function watchDir(dir: string, source: ChannelSource, mcp: Server) {\n if (!existsSync(dir)) return;\n\n let watcher: FSWatcher | null = null;\n let restartTimer: NodeJS.Timeout | null = null;\n\n const scheduleRestart = (reason: string) => {\n if (restartTimer) return;\n debug(`fs.watch restart scheduled [${source}]: ${reason}`);\n restartTimer = setTimeout(() => {\n restartTimer = null;\n if (!existsSync(dir)) {\n debug(`fs.watch restart skipped [${source}]: missing ${dir}`);\n return;\n }\n startWatcher();\n }, WATCH_RESTART_MS);\n restartTimer.unref();\n };\n\n const disposeWatcher = () => {\n if (!watcher) return;\n watcher.removeAllListeners();\n try {\n watcher.close();\n } catch {\n // Best-effort cleanup only.\n }\n watcher = null;\n };\n\n const startWatcher = () => {\n disposeWatcher();\n\n try {\n watcher = watch(dir, (eventType, filename) => {\n debug(`fs.watch [${source}]: ${eventType} ${filename}`);\n if (!filename || !filename.endsWith(\".md\")) return;\n\n const key = getSourceKey(source, filename);\n const now = Date.now();\n cleanupRecentEvents(now);\n const lastSeen = recentEvents.get(key);\n if (lastSeen && now - lastSeen < DEBOUNCE_MS) return;\n recentEvents.set(key, now);\n\n void processWatchFile(dir, source, filename, mcp).catch((error) => {\n debug(\n `watch processing failed [${source}/${filename}]: ${error instanceof Error ? error.message : String(error)}`,\n );\n });\n });\n\n watcher.on(\"error\", (error) => {\n debug(\n `fs.watch error [${source}]: ${error instanceof Error ? error.message : String(error)}`,\n );\n scheduleRestart(\"error\");\n });\n\n watcher.on(\"close\", () => {\n debug(`fs.watch closed [${source}]`);\n scheduleRestart(\"close\");\n });\n\n debug(`fs.watch active [${source}]: ${dir}`);\n } catch (error) {\n debug(\n `fs.watch start failed [${source}]: ${error instanceof Error ? error.message : String(error)}`,\n );\n scheduleRestart(\"start-failed\");\n }\n };\n\n startWatcher();\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n buildHeartbeatConnectHash,\n resolveKnownInstanceId,\n type Heartbeat,\n type HeartbeatSource,\n} from \"./tap-utils.js\";\n\ntype BridgeStateFile = {\n pid?: number;\n runtimeStateDir?: string | null;\n};\n\ntype RuntimeHeartbeat = {\n connected?: boolean;\n initialized?: boolean;\n threadId?: string | null;\n activeTurnId?: string | null;\n idleSince?: string | null;\n turnState?: \"active\" | \"idle\" | \"waiting-approval\" | \"disconnected\" | null;\n};\n\ntype RuntimeThreadState = {\n threadId?: string | null;\n};\n\nexport interface TapWhoAgent {\n id: string;\n agent: string;\n status: string;\n lastHeartbeat: string;\n lastActivity: string;\n alive: boolean;\n source: HeartbeatSource;\n instanceId: string | null;\n connectHash: string;\n presence: \"bridge-live\" | \"bridge-stale\" | \"mcp-only\";\n lifecycle:\n | \"ready\"\n | \"initializing\"\n | \"degraded-no-thread\"\n | \"bridge-stale\"\n | null;\n session:\n | \"initializing\"\n | \"active\"\n | \"idle\"\n | \"waiting-approval\"\n | \"disconnected\"\n | null;\n idleSeconds: number | null;\n}\n\ntype TapPresenceCandidate = TapWhoAgent & {\n displayName: string | null;\n lastActivityMs: number;\n};\n\nexport interface TapRecipientResolution {\n target: string;\n found: boolean;\n ambiguous: boolean;\n candidates: string[];\n warning: string | null;\n}\n\nfunction parseJsonFile<T>(filePath: string): T | null {\n if (!existsSync(filePath)) return null;\n try {\n return JSON.parse(readFileSync(filePath, \"utf-8\")) as T;\n } catch {\n return null;\n }\n}\n\nfunction formatAgentLabel(\n agentIdOrName: string,\n displayName?: string | null,\n): string {\n const normalizedId = agentIdOrName.trim();\n const normalizedName = displayName?.trim();\n\n if (!normalizedId) {\n return normalizedName ?? agentIdOrName;\n }\n\n if (!normalizedName || normalizedName === normalizedId) {\n return normalizedId;\n }\n\n return `${normalizedName} [${normalizedId}]`;\n}\n\nfunction isProcessAlive(pid: number | null | undefined): boolean {\n if (pid == null || !Number.isFinite(pid)) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction parseIsoAgeSeconds(value: string | null | undefined): number | null {\n if (!value) return null;\n const timestamp = new Date(value).getTime();\n if (Number.isNaN(timestamp)) return null;\n return Math.max(0, Math.floor((Date.now() - timestamp) / 1000));\n}\n\nfunction getActivityMs(heartbeat: Heartbeat): number {\n return new Date(heartbeat.lastActivity ?? heartbeat.timestamp ?? 0).getTime();\n}\n\nfunction resolveHeartbeatSource(heartbeat: Heartbeat): HeartbeatSource {\n return heartbeat.source === \"bridge-dispatch\" ? \"bridge-dispatch\" : \"mcp-direct\";\n}\n\nfunction resolveBridgeStatus(\n stateDir: string,\n instanceId: string | null,\n): {\n presence: \"bridge-live\" | \"bridge-stale\" | \"mcp-only\";\n lifecycle:\n | \"ready\"\n | \"initializing\"\n | \"degraded-no-thread\"\n | \"bridge-stale\"\n | null;\n session:\n | \"initializing\"\n | \"active\"\n | \"idle\"\n | \"waiting-approval\"\n | \"disconnected\"\n | null;\n idleSince: string | null;\n} {\n if (!instanceId) {\n return {\n presence: \"mcp-only\",\n lifecycle: null,\n session: null,\n idleSince: null,\n };\n }\n\n const bridgeState = parseJsonFile<BridgeStateFile>(\n join(stateDir, \"pids\", `bridge-${instanceId}.json`),\n );\n if (!bridgeState) {\n return {\n presence: \"mcp-only\",\n lifecycle: null,\n session: null,\n idleSince: null,\n };\n }\n\n if (!isProcessAlive(bridgeState.pid)) {\n return {\n presence: \"bridge-stale\",\n lifecycle: \"bridge-stale\",\n session: null,\n idleSince: null,\n };\n }\n\n const runtimeHeartbeat = bridgeState.runtimeStateDir\n ? parseJsonFile<RuntimeHeartbeat>(\n join(bridgeState.runtimeStateDir, \"heartbeat.json\"),\n )\n : null;\n const savedThread = bridgeState.runtimeStateDir\n ? parseJsonFile<RuntimeThreadState>(\n join(bridgeState.runtimeStateDir, \"thread.json\"),\n )\n : null;\n\n if (!runtimeHeartbeat || runtimeHeartbeat.initialized === false) {\n return {\n presence: \"bridge-live\",\n lifecycle: \"initializing\",\n session: \"initializing\",\n idleSince: null,\n };\n }\n\n const lifecycle =\n runtimeHeartbeat.threadId && runtimeHeartbeat.connected !== false\n ? \"ready\"\n : \"degraded-no-thread\";\n\n const session =\n runtimeHeartbeat.activeTurnId || runtimeHeartbeat.turnState === \"active\"\n ? \"active\"\n : runtimeHeartbeat.turnState === \"waiting-approval\"\n ? \"waiting-approval\"\n : runtimeHeartbeat.turnState === \"disconnected\" ||\n runtimeHeartbeat.connected === false\n ? \"disconnected\"\n : \"idle\";\n\n const idleSince =\n session === \"idle\" || session === \"waiting-approval\"\n ? (runtimeHeartbeat.idleSince ?? null)\n : null;\n\n return {\n presence: \"bridge-live\",\n lifecycle:\n lifecycle === \"degraded-no-thread\" && !savedThread?.threadId\n ? \"degraded-no-thread\"\n : lifecycle,\n session,\n idleSince,\n };\n}\n\nconst PRESENCE_PRIORITY: Record<TapWhoAgent[\"presence\"], number> = {\n \"bridge-live\": 3,\n \"mcp-only\": 2,\n \"bridge-stale\": 1,\n};\n\nconst SOURCE_PRIORITY: Record<HeartbeatSource, number> = {\n \"bridge-dispatch\": 2,\n \"mcp-direct\": 1,\n};\n\nfunction compareCandidates(a: TapPresenceCandidate, b: TapPresenceCandidate): number {\n const presenceDelta = PRESENCE_PRIORITY[b.presence] - PRESENCE_PRIORITY[a.presence];\n if (presenceDelta !== 0) return presenceDelta;\n\n const sourceDelta = SOURCE_PRIORITY[b.source] - SOURCE_PRIORITY[a.source];\n if (sourceDelta !== 0) return sourceDelta;\n\n if (a.alive !== b.alive) return a.alive ? -1 : 1;\n if (a.lastActivityMs !== b.lastActivityMs) {\n return b.lastActivityMs - a.lastActivityMs;\n }\n return a.id.localeCompare(b.id);\n}\n\nfunction dedupeByConnectHash(\n candidates: TapPresenceCandidate[],\n): TapPresenceCandidate[] {\n const deduped = new Map<string, TapPresenceCandidate>();\n for (const candidate of candidates) {\n const existing = deduped.get(candidate.connectHash);\n if (!existing || compareCandidates(candidate, existing) < 0) {\n deduped.set(candidate.connectHash, candidate);\n }\n }\n return [...deduped.values()].sort(compareCandidates);\n}\n\nexport function buildPresenceCandidates(\n store: Record<string, Heartbeat>,\n minutes?: number | null,\n): TapPresenceCandidate[] {\n const cutoff = minutes == null ? null : Date.now() - minutes * 60 * 1000;\n const stateDir = process.env.TAP_STATE_DIR;\n const agents: TapPresenceCandidate[] = [];\n\n for (const [agentId, heartbeat] of Object.entries(store)) {\n if (!heartbeat.id) continue;\n\n const lastActivityMs = getActivityMs(heartbeat);\n if (!Number.isFinite(lastActivityMs)) continue;\n if (cutoff != null && lastActivityMs < cutoff) continue;\n\n const displayName = heartbeat.agent ?? null;\n const instanceId =\n heartbeat.instanceId ?? resolveKnownInstanceId(agentId, displayName);\n const source = resolveHeartbeatSource(heartbeat);\n const connectHash =\n heartbeat.connectHash ?? buildHeartbeatConnectHash(instanceId, agentId);\n const bridge =\n stateDir != null\n ? resolveBridgeStatus(stateDir, instanceId)\n : {\n presence: \"mcp-only\" as const,\n lifecycle: null,\n session: null,\n idleSince: null,\n };\n const idleBasis =\n bridge.idleSince ??\n heartbeat.lastActivity ??\n heartbeat.timestamp ??\n null;\n\n agents.push({\n id: agentId,\n agent: formatAgentLabel(agentId, displayName),\n status: heartbeat.status ?? \"active\",\n lastHeartbeat: heartbeat.timestamp ?? \"\",\n lastActivity: heartbeat.lastActivity ?? heartbeat.timestamp ?? \"\",\n alive: heartbeat.status !== \"signing-off\",\n source,\n instanceId,\n connectHash,\n presence: bridge.presence,\n lifecycle: bridge.lifecycle,\n session: bridge.session,\n idleSeconds: parseIsoAgeSeconds(idleBasis),\n displayName,\n lastActivityMs,\n });\n }\n\n return agents.sort(compareCandidates);\n}\n\nexport function buildWhoAgents(\n store: Record<string, Heartbeat>,\n minutes: number,\n): TapWhoAgent[] {\n return dedupeByConnectHash(buildPresenceCandidates(store, minutes));\n}\n\nexport function resolvePreferredRecipient(\n store: Record<string, Heartbeat>,\n recipient: string,\n): TapRecipientResolution {\n const allCandidates = buildPresenceCandidates(store, null);\n const exactId = allCandidates.find((candidate) => candidate.id === recipient);\n if (exactId) {\n return {\n target: exactId.id,\n found: true,\n ambiguous: false,\n candidates: [exactId.id],\n warning: null,\n };\n }\n\n const deduped = dedupeByConnectHash(allCandidates);\n const nameMatches = deduped.filter(\n (candidate) => candidate.displayName === recipient,\n );\n if (nameMatches.length === 1) {\n return {\n target: nameMatches[0].id,\n found: true,\n ambiguous: false,\n candidates: [nameMatches[0].id],\n warning: null,\n };\n }\n\n if (nameMatches.length > 1) {\n const sorted = [...nameMatches].sort(compareCandidates);\n const winner = sorted[0];\n const candidateIds = sorted.map((candidate) => candidate.id);\n return {\n target: winner.id,\n found: true,\n ambiguous: true,\n candidates: candidateIds,\n warning:\n `⚠️ Routed \"${recipient}\" → \"${winner.id}\" ` +\n `(${winner.presence}/${winner.source}, preferred of ${candidateIds.join(\", \")}).`,\n };\n }\n\n return {\n target: recipient,\n found: false,\n ambiguous: false,\n candidates: [],\n warning: null,\n };\n}\n\n/**\n * Build a Map<heartbeatKey, PresenceLevel> for routing disambiguation.\n * Unlike buildWhoAgents, returns raw key→presence without label formatting.\n */\nexport function resolvePresenceMap(\n store: Record<string, Heartbeat>,\n): Map<string, \"bridge-live\" | \"bridge-stale\" | \"mcp-only\"> {\n const result = new Map<string, \"bridge-live\" | \"bridge-stale\" | \"mcp-only\">();\n\n for (const candidate of buildPresenceCandidates(store, null)) {\n result.set(candidate.id, candidate.presence);\n }\n\n return result;\n}\n","/**\n * tap-comms polling fallback: catches messages missed by fs.watch push.\n *\n * Runs periodically alongside the watcher. Scans inbox/reviews for files\n * that arrived after server start but were never pushed via channel\n * notification (e.g. due to fs.watch missing events on Windows).\n *\n * M93: Auto-poll fallback for push reliability.\n */\nimport { existsSync, readdirSync, statSync } from \"fs\";\nimport type { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n SERVER_START,\n getSourceDir,\n debug,\n type ChannelSource,\n} from \"./tap-utils.js\";\nimport { processWatchFile } from \"./tap-watcher.js\";\n\n// ── Config ──────────────────────────────────────────────────────────────\n\n// Windows fs.watch is unreliable for cross-process file creation; poll faster.\nconst POLL_INTERVAL_MS = process.platform === \"win32\" ? 10_000 : 30_000;\nconst POLL_SOURCES: ChannelSource[] = [\"inbox\", \"reviews\"];\n\n// ── Stats ───────────────────────────────────────────────────────────────\n\nlet recoveredCount = 0;\nlet pollCycles = 0;\n\nexport function getPollStats() {\n return { pollCycles, recoveredCount };\n}\n\n// ── Poll ────────────────────────────────────────────────────────────────\n\nasync function pollOnce(mcp: Server): Promise<number> {\n let recovered = 0;\n\n for (const source of POLL_SOURCES) {\n const dir = getSourceDir(source);\n if (!dir || !existsSync(dir)) continue;\n\n let filenames: string[];\n try {\n filenames = readdirSync(dir).filter((f) => f.endsWith(\".md\"));\n } catch {\n continue;\n }\n\n for (const filename of filenames) {\n // Quick pre-filter: only check files newer than server start\n const filepath = `${dir}/${filename}`;\n try {\n const mtime = statSync(filepath).mtimeMs;\n if (mtime < SERVER_START - 5000) continue;\n } catch {\n continue;\n }\n\n // processWatchFile handles notifiedFiles/inFlightFiles dedup internally.\n // If already notified, it returns false immediately (cheap).\n try {\n const sent = await processWatchFile(dir, source, filename, mcp);\n if (sent) {\n recovered++;\n debug(`poll-fallback recovered [${source}]: ${filename}`);\n }\n } catch {\n // Non-critical — skip this file\n }\n }\n }\n\n return recovered;\n}\n\n// ── Start ───────────────────────────────────────────────────────────────\n\nexport function startPollFallback(mcp: Server) {\n debug(`poll-fallback: starting (interval=${POLL_INTERVAL_MS}ms)`);\n\n const timer = setInterval(async () => {\n pollCycles++;\n try {\n const count = await pollOnce(mcp);\n if (count > 0) {\n recoveredCount += count;\n debug(\n `poll-fallback: recovered ${count} missed message(s) (total: ${recoveredCount})`,\n );\n }\n } catch (error) {\n debug(\n `poll-fallback error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }, POLL_INTERVAL_MS);\n timer.unref();\n\n // Run first poll after a short delay (let watcher settle first)\n setTimeout(async () => {\n pollCycles++;\n try {\n const count = await pollOnce(mcp);\n if (count > 0) {\n recoveredCount += count;\n debug(`poll-fallback (initial): recovered ${count} missed message(s)`);\n }\n } catch {\n // Non-critical\n }\n }, 5_000).unref();\n}\n"],"mappings":"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","names":["canonicalizeAgentId","instance","stateBootstrap","existsSync","mkdirSync","readFileSync","readdirSync","renameSync","statSync","unlinkSync","writeFileSync","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","existsSync","readFileSync","readdirSync","statSync","join","existsSync","readFileSync","readdirSync","statSync","join","existsSync","readdirSync","statSync","join","readFileSync","loadHeartbeats","loadReceipts","existsSync","readFileSync","statSync","join","resolve","statSync","readFileSync","mcp","join","existsSync","existsSync","readFileSync","join","formatAgentLabel","isProcessAlive","readdirSync","renameSync","statSync","unlinkSync","existsSync","readdirSync","statSync","mcp","existsSync","readdirSync","statSync","join","existsSync","readFileSync","mkdirSync","writeFileSync","currentName","renameSync","unlinkSync","resolveRecipient","readdirSync","statSync","isNameConfirmed","demoteAgentName"]}