@wrongstack/core 0.287.0 → 0.291.0
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.
- package/dist/agent-status-tracker.d.ts +13 -0
- package/dist/agent-status-tracker.d.ts.map +1 -1
- package/dist/boot.d.ts.map +1 -1
- package/dist/chronicle/context.d.ts +13 -0
- package/dist/chronicle/context.d.ts.map +1 -0
- package/dist/chronicle/decision-adapter.d.ts +13 -0
- package/dist/chronicle/decision-adapter.d.ts.map +1 -0
- package/dist/chronicle/domain-adapter.d.ts +13 -0
- package/dist/chronicle/domain-adapter.d.ts.map +1 -0
- package/dist/chronicle/file-observer.d.ts +20 -0
- package/dist/chronicle/file-observer.d.ts.map +1 -0
- package/dist/chronicle/health-monitor.d.ts +11 -0
- package/dist/chronicle/health-monitor.d.ts.map +1 -0
- package/dist/chronicle/identity.d.ts +18 -0
- package/dist/chronicle/identity.d.ts.map +1 -0
- package/dist/chronicle/index.d.ts +16 -0
- package/dist/chronicle/index.d.ts.map +1 -0
- package/dist/chronicle/index.js +2555 -0
- package/dist/chronicle/index.js.map +7 -0
- package/dist/chronicle/journal.d.ts +81 -0
- package/dist/chronicle/journal.d.ts.map +1 -0
- package/dist/chronicle/process-adapter.d.ts +14 -0
- package/dist/chronicle/process-adapter.d.ts.map +1 -0
- package/dist/chronicle/prompt-manifest.d.ts +34 -0
- package/dist/chronicle/prompt-manifest.d.ts.map +1 -0
- package/dist/chronicle/provider-adapter.d.ts +13 -0
- package/dist/chronicle/provider-adapter.d.ts.map +1 -0
- package/dist/chronicle/query.d.ts +108 -0
- package/dist/chronicle/query.d.ts.map +1 -0
- package/dist/chronicle/rollup-adapter.d.ts +14 -0
- package/dist/chronicle/rollup-adapter.d.ts.map +1 -0
- package/dist/chronicle/stream-adapter.d.ts +13 -0
- package/dist/chronicle/stream-adapter.d.ts.map +1 -0
- package/dist/chronicle/tool-adapter.d.ts +15 -0
- package/dist/chronicle/tool-adapter.d.ts.map +1 -0
- package/dist/chronicle/types.d.ts +82 -0
- package/dist/chronicle/types.d.ts.map +1 -0
- package/dist/coordination/agent-monitor.d.ts +40 -0
- package/dist/coordination/agent-monitor.d.ts.map +1 -1
- package/dist/coordination/agent-subagent-runner.d.ts +7 -1
- package/dist/coordination/agent-subagent-runner.d.ts.map +1 -1
- package/dist/coordination/agents/phase6-domain.d.ts.map +1 -1
- package/dist/coordination/autonomous-coordinator.d.ts +2 -0
- package/dist/coordination/autonomous-coordinator.d.ts.map +1 -1
- package/dist/coordination/brain-monitor.d.ts +1 -1
- package/dist/coordination/brain.d.ts +3 -2
- package/dist/coordination/brain.d.ts.map +1 -1
- package/dist/coordination/collab-debug.d.ts +0 -9
- package/dist/coordination/collab-debug.d.ts.map +1 -1
- package/dist/coordination/coordinator/error-classifier.d.ts.map +1 -1
- package/dist/coordination/dep-watcher.d.ts +2 -1
- package/dist/coordination/dep-watcher.d.ts.map +1 -1
- package/dist/coordination/director/director-collab.d.ts +1 -1
- package/dist/coordination/director/director-collab.d.ts.map +1 -1
- package/dist/coordination/director-tools.d.ts.map +1 -1
- package/dist/coordination/director.d.ts +10 -1
- package/dist/coordination/director.d.ts.map +1 -1
- package/dist/coordination/file-author-tracker.d.ts.map +1 -1
- package/dist/coordination/fleet-bus.d.ts.map +1 -1
- package/dist/coordination/fleet-event-validation.d.ts +0 -7
- package/dist/coordination/fleet-event-validation.d.ts.map +1 -1
- package/dist/coordination/fleet-spawn.d.ts.map +1 -1
- package/dist/coordination/fleet-supervisor.d.ts +1 -1
- package/dist/coordination/fleet-supervisor.d.ts.map +1 -1
- package/dist/coordination/fleet.d.ts +0 -44
- package/dist/coordination/fleet.d.ts.map +1 -1
- package/dist/coordination/global-mailbox.d.ts +7 -1
- package/dist/coordination/global-mailbox.d.ts.map +1 -1
- package/dist/coordination/index.d.ts +5 -3
- package/dist/coordination/index.d.ts.map +1 -1
- package/dist/coordination/index.js +2426 -299
- package/dist/coordination/index.js.map +4 -4
- package/dist/coordination/knowledge-graph.d.ts +2 -1
- package/dist/coordination/knowledge-graph.d.ts.map +1 -1
- package/dist/coordination/large-answer-store.d.ts +0 -6
- package/dist/coordination/large-answer-store.d.ts.map +1 -1
- package/dist/coordination/mail-tools.d.ts +2 -2
- package/dist/coordination/mail-tools.d.ts.map +1 -1
- package/dist/coordination/mailbox-hooks.d.ts +2 -0
- package/dist/coordination/mailbox-hooks.d.ts.map +1 -1
- package/dist/coordination/mailbox-http-router.d.ts +43 -0
- package/dist/coordination/mailbox-http-router.d.ts.map +1 -0
- package/dist/coordination/mailbox-message-codec.d.ts +35 -0
- package/dist/coordination/mailbox-message-codec.d.ts.map +1 -1
- package/dist/coordination/mailbox-tool.d.ts +1 -1
- package/dist/coordination/mailbox-tool.d.ts.map +1 -1
- package/dist/coordination/mailbox-types.d.ts +170 -10
- package/dist/coordination/mailbox-types.d.ts.map +1 -1
- package/dist/coordination/mailbox.d.ts +1 -1
- package/dist/coordination/mailbox.d.ts.map +1 -1
- package/dist/coordination/package-author-tracker.d.ts.map +1 -1
- package/dist/coordination/provider-status-tracker.d.ts +236 -0
- package/dist/coordination/provider-status-tracker.d.ts.map +1 -0
- package/dist/coordination/subagent-budget.d.ts +2 -1
- package/dist/coordination/subagent-budget.d.ts.map +1 -1
- package/dist/core/agent-loop.d.ts +8 -3
- package/dist/core/agent-loop.d.ts.map +1 -1
- package/dist/core/agent-response.d.ts +5 -4
- package/dist/core/agent-response.d.ts.map +1 -1
- package/dist/core/agent-tools.d.ts +1 -1
- package/dist/core/agent-tools.d.ts.map +1 -1
- package/dist/core/agent.d.ts +4 -2
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/context.d.ts +55 -1
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/fallback-model.d.ts +14 -8
- package/dist/core/fallback-model.d.ts.map +1 -1
- package/dist/core/fallback-profile-manager.d.ts +118 -0
- package/dist/core/fallback-profile-manager.d.ts.map +1 -0
- package/dist/core/fleet-pulse.d.ts +2 -1
- package/dist/core/fleet-pulse.d.ts.map +1 -1
- package/dist/core/iteration-limit.d.ts +2 -1
- package/dist/core/iteration-limit.d.ts.map +1 -1
- package/dist/core/mailbox-loop.d.ts +16 -1
- package/dist/core/mailbox-loop.d.ts.map +1 -1
- package/dist/core/model-availability-calendar.d.ts +27 -0
- package/dist/core/model-availability-calendar.d.ts.map +1 -0
- package/dist/core/provider-runner.d.ts.map +1 -1
- package/dist/core/system-prompt-builder.d.ts +2 -1
- package/dist/core/system-prompt-builder.d.ts.map +1 -1
- package/dist/defaults/index.js +1920 -598
- package/dist/defaults/index.js.map +4 -4
- package/dist/execution/auto-compaction-middleware.d.ts +3 -2
- package/dist/execution/auto-compaction-middleware.d.ts.map +1 -1
- package/dist/execution/compaction-core.d.ts.map +1 -1
- package/dist/execution/council-brain.d.ts +28 -49
- package/dist/execution/council-brain.d.ts.map +1 -1
- package/dist/execution/council-orchestrator.d.ts +30 -0
- package/dist/execution/council-orchestrator.d.ts.map +1 -1
- package/dist/execution/enhance-recovery.d.ts +8 -0
- package/dist/execution/enhance-recovery.d.ts.map +1 -1
- package/dist/execution/error-handler.d.ts +2 -2
- package/dist/execution/error-handler.d.ts.map +1 -1
- package/dist/execution/eternal-autonomy.d.ts.map +1 -1
- package/dist/execution/index.js +2600 -1903
- package/dist/execution/index.js.map +4 -4
- package/dist/execution/intelligent-compactor.d.ts +0 -16
- package/dist/execution/intelligent-compactor.d.ts.map +1 -1
- package/dist/execution/model-runtime.d.ts.map +1 -1
- package/dist/execution/one-shot-llm.d.ts +9 -1
- package/dist/execution/one-shot-llm.d.ts.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +36 -0
- package/dist/execution/prompt-enhancer.d.ts.map +1 -1
- package/dist/execution/prompt-enhancer.js +158 -10
- package/dist/execution/prompt-enhancer.js.map +2 -2
- package/dist/execution/retry-policy.d.ts +0 -13
- package/dist/execution/retry-policy.d.ts.map +1 -1
- package/dist/execution/skill-loader.d.ts.map +1 -1
- package/dist/execution/tool-executor.d.ts.map +1 -1
- package/dist/goal/checkpoint.d.ts.map +1 -0
- package/dist/{autophase/auto-phase-planner.d.ts → goal/goal-planner.d.ts} +8 -8
- package/dist/goal/goal-planner.d.ts.map +1 -0
- package/dist/{autophase/auto-phase-runner.d.ts → goal/goal-runner.d.ts} +10 -10
- package/dist/goal/goal-runner.d.ts.map +1 -0
- package/dist/{autophase → goal}/index.d.ts +3 -3
- package/dist/goal/index.d.ts.map +1 -0
- package/dist/goal/phase-graph-builder.d.ts.map +1 -0
- package/dist/{autophase → goal}/phase-orchestrator.d.ts +2 -2
- package/dist/goal/phase-orchestrator.d.ts.map +1 -0
- package/dist/goal/phase-store.d.ts.map +1 -0
- package/dist/{autophase → goal}/types.d.ts +2 -2
- package/dist/goal/types.d.ts.map +1 -0
- package/dist/hq/auth-store.d.ts.map +1 -1
- package/dist/hq/commands.d.ts +2 -1
- package/dist/hq/commands.d.ts.map +1 -1
- package/dist/hq/exposure.d.ts +66 -0
- package/dist/hq/exposure.d.ts.map +1 -0
- package/dist/hq/index.d.ts +1 -0
- package/dist/hq/index.d.ts.map +1 -1
- package/dist/hq/index.js +190 -21
- package/dist/hq/index.js.map +4 -4
- package/dist/hq/mailbox-mapper.d.ts +13 -1
- package/dist/hq/mailbox-mapper.d.ts.map +1 -1
- package/dist/hq/protocol/browser.d.ts +9 -1
- package/dist/hq/protocol/browser.d.ts.map +1 -1
- package/dist/hq/protocol/client.d.ts +2 -2
- package/dist/hq/protocol/client.d.ts.map +1 -1
- package/dist/hq/protocol/core.d.ts.map +1 -1
- package/dist/hq/protocol/mailbox.d.ts +6 -0
- package/dist/hq/protocol/mailbox.d.ts.map +1 -1
- package/dist/hq/protocol/session.d.ts +4 -0
- package/dist/hq/protocol/session.d.ts.map +1 -1
- package/dist/hq/publisher.d.ts.map +1 -1
- package/dist/index.d.ts +34 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30287 -22214
- package/dist/index.js.map +4 -4
- package/dist/infrastructure/index.js +60 -5
- package/dist/infrastructure/index.js.map +2 -2
- package/dist/kernel/events/agent-events.d.ts +33 -1
- package/dist/kernel/events/agent-events.d.ts.map +1 -1
- package/dist/kernel/events/file-events.d.ts +65 -0
- package/dist/kernel/events/file-events.d.ts.map +1 -0
- package/dist/kernel/events/memory-events.d.ts +36 -0
- package/dist/kernel/events/memory-events.d.ts.map +1 -1
- package/dist/kernel/events/network-events.d.ts +60 -0
- package/dist/kernel/events/network-events.d.ts.map +1 -0
- package/dist/kernel/events/process-events.d.ts +44 -0
- package/dist/kernel/events/process-events.d.ts.map +1 -0
- package/dist/kernel/events/provider-events.d.ts +89 -0
- package/dist/kernel/events/provider-events.d.ts.map +1 -1
- package/dist/kernel/events/tool-events.d.ts +10 -0
- package/dist/kernel/events/tool-events.d.ts.map +1 -1
- package/dist/kernel/events/worktree-events.d.ts +1 -1
- package/dist/kernel/events.d.ts +14 -1
- package/dist/kernel/events.d.ts.map +1 -1
- package/dist/kernel/index.js +2 -1
- package/dist/kernel/index.js.map +2 -2
- package/dist/kernel/tokens.d.ts +3 -1
- package/dist/kernel/tokens.d.ts.map +1 -1
- package/dist/mailbox-attach.d.ts.map +1 -1
- package/dist/models/index.js.map +2 -2
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +278 -0
- package/dist/observability/index.js.map +4 -4
- package/dist/observability/network-telemetry.d.ts +15 -0
- package/dist/observability/network-telemetry.d.ts.map +1 -0
- package/dist/observability/process-telemetry.d.ts +18 -0
- package/dist/observability/process-telemetry.d.ts.map +1 -0
- package/dist/observability/redact-command.d.ts +20 -0
- package/dist/observability/redact-command.d.ts.map +1 -0
- package/dist/plugins/auto-review-plugin.d.ts +56 -3
- package/dist/plugins/auto-review-plugin.d.ts.map +1 -1
- package/dist/plugins/chimera-plugin.d.ts +164 -5
- package/dist/plugins/chimera-plugin.d.ts.map +1 -1
- package/dist/plugins/review-context-builder.d.ts +52 -0
- package/dist/plugins/review-context-builder.d.ts.map +1 -0
- package/dist/security/index.d.ts +1 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +186 -9
- package/dist/security/index.js.map +4 -4
- package/dist/security/kanban-boundary.d.ts +10 -0
- package/dist/security/kanban-boundary.d.ts.map +1 -0
- package/dist/security/permission-policy.d.ts +1 -0
- package/dist/security/permission-policy.d.ts.map +1 -1
- package/dist/session-registry.d.ts +80 -0
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/skills/index.js.map +2 -2
- package/dist/storage/config-loader.d.ts +7 -0
- package/dist/storage/config-loader.d.ts.map +1 -1
- package/dist/storage/file-session-writer.d.ts +20 -7
- package/dist/storage/file-session-writer.d.ts.map +1 -1
- package/dist/storage/goal-coordination.d.ts +40 -0
- package/dist/storage/goal-coordination.d.ts.map +1 -0
- package/dist/storage/goal-store.d.ts +9 -5
- package/dist/storage/goal-store.d.ts.map +1 -1
- package/dist/storage/index.d.ts +4 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +1066 -226
- package/dist/storage/index.js.map +4 -4
- package/dist/storage/memory-consolidator.d.ts +49 -4
- package/dist/storage/memory-consolidator.d.ts.map +1 -1
- package/dist/storage/memory-graph-backend.d.ts +11 -0
- package/dist/storage/memory-graph-backend.d.ts.map +1 -1
- package/dist/storage/provider-config-watcher.d.ts +19 -0
- package/dist/storage/provider-config-watcher.d.ts.map +1 -1
- package/dist/storage/session-event-bridge.d.ts +2 -2
- package/dist/storage/session-event-bridge.d.ts.map +1 -1
- package/dist/storage/session-resume-validation.d.ts +10 -0
- package/dist/storage/session-resume-validation.d.ts.map +1 -1
- package/dist/storage/session-rewind-apply.d.ts +53 -0
- package/dist/storage/session-rewind-apply.d.ts.map +1 -0
- package/dist/storage/session-rewinder.d.ts.map +1 -1
- package/dist/storage/session-store.d.ts.map +1 -1
- package/dist/tasking/index.js.map +1 -1
- package/dist/tasking/task-store.d.ts +1 -1
- package/dist/tools/council-tool.d.ts +3 -0
- package/dist/tools/council-tool.d.ts.map +1 -1
- package/dist/tools/fallback-manage-tools.d.ts +82 -0
- package/dist/tools/fallback-manage-tools.d.ts.map +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3423 -192
- package/dist/tools/index.js.map +4 -4
- package/dist/tools/one-shot-llm-tool.d.ts +2 -0
- package/dist/tools/one-shot-llm-tool.d.ts.map +1 -1
- package/dist/types/config.d.ts +76 -7
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/file-event-record.d.ts +68 -0
- package/dist/types/file-event-record.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +13 -8
- package/dist/types/index.js.map +3 -3
- package/dist/types/memory.d.ts +12 -0
- package/dist/types/memory.d.ts.map +1 -1
- package/dist/types/multi-agent.d.ts +12 -1
- package/dist/types/multi-agent.d.ts.map +1 -1
- package/dist/types/one-shot-llm.d.ts +16 -7
- package/dist/types/one-shot-llm.d.ts.map +1 -1
- package/dist/types/provider.d.ts +1 -1
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/session.d.ts +68 -2
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/tool-executor.d.ts +2 -0
- package/dist/types/tool-executor.d.ts.map +1 -1
- package/dist/types/tool.d.ts +5 -0
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/utils/atomic-write.d.ts.map +1 -1
- package/dist/utils/index.d.ts +10 -10
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +497 -254
- package/dist/utils/index.js.map +4 -4
- package/dist/utils/message-invariants.d.ts +9 -0
- package/dist/utils/message-invariants.d.ts.map +1 -1
- package/dist/utils/safe-json.d.ts +1 -1
- package/dist/utils/safe-json.d.ts.map +1 -1
- package/dist/utils/term.d.ts +279 -0
- package/dist/utils/term.d.ts.map +1 -1
- package/dist/utils/tool-wire-compact.d.ts +9 -0
- package/dist/utils/tool-wire-compact.d.ts.map +1 -1
- package/dist/utils/wstack-paths.d.ts +12 -2
- package/dist/utils/wstack-paths.d.ts.map +1 -1
- package/dist/worktree/worktree-manager.d.ts +1 -1
- package/dist/worktree/worktree-manager.d.ts.map +1 -1
- package/instructions/agents/ios.md +113 -0
- package/instructions/agents/search.md +1 -1
- package/instructions/llm/chimera-review.md +66 -9
- package/instructions/llm/memory-consolidator.md +4 -12
- package/instructions/llm/prompt-enhancer.md +3 -1
- package/instructions/sections/tool/common-patterns.md +3 -3
- package/instructions/system.md +40 -5
- package/package.json +7 -3
- package/skills/auto-review/SKILL.md +176 -0
- package/skills/mnemosyne/SKILL.md +156 -0
- package/skills/mnemosyne/instructions/agent-prompt.md +200 -0
- package/dist/autophase/auto-phase-planner.d.ts.map +0 -1
- package/dist/autophase/auto-phase-runner.d.ts.map +0 -1
- package/dist/autophase/checkpoint.d.ts.map +0 -1
- package/dist/autophase/index.d.ts.map +0 -1
- package/dist/autophase/phase-graph-builder.d.ts.map +0 -1
- package/dist/autophase/phase-orchestrator.d.ts.map +0 -1
- package/dist/autophase/phase-store.d.ts.map +0 -1
- package/dist/autophase/types.d.ts.map +0 -1
- /package/dist/{autophase → goal}/checkpoint.d.ts +0 -0
- /package/dist/{autophase → goal}/phase-graph-builder.d.ts +0 -0
- /package/dist/{autophase → goal}/phase-store.d.ts +0 -0
- /package/instructions/{autophase → goal}/phase-planner.md +0 -0
package/dist/hq/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/hq/protocol/tool.ts", "../../src/hq/protocol/core.ts", "../../src/security/secret-scrubber.ts", "../../src/hq/redaction.ts", "../../src/hq/mailbox-mapper.ts", "../../src/hq/publisher.ts", "../../src/hq/factory.ts", "../../src/coordination/global-mailbox.ts", "../../src/utils/atomic-write.ts", "../../src/utils/session-scoped-path.ts", "../../src/utils/wstack-paths.ts", "../../src/types/errors.ts", "../../src/coordination/mailbox-constants.ts", "../../src/coordination/mailbox-message-codec.ts", "../../src/
|
|
4
|
-
"sourcesContent": ["import type { HqPathPolicy } from './project.js';\n\nexport type HqToolArgsPolicy = 'none' | 'summary' | 'redacted' | 'full';\n\nexport interface HqRedactionPolicy {\n rawContent: boolean;\n toolArgs: HqToolArgsPolicy;\n paths: HqPathPolicy;\n}\n\nexport const DEFAULT_HQ_REDACTION_POLICY: HqRedactionPolicy = {\n rawContent: true,\n toolArgs: 'full',\n paths: 'full',\n};\n\n/**\n * Per-string cap applied when redacting chat-transcript events\n * (`session.transcript` / `agent.message`). The generic 500-char summary cap\n * is right for telemetry rollups but would mangle full chat-history rendering\n * in the HQ Console once `rawContent` is enabled \u2014 messages and tool outputs\n * routinely exceed it. Applied publisher-side AND at the server's re-redaction\n * so both hops agree.\n */\nexport const HQ_TRANSCRIPT_TEXT_CAP = 16_000;\n\nexport interface HqToolStartedPayload {\n toolName: string;\n capabilities?: readonly string[];\n risk?: string;\n inputSummary?: unknown;\n}\n\nexport interface HqToolCompletedPayload {\n toolName: string;\n status: 'success' | 'error' | 'timeout' | 'cancelled';\n durationMs: number;\n outputSummary?: unknown;\n errorClass?: string;\n}\n", "import type {\n HqClientCapability,\n HqClientCommandAckMessage,\n HqClientCommandPollMessage,\n HqClientHelloPayload,\n HqClientHeartbeatPayload,\n HqClientIdentity,\n HqClientKind,\n HqClientMessage,\n} from './client.js';\nimport type { HqBrainEventPayload } from './brain.js';\nimport type {\n HqFleetEventPayload,\n HqFleetSnapshotPayload,\n HqQueuedCommand,\n HqWorktreeEventPayload,\n} from './fleet.js';\nimport type {\n HqMailboxAgentSummary,\n HqMailboxEventPayload,\n HqMailboxMessageSummary,\n HqMailboxSnapshotPayload,\n} from './mailbox.js';\nimport type {\n HqMcpFailureCounts,\n HqMcpHealthCheck,\n HqMcpHealthSnapshotPayload,\n HqMcpLatencySummary,\n HqMcpOperationPayload,\n HqMcpServerHealth,\n} from './mcp.js';\nimport type { HqProjectIdentity, HqWorkspaceKind } from './project.js';\nimport type {\n HqSessionAgentSummary,\n HqSessionEndedPayload,\n HqSessionSnapshotPayload,\n HqSubagentSummary,\n HqTranscriptAppendPayload,\n HqTranscriptEntry,\n} from './session.js';\nimport type {\n HqRedactionPolicy,\n HqToolCompletedPayload,\n HqToolStartedPayload,\n} from './tool.js';\n\nexport const HQ_PROTOCOL_VERSION = 1 as const;\n\nexport type HqProtocolVersion = typeof HQ_PROTOCOL_VERSION;\n\nexport interface HqWelcomePayload {\n type: 'hq.welcome';\n protocolVersion: HqProtocolVersion;\n serverTime: string;\n acceptedCapabilities: readonly HqClientCapability[];\n redactionPolicy: HqRedactionPolicy;\n}\n\nexport interface HqEventEnvelope<TPayload = unknown> {\n id: string;\n type: HqEventType | (string & {});\n schemaVersion: HqProtocolVersion;\n timestamp: string;\n clientId: string;\n projectId: string;\n sessionId?: string;\n runId?: string;\n seq: number;\n payload: TPayload;\n}\n\nexport type HqEventType =\n | 'client.hello'\n | 'client.heartbeat'\n | 'session.started'\n | 'session.status'\n | 'session.usage'\n | 'tool.started'\n | 'tool.completed'\n | 'fleet.snapshot'\n | 'fleet.event'\n | 'mailbox.snapshot'\n | 'mailbox.event'\n | 'worklist.snapshot'\n | 'git.snapshot'\n | 'agent.message'\n | 'agent.status'\n | 'session.snapshot'\n | 'session.transcript'\n | 'session.ended'\n | 'brain.event'\n | 'worktree.event'\n | 'mcp.health.snapshot'\n | 'mcp.operation';\n\nexport interface HqUsagePayload {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n costUsd?: number;\n durationMs?: number;\n /** Provider id that produced this usage (e.g. 'anthropic'), when known. */\n provider?: string;\n /** Model id the cost was priced against, when known. */\n model?: string;\n /** Cache-read (prompt-cache hit) tokens, when reported. */\n cacheRead?: number;\n /** Cache-write tokens, when reported. */\n cacheWrite?: number;\n}\n\n/** A physical machine, aggregated by HQ from connected clients' machineId. */\nexport interface HqMachineRecord {\n machineId: string;\n hostname?: string;\n clientCount: number;\n sessionCount: number;\n agentCount: number;\n projectIds: readonly string[];\n lastActivityAt: string;\n}\n\nexport interface HqGitSnapshotPayload {\n branch?: string;\n dirtyFiles?: number;\n stagedFiles?: number;\n ahead?: number;\n behind?: number;\n}\n\nexport interface HqAlertMessage {\n type: 'hq.alert';\n severity: 'info' | 'warn' | 'error';\n message: string;\n timestamp: string;\n}\n\nexport interface HqHeartbeatMessage {\n type: 'hq.heartbeat';\n serverTime: string;\n}\n\nexport interface HqServerCommandBatchMessage {\n type: 'hq.command_batch';\n commands: readonly HqQueuedCommand[];\n}\n\nexport type HqServerMessage = HqServerCommandBatchMessage | HqWelcomePayload;\n\n/**\n * Discriminated parse result for {@link parseHqFrame}. The `reason` field\n * is only present when `ok` is `false`; consumers should narrow on `ok`\n * before accessing `frame` or `reason`.\n */\nexport type HqParseResult =\n | { ok: true; frame: HqClientMessage }\n | { ok: false; reason: 'invalid-json' | 'unknown-type' | 'malformed' };\n\n/** Known client \u2192 server frame `type` discriminators. */\nconst KNOWN_HQ_CLIENT_FRAME_TYPES = new Set<HqClientMessage['type']>([\n 'client.hello',\n 'client.event',\n 'client.command_poll',\n 'client.command_ack',\n]);\n\nconst HQ_CLIENT_KINDS = new Set<HqClientKind>(['tui', 'repl', 'webui', 'cli', 'unknown']);\nconst HQ_WORKSPACE_KINDS = new Set<HqWorkspaceKind>(['git', 'directory', 'unknown']);\nconst HQ_CLIENT_CAPABILITIES = new Set<HqClientCapability>([\n 'telemetry.publish',\n 'session.summary',\n 'fleet.summary',\n 'mailbox.summary',\n 'control.receive',\n]);\nconst HQ_COMMAND_ACK_STATUSES = new Set<HqClientCommandAckMessage['status']>([\n 'accepted',\n 'completed',\n 'failed',\n 'rejected',\n]);\n\n/** Top-level object + string `type` guard. */\nfunction hasStringType(x: unknown): x is { type: string } {\n return typeof x === 'object' && x !== null && typeof (x as { type?: unknown }).type === 'string';\n}\n\nfunction isHqClientIdentity(x: unknown): x is HqClientIdentity {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.clientId === 'string' &&\n typeof v.kind === 'string' &&\n HQ_CLIENT_KINDS.has(v.kind as HqClientKind) &&\n typeof v.machineId === 'string' &&\n typeof v.startedAt === 'string'\n );\n}\n\nfunction isHqProjectIdentity(x: unknown): x is HqProjectIdentity {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.projectId === 'string' &&\n typeof v.projectRoot === 'string' &&\n typeof v.projectName === 'string' &&\n typeof v.machineId === 'string' &&\n typeof v.workspaceKind === 'string' &&\n HQ_WORKSPACE_KINDS.has(v.workspaceKind as HqWorkspaceKind)\n );\n}\n\nfunction isHqRedactionPolicy(x: unknown): x is HqRedactionPolicy {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.rawContent === 'boolean' &&\n (v.toolArgs === 'none' || v.toolArgs === 'summary' || v.toolArgs === 'redacted' || v.toolArgs === 'full') &&\n (v.paths === 'none' ||\n v.paths === 'project-relative' ||\n v.paths === 'redacted' ||\n v.paths === 'full')\n );\n}\n\nfunction isHqClientHelloPayload(x: unknown): x is HqClientHelloPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.protocolVersion === 'number' &&\n isHqClientIdentity(v.client) &&\n isHqProjectIdentity(v.project) &&\n Array.isArray(v.capabilities) &&\n v.capabilities.every(\n (capability) =>\n typeof capability === 'string' &&\n HQ_CLIENT_CAPABILITIES.has(capability as HqClientCapability),\n ) &&\n (v.redactionPolicy === undefined || isHqRedactionPolicy(v.redactionPolicy))\n );\n}\n\nfunction isHqEventEnvelope(x: unknown): x is HqEventEnvelope {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.id === 'string' &&\n typeof v.type === 'string' &&\n v.schemaVersion === HQ_PROTOCOL_VERSION &&\n typeof v.timestamp === 'string' &&\n typeof v.clientId === 'string' &&\n typeof v.projectId === 'string' &&\n Number.isSafeInteger(v.seq) &&\n (v.seq as number) >= 0 &&\n Object.hasOwn(v, 'payload')\n );\n}\n\nfunction isHqClientCommandPollMessage(x: unknown): x is HqClientCommandPollMessage {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.clientId === 'string' &&\n typeof v.projectId === 'string' &&\n (v.afterCommandId === undefined || typeof v.afterCommandId === 'string') &&\n (v.limit === undefined ||\n (Number.isSafeInteger(v.limit) && (v.limit as number) > 0 && (v.limit as number) <= 200))\n );\n}\n\nfunction isHqClientCommandAckMessage(x: unknown): x is HqClientCommandAckMessage {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.clientId === 'string' &&\n typeof v.projectId === 'string' &&\n typeof v.commandId === 'string' &&\n typeof v.status === 'string' &&\n HQ_COMMAND_ACK_STATUSES.has(v.status as HqClientCommandAckMessage['status']) &&\n (v.message === undefined || typeof v.message === 'string')\n );\n}\n\n/**\n * Strictly parse a raw client \u2192 server frame into a {@link HqParseResult}.\n *\n * Validates, in order:\n * 1. JSON syntax (`invalid-json` on failure)\n * 2. Top-level object with string `type` discriminator\n * 3. `type` is one of {@link HqClientMessage} union members (`unknown-type`)\n * 4. Per-type field-shape presence checks (`malformed` on failure)\n *\n * On success, `frame` is narrowed to {@link HqClientMessage} and consumers\n * can switch on `frame.type` for type-safe access to per-union-member\n * fields without `as` casts.\n */\nexport function parseHqFrame(raw: string | Buffer): HqParseResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(typeof raw === 'string' ? raw : raw.toString('utf8'));\n } catch {\n return { ok: false, reason: 'invalid-json' };\n }\n\n if (!hasStringType(parsed)) {\n return { ok: false, reason: 'malformed' };\n }\n const obj = parsed as { type: string } & Record<string, unknown>;\n\n if (!KNOWN_HQ_CLIENT_FRAME_TYPES.has(obj.type as HqClientMessage['type'])) {\n return { ok: false, reason: 'unknown-type' };\n }\n\n switch (obj.type as HqClientMessage['type']) {\n case 'client.hello':\n if (!isHqClientHelloPayload(obj.payload)) {\n return { ok: false, reason: 'malformed' };\n }\n return { ok: true, frame: { type: 'client.hello', payload: obj.payload } };\n case 'client.event':\n if (!isHqEventEnvelope(obj.event)) {\n return { ok: false, reason: 'malformed' };\n }\n return { ok: true, frame: { type: 'client.event', event: obj.event } };\n case 'client.command_poll':\n if (!isHqClientCommandPollMessage(obj)) {\n return { ok: false, reason: 'malformed' };\n }\n return {\n ok: true,\n frame: {\n type: 'client.command_poll',\n clientId: obj.clientId,\n projectId: obj.projectId,\n ...(typeof obj.afterCommandId === 'string'\n ? { afterCommandId: obj.afterCommandId }\n : {}),\n ...(typeof obj.limit === 'number' ? { limit: obj.limit } : {}),\n },\n };\n case 'client.command_ack':\n if (!isHqClientCommandAckMessage(obj)) {\n return { ok: false, reason: 'malformed' };\n }\n return {\n ok: true,\n frame: {\n type: 'client.command_ack',\n clientId: obj.clientId,\n projectId: obj.projectId,\n commandId: obj.commandId,\n status: obj.status as HqClientCommandAckMessage['status'],\n ...(typeof obj.message === 'string' ? { message: obj.message } : {}),\n },\n };\n default: {\n // Unreachable: KNOWN_HQ_CLIENT_FRAME_TYPES membership guarantees\n // `obj.type` is one of the cases above. Return `unknown-type` defensively\n // to satisfy the return type if a future HqClientMessage union member\n // is added without updating this switch.\n const _exhaustive: never = obj.type as never;\n return _exhaustive;\n }\n }\n}\n\n/** Known `client.event` envelope event types whose payload shape we validate. */\nconst KNOWN_HQ_EVENT_PAYLOAD_TYPES = new Set<string>([\n 'mailbox.snapshot',\n 'mailbox.event',\n 'session.snapshot',\n 'session.transcript',\n 'session.ended',\n 'fleet.snapshot',\n 'fleet.event',\n 'brain.event',\n 'worktree.event',\n 'tool.started',\n 'tool.completed',\n 'session.usage',\n 'client.heartbeat',\n 'mcp.health.snapshot',\n 'mcp.operation',\n]);\n\nfunction isHqMcpLatencySummary(x: unknown): x is HqMcpLatencySummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.count === 'number' &&\n (v.lastMs === undefined || typeof v.lastMs === 'number') &&\n (v.minMs === undefined || typeof v.minMs === 'number') &&\n (v.maxMs === undefined || typeof v.maxMs === 'number') &&\n (v.p50Ms === undefined || typeof v.p50Ms === 'number') &&\n (v.p95Ms === undefined || typeof v.p95Ms === 'number')\n );\n}\n\nfunction isHqMcpFailureCounts(x: unknown): x is HqMcpFailureCounts {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.transport === 'number' &&\n typeof v.protocol === 'number' &&\n typeof v.tool === 'number'\n );\n}\n\nfunction isHqMcpHealthCheck(x: unknown): x is HqMcpHealthCheck {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.name === 'string' &&\n typeof v.passed === 'boolean' &&\n (v.value === undefined || typeof v.value === 'number') &&\n (v.threshold === undefined || typeof v.threshold === 'number')\n );\n}\n\nconst HQ_MCP_HEALTH_STATES = new Set<string>([\n 'disabled',\n 'dormant',\n 'connecting',\n 'healthy',\n 'degraded',\n 'failed',\n]);\n\nconst HQ_MCP_CONNECTION_STATES = new Set<string>([\n 'idle',\n 'dormant',\n 'connecting',\n 'connected',\n 'reconnecting',\n 'disconnected',\n 'failed',\n]);\n\nfunction isHqMcpServerHealth(x: unknown): x is HqMcpServerHealth {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.name === 'string' &&\n typeof v.projectId === 'string' &&\n typeof v.clientId === 'string' &&\n typeof v.connectionState === 'string' &&\n HQ_MCP_CONNECTION_STATES.has(v.connectionState) &&\n typeof v.healthState === 'string' &&\n HQ_MCP_HEALTH_STATES.has(v.healthState) &&\n (v.lastSuccessAt === undefined || typeof v.lastSuccessAt === 'string') &&\n (v.lastFailureAt === undefined || typeof v.lastFailureAt === 'string') &&\n (v.lastFailureKind === undefined ||\n v.lastFailureKind === 'transport' ||\n v.lastFailureKind === 'protocol' ||\n v.lastFailureKind === 'tool') &&\n typeof v.consecutiveFailures === 'number' &&\n isHqMcpFailureCounts(v.failures) &&\n typeof v.reconnectCount === 'number' &&\n typeof v.wakeCount === 'number' &&\n typeof v.sleepCount === 'number' &&\n typeof v.restartCount === 'number' &&\n isHqMcpLatencySummary(v.connectionLatency) &&\n isHqMcpLatencySummary(v.discoveryLatency) &&\n isHqMcpLatencySummary(v.callLatency) &&\n typeof v.inFlightCalls === 'number' &&\n typeof v.peakInFlightCalls === 'number' &&\n Array.isArray(v.healthChecks) &&\n v.healthChecks.every(isHqMcpHealthCheck)\n );\n}\n\nfunction isHqMcpHealthSnapshotPayload(x: unknown): x is HqMcpHealthSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return Array.isArray(v.servers) && v.servers.every(isHqMcpServerHealth);\n}\n\nfunction isHqMcpOperationPayload(x: unknown): x is HqMcpOperationPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.operation === 'object' &&\n v.operation !== null &&\n Array.isArray(v.servers) &&\n v.servers.every(isHqMcpServerHealth)\n );\n}\n\nfunction isHqMailboxMessageSummary(x: unknown): x is HqMailboxMessageSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.messageId === 'string' &&\n typeof v.from === 'string' &&\n typeof v.to === 'string' &&\n typeof v.subject === 'string' &&\n typeof v.priority === 'string' &&\n typeof v.timestamp === 'string' &&\n typeof v.completed === 'boolean' &&\n typeof v.hasBody === 'boolean'\n );\n}\n\nfunction isHqMailboxAgentSummary(x: unknown): x is HqMailboxAgentSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.agentId === 'string' &&\n typeof v.name === 'string' &&\n typeof v.sessionId === 'string' &&\n typeof v.status === 'string' &&\n typeof v.iterations === 'number' &&\n typeof v.toolCalls === 'number' &&\n typeof v.lastActivityAt === 'string' &&\n typeof v.lastSeenAt === 'string' &&\n typeof v.online === 'boolean'\n );\n}\n\nfunction isHqMailboxSnapshotPayload(x: unknown): x is HqMailboxSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.mailboxId !== 'string' ||\n (v.scope !== 'project' && v.scope !== 'global') ||\n !Array.isArray(v.messages) ||\n !Array.isArray(v.agents) ||\n typeof v.totals !== 'object' ||\n v.totals === null\n ) {\n return false;\n }\n const totals = v.totals as Record<string, unknown>;\n if (\n typeof totals.messages !== 'number' ||\n typeof totals.unread !== 'number' ||\n typeof totals.incomplete !== 'number' ||\n typeof totals.highPriority !== 'number' ||\n typeof totals.onlineAgents !== 'number'\n ) {\n return false;\n }\n for (const message of v.messages) {\n if (!isHqMailboxMessageSummary(message)) return false;\n }\n for (const agent of v.agents) {\n if (!isHqMailboxAgentSummary(agent)) return false;\n }\n return true;\n}\n\nconst HQ_MAILBOX_EVENT_ACTIONS = new Set<string>([\n 'message.sent',\n 'message.read',\n 'message.completed',\n 'message.updated',\n 'agent.registered',\n 'agent.heartbeat',\n 'agent.offline',\n 'agent.deregistered',\n]);\n\nfunction isHqMailboxEventPayload(x: unknown): x is HqMailboxEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.mailboxId !== 'string') return false;\n if (typeof v.action !== 'string' || !HQ_MAILBOX_EVENT_ACTIONS.has(v.action)) return false;\n // `message` and `agent` are optional but, when present, must satisfy\n // their respective shape guard so a downstream consumer can rely on\n // the typed fields.\n if (v.message !== undefined && !isHqMailboxMessageSummary(v.message)) return false;\n if (v.agent !== undefined && !isHqMailboxAgentSummary(v.agent)) return false;\n return true;\n}\n\nconst HQ_SESSION_AGENT_STATUSES = new Set<string>([\n 'idle',\n 'running',\n 'streaming',\n 'waiting_user',\n 'error',\n]);\n\nfunction isHqSessionAgentSummary(x: unknown): x is HqSessionAgentSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.id === 'string' &&\n typeof v.name === 'string' &&\n typeof v.status === 'string' &&\n HQ_SESSION_AGENT_STATUSES.has(v.status) &&\n typeof v.iterations === 'number' &&\n typeof v.toolCalls === 'number' &&\n typeof v.lastActivityAt === 'string'\n );\n}\n\nconst HQ_SESSION_STATUSES = new Set<string>(['active', 'idle', 'closing', 'stale']);\n\nfunction isHqSessionSnapshotPayload(x: unknown): x is HqSessionSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.sessionId !== 'string' ||\n typeof v.clientKind !== 'string' ||\n typeof v.machineId !== 'string' ||\n typeof v.projectId !== 'string' ||\n typeof v.projectName !== 'string' ||\n typeof v.projectRoot !== 'string' ||\n typeof v.status !== 'string' ||\n !HQ_SESSION_STATUSES.has(v.status) ||\n typeof v.startedAt !== 'string' ||\n typeof v.lastActivityAt !== 'string' ||\n typeof v.agentCount !== 'number' ||\n !Array.isArray(v.agents)\n ) {\n return false;\n }\n for (const agent of v.agents) {\n if (!isHqSessionAgentSummary(agent)) return false;\n }\n return true;\n}\n\nconst HQ_TRANSCRIPT_ROLES = new Set<string>([\n 'user',\n 'assistant',\n 'thinking',\n 'tool',\n 'system',\n 'error',\n]);\n\nfunction isHqTranscriptEntry(x: unknown): x is HqTranscriptEntry {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.ts === 'string' &&\n typeof v.role === 'string' &&\n HQ_TRANSCRIPT_ROLES.has(v.role) &&\n typeof v.text === 'string'\n );\n}\n\nfunction isHqTranscriptAppendPayload(x: unknown): x is HqTranscriptAppendPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.sessionId !== 'string' ||\n typeof v.fromSeq !== 'number' ||\n !Array.isArray(v.entries)\n ) {\n return false;\n }\n for (const entry of v.entries) {\n if (!isHqTranscriptEntry(entry)) return false;\n }\n return true;\n}\n\nfunction isHqSessionEndedPayload(x: unknown): x is HqSessionEndedPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return typeof v.sessionId === 'string' && typeof v.endedAt === 'string';\n}\n\nconst HQ_FLEET_SUBAGENT_STATUS = new Set<string>([\n 'pending',\n 'running',\n 'idle',\n 'completed',\n 'failed',\n 'stopped',\n]);\n\nfunction isHqSubagentSummary(x: unknown): x is HqSubagentSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.subagentId === 'string' &&\n typeof v.status === 'string' &&\n HQ_FLEET_SUBAGENT_STATUS.has(v.status)\n );\n}\n\nfunction isHqFleetSnapshotPayload(x: unknown): x is HqFleetSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.runId !== 'string' ||\n typeof v.activeSubagents !== 'number' ||\n typeof v.queuedTasks !== 'number' ||\n typeof v.completedTasks !== 'number' ||\n typeof v.failedTasks !== 'number' ||\n !Array.isArray(v.subagents)\n ) {\n return false;\n }\n for (const s of v.subagents) {\n if (!isHqSubagentSummary(s)) return false;\n }\n return true;\n}\n\nfunction isHqFleetEventPayload(x: unknown): x is HqFleetEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return typeof v.runId === 'string' && typeof v.event === 'string';\n}\n\nconst HQ_BRAIN_EVENT_KINDS = new Set<string>([\n 'decision_requested',\n 'decision_answered',\n 'decision_ask_human',\n 'human_answered',\n 'decision_denied',\n 'intervention',\n]);\n\nfunction isHqBrainEventPayload(x: unknown): x is HqBrainEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.kind !== 'string' || !HQ_BRAIN_EVENT_KINDS.has(v.kind)) return false;\n if (typeof v.at !== 'number') return false;\n return true;\n}\n\nconst HQ_WORKTREE_EVENT_KINDS = new Set<string>([\n 'allocated',\n 'committed',\n 'merged',\n 'conflict',\n 'released',\n 'failed',\n]);\n\nfunction isHqWorktreeEventPayload(x: unknown): x is HqWorktreeEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.kind !== 'string' || !HQ_WORKTREE_EVENT_KINDS.has(v.kind)) return false;\n if (typeof v.handleId !== 'string' || typeof v.ownerId !== 'string') return false;\n return true;\n}\n\nfunction isHqToolStartedPayload(x: unknown): x is HqToolStartedPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return typeof v.toolName === 'string';\n}\n\nfunction isHqToolCompletedPayload(x: unknown): x is HqToolCompletedPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.toolName === 'string' &&\n typeof v.status === 'string' &&\n typeof v.durationMs === 'number'\n );\n}\n\nfunction isHqUsagePayload(x: unknown): x is HqUsagePayload {\n if (typeof x !== 'object' || x === null) return false;\n // HqUsagePayload has all-optional numeric fields; accept any object so the\n // cost signal is never dropped on a partial payload, but require it be a\n // plain object (not array/null) to keep the downstream typed.\n return !Array.isArray(x);\n}\n\nfunction isHqClientHeartbeatPayload(x: unknown): x is HqClientHeartbeatPayload {\n if (typeof x !== 'object' || x === null || Array.isArray(x)) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.uptimeMs === 'number' &&\n (v.activeSessionId === undefined || typeof v.activeSessionId === 'string') &&\n (v.activeRunId === undefined || typeof v.activeRunId === 'string') &&\n typeof v.status === 'string' &&\n (v.status === 'active' ||\n v.status === 'idle' ||\n v.status === 'stale' ||\n v.status === 'error') &&\n (v.activeSubagents === undefined || typeof v.activeSubagents === 'number') &&\n (v.queuedTasks === undefined || typeof v.queuedTasks === 'number')\n );\n}\n\n/**\n * Validate the `payload` field of a {@link HqEventEnvelope} for known\n * event types. Returns `{ ok: true, payload }` with a narrowed payload\n * type when the event type has a registered shape guard and the payload\n * matches it; `{ ok: true, payload: unknown }` for event types that the\n * server does not yet validate; or `{ ok: false, reason }` when the\n * payload fails the registered guard.\n *\n * Use this after {@link parseHqFrame} has produced a valid frame, when\n * the frame is `client.event` and the server is about to consume the\n * event payload.\n */\nexport type HqEventPayloadResult<T> =\n | { ok: true; payload: T }\n | { ok: false; reason: 'unknown-event-type' | 'malformed-payload' };\n\nexport function parseHqEventPayload(\n eventType: string,\n payload: unknown,\n): HqEventPayloadResult<unknown> {\n if (!KNOWN_HQ_EVENT_PAYLOAD_TYPES.has(eventType)) {\n // Server does not validate this event type yet \u2014 pass it through\n // untyped so the publish pipeline is not blocked. Future events\n // can opt-in by adding their type + guard here.\n return { ok: true, payload };\n }\n switch (eventType) {\n case 'mailbox.snapshot':\n return isHqMailboxSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'mailbox.event':\n return isHqMailboxEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.snapshot':\n return isHqSessionSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.transcript':\n return isHqTranscriptAppendPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.ended':\n return isHqSessionEndedPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'fleet.snapshot':\n return isHqFleetSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'fleet.event':\n return isHqFleetEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'brain.event':\n return isHqBrainEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'worktree.event':\n return isHqWorktreeEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'tool.started':\n return isHqToolStartedPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'tool.completed':\n return isHqToolCompletedPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.usage':\n return isHqUsagePayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'client.heartbeat':\n return isHqClientHeartbeatPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'mcp.health.snapshot':\n return isHqMcpHealthSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'mcp.operation':\n return isHqMcpOperationPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n default: {\n const _exhaustive: never = eventType as never;\n return _exhaustive;\n }\n }\n}\n\nexport function createHqEventEnvelope<TPayload>(input: {\n id: string;\n type: HqEventType | (string & {});\n timestamp: string;\n clientId: string;\n projectId: string;\n seq: number;\n payload: TPayload;\n sessionId?: string;\n runId?: string;\n}): HqEventEnvelope<TPayload> {\n return {\n id: input.id,\n type: input.type,\n schemaVersion: HQ_PROTOCOL_VERSION,\n timestamp: input.timestamp,\n clientId: input.clientId,\n projectId: input.projectId,\n seq: input.seq,\n payload: input.payload,\n ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),\n ...(input.runId !== undefined ? { runId: input.runId } : {}),\n };\n}\n", "import type { SecretScrubber } from '../types/secret-scrubber.js';\n\ninterface Pattern {\n type: string;\n regex: RegExp;\n}\n\nconst PATTERNS: Pattern[] = [\n // Anchored at the start where possible so partial matches inside larger\n // strings don't trigger false positives.\n {\n type: 'anthropic_key',\n regex: /(?<![A-Za-z0-9])sk-ant-api\\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g,\n },\n { type: 'openai_key', regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },\n { type: 'github_pat', regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g },\n { type: 'github_pat_v2', regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g },\n { type: 'aws_access_key', regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g },\n { type: 'gcp_key', regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g },\n { type: 'slack_token', regex: /(?<![A-Za-z0-9-])xox[abpos]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g },\n {\n type: 'stripe_key',\n regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'twilio_sid', regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g,\n },\n {\n type: 'telegram_bot_token',\n // Telegram tokens are of the form bot<digits>:<alphanum> in URL paths\n regex: /\\/bot\\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,\n },\n {\n type: 'jwt',\n // Anchored: look for literal \"eyJ\" which is unambiguous for JWT header\n regex:\n /(?<![A-Za-z0-9/+=])eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9/+=])/g,\n },\n {\n type: 'private_key',\n // Anchored: start must be BEGIN, end must be END with no extra dashes after END\n regex:\n /(?:^|\\n)-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----[\\s\\S]*?-----END[^-]*-----(?:\\n|$)/g,\n },\n { type: 'mongodb_uri', regex: /mongodb(?:\\+srv)?:\\/\\/[^\\s\"'`]+/g },\n { type: 'postgres_uri', regex: /postgres(?:ql)?:\\/\\/[^\\s\"'`]+/g },\n { type: 'mysql_uri', regex: /mysql:\\/\\/[^\\s\"'`]+/g },\n { type: 'redis_uri', regex: /redis:\\/\\/[^\\s\"'`]+/g },\n // AI/ML provider keys \u2014 modern LLM services with well-known prefixes\n {\n type: 'huggingface_token',\n // HuggingFace tokens: hf_ followed by 34 alphanumeric chars\n regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g,\n },\n {\n type: 'replicate_token',\n // Replicate tokens: r8_ followed by 40+ alphanumeric chars\n regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'perplexity_key',\n // Perplexity API keys: pplx- followed by 40+ alphanumeric chars\n regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'groq_key',\n // Groq API keys: gsk_ followed by 40+ alphanumeric chars\n regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'bearer_token',\n // Anchored with alternation instead of negative lookahead \u2014 avoids V8\n // backtracking risk on adversarial input. Bounded at 512 chars.\n // Min 12 chars: some OAuth providers issue shorter-lived tokens (< 20\n // chars). A 12-char base64 string has ~71 bits of entropy \u2014 above the\n // threshold where random strings are unlikely to produce false matches.\n // The trailing boundary is a NON-consuming lookahead: two adjacent bearer\n // tokens sharing a single delimiter (`Bearer a\u2026 Bearer b\u2026`) must both be\n // redacted. A consuming trailing delimiter would eat the separator the\n // next match needs for its leading anchor, leaking the second token.\n regex: /(?:^|[^A-Za-z0-9_.~+/-])Bearer\\s+[A-Za-z0-9._~+/-]{12,512}=*(?=$|[^A-Za-z0-9_.~+/-])/g,\n },\n {\n type: 'high_entropy_env',\n // Anchored with alternation instead of lookbehind to avoid backtracking.\n // Value bounded at 512 chars.\n // The trailing boundary is a NON-consuming lookahead so two secrets\n // separated by a single delimiter (one space OR one newline, e.g.\n // `printenv` / `.env` dumps: `API_KEY=\u2026 \\n SESSION_TOKEN=\u2026`) are BOTH\n // redacted. A consuming trailing `\\s` would swallow the separator the\n // next match needs for its leading anchor, so every other secret would\n // leak in plaintext.\n // The leading delimiter is CAPTURED (group 1) and re-emitted by the\n // replacement so the separator between adjacent secrets is preserved\n // rather than collapsed. Capture groups are therefore: 1=leading\n // delimiter, 2=key name, 3=value.\n regex: /(^|\\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\\s*[:=]\\s*['\"]?([A-Za-z0-9_/+=-]{20,512})['\"]?(?=\\s|$)/g,\n },\n];\n\n/**\n * `high_entropy_env` is the one pattern that needs special replacement logic\n * (it preserves the key name), so it runs in its own pass. Every other pattern\n * is folded into a single combined regex. Derive the split by type rather than\n * by hard-coded indices so adding/removing a pattern can't silently drop one.\n */\nconst SIMPLE_PATTERNS = PATTERNS.filter((p) => p.type !== 'high_entropy_env');\n\n/**\n * Combined single-pass regex for all simple patterns. Each alternative is a\n * capturing group so the callback can determine which original pattern fired\n * (only one group is non-undefined at match time). Order matches SIMPLE_PATTERNS\n * (longer/more-specific prefixes first). Relies on each simple pattern source\n * containing no internal capturing groups \u2014 only `(?:...)` and lookarounds.\n */\nconst COMBINED_REGEX = new RegExp(SIMPLE_PATTERNS.map((p) => `(${p.regex.source})`).join('|'), 'g');\n\n/** Separate pattern for high_entropy_env (different replacement logic). */\nconst HIGH_ENTROPY_REGEX = PATTERNS.find((p) => p.type === 'high_entropy_env')!.regex;\n\n/**\n * Replacements for the combined patterns, parallel to SIMPLE_PATTERNS. The\n * combined-regex callback indexes into this with the matched group's position.\n */\nconst COMBINED_REPLACEMENTS = SIMPLE_PATTERNS.map((p) => `[REDACTED:${p.type}]`);\n\n/**\n * Per-chunk cap. Splits long inputs into 64 KB chunks to keep scrub() memory\n * bounded. Real scrub() inputs (LLM responses, tool outputs) are typically\n * much smaller; this cap handles edge cases without impacting normal usage.\n */\nconst SCRUB_CHUNK_BYTES = 64 * 1024;\n\n/**\n * Overlap window used to nudge a chunk boundary onto a safe separator so a\n * secret straddling the 64 KB cut isn't split in half (which would leave\n * neither half matching, leaking the secret verbatim).\n *\n * Sized above the longest BOUNDED credential pattern: `high_entropy_env`\n * caps its value at 512 chars (+ key name + quotes \u2248 560) and `bearer_token`\n * at 512; every prefix-keyed pattern is far shorter. Because all of these\n * patterns are whitespace-free, the first whitespace at/after the nominal cut\n * is guaranteed to sit *past the end* of any such secret \u2014 so snapping the\n * boundary forward to it keeps every bounded secret wholly inside one chunk.\n * 1 KB gives comfortable headroom over the 560-char worst case.\n */\nconst SCRUB_OVERLAP_BYTES = 1024;\n\n/**\n * Quick pre-scan: check if the text contains any substring that MUST be\n * present for a credential pattern to match. If none are found, the text\n * is guaranteed clean \u2014 skip all regex passes (2 total: 16-pattern combined + high_entropy_env).\n *\n * Each anchor is the shortest unique substring from the corresponding pattern.\n * V8's `String.includes()` is hand-tuned C++ \u2014 O(n) with near-zero overhead\n * for typical tool-output lengths (100\u20135000 chars). A single combined regex\n * via `text.search()` is consistently slower for this many alternatives.\n */\nfunction hasCredentialAnchors(text: string): boolean {\n return (\n text.includes('-----BEGIN') || // Private keys (most unique \u2192 cheap reject)\n text.includes('sk-') || // Anthropic + OpenAI keys\n text.includes('sk_') || // Stripe live/test keys\n text.includes('ghp_') || // GitHub PAT v1\n text.includes('github_pat_') || // GitHub PAT v2\n text.includes('eyJ') || // JWT\n text.includes('AKIA') || // AWS access key\n text.includes('AIza') || // GCP service key\n text.includes('xox') || // Slack token (xoxa/xoxb/xoxp/xoxo/xoxs)\n text.includes('Bearer ') || // Bearer token (space suffix reduces false positives)\n text.includes('/bot') || // Telegram bot token (URL path pattern)\n text.includes('hf_') || // HuggingFace token\n text.includes('r8_') || // Replicate token\n text.includes('pplx-') || // Perplexity API key\n text.includes('gsk_') || // Groq API key\n text.includes('_KEY=') || // High-entropy env vars: API_KEY=, SECRET_KEY=, ...\n text.includes('_TOKEN=') || // ACCESS_TOKEN=, AUTH_TOKEN=, ...\n text.includes('_SECRET=') || // API_SECRET=, CLIENT_SECRET=, ...\n text.includes('_PASSWORD=') || // DB_PASSWORD=, ROOT_PASSWORD=, ...\n text.includes('mongodb://') ||\n text.includes('mongodb+srv://') ||\n text.includes('postgres://') ||\n text.includes('postgresql://') ||\n text.includes('mysql://') ||\n text.includes('redis://') ||\n // JSON-style credential keys: tool outputs often serialise objects as\n // raw JSON strings rather than parsed objects. The value may not start\n // with a recognisable prefix (sk-, ghp_, etc.), so we anchor on common\n // key names. The `\"` prefix avoids matching prose that happens to mention\n // these words \u2014 JSON serialisation always quotes string keys.\n text.includes('\"apiKey\"') ||\n text.includes('\"api_key\"') ||\n text.includes('\"token\"') ||\n text.includes('\"secret\"') ||\n text.includes('\"password\"') ||\n text.includes('\"authorization\"') ||\n text.includes('\"bearer\"') ||\n text.includes('\"private_key\"') ||\n text.includes('\"access_token\"') ||\n text.includes('\"refresh_token\"') ||\n text.includes('\"client_secret\"')\n );\n}\n\nexport class DefaultSecretScrubber implements SecretScrubber {\n scrub(text: string): string {\n if (!text) return text;\n\n // Fast path: if no credential anchor substrings exist in the text,\n // none of the 17 regex patterns can match. Skip all regex work.\n // This covers the vast majority of tool outputs (~95% of calls on\n // typical sessions are file paths, status messages, diffs, etc.).\n if (!hasCredentialAnchors(text)) return text;\n\n // For oversize inputs, scrub in fixed chunks to keep memory bounded.\n // The boundary is snapped FORWARD to the next whitespace within an\n // overlap window so a secret straddling the nominal 64 KB cut is never\n // split in half. Every bounded credential pattern is whitespace-free, so\n // the next whitespace at/after the cut necessarily falls past the end of\n // any such secret \u2014 guaranteeing it stays wholly inside the current chunk.\n if (text.length <= SCRUB_CHUNK_BYTES) {\n return this.scrubOne(text);\n }\n const out: string[] = [];\n let i = 0;\n while (i < text.length) {\n let end = Math.min(i + SCRUB_CHUNK_BYTES, text.length);\n if (end < text.length) {\n // Look for the first whitespace at/after the nominal cut, bounded by\n // the overlap window. Extending forward (not backward) ensures any\n // secret that began before `end` finishes before the new boundary.\n const limit = Math.min(end + SCRUB_OVERLAP_BYTES, text.length);\n let safe = -1;\n for (let j = end; j < limit; j++) {\n const ch = text.charCodeAt(j);\n // space, \\t, \\n, \\r\n if (ch === 32 || ch === 9 || ch === 10 || ch === 13) {\n safe = j;\n break;\n }\n }\n // Snap onto the whitespace if found; otherwise fall back to the hard\n // cut (an unbroken >1 KB run with no whitespace can't be a bounded\n // secret anyway \u2014 those are all \u2264 ~560 chars and whitespace-free).\n end = safe === -1 ? end : safe + 1;\n }\n out.push(this.scrubOne(text.slice(i, end)));\n i = end;\n }\n return out.join('');\n }\n\n private scrubOne(text: string): string {\n // Redundant guard: if we reached scrubOne via the chunked path, the\n // chunk may have been small enough to anchor-skip independently.\n if (!hasCredentialAnchors(text)) return text;\n\n // Pass 1: combined single-pass regex for all simple patterns. Each\n // alternative is a capturing group; only the group that matched is\n // non-undefined. The trailing offset/string args replace() appends are\n // always defined, so the matched group (which precedes them) is found first.\n let out = text.replace(\n COMBINED_REGEX,\n (match, ...groups) => {\n // groups[i] corresponds to SIMPLE_PATTERNS[i]; find which one fired.\n const idx = groups.findIndex((g) => g !== undefined);\n if (idx < 0) return match;\n const replacement = COMBINED_REPLACEMENTS[idx];\n return replacement !== undefined ? replacement : match;\n },\n );\n\n // Pass 2: high_entropy_env needs special handling \u2014 preserve the key name.\n // Groups: 1=leading delimiter (re-emitted so adjacent-secret separators\n // aren't collapsed), 2=key name, 3=value (redacted).\n out = out.replace(HIGH_ENTROPY_REGEX, (_match, lead, key, _value) => {\n return `${lead}${key}=[REDACTED:high_entropy_env]`;\n });\n\n return out;\n }\n\n /**\n * Recursively scrub every string value in an object/array graph. Secrets can\n * appear under any key \u2014 a URL query param, an `authorization` header, an\n * arbitrarily-named nested field \u2014 so we don't gate recursion on key names.\n * The per-string `scrub()` fast-path (anchor pre-scan) keeps this cheap: any\n * value without a credential anchor returns immediately without regex work.\n */\n scrubObject<T>(obj: T): T {\n const seen = new WeakSet();\n const visit = (v: unknown): unknown => {\n if (typeof v === 'string') return this.scrub(v);\n if (v === null || typeof v !== 'object') return v;\n if (seen.has(v as object)) return v;\n seen.add(v as object);\n if (Array.isArray(v)) return v.map(visit);\n const out: Record<string, unknown> = {};\n for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n out[k] = visit(val);\n }\n return out;\n };\n return visit(obj) as T;\n }\n}\n", "import { DefaultSecretScrubber } from '../security/secret-scrubber.js';\nimport {\n DEFAULT_HQ_REDACTION_POLICY,\n type HqEventEnvelope,\n type HqRedactionPolicy,\n} from './protocol.js';\n\nconst RAW_CONTENT_REPLACEMENT = '[REDACTED:hq_raw_content]';\nconst SENSITIVE_FIELD_REPLACEMENT = '[REDACTED:hq_sensitive_field]';\nconst REDACTED_PATH_REPLACEMENT = '[REDACTED:hq_path]';\n\nconst RAW_CONTENT_KEYS = new Set([\n 'content',\n 'contents',\n 'raw',\n 'rawContent',\n 'body',\n 'message',\n 'messages',\n 'prompt',\n 'prompts',\n 'completion',\n 'response',\n 'text',\n 'partialText',\n 'assistantMessage',\n 'userMessage',\n 'stdout',\n 'stderr',\n 'output',\n 'toolInput',\n 'toolOutput',\n 'outputSummary',\n 'body',\n 'mailboxBody',\n 'messageBody',\n 'outcome',\n 'fileContent',\n 'diff',\n 'patch',\n 'transcript',\n 'logs',\n]);\n\nconst SENSITIVE_KEYS = new Set([\n 'authorization',\n 'cookie',\n 'password',\n 'passwd',\n 'pwd',\n 'secret',\n 'token',\n 'accessToken',\n 'refreshToken',\n 'apiKey',\n 'apikey',\n 'clientSecret',\n 'privateKey',\n]);\n\nconst PATH_KEYS = new Set([\n 'path',\n 'paths',\n 'file',\n 'files',\n 'filepath',\n 'filePath',\n 'filename',\n 'projectRoot',\n 'projectRootDisplay',\n 'cwd',\n 'workingDir',\n 'workingDirectory',\n]);\n\nexport interface HqRedactOptions {\n policy?: Partial<HqRedactionPolicy>;\n projectRoot?: string;\n maxSummaryLength?: number;\n}\n\nexport interface HqRedactionResult<T> {\n value: T;\n redacted: boolean;\n}\n\nconst defaultScrubber = new DefaultSecretScrubber();\n\nexport function resolveHqRedactionPolicy(\n policy?: Partial<HqRedactionPolicy>,\n): HqRedactionPolicy {\n return {\n ...DEFAULT_HQ_REDACTION_POLICY,\n ...policy,\n };\n}\n\n/**\n * Apply an operator policy as a one-way privacy clamp. An override can make a\n * publisher policy stricter, but can never enable raw content or broader path\n * / tool-argument disclosure than the publisher selected.\n */\nexport function tightenHqRedactionPolicy(\n publisherPolicy: HqRedactionPolicy,\n operatorPolicy?: Partial<HqRedactionPolicy>,\n): HqRedactionPolicy {\n if (operatorPolicy === undefined) return publisherPolicy;\n const toolRank: Record<HqRedactionPolicy['toolArgs'], number> = {\n none: 0,\n summary: 1,\n redacted: 2,\n full: 3,\n };\n const pathRank: Record<HqRedactionPolicy['paths'], number> = {\n none: 0,\n redacted: 0,\n 'project-relative': 1,\n full: 2,\n };\n const requestedToolArgs = operatorPolicy.toolArgs;\n const requestedPaths = operatorPolicy.paths;\n return {\n rawContent:\n publisherPolicy.rawContent &&\n (operatorPolicy.rawContent === undefined || operatorPolicy.rawContent),\n toolArgs:\n requestedToolArgs !== undefined &&\n toolRank[requestedToolArgs] < toolRank[publisherPolicy.toolArgs]\n ? requestedToolArgs\n : publisherPolicy.toolArgs,\n paths:\n requestedPaths !== undefined && pathRank[requestedPaths] < pathRank[publisherPolicy.paths]\n ? requestedPaths\n : publisherPolicy.paths,\n };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]';\n}\n\nfunction isSensitiveKey(key: string): boolean {\n const lower = key.toLowerCase();\n return (\n SENSITIVE_KEYS.has(key) ||\n lower.includes('authorization') ||\n lower.includes('password') ||\n lower.includes('secret') ||\n lower.endsWith('token') ||\n lower.endsWith('apikey') ||\n lower.endsWith('api_key')\n );\n}\n\nfunction isRawContentKey(key: string): boolean {\n return RAW_CONTENT_KEYS.has(key) || RAW_CONTENT_KEYS.has(key.toLowerCase());\n}\n\nfunction isPathKey(key: string): boolean {\n return PATH_KEYS.has(key) || PATH_KEYS.has(key.toLowerCase());\n}\n\nfunction normalizePathForCompare(value: string): string {\n return value.replace(/\\\\/g, '/').replace(/\\/+$/g, '');\n}\n\nfunction redactPath(\n value: string,\n projectRoot: string | undefined,\n policy: HqRedactionPolicy,\n): string {\n if (policy.paths === 'full') return value;\n if (policy.paths === 'none' || policy.paths === 'redacted') return REDACTED_PATH_REPLACEMENT;\n\n const normalizedValue = normalizePathForCompare(value);\n if (!projectRoot) return normalizedValue.split('/').at(-1) ?? REDACTED_PATH_REPLACEMENT;\n\n const normalizedRoot = normalizePathForCompare(projectRoot);\n if (normalizedValue === normalizedRoot) return '.';\n if (normalizedValue.startsWith(`${normalizedRoot}/`)) {\n return normalizedValue.slice(normalizedRoot.length + 1) || '.';\n }\n return normalizedValue.split('/').at(-1) ?? REDACTED_PATH_REPLACEMENT;\n}\n\nfunction summarizeString(value: string, maxSummaryLength: number, scrub: boolean): string {\n const scrubbed = scrub ? defaultScrubber.scrub(value) : value;\n if (scrubbed.length <= maxSummaryLength) return scrubbed;\n return `${scrubbed.slice(0, maxSummaryLength)}\u2026[truncated:${scrubbed.length - maxSummaryLength}]`;\n}\n\n/**\n * Scrub a free-text preview field and truncate it to a maximum length so\n * it is safe to embed in HQ event envelopes and broadcast to browsers\n * without leaking secrets or running away on unbounded input.\n *\n * Returns `undefined` when the input is empty or non-string. Truncation\n * suffix is `\"\u2026[truncated:N]\"` where N is the number of dropped chars.\n */\nexport function scrubAndTruncateHqPreview(\n value: unknown,\n maxLength: number = 280,\n): string | undefined {\n if (typeof value !== 'string' || value.length === 0) return undefined;\n return summarizeString(value, maxLength, true);\n}\n\nfunction visitValue(\n value: unknown,\n options: {\n policy: HqRedactionPolicy;\n projectRoot?: string;\n maxSummaryLength: number;\n seen: WeakSet<object>;\n },\n key?: string,\n): { value: unknown; redacted: boolean } {\n if (!options.policy.rawContent && key !== undefined && isSensitiveKey(key)) {\n return { value: SENSITIVE_FIELD_REPLACEMENT, redacted: true };\n }\n\n if (typeof value === 'string') {\n if (key !== undefined && isPathKey(key)) {\n const redactedPath = redactPath(value, options.projectRoot, options.policy);\n return { value: redactedPath, redacted: redactedPath !== value };\n }\n\n if (!options.policy.rawContent && key !== undefined && isRawContentKey(key)) {\n return { value: RAW_CONTENT_REPLACEMENT, redacted: true };\n }\n\n const scrubbed = summarizeString(value, options.maxSummaryLength, !options.policy.rawContent);\n return { value: scrubbed, redacted: scrubbed !== value };\n }\n\n if (value === null || typeof value !== 'object') return { value, redacted: false };\n\n if (options.seen.has(value)) return { value: '[REDACTED:hq_circular]', redacted: true };\n options.seen.add(value);\n\n if (Array.isArray(value)) {\n let redacted = false;\n const out = value.map((item) => {\n const next = visitValue(item, options, key);\n redacted ||= next.redacted;\n return next.value;\n });\n return { value: out, redacted };\n }\n\n if (!isPlainObject(value)) return { value: String(value), redacted: true };\n\n let redacted = false;\n const out: Record<string, unknown> = {};\n for (const [childKey, childValue] of Object.entries(value)) {\n const next = visitValue(childValue, options, childKey);\n redacted ||= next.redacted;\n out[childKey] = next.value;\n }\n return { value: out, redacted };\n}\n\nexport function redactHqValue<T>(value: T, options: HqRedactOptions = {}): HqRedactionResult<T> {\n const result = visitValue(value, {\n policy: resolveHqRedactionPolicy(options.policy),\n ...(options.projectRoot !== undefined ? { projectRoot: options.projectRoot } : {}),\n maxSummaryLength: options.maxSummaryLength ?? 500,\n seen: new WeakSet<object>(),\n });\n return { value: result.value as T, redacted: result.redacted };\n}\n\nexport function redactHqEvent<TPayload>(\n event: HqEventEnvelope<TPayload>,\n options: HqRedactOptions = {},\n): HqRedactionResult<HqEventEnvelope<TPayload>> {\n const payload = redactHqValue(event.payload, options);\n const nextEvent = {\n ...event,\n payload: payload.value,\n };\n return { value: nextEvent, redacted: payload.redacted };\n}\n\nexport function summarizeHqToolArgs(value: unknown, options: HqRedactOptions = {}): unknown {\n const policy = resolveHqRedactionPolicy(options.policy);\n if (policy.toolArgs === 'full') return value;\n if (policy.toolArgs === 'none') return '[REDACTED:hq_tool_args]';\n if (policy.toolArgs === 'redacted') return redactHqValue(value, options).value;\n\n if (value === null || typeof value !== 'object') return redactHqValue(value, options).value;\n if (Array.isArray(value)) return `[array:${value.length}]`;\n\n const entries = Object.entries(value as Record<string, unknown>);\n const summary: Record<string, unknown> = {};\n for (const [key, item] of entries.slice(0, 20)) {\n if (isSensitiveKey(key)) {\n summary[key] = SENSITIVE_FIELD_REPLACEMENT;\n } else if (typeof item === 'string') {\n summary[key] = isPathKey(key)\n ? redactPath(item, options.projectRoot, policy)\n : summarizeString(item, 120, true);\n } else if (Array.isArray(item)) {\n summary[key] = `[array:${item.length}]`;\n } else if (item !== null && typeof item === 'object') {\n summary[key] = '[object]';\n } else {\n summary[key] = item;\n }\n }\n if (entries.length > 20) summary.__truncatedKeys = entries.length - 20;\n return summary;\n}\n", "import type { Mailbox, MailboxAgentStatus, MailboxMessage } from '../coordination/mailbox-types.js';\nimport type {\n HqMailboxAgentSummary,\n HqMailboxEventPayload,\n HqMailboxMessageSummary,\n HqMailboxSnapshotPayload,\n HqRedactionPolicy,\n} from './protocol.js';\nimport { scrubAndTruncateHqPreview } from './redaction.js';\n\nexport interface HqMailboxMappingOptions {\n mailboxId: string;\n scope?: 'project' | 'global';\n limit?: number;\n previewLength?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n}\n\nexport interface HqMailboxSnapshotOptions extends HqMailboxMappingOptions {\n includeCompleted?: boolean;\n}\n\nexport type HqMailboxEventAction = HqMailboxEventPayload['action'];\n\nfunction previewText(value: string | undefined, maxLength: number, policy?: Partial<HqRedactionPolicy>): string | undefined {\n if (value === undefined || value.length === 0) return undefined;\n if (policy?.rawContent === false) return '[REDACTED:hq_raw_content]';\n if (policy?.rawContent === true) {\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength)}\u2026`;\n }\n return scrubAndTruncateHqPreview(value, maxLength);\n}\n\nfunction readCount(message: MailboxMessage): number {\n return Object.keys(message.readBy).length;\n}\n\nfunction taskSummary(message: MailboxMessage): HqMailboxMessageSummary['task'] {\n if (message.taskContext === undefined) return undefined;\n const task = {\n ...(message.taskContext.taskId !== undefined ? { taskId: message.taskContext.taskId } : {}),\n ...(message.taskContext.agentRole !== undefined ? { agentRole: message.taskContext.agentRole } : {}),\n ...(message.taskContext.agentName !== undefined ? { agentName: message.taskContext.agentName } : {}),\n ...(message.taskContext.status !== undefined ? { status: message.taskContext.status } : {}),\n } satisfies HqMailboxMessageSummary['task'];\n return Object.keys(task).length > 0 ? task : undefined;\n}\n\nexport function mapMailboxMessageToHqSummary(\n message: MailboxMessage,\n options: Pick<HqMailboxMappingOptions, 'previewLength' | 'redactionPolicy'> = {},\n): HqMailboxMessageSummary {\n const previewLength = options.previewLength ?? 500;\n const bodyPreview = previewText(message.body, previewLength, options.redactionPolicy);\n const outcomePreview = previewText(message.outcome, previewLength, options.redactionPolicy);\n const task = taskSummary(message);\n\n return {\n mailId: message.id, // unique UUID per message record, used for deduplication\n messageId: message.id,\n from: message.from,\n to: message.to,\n type: message.type,\n subject: previewText(message.subject, previewLength, options.redactionPolicy) ?? '',\n priority: message.priority,\n timestamp: message.timestamp,\n ...(message.replyTo !== undefined ? { replyTo: message.replyTo } : {}),\n ...(message.senderSessionId !== undefined ? { senderSessionId: message.senderSessionId } : {}),\n completed: message.completed,\n ...(message.completedBy !== undefined ? { completedBy: message.completedBy } : {}),\n ...(message.completedAt !== undefined ? { completedAt: message.completedAt } : {}),\n readCount: readCount(message),\n hasBody: message.body.length > 0,\n ...(bodyPreview !== undefined ? { bodyPreview } : {}),\n ...(outcomePreview !== undefined ? { outcomePreview } : {}),\n ...(task !== undefined ? { task } : {}),\n };\n}\n\nexport function mapMailboxAgentToHqSummary(agent: MailboxAgentStatus): HqMailboxAgentSummary {\n return {\n agentId: agent.agentId,\n name: agent.name,\n ...(agent.role !== undefined ? { role: agent.role } : {}),\n sessionId: agent.sessionId,\n status: agent.status,\n ...(agent.currentTool !== undefined ? { currentTool: agent.currentTool } : {}),\n ...(agent.currentTask !== undefined ? { currentTask: agent.currentTask } : {}),\n iterations: agent.iterations,\n toolCalls: agent.toolCalls,\n lastActivityAt: agent.lastActivityAt,\n lastSeenAt: agent.lastSeenAt,\n online: agent.online,\n ...(agent.source !== undefined ? { source: agent.source } : {}),\n };\n}\n\nexport function createMailboxSnapshotPayload(\n messages: readonly MailboxMessage[],\n agents: readonly MailboxAgentStatus[],\n options: HqMailboxSnapshotOptions,\n): HqMailboxSnapshotPayload {\n const includeCompleted = options.includeCompleted ?? true;\n const filteredMessages = includeCompleted ? messages : messages.filter((message) => !message.completed);\n const limit = options.limit ?? 50;\n const sortedMessages = [...filteredMessages].sort((a, b) => b.timestamp.localeCompare(a.timestamp)).slice(0, limit);\n const summaries = sortedMessages.map((message) => mapMailboxMessageToHqSummary(message, options));\n const agentSummaries = agents.map(mapMailboxAgentToHqSummary);\n\n return {\n mailboxId: options.mailboxId,\n scope: options.scope ?? 'project',\n messages: summaries,\n agents: agentSummaries,\n totals: {\n messages: messages.length,\n unread: messages.filter((message) => !message.completed && readCount(message) === 0).length,\n incomplete: messages.filter((message) => !message.completed).length,\n highPriority: messages.filter((message) => message.priority === 'high').length,\n onlineAgents: agents.filter((agent) => agent.online).length,\n },\n };\n}\n\nexport async function createMailboxSnapshotPayloadFromMailbox(\n mailbox: Pick<Mailbox, 'query' | 'getAgentStatuses'>,\n options: HqMailboxSnapshotOptions,\n): Promise<HqMailboxSnapshotPayload> {\n const limit = options.limit ?? 50;\n const [messages, agents] = await Promise.all([\n mailbox.query({ limit }),\n mailbox.getAgentStatuses(),\n ]);\n return createMailboxSnapshotPayload(messages, agents, options);\n}\n\nexport function createMailboxEventPayload(input: {\n mailboxId: string;\n action: HqMailboxEventAction;\n message?: MailboxMessage;\n agent?: MailboxAgentStatus;\n summary?: string;\n previewLength?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n}): HqMailboxEventPayload {\n const summaryOptions: Pick<HqMailboxMappingOptions, 'previewLength' | 'redactionPolicy'> = {\n ...(input.previewLength !== undefined ? { previewLength: input.previewLength } : {}),\n ...(input.redactionPolicy !== undefined ? { redactionPolicy: input.redactionPolicy } : {}),\n };\n\n return {\n mailboxId: input.mailboxId,\n action: input.action,\n ...(input.message !== undefined ? { message: mapMailboxMessageToHqSummary(input.message, summaryOptions) } : {}),\n ...(input.agent !== undefined ? { agent: mapMailboxAgentToHqSummary(input.agent) } : {}),\n ...(input.summary !== undefined\n ? { summary: previewText(input.summary, input.previewLength ?? 160, input.redactionPolicy) ?? '' }\n : {}),\n };\n}\n", "import { randomUUID } from 'node:crypto';\nimport type { Logger } from '../types/logger.js';\nimport type { Mailbox, MailboxAgentStatus, MailboxMessage } from '../coordination/mailbox-types.js';\nimport {\n createMailboxEventPayload,\n createMailboxSnapshotPayloadFromMailbox,\n type HqMailboxEventAction,\n type HqMailboxSnapshotOptions,\n} from './mailbox-mapper.js';\nimport { redactHqEvent, resolveHqRedactionPolicy } from './redaction.js';\nimport {\n createHqEventEnvelope,\n HQ_PROTOCOL_VERSION,\n HQ_TRANSCRIPT_TEXT_CAP,\n type HqClientCapability,\n type HqClientCommandAckMessage,\n type HqClientCommandPollMessage,\n type HqClientEventMessage,\n type HqClientHelloMessage,\n type HqClientIdentity,\n type HqEventEnvelope,\n type HqEventType,\n type HqFleetSnapshotPayload,\n type HqMailboxEventPayload,\n type HqMailboxSnapshotPayload,\n type HqProjectIdentity,\n type HqQueuedCommand,\n type HqRedactionPolicy,\n type HqServerCommandBatchMessage,\n type HqSessionEndedPayload,\n type HqSessionSnapshotPayload,\n type HqTranscriptAppendPayload,\n} from './protocol.js';\n\nexport interface HqSocketLike {\n readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n addEventListener?(\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n ): void;\n removeEventListener?(\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n ): void;\n on?(type: 'open' | 'close' | 'error' | 'message', listener: (event: unknown) => void): void;\n off?(type: 'open' | 'close' | 'error' | 'message', listener: (event: unknown) => void): void;\n}\n\nexport type HqSocketFactory = (url: string, init: { token?: string }) => HqSocketLike;\n\nexport interface HqPublisherCommandResult {\n commandId: string;\n status: 'accepted' | 'completed' | 'failed' | 'rejected';\n message?: string;\n}\n\nexport type HqPublisherCommandHandler = (\n command: HqQueuedCommand,\n) => void | HqPublisherCommandResult | Promise<void | HqPublisherCommandResult>;\n\nexport interface HqPublisherOptions {\n url: string;\n token?: string;\n client: HqClientIdentity;\n project: HqProjectIdentity;\n capabilities?: readonly HqClientCapability[];\n socketFactory?: HqSocketFactory;\n now?: () => string;\n idFactory?: () => string;\n reconnect?: boolean;\n reconnectBaseMs?: number;\n reconnectMaxMs?: number;\n maxQueuedMessages?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n commandPollIntervalMs?: number;\n commandPollLimit?: number;\n onCommand?: HqPublisherCommandHandler;\n /**\n * Local auto-discovery hook: re-resolve the HQ endpoint before EVERY\n * connect attempt (e.g. by reading `<hq dataDir>/runtime.json`). Returning\n * `undefined` means no HQ is currently discoverable \u2014 the publisher stays\n * dormant (events keep queueing, bounded) and re-checks every\n * {@link HqPublisherOptions.discoveryPollMs}. Because the endpoint is\n * re-resolved per attempt, an HQ started AFTER this client \u2014 or restarted\n * on a different port, or one that minted its first client token on boot \u2014\n * is picked up automatically.\n */\n resolveEndpoint?: () => { url: string; token?: string | undefined } | undefined;\n /** Dormant re-check interval while `resolveEndpoint` yields nothing. Default 5s. */\n discoveryPollMs?: number;\n /**\n * Application-level heartbeat interval for the `/ws/client` connection.\n * The HQ server evicts silent sockets, so this must be comfortably below\n * the server-side client TTL even when no command handler is installed.\n */\n heartbeatIntervalMs?: number;\n /**\n * Diagnostic sink for the one-time consecutive-connect-failure warning.\n * The publisher is otherwise deliberately silent (dormant queueing), which\n * made auth failures invisible: a token the server rejects \u2014 e.g. a wrong\n * `WRONGSTACK_HQ_TOKEN` against a remote HQ \u2014 looked exactly like \"HQ not\n * running\". Defaults to a single structured `console.warn` line.\n */\n warn?: (message: string) => void;\n /** Logger for structured events. When provided, the `warn` callback is derived from it. */\n logger?: Logger | undefined;\n}\n\nexport interface HqPublishEventOptions {\n type: HqEventType | (string & {});\n payload: unknown;\n sessionId?: string;\n runId?: string;\n timestamp?: string;\n /**\n * Per-string redaction cap override. Defaults to the generic 500-char\n * summary cap; chat-transcript event types (`session.transcript`,\n * `agent.message`) automatically get {@link HQ_TRANSCRIPT_TEXT_CAP} so\n * full chat history survives when `rawContent` is enabled.\n */\n maxSummaryLength?: number;\n}\n\n/** Event types that carry full chat turns rather than telemetry summaries. */\nconst TRANSCRIPT_EVENT_TYPES = new Set<string>(['session.transcript', 'agent.message']);\n\nconst OPEN_STATE = 1;\n/**\n * After this many consecutive failed connects (never reaching `open`), emit\n * ONE diagnostic warning. The WS handshake gives the browser-style socket no\n * HTTP status, so a 401 (token mismatch) is indistinguishable from a dead\n * server at this layer \u2014 the warning names both possibilities.\n */\nconst CONNECT_WARN_AFTER_FAILURES = 5;\nconst DEFAULT_RECONNECT_BASE_MS = 1_000;\nconst DEFAULT_RECONNECT_MAX_MS = 30_000;\nconst DEFAULT_DISCOVERY_POLL_MS = 5_000;\nconst DEFAULT_MAX_QUEUED_MESSAGES = 2000;\nconst DEFAULT_COMMAND_POLL_INTERVAL_MS = 2_000;\nconst DEFAULT_COMMAND_POLL_LIMIT = 25;\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 25_000;\n\nfunction defaultSocketFactory(url: string): HqSocketLike {\n const WebSocketCtor = globalThis.WebSocket;\n if (WebSocketCtor === undefined) {\n throw new Error(\n 'No global WebSocket implementation is available; provide HqPublisherOptions.socketFactory.',\n );\n }\n return new WebSocketCtor(url) as HqSocketLike;\n}\n\nfunction toClientUrl(baseUrl: string, token: string | undefined): string {\n const url = new URL(baseUrl);\n url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';\n if (url.pathname === '/' || url.pathname === '') url.pathname = '/ws/client';\n if (token !== undefined && token.length > 0) url.searchParams.set('token', token);\n return url.toString();\n}\n\nfunction addSocketListener(\n socket: HqSocketLike,\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n): void {\n if (socket.addEventListener !== undefined) {\n socket.addEventListener(type, listener);\n return;\n }\n socket.on?.(type, listener);\n}\n\nfunction removeSocketListener(\n socket: HqSocketLike,\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n): void {\n if (socket.removeEventListener !== undefined) {\n socket.removeEventListener(type, listener);\n return;\n }\n socket.off?.(type, listener);\n}\n\nexport class HqPublisher {\n private readonly socketFactory: HqSocketFactory;\n private readonly now: () => string;\n private readonly idFactory: () => string;\n private readonly capabilities: readonly HqClientCapability[];\n private readonly reconnect: boolean;\n private readonly reconnectBaseMs: number;\n private readonly reconnectMaxMs: number;\n private readonly maxQueuedMessages: number;\n private readonly resolvedRedactionPolicy: HqRedactionPolicy;\n private readonly logger: Logger | undefined;\n private socket: HqSocketLike | null = null;\n private seq = 0;\n private queue: string[] = [];\n private stopped = false;\n private reconnectAttempt = 0;\n private connectWarningEmitted = false;\n private lastAttempt: { url: string; hadToken: boolean } | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private commandPollTimer: ReturnType<typeof setInterval> | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private lastCommandId: string | undefined;\n\n constructor(private readonly options: HqPublisherOptions) {\n this.socketFactory = options.socketFactory ?? defaultSocketFactory;\n this.now = options.now ?? (() => new Date().toISOString());\n this.idFactory = options.idFactory ?? randomUUID;\n this.capabilities = options.capabilities ?? [\n 'telemetry.publish',\n 'mailbox.summary',\n 'fleet.summary',\n 'session.summary',\n ];\n this.reconnect = options.reconnect ?? true;\n this.reconnectBaseMs = options.reconnectBaseMs ?? DEFAULT_RECONNECT_BASE_MS;\n this.reconnectMaxMs = options.reconnectMaxMs ?? DEFAULT_RECONNECT_MAX_MS;\n this.maxQueuedMessages = options.maxQueuedMessages ?? DEFAULT_MAX_QUEUED_MESSAGES;\n this.resolvedRedactionPolicy = resolveHqRedactionPolicy(options.redactionPolicy);\n this.logger = options.logger;\n }\n\n connect(): void {\n if (this.socket !== null || this.stopped) return;\n // A retry / discovery poll is already scheduled \u2014 let it fire instead of\n // dialing (and re-resolving the endpoint) on every publish while offline.\n if (this.reconnectTimer !== null) return;\n\n let url = this.options.url;\n let token = this.options.token;\n if (this.options.resolveEndpoint !== undefined) {\n const endpoint = this.options.resolveEndpoint();\n if (endpoint === undefined) {\n this.scheduleDiscoveryPoll();\n return;\n }\n url = endpoint.url;\n token = endpoint.token ?? token;\n }\n this.lastAttempt = { url, hadToken: token !== undefined };\n\n let socket: HqSocketLike;\n try {\n socket = this.socketFactory(toClientUrl(url, token), {\n ...(token !== undefined ? { token } : {}),\n });\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.socket = socket;\n\n const onOpen = () => {\n this.reconnectAttempt = 0;\n this.sendHelloNow();\n this.flushQueue();\n this.startHeartbeat();\n if (this.options.onCommand !== undefined) {\n this.startCommandPolling();\n this.pollCommands();\n }\n };\n const onMessage = (event: unknown) => {\n void this.handleServerMessage(event);\n };\n const onCloseOrError = () => {\n removeSocketListener(socket, 'open', onOpen);\n removeSocketListener(socket, 'message', onMessage);\n removeSocketListener(socket, 'close', onCloseOrError);\n removeSocketListener(socket, 'error', onCloseOrError);\n this.stopCommandPolling();\n this.stopHeartbeat();\n if (this.socket === socket) this.socket = null;\n this.scheduleReconnect();\n };\n\n addSocketListener(socket, 'open', onOpen);\n addSocketListener(socket, 'message', onMessage);\n addSocketListener(socket, 'close', onCloseOrError);\n addSocketListener(socket, 'error', onCloseOrError);\n\n if (socket.readyState === OPEN_STATE) onOpen();\n }\n\n close(): void {\n this.stopped = true;\n if (this.reconnectTimer !== null) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.stopCommandPolling();\n this.stopHeartbeat();\n this.queue = [];\n const socket = this.socket;\n this.socket = null;\n socket?.close(1000, 'hq publisher closed');\n }\n\n publishEvent<TPayload>(\n options: HqPublishEventOptions & { payload: TPayload },\n ): HqEventEnvelope<TPayload> {\n const event = createHqEventEnvelope({\n id: this.idFactory(),\n type: options.type,\n timestamp: options.timestamp ?? this.now(),\n clientId: this.options.client.clientId,\n projectId: this.options.project.projectId,\n seq: ++this.seq,\n payload: options.payload,\n ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),\n ...(options.runId !== undefined ? { runId: options.runId } : {}),\n });\n const maxSummaryLength =\n options.maxSummaryLength ??\n (TRANSCRIPT_EVENT_TYPES.has(options.type) ? HQ_TRANSCRIPT_TEXT_CAP : undefined);\n const redacted = redactHqEvent(event, {\n policy: this.resolvedRedactionPolicy,\n projectRoot: this.options.project.projectRoot,\n ...(maxSummaryLength !== undefined ? { maxSummaryLength } : {}),\n }).value;\n this.sendFrame({ type: 'client.event', event: redacted });\n return redacted;\n }\n\n async publishMailboxSnapshot(\n mailbox: Pick<Mailbox, 'query' | 'getAgentStatuses'>,\n options: Omit<HqMailboxSnapshotOptions, 'redactionPolicy'> & {\n sessionId?: string;\n timestamp?: string;\n },\n ): Promise<HqEventEnvelope<HqMailboxSnapshotPayload>> {\n const payload = await createMailboxSnapshotPayloadFromMailbox(mailbox, {\n ...options,\n redactionPolicy: this.resolvedRedactionPolicy,\n });\n return this.publishEvent({\n type: 'mailbox.snapshot',\n payload,\n ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),\n ...(options.timestamp !== undefined ? { timestamp: options.timestamp } : {}),\n });\n }\n\n publishMailboxEvent(input: {\n mailboxId: string;\n action: HqMailboxEventAction;\n message?: MailboxMessage;\n agent?: MailboxAgentStatus;\n summary?: string;\n previewLength?: number;\n sessionId?: string;\n timestamp?: string;\n }): HqEventEnvelope<HqMailboxEventPayload> {\n const payload = createMailboxEventPayload({\n mailboxId: input.mailboxId,\n action: input.action,\n ...(input.message !== undefined ? { message: input.message } : {}),\n ...(input.agent !== undefined ? { agent: input.agent } : {}),\n ...(input.summary !== undefined ? { summary: input.summary } : {}),\n ...(input.previewLength !== undefined ? { previewLength: input.previewLength } : {}),\n redactionPolicy: this.resolvedRedactionPolicy,\n });\n return this.publishEvent({\n type: 'mailbox.event',\n payload,\n ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),\n ...(input.timestamp !== undefined ? { timestamp: input.timestamp } : {}),\n });\n }\n\n /** The client identity this publisher announced (clientId, kind, machineId, \u2026). */\n get identity(): HqClientIdentity {\n return this.options.client;\n }\n\n /** The project identity this publisher is bound to. */\n get project(): HqProjectIdentity {\n return this.options.project;\n }\n\n /** Effective publisher-side policy applied before any event leaves this process. */\n get redactionPolicy(): HqRedactionPolicy {\n return this.resolvedRedactionPolicy;\n }\n\n /** Publish a live session/terminal snapshot (state + agents). */\n publishSessionSnapshot(\n payload: HqSessionSnapshotPayload,\n opts?: { timestamp?: string },\n ): HqEventEnvelope<HqSessionSnapshotPayload> {\n return this.publishEvent({\n type: 'session.snapshot',\n payload,\n sessionId: payload.sessionId,\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n /** Publish an incremental batch of transcript turns for a session. */\n publishTranscriptAppend(\n payload: HqTranscriptAppendPayload,\n opts?: { timestamp?: string },\n ): HqEventEnvelope<HqTranscriptAppendPayload> {\n return this.publishEvent({\n type: 'session.transcript',\n payload,\n sessionId: payload.sessionId,\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n /** Mark a session/terminal as ended. */\n publishSessionEnded(\n payload: HqSessionEndedPayload,\n opts?: { timestamp?: string },\n ): HqEventEnvelope<HqSessionEndedPayload> {\n return this.publishEvent({\n type: 'session.ended',\n payload,\n sessionId: payload.sessionId,\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n /** Publish a fleet (multi-agent coordinator) snapshot. */\n publishFleetSnapshot(\n payload: HqFleetSnapshotPayload,\n opts?: { sessionId?: string; timestamp?: string },\n ): HqEventEnvelope<HqFleetSnapshotPayload> {\n return this.publishEvent({\n type: 'fleet.snapshot',\n payload,\n runId: payload.runId,\n ...(opts?.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n pollCommands(): void {\n this.sendFrame({\n type: 'client.command_poll',\n clientId: this.options.client.clientId,\n projectId: this.options.project.projectId,\n ...(this.lastCommandId !== undefined ? { afterCommandId: this.lastCommandId } : {}),\n limit: this.options.commandPollLimit ?? DEFAULT_COMMAND_POLL_LIMIT,\n });\n }\n\n ackCommand(result: HqPublisherCommandResult): void {\n this.sendFrame({\n type: 'client.command_ack',\n clientId: this.options.client.clientId,\n projectId: this.options.project.projectId,\n commandId: result.commandId,\n status: result.status,\n ...(result.message !== undefined ? { message: result.message } : {}),\n });\n }\n\n private createHelloFrame(): HqClientHelloMessage {\n return {\n type: 'client.hello',\n payload: {\n protocolVersion: HQ_PROTOCOL_VERSION,\n client: this.options.client,\n project: this.options.project,\n capabilities: this.capabilities,\n redactionPolicy: this.resolvedRedactionPolicy,\n },\n };\n }\n\n private sendHelloNow(): void {\n const socket = this.socket;\n if (socket?.readyState !== OPEN_STATE) {\n this.sendFrame(this.createHelloFrame());\n return;\n }\n socket.send(JSON.stringify(this.createHelloFrame()));\n }\n\n private sendFrame(\n frame:\n | HqClientHelloMessage\n | HqClientEventMessage\n | HqClientCommandPollMessage\n | HqClientCommandAckMessage,\n ): void {\n const serialized = JSON.stringify(frame);\n const socket = this.socket;\n // Fast path: socket is open and nothing queued \u2014 send immediately.\n if (socket?.readyState === OPEN_STATE && this.queue.length === 0) {\n socket.send(serialized);\n return;\n }\n // Slow path: socket offline or queue already has pending frames \u2014 enqueue.\n this.enqueue(serialized);\n this.connect();\n }\n\n private enqueue(serialized: string): void {\n if (this.queue.length >= this.maxQueuedMessages) this.queue.shift();\n this.queue.push(serialized);\n }\n\n /** Batch-dequeue up to 50 frames at a time, yielding to the microtask\n * queue between batches so we don't starve the event loop on reconnect. */\n private flushQueue(): void {\n const socket = this.socket;\n if (socket?.readyState !== OPEN_STATE || this.queue.length === 0) return;\n const batch = this.queue.splice(0, 50);\n for (const frame of batch) socket.send(frame);\n if (this.queue.length > 0) setImmediate(() => this.flushQueue());\n }\n\n private startCommandPolling(): void {\n if (this.options.onCommand === undefined || this.commandPollTimer !== null) return;\n this.commandPollTimer = setInterval(\n () => this.pollCommands(),\n this.options.commandPollIntervalMs ?? DEFAULT_COMMAND_POLL_INTERVAL_MS,\n );\n this.commandPollTimer.unref?.();\n }\n\n private stopCommandPolling(): void {\n if (this.commandPollTimer === null) return;\n clearInterval(this.commandPollTimer);\n this.commandPollTimer = null;\n }\n\n private startHeartbeat(): void {\n if (this.heartbeatTimer !== null) return;\n this.heartbeatTimer = setInterval(\n () => this.publishHeartbeat(),\n this.options.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS,\n );\n this.heartbeatTimer.unref?.();\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer === null) return;\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n private publishHeartbeat(): void {\n const startedAt = Date.parse(this.options.client.startedAt);\n const now = Date.parse(this.now());\n this.publishEvent({\n type: 'client.heartbeat',\n payload: {\n uptimeMs:\n Number.isFinite(startedAt) && Number.isFinite(now) ? Math.max(0, now - startedAt) : 0,\n status: 'idle',\n },\n });\n }\n\n private async handleServerMessage(event: unknown): Promise<void> {\n const message = this.parseServerMessage(event);\n if (message?.type !== 'hq.command_batch') return;\n await this.handleCommandBatch(message);\n }\n\n private parseServerMessage(event: unknown): HqServerCommandBatchMessage | null {\n const data = this.extractMessageData(event);\n if (data === null) return null;\n try {\n const parsed = JSON.parse(data) as Partial<HqServerCommandBatchMessage>;\n if (parsed.type !== 'hq.command_batch' || !Array.isArray(parsed.commands)) return null;\n return parsed as HqServerCommandBatchMessage;\n } catch {\n return null;\n }\n }\n\n private extractMessageData(event: unknown): string | null {\n const value =\n typeof event === 'object' && event !== null && 'data' in event\n ? (event as { data?: unknown }).data\n : event;\n if (typeof value === 'string') return value;\n if (value instanceof ArrayBuffer) return new TextDecoder().decode(value);\n if (ArrayBuffer.isView(value)) {\n const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n return new TextDecoder().decode(bytes);\n }\n return null;\n }\n\n private async handleCommandBatch(message: HqServerCommandBatchMessage): Promise<void> {\n const handler = this.options.onCommand;\n if (handler === undefined) return;\n\n for (const command of message.commands) {\n this.lastCommandId = command.commandId;\n try {\n const result = await handler(command);\n if (result !== undefined) this.ackCommand(result);\n else if (command.requiresAck)\n this.ackCommand({ commandId: command.commandId, status: 'accepted' });\n } catch (err) {\n this.ackCommand({\n commandId: command.commandId,\n status: 'failed',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.stopped || !this.reconnect || this.reconnectTimer !== null) return;\n const delay = Math.min(this.reconnectMaxMs, this.reconnectBaseMs * 2 ** this.reconnectAttempt);\n this.reconnectAttempt += 1;\n // One-time visibility for persistent failures. `reconnectAttempt` resets\n // on every successful open, so reaching the threshold means the endpoint\n // has NEVER accepted us in this streak \u2014 dead server or rejected token.\n if (!this.connectWarningEmitted && this.reconnectAttempt >= CONNECT_WARN_AFTER_FAILURES) {\n this.connectWarningEmitted = true;\n this.emitConnectWarning();\n }\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, delay);\n this.reconnectTimer.unref?.();\n }\n\n private emitConnectWarning(): void {\n const attempt = this.lastAttempt;\n const message =\n `WrongStack HQ publisher: ${this.reconnectAttempt} consecutive connection failures` +\n `${attempt !== null ? ` to ${attempt.url} (client token ${attempt.hadToken ? 'present' : 'absent'})` : ''}. ` +\n 'Either the HQ server is unreachable or it rejected the token (401). ' +\n 'If HQ runs in client-token mode, verify WRONGSTACK_HQ_TOKEN / auth.json. Retries continue with backoff.';\n if (this.logger) {\n this.logger.warn(message, { event: 'hq.publisher.connect_failed' });\n return;\n }\n const warn =\n this.options.warn ??\n ((msg: string) =>\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.publisher.connect_failed',\n message: msg,\n timestamp: this.now(),\n }),\n ));\n try {\n warn(message);\n } catch {\n /* diagnostics must never break publishing */\n }\n }\n\n /**\n * Dormant re-check while no HQ endpoint is discoverable. Uses a FIXED\n * interval (not the exponential reconnect backoff): the check is a cheap\n * local file read, and backing off would delay attaching to an HQ the\n * user just started \u2014 the whole point of auto-discovery.\n */\n private scheduleDiscoveryPoll(): void {\n if (this.stopped || !this.reconnect || this.reconnectTimer !== null) return;\n this.reconnectAttempt = 0;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, this.options.discoveryPollMs ?? DEFAULT_DISCOVERY_POLL_MS);\n this.reconnectTimer.unref?.();\n }\n}\n", "import { createHash, randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport { hostname } from 'node:os';\nimport { basename } from 'node:path';\nimport { GlobalMailbox } from '../coordination/global-mailbox.js';\nimport type { EventBus } from '../kernel/events.js';\nimport type { HqClientConfig } from '../types/config.js';\nimport type { Logger } from '../types/logger.js';\nimport {\n type HqAuthFile,\n hqAuthFilePath,\n readHqRuntimeFileSync,\n resolveHqDataDir,\n} from './auth-store.js';\nimport type {\n HqClientCapability,\n HqClientIdentity,\n HqProjectIdentity,\n HqRedactionPolicy,\n} from './protocol.js';\nimport { HqPublisher, type HqPublisherCommandHandler, type HqSocketFactory } from './publisher.js';\n\nexport interface HqPublisherEnvConfig {\n url: string;\n token?: string;\n enabled?: boolean;\n rawContent?: boolean;\n projectAlias?: string;\n /**\n * Same-machine auto-discovery mode: no explicit URL was configured, so the\n * publisher should re-resolve the endpoint from `<dataDir>/runtime.json`\n * (+ the first client token in `auth.json`) before every connect attempt.\n * This lets every client on the machine attach to a `wstack --hq` that is\n * already running, starts later, or restarts on a different port.\n */\n discover?: boolean;\n /** Resolved HQ data dir the discovery reads from. */\n dataDir?: string;\n}\n\n/**\n * Discover a locally running `wstack --hq` endpoint: reads the runtime\n * marker (pid-liveness-checked) and the first client token. Returns\n * `undefined` when no live HQ is advertised on this machine.\n */\nexport function discoverLocalHqEndpoint(options: {\n dataDir?: string | undefined;\n env?: NodeJS.ProcessEnv | undefined;\n} = {}): { url: string; token?: string | undefined } | undefined {\n const dataDir = resolveHqDataDir(options.dataDir, options.env ?? process.env);\n const runtime = readHqRuntimeFileSync(dataDir);\n if (runtime === undefined) return undefined;\n const token = readFirstClientTokenFromAuthFile(dataDir);\n return { url: runtime.url, ...(token ? { token } : {}) };\n}\n\nfunction readFirstClientTokenFromAuthFile(dataDir: string): string | undefined {\n try {\n const raw = fs.readFileSync(hqAuthFilePath(dataDir), 'utf8');\n const parsed = JSON.parse(raw) as HqAuthFile;\n return parsed.clientTokens?.find((t) => t.token.trim().length > 0)?.token;\n } catch {\n return undefined;\n }\n}\n\n/**\n * True when an explicit HQ URL targets this machine. Falling back to the\n * LOCAL auth.json client token is only valid for same-machine servers \u2014 a\n * remote HQ has its own auth.json, and sending the local token would put the\n * publisher into a silent 401 reconnect loop.\n */\nfunction isLoopbackHqUrl(url: string): boolean {\n try {\n const host = new URL(url).hostname.toLowerCase();\n return host === '127.0.0.1' || host === 'localhost' || host === '::1' || host === '[::1]' || host === '0.0.0.0';\n } catch {\n return false;\n }\n}\n\nexport function resolveHqConfigFromEnv(env: NodeJS.ProcessEnv = process.env): HqPublisherEnvConfig | undefined {\n return resolveHqConfig({ env });\n}\n\nexport function resolveHqConfig(options: {\n env?: NodeJS.ProcessEnv | undefined;\n config?: HqClientConfig | undefined;\n} = {}): HqPublisherEnvConfig | undefined {\n const env = options.env ?? process.env;\n const fileConfig = options.config;\n const envUrl = env['WRONGSTACK_HQ_URL']?.trim();\n const envToken = env['WRONGSTACK_HQ_TOKEN']?.trim();\n const configUrl = fileConfig?.url?.trim();\n const configToken = fileConfig?.token?.trim();\n const envEnabledRaw = env['WRONGSTACK_HQ_ENABLED']?.trim();\n const enabled = envEnabledRaw !== undefined && envEnabledRaw.length > 0\n ? envEnabledRaw !== '0'\n : fileConfig?.enabled;\n const dataDir = resolveHqDataDir(fileConfig?.dataDir, env);\n const explicitToken = envToken || configToken;\n const runtimeUrl = readHqRuntimeFileSync(dataDir)?.url.trim();\n const url = envUrl || configUrl;\n // The local auth.json client token is only a valid fallback for\n // same-machine endpoints (discovery, or an explicit loopback URL). For a\n // remote URL without an explicit token, send NO token \u2014 the server's 401\n // is then an honest signal instead of a guaranteed-wrong local token.\n const localFallbackToken =\n !url || isLoopbackHqUrl(url) ? readFirstClientTokenFromAuthFile(dataDir) : undefined;\n const token = explicitToken || localFallbackToken;\n\n const rawContentEnv = env['WRONGSTACK_HQ_RAW_CONTENT']?.trim();\n const explicitRawContent = rawContentEnv ? rawContentEnv === '1' : fileConfig?.rawContent;\n const projectAliasEnv = env['WRONGSTACK_HQ_PROJECT_ALIAS']?.trim();\n const projectAlias = projectAliasEnv || fileConfig?.projectAlias;\n\n if (!url) {\n if (enabled === false) return undefined;\n // No explicit endpoint \u2192 same-machine auto-discovery (default ON).\n // The publisher re-resolves runtime.json + auth.json before every\n // connect attempt, so an HQ started AFTER this client \u2014 or restarted on\n // another port \u2014 is attached to automatically. While no HQ is running\n // the publisher stays dormant (bounded queue, cheap file poll).\n // Opt out with WRONGSTACK_HQ_ENABLED=0 or config `hq.enabled: false`.\n //\n // Same-machine HQ defaults to RAW content: the data never leaves this\n // machine and the operator watching HQ is the same user running the\n // sessions \u2014 a redacted chat history there is useless. Opt out with\n // WRONGSTACK_HQ_RAW_CONTENT=0 or `hq.rawContent: false` (/hq raw off).\n // Secret scrubbing + sensitive-field masking still always apply.\n return {\n url: runtimeUrl || 'http://127.0.0.1:3499',\n enabled: true,\n discover: true,\n dataDir,\n rawContent: explicitRawContent ?? true,\n ...(token ? { token } : {}),\n ...(projectAlias ? { projectAlias } : {}),\n };\n }\n\n // Explicit URL: raw content is the default for every HQ target. Operators\n // can still opt out with WRONGSTACK_HQ_RAW_CONTENT=0 or hq.rawContent=false,\n // and the HQ server can clamp disclosure with auth.json redactionPolicy.\n const rawContent = explicitRawContent ?? true;\n return {\n url,\n ...(token ? { token } : {}),\n ...(enabled !== undefined ? { enabled } : {}),\n ...(rawContent !== undefined ? { rawContent } : {}),\n ...(projectAlias ? { projectAlias } : {}),\n };\n}\n\nfunction stableMachineId(): string {\n // Stable per *physical machine*, NOT per process \u2014 every terminal on the\n // same computer must share one machineId so HQ groups them under a single\n // machine node. (Process identity already lives in clientId via the pid.)\n return createHash('sha256').update(hostname()).digest('hex').slice(0, 12);\n}\n\nfunction deriveProjectId(projectRoot: string): string {\n return createHash('sha256').update(projectRoot).digest('hex').slice(0, 12);\n}\n\nexport interface CreateHqPublisherOptions {\n clientKind: HqClientIdentity['kind'];\n projectRoot: string;\n projectName?: string;\n machineId?: string;\n hostnameOverride?: string;\n socketFactory?: HqSocketFactory;\n config?: HqPublisherEnvConfig;\n appConfig?: { hq?: HqClientConfig | undefined } | undefined;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n /** Forwarded to the HqPublisher constructor (Phase 4 control plane). */\n capabilities?: readonly HqClientCapability[];\n /** Forwarded to the HqPublisher constructor (Phase 4 control plane). */\n onCommand?: HqPublisherCommandHandler;\n /** Dormant discovery re-check interval override (tests / tight loops). */\n discoveryPollMs?: number;\n /** Logger for structured connect-failure diagnostics. */\n logger?: Logger | undefined;\n}\n\nexport function createHqPublisherFromEnv(options: CreateHqPublisherOptions): HqPublisher | undefined {\n const config = options.config ?? resolveHqConfig({ config: options.appConfig?.hq });\n if (!config || config.enabled === false) return undefined;\n\n const machineId = options.machineId ?? stableMachineId();\n const host = options.hostnameOverride ?? hostname();\n const projectName = options.projectName ?? config.projectAlias ?? (basename(options.projectRoot) || 'unknown');\n\n const client: HqClientIdentity = {\n clientId: `${machineId}:${options.clientKind}:${process.pid}:${randomUUID().slice(0, 8)}`,\n kind: options.clientKind,\n machineId,\n ...(host ? { hostname: host } : {}),\n pid: process.pid,\n startedAt: new Date().toISOString(),\n };\n\n const project: HqProjectIdentity = {\n projectId: deriveProjectId(options.projectRoot),\n projectRoot: options.projectRoot,\n projectName,\n machineId,\n workspaceKind: 'git',\n };\n\n const redactionPolicy: Partial<HqRedactionPolicy> | undefined =\n options.redactionPolicy || config.rawContent !== undefined\n ? {\n ...(config.rawContent !== undefined ? { rawContent: config.rawContent } : {}),\n ...(options.redactionPolicy ?? {}),\n }\n : undefined;\n\n const discoveryDataDir = config.dataDir;\n return new HqPublisher({\n url: config.url,\n ...(config.token ? { token: config.token } : {}),\n client,\n project,\n ...(options.socketFactory ? { socketFactory: options.socketFactory } : {}),\n ...(redactionPolicy !== undefined ? { redactionPolicy } : {}),\n ...(options.capabilities !== undefined ? { capabilities: options.capabilities } : {}),\n ...(options.onCommand !== undefined ? { onCommand: options.onCommand } : {}),\n // Auto-discovery: re-read the local HQ runtime marker + client token on\n // every connect attempt so late-started/restarted HQs are picked up.\n ...(config.discover\n ? { resolveEndpoint: () => discoverLocalHqEndpoint({ dataDir: discoveryDataDir }) }\n : {}),\n ...(options.discoveryPollMs !== undefined ? { discoveryPollMs: options.discoveryPollMs } : {}),\n ...(options.logger !== undefined ? { logger: options.logger } : {}),\n });\n}\n\nexport interface CreateGlobalMailboxOptions {\n projectDir: string;\n events?: EventBus;\n hqPublisher?: HqPublisher;\n}\n\nexport function createGlobalMailbox(options: CreateGlobalMailboxOptions): GlobalMailbox {\n return new GlobalMailbox(options.projectDir, options.events, options.hqPublisher);\n}\n", "/**\n * GlobalMailbox \u2014 project-level inter-agent mailbox with cross-session support.\n *\n * Stores messages at `~/.wrongstack/projects/<slug>/_mailbox.jsonl` so every\n * client and agent working on the same canonical project shares one inbox,\n * including agents in different processes, sessions, branches, and linked Git\n * worktrees.\n *\n * Features:\n * - Agent registration + heartbeat (agents go stale after 60s without heartbeat)\n * - Per-recipient read receipts (readBy[agentId] = ISO8601)\n * - Atomic file-locking for concurrent multi-process writes\n * - Unread count for new-mail notifications\n * - Online agent list\n *\n * @module GlobalMailbox\n */\n\nimport { randomUUID } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\n\nimport * as path from 'node:path';\nimport type { HqPublisher } from '../hq/publisher.js';\nimport type { EventBus } from '../kernel/events.js';\nimport { withFileLock } from '../utils/atomic-write.js';\nimport { projectSlug } from '../utils/wstack-paths.js';\nimport {\n AGENT_STALE_MS,\n AUTO_COMPACT_DEFAULT_TTL_MS,\n AUTO_COMPACT_INTERVAL_MS,\n AUTO_COMPACT_READ_MAX_AGE_MS,\n CLIENT_STALE_MS,\n HEARTBEAT_THROTTLE_MS,\n LINE_SEPARATOR,\n MESSAGE_CACHE_MAX_ENTRIES,\n REGISTRY_CACHE_TTL_MS,\n} from './mailbox-constants.js';\nimport type { MailboxEventEmitter } from './mailbox-events.js';\nimport {\n applyAckToMessage,\n isAckRecord,\n normalizeMailboxMessageType,\n parseMailboxLine,\n serializeAckRecord,\n} from './mailbox-message-codec.js';\nimport type {\n AckRecord,\n AgentHeartbeatInput,\n AgentRegistrationInput,\n AutoCompactOptions,\n AutoCompactResult,\n ClientHeartbeatInput,\n ClientRegistrationInput,\n ClientStatus,\n Mailbox,\n MailboxAckBatchInput,\n MailboxAckInput,\n MailboxAgentStatus,\n MailboxMessage,\n MailboxQuery,\n MailboxSendInput,\n PurgeOptions,\n PurgeResult,\n RegisteredAgent,\n RegisteredClient,\n} from './mailbox-types.js';\nimport { normalizeRecipient } from './mailbox-types.js';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst MAILBOX_FILE = '_mailbox.jsonl';\nconst CLIENT_REGISTRY_FILE = '_mailbox.clients.json';\n\ntype HqPublisherRef = HqPublisher | (() => HqPublisher | undefined);\n\n/**\n * Derive the project-level mailbox directory path.\n *\n * Delegates to the CANONICAL `projectSlug()` from wstack-paths so every\n * surface (CLI, TUI, WebUI, mailbox tool, loop checker) lands in the exact\n * same `~/.wrongstack/projects/<slug>/` directory. `projectSlug()` also folds\n * linked Git worktrees into their shared common project identity, preventing\n * branch/worktree isolation from accidentally becoming mailbox isolation.\n *\n * @param projectRoot \u2014 absolute path to the project root\n * @param globalRoot \u2014 `~/.wrongstack` (or custom global root)\n */\nexport function resolveProjectDir(projectRoot: string, globalRoot: string): string {\n return path.join(globalRoot, 'projects', projectSlug(projectRoot));\n}\n\n// \u2500\u2500 Singleton factory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Process-wide registry of GlobalMailbox instances, keyed by projectDir.\n *\n * Without this, `attachMailboxChecker` and `attachFleetPulse` each created\n * a SEPARATE GlobalMailbox for the same project directory \u2014 two independent\n * mtime caches, two read chains, two sets of heartbeat timers. The factory\n * ensures that within a single process there is at most one instance per\n * project directory, so cache hit ratio is maximized and I/O is minimized.\n *\n * Cross-process sharing still works as before (the JSONL file + file lock\n * is the source of truth); this is purely an in-process optimization.\n *\n * Pass `forceNew: true` to bypass the cache (used by tests that need an\n * isolated tmpdir instance without polluting the singleton).\n */\nconst _mailboxInstances = new Map<string, GlobalMailbox>();\n\nexport function getSharedMailbox(\n projectDir: string,\n events?: EventBus,\n hqPublisher?: HqPublisherRef,\n opts?: { forceNew?: boolean },\n): GlobalMailbox {\n if (opts?.forceNew) {\n return new GlobalMailbox(projectDir, events, hqPublisher);\n }\n const existing = _mailboxInstances.get(projectDir);\n if (existing !== undefined) return existing;\n const mb = new GlobalMailbox(projectDir, events, hqPublisher);\n _mailboxInstances.set(projectDir, mb);\n return mb;\n}\n\n/** Clear the singleton registry \u2014 used by tests to avoid cross-test leakage. */\nexport function _clearMailboxSingletons(): void {\n _mailboxInstances.clear();\n}\n\n// \u2500\u2500 GlobalMailbox \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class GlobalMailbox implements Mailbox {\n /** Path to the JSONL message file. */\n readonly messagePath: string;\n /** Path to the JSON agent registry file. */\n readonly registryPath: string;\n /** Path to the JSON client registry file. */\n readonly clientRegistryPath: string;\n /** Optional event bus for emitting agent registration/heartbeat events. */\n private readonly _events?: EventBus | undefined;\n /** Optional HQ publisher for cross-project command-center telemetry. */\n private readonly _hqPublisher?: HqPublisherRef | undefined;\n /**\n * Optional SSE event emitter for real-time push to HTTP bridge clients.\n * When present, `send`/`ack`/`softDelete`/`restore` emit events that\n * connected SSE subscribers receive instantly.\n */\n readonly eventEmitter?: MailboxEventEmitter | undefined;\n /**\n * Local cache of the agent registry to avoid re-reading on every call.\n * Time-bounded: the registry file is shared ACROSS PROCESSES (that's the\n * whole point of GlobalMailbox), so a cache served forever would never see\n * agents registered by other sessions. Writers always bypass it.\n */\n private _registryCache: Map<string, RegisteredAgent> | null = null;\n /** When the registry cache was last refreshed from disk (epoch ms). */\n private _registryCacheAt = 0;\n /**\n * Local cache of the client registry to avoid re-reading on every call.\n * Same reasoning as agent registry cache.\n */\n private _clientRegistryCache: Map<string, RegisteredClient> | null = null;\n /** When the client registry cache was last refreshed from disk (epoch ms). */\n private _clientRegistryCacheAt = 0;\n /** Last time each local agent sent a heartbeat (throttle). */\n private _lastHeartbeat = new Map<string, number>();\n /** Last time each local client sent a heartbeat (throttle). */\n private _lastClientHeartbeat = new Map<string, number>();\n /**\n * In-memory mirror of the JSONL message file. The mailbox is shared\n * ACROSS PROCESSES, so reads cannot trust the cache blindly \u2014 we pair it\n * with an mtime check. The file lock serializes every write, so a\n * changed mtimeMs is a definitive signal that another process (or this\n * one) wrote; an unchanged mtimeMs guarantees no write happened and the\n * cache is current. This collapses the per-iteration `query()` cost from\n * O(file_size) disk + parse to O(messages) in memory.\n */\n private _messageCache: MailboxMessage[] | null = null;\n /** mtimeMs of the file when `_messageCache` was populated. */\n private _messageCacheMtime = -1;\n /** Size of the file when `_messageCache` was populated (extra guard). */\n private _messageCacheSize = -1;\n /**\n * Serializes reads of the message file so overlapping concurrent\n * `_readMessagesCached()` calls don't both enter the incremental \"file\n * only grew\" branch against the same stale `_messageCacheSize` and\n * each push the same tail bytes onto the cache (duplicating every\n * appended message). The chain runs each read to completion before\n * the next starts, in issue order \u2014 readers are read-only and never\n * conflict with each other on content, only on the cache mutation\n * that follows the read. Pattern mirrors a serialized mutation chain.\n */\n private _readChain: Promise<MailboxMessage[]> = Promise.resolve([] as MailboxMessage[]);\n\n /**\n * Recipient \u2192 Set of indices into `_messageCache`. Maintained alongside\n * the cache so `query({ to })` and `unreadCount(agentId)` can skip the\n * O(N) full scan and iterate only the messages addressed to the target\n * recipient (plus broadcasts `*`).\n *\n * The index is rebuilt whenever the cache array is replaced\n * (`_setMessageCache`), extended when new messages are pushed\n * (`_pushToCache`), and cleared on `close()`.\n * It is `null` when the cache itself is null (> MESSAGE_CACHE_MAX_ENTRIES\n * or never populated).\n *\n * Safety: array indices are valid only as long as the cache array\n * reference hasn't changed. Since we rebuild the index in the same\n * synchronous step that replaces the cache, a reader that calls\n * `_readMessagesCached()` either gets the old array + old index, or\n * the new array + new index \u2014 never a mismatch.\n */\n private _recipientIndex: Map<string, Set<number>> | null = null;\n\n /**\n * Sender \u2192 Set of indices into `_messageCache`. Same lifecycle and\n * safety properties as `_recipientIndex`, but keyed on `msg.from`\n * so `query({ from })` can skip the full scan.\n */\n private _senderIndex: Map<string, Set<number>> | null = null;\n\n /**\n * @param projectDir \u2014 `~/.wrongstack/projects/<slug>/`\n * @param events \u2014 optional EventBus for real-time TUI/WebUI notifications\n * @param hqPublisher \u2014 optional HQ publisher, or getter, for cross-project telemetry\n * @param eventEmitter \u2014 optional SSE event emitter for HTTP bridge push\n */\n constructor(\n projectDir: string,\n events?: EventBus,\n hqPublisher?: HqPublisherRef,\n eventEmitter?: MailboxEventEmitter,\n ) {\n this.messagePath = path.join(projectDir, MAILBOX_FILE);\n this.registryPath = path.join(projectDir, '_mailbox.registry.json');\n this.clientRegistryPath = path.join(projectDir, CLIENT_REGISTRY_FILE);\n this._events = events;\n this._hqPublisher = hqPublisher;\n this.eventEmitter = eventEmitter;\n }\n\n private get hqMailboxId(): string {\n return `${path.basename(path.dirname(this.messagePath))}:mailbox`;\n }\n\n private get hqPublisher(): HqPublisher | undefined {\n return typeof this._hqPublisher === 'function' ? this._hqPublisher() : this._hqPublisher;\n }\n\n private publishHqMailboxEvent(input: Parameters<HqPublisher['publishMailboxEvent']>[0]): void {\n try {\n this.hqPublisher?.publishMailboxEvent(input);\n } catch {\n // HQ telemetry is best-effort and must never affect mailbox behavior.\n }\n }\n\n private publishHqMailboxSnapshot(): void {\n const publisher = this.hqPublisher;\n if (publisher === undefined) return;\n void publisher.publishMailboxSnapshot(this, { mailboxId: this.hqMailboxId }).catch(() => {\n // HQ telemetry is best-effort and must never affect mailbox behavior.\n });\n }\n\n // \u2500\u2500 Messages \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async send(input: MailboxSendInput): Promise<MailboxMessage> {\n const now = new Date().toISOString();\n const msg: MailboxMessage = {\n id: randomUUID(),\n from: input.from,\n // \"all\" is an accepted spelling of the broadcast address \u2014 canonical\n // form on disk is '*' so every query/checker matches it.\n to: normalizeRecipient(input.to),\n type: normalizeMailboxMessageType(input.type),\n subject: input.subject,\n body: input.body,\n priority: input.priority ?? 'normal',\n readBy: {},\n completed: false,\n timestamp: now,\n replyTo: input.replyTo,\n taskContext: input.taskContext,\n expiresAt:\n input.ttlMs !== undefined ? new Date(Date.now() + input.ttlMs).toISOString() : undefined,\n };\n\n const line = JSON.stringify(msg) + LINE_SEPARATOR;\n await fsp.mkdir(path.dirname(this.messagePath), { recursive: true });\n // The append must hold the same lock ack() rewrites under: an unlocked\n // append racing ack's read\u2192rewrite gets silently erased when the rewrite\n // lands. This file is shared ACROSS PROCESSES, so the window is real.\n await withFileLock(this.messagePath, async () => {\n await fsp.appendFile(this.messagePath, line, 'utf8');\n // Capture the post-append stat INSIDE the lock so the cache trackers\n // advance with the pushed content. A concurrent reader that lands\n // after we release but before a future stat would otherwise see the\n // file grew and re-append the just-sent tail, duplicating it.\n const { mtimeMs, size } = await this._statMessageFile();\n // Refresh the in-memory cache from the message we just appended \u2014\n // cheaper than re-reading the whole file, and correct because we\n // held the lock so nothing else changed underneath us.\n this._pushToCache(msg, mtimeMs, size);\n });\n\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'message.sent',\n message: msg,\n });\n this.publishHqMailboxSnapshot();\n\n // In-process push notification: same-process mailbox consumers (the\n // awareness poller, fleet pulse, TUI/WebUI) can listen on this event\n // to get real-time updates instead of polling on every iteration.\n this._events?.emitCustom('mailbox.message_sent', {\n messageId: msg.id,\n from: msg.from,\n to: msg.to,\n type: msg.type,\n subject: msg.subject,\n });\n // SSE push for external HTTP bridge clients.\n this.eventEmitter?.emit({\n type: 'message.sent' as const,\n messageId: msg.id,\n from: msg.from,\n to: msg.to,\n timestamp: now,\n });\n\n return msg;\n }\n\n async query(q: MailboxQuery): Promise<MailboxMessage[]> {\n const queryType = q.type === undefined ? undefined : normalizeMailboxMessageType(q.type);\n const all = await this._readMessagesCached();\n const limit = q.limit ?? 50;\n\n // Single-pass filter \u2014 previously 7 chained .filter() allocations each\n // producing a fresh array. Predicates are independent, so we can AND\n // them in one walk and short-circuit per element.\n const order = q.minPriority !== undefined ? ({ low: 0, normal: 1, high: 2 } as const) : null;\n const minPriorityRank = order && q.minPriority !== undefined ? order[q.minPriority] : 0;\n const out: MailboxMessage[] = [];\n\n // Recipient index fast-path: when the query filters by `to` AND no\n // other broad filter (from, type, etc.) would benefit from the index,\n // iterate only the messages addressed to the target recipient (plus\n // broadcasts `*`) instead of scanning the full cache. Falls back to\n // the full scan when the index is unavailable or when multiple\n // non-recipient filters are present (the index doesn't help there).\n //\n // Sender index fast-path: symmetric \u2014 when filtering ONLY by `from`\n // (no `to`, `type`, `minPriority`), iterate only messages from that\n // sender.\n let candidates: Iterable<MailboxMessage>;\n if (\n q.to !== undefined &&\n this._recipientIndex !== null &&\n q.from === undefined &&\n q.type === undefined &&\n q.minPriority === undefined\n ) {\n // Collect candidate indices: messages addressed to `q.to` + broadcasts.\n const indices = new Set<number>();\n const direct = this._recipientIndex.get(q.to);\n if (direct !== undefined) for (const i of direct) indices.add(i);\n const broadcasts = this._recipientIndex.get('*');\n if (broadcasts !== undefined) for (const i of broadcasts) indices.add(i);\n candidates = [...indices].sort((a, b) => a - b).map((i) => all[i]!);\n } else if (\n q.from !== undefined &&\n q.to === undefined &&\n this._senderIndex !== null &&\n q.type === undefined &&\n q.minPriority === undefined\n ) {\n // Sender index fast-path: iterate only messages from `q.from`.\n const indices = this._senderIndex.get(q.from);\n candidates =\n indices !== undefined ? [...indices].sort((a, b) => a - b).map((i) => all[i]!) : [];\n } else {\n candidates = all;\n }\n\n for (const m of candidates) {\n if (q.to !== undefined && m.to !== q.to && m.to !== '*') continue;\n if (q.from !== undefined && m.from !== q.from) continue;\n if (q.unreadBy !== undefined && q.unreadBy in m.readBy) continue;\n if (q.incompleteOnly && m.completed) continue;\n if (queryType !== undefined && m.type !== queryType) continue;\n if (order !== null && (order[m.priority as keyof typeof order] ?? 1) < minPriorityRank!) {\n continue;\n }\n if (q.since !== undefined && m.timestamp <= q.since) continue;\n // Default behavior: soft-deleted messages are hidden unless the\n // caller explicitly opts in via `includeDeleted: true` (used by\n // the WebUI's \"trash\" view).\n if (!q.includeDeleted && m.deletedAt !== undefined) continue;\n out.push(m);\n }\n\n out.sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n // Return defensive shallow copies so callers cannot mutate the shared\n // cache entries. Only the returned slice is copied \u2014 O(limit), not O(N).\n return out.slice(0, limit).map((m) => ({ ...m, readBy: { ...m.readBy } }));\n }\n\n async ack(input: MailboxAckInput): Promise<MailboxMessage | null> {\n const updated = await this.ackMany({ acks: [input] });\n return updated.length > 0 ? updated[0]! : null;\n }\n\n /** Diagnostic counters exposed for test/tool introspection. */\n readonly diag = {\n ackManyCacheDesync: 0,\n ackManyPreLockMtime: 0,\n ackManyPostLockMtime: 0,\n ackManyPreLockSize: 0,\n ackManyPostLockSize: 0,\n ackManyMessageCount: 0,\n ackManyAckCount: 0,\n cacheHitCount: 0,\n cacheMissCount: 0,\n cacheDesyncNoOp: 0,\n applyAckTargetMissing: 0,\n setMessageCacheCount: 0,\n pushToCacheCount: 0,\n };\n\n async ackMany(input: MailboxAckBatchInput): Promise<MailboxMessage[]> {\n // Append-only ack: instead of reading all messages, mutating them,\n // and rewriting the entire file (O(N) read + O(N) write), we append\n // small ack records (O(K) append where K = number of acks). At read\n // time, ack records are folded into their target messages.\n //\n // This is the #1 performance fix: every agent iteration calls ackMany\n // on the mailbox-loop hot path. Previously it was O(N) per iteration.\n if (input.acks.length === 0) return [];\n\n const now = new Date().toISOString();\n const ackRecords: AckRecord[] = [];\n const updated: MailboxMessage[] = [];\n const targetIds = new Set<string>();\n const byId = new Map<string, MailboxAckInput>();\n\n for (const a of input.acks) {\n byId.set(a.messageId, a);\n targetIds.add(a.messageId);\n }\n\n // \u2500\u2500 Pre-lock snapshot for cross-process desync detection \u2500\u2500\n const preLockMtime = this._messageCacheMtime;\n const preLockSize = this._messageCacheSize;\n this.diag.ackManyPreLockMtime = preLockMtime;\n this.diag.ackManyPreLockSize = preLockSize;\n\n // Build ack records and find target messages.\n // We need to find messages to return them; use cached view for speed.\n const all = await this._readMessagesCached();\n for (const msg of all) {\n const a = byId.get(msg.id);\n if (!a) continue;\n\n // Determine what this ack actually changes to avoid no-op appends.\n const needsRead = a.read !== false && !(a.readerId in msg.readBy);\n const needsComplete = a.completed && !msg.completed;\n const needsOutcome = a.outcome !== undefined && msg.outcome !== a.outcome;\n\n if (!needsRead && !needsComplete && !needsOutcome) {\n // No-op ack \u2014 return the pre-ack state (defensive copy matches\n // the original semantics: re-acking an already-read message\n // returns the message as it was).\n updated.push({ ...msg, readBy: { ...msg.readBy } });\n continue;\n }\n\n // Apply changes to a defensive copy for the return value.\n const copy = { ...msg, readBy: { ...msg.readBy } };\n if (needsRead) copy.readBy[a.readerId] = now;\n if (needsComplete) {\n copy.completed = true;\n copy.completedBy = a.readerId;\n copy.completedAt = now;\n }\n if (needsOutcome) copy.outcome = a.outcome;\n updated.push(copy);\n\n ackRecords.push({\n __ack: true,\n messageId: msg.id,\n readerId: a.readerId,\n timestamp: now,\n read: a.read !== false,\n completed: a.completed,\n completedBy: a.completed ? a.readerId : undefined,\n outcome: a.outcome,\n });\n }\n\n if (ackRecords.length === 0) {\n // All requested acks were no-ops (already read/completed).\n // Still return the messages that were found (updated may be empty if\n // none matched, which preserves prior silent-skip semantics).\n if (updated.length > 0) {\n for (const message of updated) {\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: message.completed ? 'message.completed' : 'message.read',\n message,\n });\n }\n }\n return updated;\n }\n\n // Append ack records to the file under the lock.\n const serialized = ackRecords.map((a) => serializeAckRecord(a)).join('');\n await withFileLock(this.messagePath, async () => {\n await fsp.appendFile(this.messagePath, serialized, 'utf8');\n // Capture the post-append stat inside the lock.\n const { mtimeMs, size } = await this._statMessageFile();\n // Apply ack effects directly to the in-memory cache.\n for (const ack of ackRecords) {\n this._applyAckToCache(ack);\n }\n // Advance cache trackers so the next read sees current size.\n this._messageCacheMtime = mtimeMs;\n this._messageCacheSize = size;\n\n // \u2500\u2500 Post-lock diagnostics \u2500\u2500\n this.diag.ackManyPostLockMtime = mtimeMs;\n this.diag.ackManyPostLockSize = size;\n this.diag.ackManyMessageCount = this._messageCache?.length ?? -1;\n this.diag.ackManyAckCount = ackRecords.length;\n\n // DETECT: cross-process cache desync\n // If the post-append stat jumped ahead more than our serialized ack\n // bytes alone, another process appended data between our cache read\n // and lock acquisition. The cache would then be missing those messages.\n const expectedMinSize = preLockSize + serialized.length;\n if (preLockSize > 0 && size > expectedMinSize) {\n const extraBytes = size - expectedMinSize;\n console.error(\n `[MAILBOX-DIAG] ackMany: post-lock size ${size} exceeds expected ${expectedMinSize} by ${extraBytes}B (mtime ${preLockMtime}->${mtimeMs}). ` +\n `Cache may be missing cross-process messages. diag.ackManyCacheDesync=${++this.diag.ackManyCacheDesync}`,\n );\n }\n });\n\n for (const message of updated) {\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: message.completed ? 'message.completed' : 'message.read',\n message,\n });\n this.eventEmitter?.emit({\n type: 'message.acked' as const,\n messageId: message.id,\n from: message.from,\n to: message.to,\n timestamp: new Date().toISOString(),\n });\n }\n if (updated.length > 0) this.publishHqMailboxSnapshot();\n return updated;\n }\n\n async unreadCount(forAgentId: string): Promise<number> {\n const all = await this._readMessagesCached();\n let count = 0;\n\n // Recipient index fast-path: iterate only messages addressed to this\n // agent + broadcasts, instead of the full cache.\n if (this._recipientIndex !== null) {\n const indices = new Set<number>();\n const direct = this._recipientIndex.get(forAgentId);\n if (direct !== undefined) for (const i of direct) indices.add(i);\n const broadcasts = this._recipientIndex.get('*');\n if (broadcasts !== undefined) for (const i of broadcasts) indices.add(i);\n for (const i of indices) {\n const m = all[i]!;\n if (!(forAgentId in m.readBy) && !m.completed) count++;\n }\n } else {\n for (let i = 0; i < all.length; i++) {\n const m = all[i]!;\n if ((m.to === forAgentId || m.to === '*') && !(forAgentId in m.readBy) && !m.completed) {\n count++;\n }\n }\n }\n return count;\n }\n\n async softDelete(mailId: string, by: string): Promise<MailboxMessage | null> {\n // Append-only soft-delete: instead of reading all messages, mutating\n // one, and rewriting the entire file, we append a single ack record\n // with `deleted: true`. At read time, the delete is applied to the\n // target message via _parseLines / applyAckToMessage.\n // No-op when the message is already soft-deleted.\n\n const all = await this._readMessagesCached();\n const target = all.find((m) => m.id === mailId);\n if (target === undefined) return null;\n if (target.deletedAt !== undefined) {\n return { ...target, readBy: { ...target.readBy } };\n }\n\n const now = new Date().toISOString();\n const ack: AckRecord = {\n __ack: true,\n messageId: mailId,\n readerId: by,\n timestamp: now,\n read: true,\n deleted: true,\n deletedBy: by,\n };\n\n await withFileLock(this.messagePath, async () => {\n await fsp.appendFile(this.messagePath, serializeAckRecord(ack), 'utf8');\n const { mtimeMs, size } = await this._statMessageFile();\n this._applyAckToCache(ack);\n this._messageCacheMtime = mtimeMs;\n this._messageCacheSize = size;\n });\n\n const msg = { ...target, readBy: { ...target.readBy } };\n msg.deletedAt = now;\n msg.deletedBy = by;\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'message.updated',\n message: msg,\n });\n this.publishHqMailboxSnapshot();\n this.eventEmitter?.emit({\n type: 'message.deleted' as const,\n messageId: msg.id,\n from: msg.from,\n to: msg.to,\n timestamp: msg.deletedAt ?? now,\n });\n return msg;\n }\n\n async restore(mailId: string): Promise<MailboxMessage | null> {\n // Append-only restore (inverse of append-only softDelete). Same\n // pattern: put a `deleted: false` ack record on disk, apply it to\n // the cache. No-op when the message is not currently soft-deleted.\n\n const all = await this._readMessagesCached();\n const target = all.find((m) => m.id === mailId);\n if (target === undefined) return null;\n if (target.deletedAt === undefined && target.deletedBy === undefined) {\n return { ...target, readBy: { ...target.readBy } };\n }\n\n const now = new Date().toISOString();\n const ack: AckRecord = {\n __ack: true,\n messageId: mailId,\n readerId: '',\n timestamp: now,\n read: true,\n deleted: false,\n };\n\n await withFileLock(this.messagePath, async () => {\n await fsp.appendFile(this.messagePath, serializeAckRecord(ack), 'utf8');\n const { mtimeMs, size } = await this._statMessageFile();\n this._applyAckToCache(ack);\n this._messageCacheMtime = mtimeMs;\n this._messageCacheSize = size;\n });\n\n const msg = { ...target, readBy: { ...target.readBy } };\n delete msg.deletedAt;\n delete msg.deletedBy;\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'message.updated',\n message: msg,\n });\n this.publishHqMailboxSnapshot();\n this.eventEmitter?.emit({\n type: 'message.restored' as const,\n messageId: msg.id,\n from: msg.from,\n to: msg.to,\n timestamp: now,\n });\n return msg;\n }\n\n // \u2500\u2500 Agent registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async registerAgent(input: AgentRegistrationInput): Promise<void> {\n await this._ensureRegistry();\n const now = new Date().toISOString();\n const agent: RegisteredAgent = {\n agentId: input.agentId,\n sessionId: input.sessionId,\n name: input.name,\n role: input.role,\n status: 'idle',\n currentTool: undefined,\n currentTask: undefined,\n iterations: 0,\n toolCalls: 0,\n registeredAt: now,\n lastSeenAt: now,\n pid: input.pid,\n source: input.source,\n };\n\n await withFileLock(this.registryPath, async () => {\n // fresh: read-modify-write must start from the on-disk state, not the\n // cache \u2014 other processes may have registered agents since.\n const registry = await this._readRegistry({ fresh: true });\n // Prune stale agents\n this._pruneStaleInPlace(registry);\n // Upsert\n registry.set(input.agentId, agent);\n // Update cache\n this._registryCache = registry;\n this._registryCacheAt = Date.now();\n await this._writeRegistry(registry);\n });\n\n // Emit event for TUI/WebUI to update online agent count\n this._events?.emitCustom('mailbox.agent_registered', {\n agentId: input.agentId,\n sessionId: input.sessionId,\n name: input.name,\n role: input.role,\n source: input.source,\n });\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'agent.registered',\n agent: {\n agentId: input.agentId,\n name: input.name,\n ...(input.role !== undefined ? { role: input.role } : {}),\n sessionId: input.sessionId,\n status: 'idle',\n iterations: 0,\n toolCalls: 0,\n lastActivityAt: now,\n lastSeenAt: now,\n online: true,\n pid: input.pid,\n ...(input.source !== undefined ? { source: input.source } : {}),\n },\n });\n this.publishHqMailboxSnapshot();\n }\n\n async deregisterAgent(agentId: string): Promise<void> {\n await this._ensureRegistry();\n let removed: RegisteredAgent | undefined;\n await withFileLock(this.registryPath, async () => {\n const registry = await this._readRegistry({ fresh: true });\n this._pruneStaleInPlace(registry);\n // Capture the record before deletion so HQ telemetry can emit a full,\n // well-typed agent summary rather than a bare id.\n removed = registry.get(agentId);\n registry.delete(agentId);\n this._registryCache = registry;\n this._registryCacheAt = Date.now();\n await this._writeRegistry(registry);\n });\n this._events?.emitCustom('mailbox.agent_deregistered', {\n agentId,\n });\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'agent.deregistered',\n agent: {\n agentId,\n name: removed?.name ?? agentId,\n ...(removed?.role !== undefined ? { role: removed.role } : {}),\n sessionId: removed?.sessionId ?? '',\n status: 'offline',\n ...(removed?.currentTool !== undefined ? { currentTool: removed.currentTool } : {}),\n ...(removed?.currentTask !== undefined ? { currentTask: removed.currentTask } : {}),\n iterations: removed?.iterations ?? 0,\n toolCalls: removed?.toolCalls ?? 0,\n lastActivityAt: removed?.lastSeenAt ?? new Date().toISOString(),\n lastSeenAt: removed?.lastSeenAt ?? new Date().toISOString(),\n online: false,\n pid: removed?.pid ?? 0,\n ...(removed?.source !== undefined ? { source: removed.source } : {}),\n },\n });\n this.publishHqMailboxSnapshot();\n }\n\n async heartbeat(input: AgentHeartbeatInput): Promise<void> {\n // Throttle: at most one heartbeat per agent per HEARTBEAT_THROTTLE_MS\n const last = this._lastHeartbeat.get(input.agentId) ?? 0;\n const now = Date.now();\n if (now - last < HEARTBEAT_THROTTLE_MS) return;\n\n this._lastHeartbeat.set(input.agentId, now);\n\n await this._ensureRegistry();\n\n await withFileLock(this.registryPath, async () => {\n // fresh: see registerAgent \u2014 never read-modify-write from the cache.\n const registry = await this._readRegistry({ fresh: true });\n this._pruneStaleInPlace(registry);\n\n const agent = registry.get(input.agentId);\n if (agent) {\n const iso = new Date().toISOString();\n agent.lastSeenAt = iso;\n if (input.status !== undefined) agent.status = input.status;\n if (input.currentTool !== undefined) agent.currentTool = input.currentTool;\n if (input.currentTask !== undefined) agent.currentTask = input.currentTask;\n if (input.iterations !== undefined) agent.iterations = input.iterations;\n if (input.toolCalls !== undefined) agent.toolCalls = input.toolCalls;\n }\n // If agent not registered yet, silently skip \u2014 registerAgent first\n\n this._registryCache = registry;\n this._registryCacheAt = Date.now();\n await this._writeRegistry(registry);\n });\n\n // Emit event so TUI/WebUI can track online agents in real time\n this._events?.emitCustom('mailbox.agent_heartbeat', {\n agentId: input.agentId,\n status: input.status,\n currentTool: input.currentTool,\n currentTask: input.currentTask,\n });\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'agent.heartbeat',\n summary: input.agentId,\n });\n this.publishHqMailboxSnapshot();\n }\n\n async getAgentStatuses(): Promise<MailboxAgentStatus[]> {\n await this._ensureRegistry();\n let registry = await this._readRegistry();\n const before = registry.size;\n this._pruneStaleInPlace(registry);\n\n // A read can be the only activity after every process in a project exits.\n // Persist expiry under the file lock so old agents do not survive forever\n // in `_mailbox.registry.json` (or race a concurrent registration).\n if (registry.size < before) {\n await withFileLock(this.registryPath, async () => {\n const fresh = await this._readRegistry({ fresh: true });\n this._pruneStaleInPlace(fresh);\n this._registryCache = fresh;\n this._registryCacheAt = Date.now();\n await this._writeRegistry(fresh);\n registry = fresh;\n });\n }\n\n const now = Date.now();\n return Array.from(registry.values())\n .map((a) => ({\n agentId: a.agentId,\n name: a.name,\n role: a.role,\n sessionId: a.sessionId,\n status: a.status,\n currentTool: a.currentTool,\n currentTask: a.currentTask,\n iterations: a.iterations,\n toolCalls: a.toolCalls,\n lastActivityAt: a.lastSeenAt,\n lastSeenAt: a.lastSeenAt,\n online: now - new Date(a.lastSeenAt).getTime() < AGENT_STALE_MS,\n pid: a.pid,\n source: a.source,\n }))\n .sort((a, b) => b.lastSeenAt.localeCompare(a.lastSeenAt));\n }\n\n async getOnlineAgents(): Promise<MailboxAgentStatus[]> {\n const all = await this.getAgentStatuses();\n return all.filter((a) => a.online);\n }\n\n // \u2500\u2500 Client registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async registerClient(input: ClientRegistrationInput): Promise<void> {\n await this._ensureClientRegistry();\n const now = new Date().toISOString();\n const client: RegisteredClient = {\n clientId: input.clientId,\n sessionId: input.sessionId,\n name: input.name,\n source: input.source,\n registeredAt: now,\n lastSeenAt: now,\n pid: input.pid,\n };\n\n await withFileLock(this.clientRegistryPath, async () => {\n const registry = await this._readClientRegistry({ fresh: true });\n this._pruneStaleClientsInPlace(registry);\n registry.set(input.clientId, client);\n this._clientRegistryCache = registry;\n this._clientRegistryCacheAt = Date.now();\n await this._writeClientRegistry(registry);\n });\n\n // Emit event for TUI/WebUI to update online client count\n this._events?.emitCustom('mailbox.client_registered', {\n clientId: input.clientId,\n sessionId: input.sessionId,\n name: input.name,\n source: input.source,\n });\n this.publishHqMailboxSnapshot();\n }\n\n async deregisterClient(clientId: string): Promise<void> {\n await this._ensureClientRegistry();\n await withFileLock(this.clientRegistryPath, async () => {\n const registry = await this._readClientRegistry({ fresh: true });\n this._pruneStaleClientsInPlace(registry);\n registry.delete(clientId);\n this._clientRegistryCache = registry;\n this._clientRegistryCacheAt = Date.now();\n await this._writeClientRegistry(registry);\n });\n this._lastClientHeartbeat.delete(clientId);\n this._events?.emitCustom('mailbox.client_deregistered', { clientId });\n this.publishHqMailboxSnapshot();\n }\n\n async clientHeartbeat(input: ClientHeartbeatInput): Promise<void> {\n // Throttle: at most one heartbeat per client per HEARTBEAT_THROTTLE_MS\n const last = this._lastClientHeartbeat.get(input.clientId) ?? 0;\n const now = Date.now();\n if (now - last < HEARTBEAT_THROTTLE_MS) return;\n\n this._lastClientHeartbeat.set(input.clientId, now);\n\n await this._ensureClientRegistry();\n\n await withFileLock(this.clientRegistryPath, async () => {\n const registry = await this._readClientRegistry({ fresh: true });\n this._pruneStaleClientsInPlace(registry);\n\n const client = registry.get(input.clientId);\n if (client) {\n client.lastSeenAt = new Date().toISOString();\n if (typeof input.sessionId === 'string' && input.sessionId.length > 0) {\n client.sessionId = input.sessionId;\n }\n }\n\n this._clientRegistryCache = registry;\n this._clientRegistryCacheAt = Date.now();\n await this._writeClientRegistry(registry);\n });\n\n // Emit event so TUI/WebUI can track online clients in real time\n this._events?.emitCustom('mailbox.client_heartbeat', {\n clientId: input.clientId,\n ...(input.sessionId ? { sessionId: input.sessionId } : {}),\n });\n this.publishHqMailboxSnapshot();\n }\n\n async getClientStatuses(): Promise<ClientStatus[]> {\n await this._ensureClientRegistry();\n let registry = await this._readClientRegistry();\n const before = registry.size;\n this._pruneStaleClientsInPlace(registry);\n\n // Persist the pruning so stale entries in _mailbox.clients.json don't\n // accumulate indefinitely. Without this, `getClientStatuses` prunes in\n // memory only \u2014 the stale JSON records survive on disk until another\n // write happens (registerClient / clientHeartbeat), which may never\n // occur if all bridge clients are dead.\n //\n // Lock around the read-prune-write to prevent racing concurrent\n // registerClient / clientHeartbeat / deregisterClient calls, all of\n // which also acquire this lock.\n if (registry.size < before) {\n await withFileLock(this.clientRegistryPath, async () => {\n // Re-read under the lock so a concurrent write since our\n // initial read is not overwritten.\n registry = await this._readClientRegistry({ fresh: true });\n const postLockBefore = registry.size;\n this._pruneStaleClientsInPlace(registry);\n if (registry.size < postLockBefore) {\n await this._writeClientRegistry(registry);\n }\n });\n }\n\n const now = Date.now();\n return Array.from(registry.values())\n .map((c) => ({\n clientId: c.clientId,\n name: c.name,\n source: c.source,\n sessionId: c.sessionId,\n lastSeenAt: c.lastSeenAt,\n online: now - new Date(c.lastSeenAt).getTime() < CLIENT_STALE_MS,\n pid: c.pid,\n }))\n .sort((a, b) => b.lastSeenAt.localeCompare(a.lastSeenAt));\n }\n\n /**\n * Explicitly purge stale clients from the registry and write back to disk.\n * Removes client entries whose lastSeenAt is older than CLIENT_STALE_MS.\n * Returns the number of entries purged.\n *\n * Idempotent \u2014 safe to call regularly. The same pruning runs implicitly\n * inside registerClient, clientHeartbeat, and getClientStatuses, but if\n * no client registers or heartbeats for a long time, this public method\n * ensures the file gets cleaned up on demand.\n */\n async purgeClients(): Promise<number> {\n await this._ensureClientRegistry();\n let purged = 0;\n await withFileLock(this.clientRegistryPath, async () => {\n const registry = await this._readClientRegistry({ fresh: true });\n const before = registry.size;\n this._pruneStaleClientsInPlace(registry);\n purged = before - registry.size;\n if (purged > 0) {\n this._clientRegistryCache = registry;\n this._clientRegistryCacheAt = Date.now();\n await this._writeClientRegistry(registry);\n }\n });\n return purged;\n }\n\n // \u2500\u2500 Lifecycle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async close(): Promise<void> {\n // JSONL append-only \u2014 no flush needed\n this._registryCache = null;\n this._clientRegistryCache = null;\n this._messageCache = null;\n this._messageCacheMtime = -1;\n this._messageCacheSize = -1;\n this._recipientIndex = null;\n this._senderIndex = null;\n }\n\n async clearAll(): Promise<void> {\n // Truncate the mailbox file and promote the empty cache under the same\n // lock, with the post-truncate stat captured synchronously so a\n // concurrent reader doesn't misclassify the shrink as a \"file only\n // grew\" append.\n await withFileLock(this.messagePath, async () => {\n await fsp.writeFile(this.messagePath, '', 'utf8');\n const { mtimeMs, size } = await this._statMessageFile();\n this._setMessageCache([], mtimeMs, size);\n });\n }\n\n async purgeStale(opts?: PurgeOptions): Promise<PurgeResult> {\n const COMPLETED_MAX_AGE_MS = opts?.completedMaxAgeMs ?? 86_400_000; // 1 day\n const INCOMPLETE_MAX_AGE_MS = opts?.incompleteMaxAgeMs ?? 604_800_000; // 7 days\n\n let completedPurged = 0;\n let incompletePurged = 0;\n let remaining = 0;\n\n // Read-modify-write under the lock \u2014 same pattern as ack().\n await withFileLock(this.messagePath, async () => {\n const all = await this._readMessagesFresh();\n const now = Date.now();\n const cutoffCompleted = now - COMPLETED_MAX_AGE_MS;\n const cutoffIncomplete = now - INCOMPLETE_MAX_AGE_MS;\n\n const kept: MailboxMessage[] = [];\n\n for (const msg of all) {\n const msgTime = new Date(msg.timestamp).getTime();\n const completedTime = msg.completedAt ? new Date(msg.completedAt).getTime() : 0;\n\n if (msg.completed && completedTime < cutoffCompleted) {\n completedPurged++;\n continue; // drop\n }\n if (!msg.completed && msgTime < cutoffIncomplete) {\n incompletePurged++;\n continue; // drop\n }\n\n kept.push(msg);\n }\n remaining = kept.length;\n\n // Rewrite only if something changed\n if (kept.length < all.length) {\n const content = kept.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;\n await fsp.writeFile(this.messagePath, content, 'utf8');\n }\n // Capture the post-write (or post-read when nothing purged) stat\n // inside the lock so the cache trackers match the on-disk state.\n const { mtimeMs, size } = await this._statMessageFile();\n // Either way we just read fresh under the lock, so adopt the kept\n // snapshot (== all when nothing was purged) as the cache.\n this._setMessageCache(kept, mtimeMs, size);\n });\n\n return {\n completedPurged,\n incompletePurged,\n totalPurged: completedPurged + incompletePurged,\n remaining,\n };\n }\n\n // \u2500\u2500 Auto-compaction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _autoCompactTimer: NodeJS.Timeout | null = null;\n\n async autoCompact(opts?: AutoCompactOptions): Promise<AutoCompactResult> {\n const readMaxAgeMs = opts?.readMaxAgeMs ?? AUTO_COMPACT_READ_MAX_AGE_MS;\n const defaultTtlMs = opts?.defaultTtlMs ?? AUTO_COMPACT_DEFAULT_TTL_MS;\n const completedMaxAgeMs = opts?.completedMaxAgeMs ?? 86_400_000; // 1 day\n const incompleteMaxAgeMs = opts?.incompleteMaxAgeMs ?? 604_800_000; // 7 days\n\n let expiredPurged = 0;\n let readByAllPurged = 0;\n let completedPurged = 0;\n let incompletePurged = 0;\n let remaining = 0;\n\n // Resolve the set of currently-online agent ids so we can check\n // \"has every online agent read this?\" without a second file read.\n // Online set is advisory \u2014 if the registry is temporarily empty we\n // skip the read-by-all pass rather than purging everything.\n let onlineAgentIds: Set<string> | null = null;\n try {\n const statuses = await this.getAgentStatuses();\n const online = statuses.filter((s) => s.online);\n onlineAgentIds = online.length > 0 ? new Set(online.map((s) => s.agentId)) : null;\n } catch {\n onlineAgentIds = null;\n }\n\n await withFileLock(this.messagePath, async () => {\n const all = await this._readMessagesFresh();\n const now = Date.now();\n const cutoffReadAge = now - readMaxAgeMs;\n const cutoffCompleted = now - completedMaxAgeMs;\n const cutoffIncomplete = now - incompleteMaxAgeMs;\n const cutoffDefaultTtl = now - defaultTtlMs;\n\n const kept: MailboxMessage[] = [];\n\n for (const msg of all) {\n const msgTime = new Date(msg.timestamp).getTime();\n\n // Pass 1: Explicit expiry.\n if (msg.expiresAt !== undefined) {\n if (new Date(msg.expiresAt).getTime() < now) {\n expiredPurged++;\n continue;\n }\n } else if (msgTime < cutoffDefaultTtl) {\n // No explicit expiry; use default TTL from send time.\n expiredPurged++;\n continue;\n }\n\n // Pass 2: Read by ALL currently-online agents.\n if (onlineAgentIds !== null && !msg.completed) {\n const readByAll =\n onlineAgentIds.size > 0 && [...onlineAgentIds].every((id) => id in msg.readBy);\n if (readByAll) {\n // Check age of the most recent read receipt.\n const readTimes = Object.values(msg.readBy).map((t) => new Date(t).getTime());\n const latestRead = Math.max(...readTimes);\n if (latestRead < cutoffReadAge) {\n readByAllPurged++;\n continue;\n }\n }\n }\n\n // Pass 3: Standard purge-stale logic.\n const completedTime = msg.completedAt ? new Date(msg.completedAt).getTime() : 0;\n if (msg.completed && completedTime < cutoffCompleted) {\n completedPurged++;\n continue;\n }\n if (!msg.completed && msgTime < cutoffIncomplete) {\n incompletePurged++;\n continue;\n }\n\n kept.push(msg);\n }\n remaining = kept.length;\n\n if (kept.length < all.length) {\n const content = kept.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;\n await fsp.writeFile(this.messagePath, content, 'utf8');\n }\n const { mtimeMs, size } = await this._statMessageFile();\n this._setMessageCache(kept, mtimeMs, size);\n });\n\n const totalRemoved = expiredPurged + readByAllPurged + completedPurged + incompletePurged;\n return {\n expiredRemoved: expiredPurged,\n readByAllRemoved: readByAllPurged,\n stalePurged: completedPurged + incompletePurged,\n totalRemoved,\n remaining,\n };\n }\n\n startAutoCompactTimer(opts?: AutoCompactOptions): () => void {\n // Replace any prior timer.\n if (this._autoCompactTimer !== null) {\n clearInterval(this._autoCompactTimer);\n }\n const intervalMs = opts?.intervalMs ?? AUTO_COMPACT_INTERVAL_MS;\n const timer = setInterval(() => {\n this.autoCompact(opts).catch(() => {\n // Best-effort \u2014 background compaction must never crash the process.\n });\n }, intervalMs);\n timer.unref?.();\n this._autoCompactTimer = timer;\n return () => {\n clearInterval(timer);\n this._autoCompactTimer = null;\n };\n }\n\n // \u2500\u2500 Internal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Read all messages from the JSONL file. Always reads + parses the file.\n * Callers that can tolerate a stale-by-mtime view should use\n * {@link _readMessagesCached}; writers that need the post-lock truth\n * should call this directly (it's what {@link _readMessagesFresh} aliases).\n */\n private async _readMessages(): Promise<MailboxMessage[]> {\n try {\n const raw = await fsp.readFile(this.messagePath, 'utf8');\n return this._parseLines(raw);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw err;\n }\n }\n\n /** Parse a JSONL string into MailboxMessage[], applying ack records. */\n private _parseLines(raw: string): MailboxMessage[] {\n const lines = raw.split(LINE_SEPARATOR).filter((l) => l.trim().length > 0);\n const messages: MailboxMessage[] = [];\n const acks: AckRecord[] = [];\n for (const line of lines) {\n const parsed = parseMailboxLine(line);\n if (isAckRecord(parsed)) {\n acks.push(parsed);\n } else if (parsed !== null) {\n messages.push(parsed);\n }\n }\n // Apply ack records to messages (event-sourcing fold).\n for (const ack of acks) {\n const target = messages.find((m) => m.id === ack.messageId);\n if (target) applyAckToMessage(target, ack);\n }\n return messages;\n }\n\n /**\n * Read messages, then adopt the result as the in-memory cache. Use this\n * from writers that just took the file lock \u2014 the read reflects the\n * authoritative post-lock state and should be served to subsequent\n * queries without re-reading.\n *\n * The mtime/size are captured from the stat at read time so the cache\n * trackers match exactly what was parsed. Writers that subsequently\n * rewrite the file MUST re-stat after the write and re-promote with the\n * post-write values (see ackMany / softDelete / restore / purgeStale /\n * clearAll) \u2014 otherwise a concurrent reader misclassifies the rewrite\n * as a \"file only grew\" append and corrupts the cache.\n */\n private async _readMessagesFresh(): Promise<MailboxMessage[]> {\n const all = await this._readMessages();\n const { mtimeMs, size } = await this._statMessageFile();\n this._setMessageCache(all, mtimeMs, size);\n return all;\n }\n\n /**\n * Stat the message file, returning its mtimeMs and size. Returns\n * `-1/-1` when the file does not yet exist (ENOENT) so callers can\n * still promote a cache snapshot \u2014 the next read will re-stat and\n * fall through to a full re-read. Call from inside the file lock so\n * the result reflects the post-write on-disk state, not a later\n * intermediate state from another process.\n */\n private async _statMessageFile(): Promise<{ mtimeMs: number; size: number }> {\n try {\n const st = await fsp.stat(this.messagePath);\n return { mtimeMs: st.mtimeMs, size: st.size };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { mtimeMs: -1, size: -1 };\n }\n throw err;\n }\n }\n\n /**\n * Read messages, consulting the mtime-bounded in-memory cache first,\n * serialized so concurrent callers don't both mutate the cache.\n *\n * The mailbox file is shared across processes; every `send`/`ack`/\n * `clearAll`/`purgeStale` takes the file lock, so writes are serialized\n * and a changed mtimeMs is a definitive freshness signal. When the\n * stat matches the cached mtime+size we return the cached array \u2014 no\n * file read and no JSON.parse \u2014 collapsing the per-iteration query\n * cost on the mailbox-loop hot path.\n *\n * When the file only grew (new messages appended by another process),\n * we read and parse just the tail bytes instead of the entire file.\n * This avoids re-parsing the full 10K-message history on every check.\n *\n * SERIALIZATION: the actual work is chained onto `_readChain` so two\n * overlapping calls can't both pass the `st.size > _messageCacheSize`\n * incremental check against the same stale tracker and each push the\n * same tail bytes onto the cache (duplicating every appended message).\n * Readers don't conflict on file content \u2014 only on the cache mutation\n * that follows the read \u2014 so we run them one at a time in issue order.\n * Errors in the chain are swallowed so a failed read never poisons\n * subsequent reads; each caller observes and re-throws its own error.\n */\n private _readMessagesCached(): Promise<MailboxMessage[]> {\n // Chain this read after the prior one settles. Catch-and-swallow the\n // prior's error so the chain stays alive for this call regardless.\n const run = this._readChain\n .catch(() => undefined as unknown as MailboxMessage[])\n .then(() => this._readMessagesCachedWork());\n this._readChain = run.catch(() => [] as MailboxMessage[]);\n return run;\n }\n\n /**\n * The un-serialized body of {@link _readMessagesCached}. Reads the\n * message file with the mtime-bounded cache + incremental-tail\n * optimization. Must only be called from `_readMessagesCached` so the\n * cache mutations here don't race a sibling read.\n */\n private async _readMessagesCachedWork(): Promise<MailboxMessage[]> {\n try {\n const st = await fsp.stat(this.messagePath);\n\n // Fast path: cache is current \u2014 no disk I/O beyond stat.\n if (\n this._messageCache !== null &&\n this._messageCacheMtime === st.mtimeMs &&\n this._messageCacheSize === st.size\n ) {\n return this._messageCache;\n }\n\n // Full re-read when the cache is stale. With append-only acks, the\n // file grows monotonously (no rewrites except compaction/purge/clear).\n // A simple incremental tail-read optimization could apply here for\n // cross-process scenarios, but the full re-read is correct and in the\n // common case (same-process) the cache stays current via `_pushToCache`\n // and `_applyAckToCache` which update the cache synchronously with\n // every send/ack. The full re-read also correctly handles ack records\n // via _parseLines which folds them into messages.\n\n // Full re-read: cache empty, file was rewritten (ack/purge), or\n // this is the first read.\n const all = await this._readMessages();\n this._setMessageCache(all, st.mtimeMs, st.size);\n return all;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n this._setMessageCache([], -1, -1);\n return [];\n }\n throw err;\n }\n }\n\n /**\n * Replace the in-memory cache, setting the mtime/size trackers\n * synchronously in the same step. Callers MUST pass the stat of the\n * on-disk file state that produced `messages`.\n *\n * Why both are required (not fire-and-forget): `_readMessagesCached()`\n * validates the cache against a fresh stat using these two trackers.\n * If the cache array is updated but the trackers lag behind (e.g. via\n * a deferred `stat().then(...)`), a concurrent reader landing in that\n * window sees a mismatched mtime and falls into the incremental\n * \"file only grew\" branch \u2014 parsing rewritten bytes as an appended\n * tail and corrupting the cache with duplicates/garbage. So both\n * values are captured under the file lock and applied synchronously\n * here, matching the fix already shipped in DefaultMailbox.\n */\n private _setMessageCache(messages: MailboxMessage[], mtime: number, size: number): void {\n // Bound the cache so a runaway mailbox can't balloon memory. The cap\n // is high enough that any realistic project mailbox fits; if it ever\n // exceeds the cap we just refuse to cache and the next read goes to\n // disk (the unoptimized but correct behavior).\n if (messages.length > MESSAGE_CACHE_MAX_ENTRIES) {\n this._messageCache = null;\n this._messageCacheMtime = -1;\n this._messageCacheSize = -1;\n this._recipientIndex = null;\n this._senderIndex = null;\n return;\n }\n this._messageCache = messages;\n this._messageCacheMtime = mtime;\n this._messageCacheSize = size;\n this._rebuildRecipientIndex();\n }\n\n /**\n * Fold a single ack record into the in-memory cache, mutating the target\n * message in place. Called from `ackMany` after appending the record to\n * disk so the cache reflects the ack without a full re-read + re-parse.\n *\n * An ack only touches `readBy`/`completed*`/`outcome` \u2014 none of which\n * affect the recipient/sender indexes \u2014 so no index rebuild is needed.\n * No-op when the cache is empty or the target message isn't cached.\n */\n private _applyAckToCache(ack: AckRecord): void {\n const cache = this._messageCache;\n if (cache === null) return;\n const target = cache.find((m) => m.id === ack.messageId);\n if (target !== undefined) applyAckToMessage(target, ack);\n }\n\n /**\n * Build the recipient AND sender indexes from the current `_messageCache`.\n * Called only from `_setMessageCache` so both indexes are always in sync\n * with a freshly-replaced cache array.\n */\n private _rebuildRecipientIndex(): void {\n const cache = this._messageCache;\n if (cache === null) {\n this._recipientIndex = null;\n this._senderIndex = null;\n return;\n }\n const recIdx = new Map<string, Set<number>>();\n const sndIdx = new Map<string, Set<number>>();\n for (let i = 0; i < cache.length; i++) {\n const msg = cache[i]!;\n let rSet = recIdx.get(msg.to);\n if (rSet === undefined) {\n rSet = new Set();\n recIdx.set(msg.to, rSet);\n }\n rSet.add(i);\n let sSet = sndIdx.get(msg.from);\n if (sSet === undefined) {\n sSet = new Set();\n sndIdx.set(msg.from, sSet);\n }\n sSet.add(i);\n }\n this._recipientIndex = recIdx;\n this._senderIndex = sndIdx;\n }\n\n /**\n * Append a single just-sent message to the in-memory cache without\n * re-reading the file. The caller must hold the file lock (or have\n * just released it after a successful append) and MUST pass the\n * post-append stat so the mtime/size trackers advance in lock-step\n * with the pushed content.\n *\n * Why the stat is required here: without it, `_messageCacheSize`\n * stays at the pre-append value. A concurrent `_readMessagesCached()`\n * then sees `st.size > _messageCacheSize` (the file did grow), takes\n * the incremental branch, and re-reads the just-appended tail \u2014\n * pushing the same message onto the cache a second time. Setting the\n * trackers here closes that window for the local-process append path.\n */\n private _pushToCache(msg: MailboxMessage, mtime: number, size: number): void {\n if (this._messageCache === null) {\n // No cache to extend \u2014 leave trackers at -1 so the next read does\n // a full re-read and rebuilds the cache from disk.\n return;\n }\n if (this._messageCache.length >= MESSAGE_CACHE_MAX_ENTRIES) {\n this._messageCache = null;\n this._messageCacheMtime = -1;\n this._messageCacheSize = -1;\n return;\n }\n // The cache holds shared message objects; we mirror the on-disk line\n // by storing the same reference. Callers of `query()` get defensive\n // copies, so this shared reference is safe.\n this._messageCache.push(msg);\n // Update the recipient index with the new message's position.\n const newIdx = this._messageCache.length - 1;\n if (this._recipientIndex !== null) {\n let set = this._recipientIndex.get(msg.to);\n if (set === undefined) {\n set = new Set();\n this._recipientIndex.set(msg.to, set);\n }\n set.add(newIdx);\n }\n // Update the sender index with the new message's position.\n if (this._senderIndex !== null) {\n let set = this._senderIndex.get(msg.from);\n if (set === undefined) {\n set = new Set();\n this._senderIndex.set(msg.from, set);\n }\n set.add(newIdx);\n }\n // Advance the trackers synchronously with the content push so a\n // concurrent reader does not re-append this same message.\n this._messageCacheMtime = mtime;\n this._messageCacheSize = size;\n }\n\n private async _ensureRegistry(): Promise<void> {\n await fsp.mkdir(path.dirname(this.registryPath), { recursive: true });\n }\n\n private async _readRegistry(opts?: { fresh?: boolean }): Promise<Map<string, RegisteredAgent>> {\n // The registry file is shared across processes. Reads may use a short\n // TTL cache; writers (under the file lock) MUST pass { fresh: true } \u2014\n // a read-modify-write from a stale cache would silently erase agents\n // registered by other sessions.\n if (\n !opts?.fresh &&\n this._registryCache &&\n Date.now() - this._registryCacheAt < REGISTRY_CACHE_TTL_MS\n ) {\n return new Map(this._registryCache);\n }\n\n try {\n const raw = await fsp.readFile(this.registryPath, 'utf8');\n const data = JSON.parse(raw) as Record<string, RegisteredAgent>;\n // Parse lastSeenAt strings back into objects\n const map = new Map<string, RegisteredAgent>();\n for (const [id, agent] of Object.entries(data)) {\n map.set(id, agent as RegisteredAgent);\n }\n this._registryCache = map;\n this._registryCacheAt = Date.now();\n return new Map(map);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const empty = new Map<string, RegisteredAgent>();\n this._registryCache = empty;\n this._registryCacheAt = Date.now();\n return empty;\n }\n throw err;\n }\n }\n\n private _pruneStaleInPlace(registry: Map<string, RegisteredAgent>): void {\n const cutoff = Date.now() - AGENT_STALE_MS;\n for (const [id, agent] of registry) {\n const lastSeen = Date.parse(agent.lastSeenAt);\n // Missing/invalid heartbeat timestamps cannot establish liveness. Remove\n // them alongside expired entries instead of making malformed ghosts\n // immortal through NaN comparisons.\n if (!Number.isFinite(lastSeen) || lastSeen < cutoff) {\n registry.delete(id);\n }\n }\n }\n\n private async _writeRegistry(registry: Map<string, RegisteredAgent>): Promise<void> {\n const obj: Record<string, RegisteredAgent> = {};\n for (const [id, agent] of registry) {\n obj[id] = agent;\n }\n const tmp = `${this.registryPath}.${randomUUID().slice(0, 8)}.tmp`;\n await fsp.writeFile(tmp, JSON.stringify(obj), 'utf8');\n await fsp.rename(tmp, this.registryPath);\n }\n\n // \u2500\u2500 Client registry internals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async _ensureClientRegistry(): Promise<void> {\n await fsp.mkdir(path.dirname(this.clientRegistryPath), { recursive: true });\n }\n\n private async _readClientRegistry(opts?: {\n fresh?: boolean;\n }): Promise<Map<string, RegisteredClient>> {\n if (\n !opts?.fresh &&\n this._clientRegistryCache &&\n Date.now() - this._clientRegistryCacheAt < REGISTRY_CACHE_TTL_MS\n ) {\n return new Map(this._clientRegistryCache);\n }\n\n try {\n const raw = await fsp.readFile(this.clientRegistryPath, 'utf8');\n const data = JSON.parse(raw) as Record<string, RegisteredClient>;\n const map = new Map<string, RegisteredClient>();\n for (const [id, client] of Object.entries(data)) {\n map.set(id, client as RegisteredClient);\n }\n this._clientRegistryCache = map;\n this._clientRegistryCacheAt = Date.now();\n return new Map(map);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const empty = new Map<string, RegisteredClient>();\n this._clientRegistryCache = empty;\n this._clientRegistryCacheAt = Date.now();\n return empty;\n }\n throw err;\n }\n }\n\n private _pruneStaleClientsInPlace(registry: Map<string, RegisteredClient>): void {\n const cutoff = Date.now() - CLIENT_STALE_MS;\n for (const [id, client] of registry) {\n const lastSeen = Date.parse(client.lastSeenAt);\n if (!Number.isFinite(lastSeen) || lastSeen < cutoff) {\n registry.delete(id);\n }\n }\n }\n\n private async _writeClientRegistry(registry: Map<string, RegisteredClient>): Promise<void> {\n const obj: Record<string, RegisteredClient> = {};\n for (const [id, client] of registry) {\n obj[id] = client;\n }\n const tmp = `${this.clientRegistryPath}.${randomUUID().slice(0, 8)}.tmp`;\n await fsp.writeFile(tmp, JSON.stringify(obj), 'utf8');\n await fsp.rename(tmp, this.clientRegistryPath);\n }\n}\n", "import { randomBytes } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport { watch as watchDir } from 'node:fs';\nimport type { FSWatcher } from 'node:fs';\nimport * as path from 'node:path';\nimport { FsError } from '../types/errors.js';\n\nexport interface AtomicWriteOptions {\n mode?: number | undefined;\n encoding?: BufferEncoding | undefined;\n}\n\nexport interface FileLockOptions {\n timeoutMs?: number | undefined;\n staleMs?: number | undefined;\n}\n\nexport async function atomicWrite(\n targetPath: string,\n content: string | Uint8Array,\n opts: AtomicWriteOptions = {},\n): Promise<void> {\n const dir = path.dirname(targetPath);\n await fs.mkdir(dir, { recursive: true });\n const tmp = path.join(dir, `.${path.basename(targetPath)}.${randomBytes(6).toString('hex')}.tmp`);\n\n // Write content to tmp first; 'wx' ensures exclusive creation (fails if\n // tmp already exists \u2014 extremely unlikely with 6-byte random suffix).\n try {\n if (typeof content === 'string') {\n await fs.writeFile(tmp, content, { flag: 'wx', encoding: opts.encoding ?? 'utf8' });\n } else {\n await fs.writeFile(tmp, content, { flag: 'wx' });\n }\n try {\n const fh = await fs.open(tmp, 'r+');\n try {\n await fh.sync();\n } finally {\n await fh.close();\n }\n } catch {\n // fsync best-effort\n }\n // Now safely read mode from target (if it exists) and apply to tmp before rename.\n // Prefer opts.mode for new files; for existing files preserve their mode.\n let mode: number | undefined;\n try {\n const stat = await fs.stat(targetPath);\n mode = stat.mode & 0o777;\n } catch {\n mode = opts.mode;\n }\n if (mode !== undefined) {\n await fs.chmod(tmp, mode);\n }\n await renameWithRetry(tmp, targetPath);\n // P3 #20 (before-release.md): on Windows, fs.rename (MoveFileExW) does\n // not preserve Unix permission bits \u2014 the chmod above applies to the tmp\n // file, but the rename may reset the destination's mode to the Windows\n // default. Re-apply the mode after rename on win32 so an edited file\n // keeps its executable bit (or any non-default permission). On POSIX,\n // rename preserves metadata so this is a no-op (chmod is idempotent and\n // cheap), but we gate it on win32 to avoid the extra stat+chmod on the\n // common path.\n if (mode !== undefined && process.platform === 'win32') {\n try {\n await fs.chmod(targetPath, mode);\n } catch {\n // Best-effort: a transient EPERM (antivirus lock) should not fail\n // the write \u2014 the content is already on disk.\n }\n }\n } catch (err) {\n try {\n await fs.unlink(tmp);\n } catch {\n // ignore cleanup error\n }\n throw err;\n }\n}\n\nexport async function ensureDir(dir: string): Promise<void> {\n await fs.mkdir(dir, { recursive: true });\n}\n\nexport async function withFileLock<T>(\n targetPath: string,\n fn: () => Promise<T>,\n opts: FileLockOptions = {},\n): Promise<T> {\n const dir = path.dirname(targetPath);\n await fs.mkdir(dir, { recursive: true });\n const lockPath = path.join(dir, `.${path.basename(targetPath)}.lock`);\n const timeoutMs = opts.timeoutMs ?? 5_000;\n const staleMs = opts.staleMs ?? 30_000;\n const started = Date.now();\n let handle: fs.FileHandle | undefined;\n\n for (;;) {\n try {\n handle = await fs.open(lockPath, 'wx');\n await handle.writeFile(`${process.pid}:${Date.now()}`);\n break;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n // ENOENT means the directory was deleted (e.g. by concurrent cleanup).\n // Recreate it and retry acquiring the lock.\n if (code === 'ENOENT') {\n await fs.mkdir(dir, { recursive: true });\n continue;\n }\n if (code !== 'EEXIST' && code !== 'EPERM') throw err;\n try {\n const stat = await fs.stat(lockPath);\n if (Date.now() - stat.mtimeMs > staleMs) {\n await fs.unlink(lockPath);\n continue;\n }\n } catch {\n continue;\n }\n const elapsed = Date.now() - started;\n if (elapsed >= timeoutMs) {\n throw new FsError({\n message: `Timed out waiting for file lock: ${targetPath}`,\n code: 'FS_ATOMIC_WRITE_FAILED',\n path: targetPath,\n context: { timeoutMs },\n });\n }\n // Wait for the lock to be released, using a filesystem watcher for\n // nearly-instant wake-up instead of polling. The watcher is best-effort:\n // a safety timeout fires at most every 100ms so we don't busy-wait.\n await waitForLockRelease(lockPath, timeoutMs - elapsed);\n }\n }\n\n try {\n return await fn();\n } finally {\n try {\n await handle?.close();\n } catch {\n // ignore\n }\n try {\n await fs.unlink(lockPath);\n } catch {\n // ignore\n }\n }\n}\n\n/**\n * Watch a lock file's parent directory for the file being removed (unlinked),\n * which signals that the lock holder has released it. A safety timeout caps\n * the wait so the overall `withFileLock` timeout is always respected.\n *\n * Uses a bounded safety interval (up to 100ms) so even if `fs.watch` is\n * unavailable or misses the event, we never busy-wait at 25ms fixed polling.\n */\nasync function waitForLockRelease(lockPath: string, remainingMs: number): Promise<void> {\n const parentDir = path.dirname(lockPath);\n const lockName = path.basename(lockPath);\n const intervalMs = Math.min(remainingMs, 100);\n\n return new Promise<void>((resolve) => {\n let settled = false;\n let watcher: FSWatcher | null = null;\n\n // Safety timer \u2014 always fires, even if fs.watch is unavailable.\n const timer = setTimeout(() => {\n settled = true;\n watcher?.close();\n resolve();\n }, intervalMs);\n\n try {\n watcher = watchDir(parentDir, (eventType, filename) => {\n if (settled) return;\n // 'rename' fires on unlink on most platforms; 'change' is a\n // conservative fallback for environments that only emit 'change'.\n if (filename === lockName && (eventType === 'rename' || eventType === 'change')) {\n settled = true;\n clearTimeout(timer);\n watcher?.close();\n resolve();\n }\n });\n } catch {\n // fs.watch not supported (e.g. some container environments, network\n // filesystems). Clear the safety timer and fall back to a single\n // short delay \u2014 the caller's loop will retry on the next iteration.\n clearTimeout(timer);\n if (!settled) {\n settled = true;\n setTimeout(resolve, Math.min(remainingMs, 25));\n }\n return;\n }\n\n // Re-check lock existence after setting up the watch to close the race\n // where the lock was released between our last EEXIST check and now.\n fs.access(lockPath).then(\n () => {\n // Lock still exists \u2014 the watch (or safety timer) will resolve.\n },\n () => {\n // Lock was already released \u2014 respond immediately.\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n watcher?.close();\n resolve();\n }\n },\n );\n });\n}\n\n// On Windows, fs.rename over an existing file can fail with EPERM/EBUSY/EACCES\n// when antivirus, file indexers, editor file watchers, or a concurrent writer\n// briefly hold a handle on the destination. These are transient \u2014 retry with a\n// short backoff before giving up. POSIX renames are atomic and won't hit this.\nconst TRANSIENT_RENAME_CODES = new Set(['EPERM', 'EBUSY', 'EACCES', 'ENOTEMPTY']);\n\nasync function renameWithRetry(from: string, to: string): Promise<void> {\n if (process.platform !== 'win32') {\n await fs.rename(from, to);\n return;\n }\n const delays = [10, 25, 60, 120, 250];\n let lastErr: unknown;\n for (let i = 0; i <= delays.length; i++) {\n try {\n await fs.rename(from, to);\n return;\n } catch (err) {\n lastErr = err;\n const code = (err as NodeJS.ErrnoException)?.code;\n if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {\n throw err;\n }\n await new Promise((resolve) => setTimeout(resolve, delays[i]));\n }\n }\n throw lastErr;\n}\n", "import * as path from 'node:path';\nimport { ERROR_CODES, FsError } from '../types/errors.js';\n\n/**\n * Resolve `<dir>/<sessionId><suffix>` for per-session sidecar files\n * (annotations, audit chain, replay log, the session JSONL itself).\n *\n * Modern session ids are date-sharded (\"2026-06-11/sess_<ULID>\"),\n * so a forward slash is a legitimate shard separator \u2014 NOT traversal.\n * Escape attempts are blocked two ways: an explicit ban on `..` and\n * backslashes, plus a resolved-path containment check that rejects any\n * id whose resolved target leaves `dir`. Character bans alone are how\n * several stores ended up throwing on every modern session id.\n */\nexport function sessionScopedPath(dir: string, sessionId: string, suffix: string): string {\n if (!sessionId || sessionId.includes('\\\\') || sessionId.includes('..')) {\n throw invalid(sessionId);\n }\n const resolved = path.resolve(dir, `${sessionId}${suffix}`);\n const rel = path.relative(path.resolve(dir), resolved);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw invalid(sessionId);\n }\n return resolved;\n}\n\nfunction invalid(sessionId: string): FsError {\n return new FsError({\n message: `Invalid sessionId: ${sessionId}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: sessionId,\n context: { reason: 'path_traversal' },\n });\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\n/**\n * Path layout. All developer-level state lives in ~/.wrongstack/.\n * Per-project state is keyed by the canonical project root under\n * ~/.wrongstack/projects/<slug>/. Linked Git worktrees resolve to their main\n * checkout so coordination and durable state are shared across worktrees.\n *\n * The ONLY thing inside the project tree is the optional\n * .wrongstack/AGENTS.md (committed) and .wrongstack/skills/ (committed).\n */\n\nexport interface WstackPaths {\n /** ~/.wrongstack \u2014 global root. */\n globalRoot: string;\n /** Absolute project root. */\n projectRoot: string;\n /** Home directory (~) \u2014 base for foreign tool state (~/.codex, ~/.agents, \u2026). */\n homeDir: string;\n /**\n * ~/.wrongstack \u2014 directory for user-global stateful config files\n * (mode.json, theme.json, \u2026). Currently an alias for `globalRoot`;\n * separate name lets us split out per-OS XDG_CONFIG_HOME later\n * without rewriting callers.\n */\n configDir: string;\n /** ~/.wrongstack/config.json */\n globalConfig: string;\n /** ~/.wrongstack/.key \u2014 32 random bytes, mode 0600, AES-GCM key for the secret vault. */\n secretsKey: string;\n /** ~/.wrongstack/memory.md \u2014 user-global memory. */\n globalMemory: string;\n /** ~/.wrongstack/skills \u2014 user-global skills. */\n globalSkills: string;\n /** ~/.claude/skills \u2014 user-global skills from foreign coding agents (Claude Code, Codex, \u2026). Read-only. */\n globalClaudeSkills: string;\n /** ~/.wrongstack/design-kits \u2014 user-global Design Studio kits. */\n globalDesignKits: string;\n /** ~/.wrongstack/prompts \u2014 user-global prompt library. */\n globalPrompts: string;\n /** ~/.wrongstack/instructions \u2014 user-global system instruction overrides. */\n globalInstructions: string;\n /** ~/.wrongstack/prompt-usage.json \u2014 per-slug insert counts (recent/popular). */\n promptUsage: string;\n /** ~/.wrongstack/cache \u2014 fetched data (models.dev, etc.). */\n cacheDir: string;\n /** ~/.wrongstack/cache/models.dev.json */\n modelsCache: string;\n /** ~/.wrongstack/cache/models-overlay.json \u2014 cached curated overlay. */\n modelsOverlayCache: string;\n /**\n * Per-project codebase symbol index (SQLite). Lives under the global project\n * dir \u2014 NOT inside the repo \u2014 so it never clutters the working tree or needs\n * gitignoring. `~/.wrongstack/projects/<hash>/codebase-index`.\n */\n projectCodebaseIndex: string;\n /** ~/.wrongstack/history \u2014 REPL line history. */\n historyFile: string;\n /** ~/.wrongstack/logs/wrongstack.log */\n logFile: string;\n /** ~/.wrongstack/projects/<hash> */\n projectDir: string;\n /** ~/.wrongstack/projects/<hash>/memory.md */\n projectMemory: string;\n /** ~/.wrongstack/projects/<hash>/sessions */\n projectSessions: string;\n /** ~/.wrongstack/projects/<hash>/trust.json */\n projectTrust: string;\n /** ~/.wrongstack/projects/<hash>/meta.json */\n projectMeta: string;\n /** ~/.wrongstack/projects/<hash>/config.local.json \u2014 optional override */\n projectLocalConfig: string;\n /** <project>/.wrongstack/config.json \u2014 per-project settings (safe fields only).\n * This lives inside the project root so it can be gitignored or shared. */\n inProjectConfig: string;\n /** <project>/.wrongstack/AGENTS.md \u2014 committed project memory. */\n inProjectAgentsFile: string;\n /** <project>/.wrongstack/skills \u2014 committed project skills. */\n inProjectSkills: string;\n /** <project>/.claude/skills \u2014 project skills authored for foreign coding agents (Claude Code, \u2026). Read-only. */\n inProjectClaudeSkills: string;\n /** <project>/.wrongstack/prompts \u2014 committed project prompt library. */\n inProjectPrompts: string;\n /** <project>/.wrongstack/instructions \u2014 committed project instruction overrides. */\n inProjectInstructions: string;\n /** <project>/.wrongstack/design-kits \u2014 committed project Design Studio kits. */\n inProjectDesignKits: string;\n /** <project>/.wrongstack/worktrees \u2014 git worktrees for per-phase isolation (gitignored). */\n inProjectWorktrees: string;\n /** Stable hash for the canonical project root (shared by linked Git worktrees). */\n projectHash: string;\n /** Human-readable canonical project slug, shared by linked Git worktrees. */\n projectSlug: string;\n /** ~/.wrongstack/projects/<hash>/goal.json \u2014 goal persistence */\n projectGoal: string;\n /** ~/.wrongstack/projects/<hash>/input-history.json \u2014 TUI prompt input history */\n projectInputHistory: string;\n /** ~/.wrongstack/projects/<hash>/specs \u2014 SDD spec files */\n projectSpecs: string;\n /** ~/.wrongstack/projects/<hash>/task-graphs \u2014 SDD task graphs */\n projectTaskGraphs: string;\n /** ~/.wrongstack/projects/<hash>/sdd-session.json \u2014 SDD session state */\n projectSddSession: string;\n /** ~/.wrongstack/projects/<hash>/plan.json \u2014 plan persistence */\n projectPlan: string;\n /** ~/.wrongstack/projects/<hash>/autophase \u2014 AutoPhase phase-graph JSON files */\n projectAutophase: string;\n /** ~/.wrongstack/projects/<hash>/sdd-boards \u2014 live SDD board snapshots + JSONL event logs */\n projectSddBoards: string;\n /** ~/.wrongstack/sync.json \u2014 CloudSync configuration */\n syncConfig: string;\n /** Function to get the status.json path for a project given its hash. */\n projectStatus: (projectHash: string) => string;\n}\n\n/**\n * Resolve the stable project identity root used by global WrongStack state.\n *\n * A linked Git worktree has its own checkout path and a `.git` *file* that\n * points into `<main>/.git/worktrees/<name>`. Its `commondir` points back to\n * the main checkout's `.git` directory. Treating the linked checkout path as\n * the project identity would split one repository into multiple session,\n * registry, and mailbox directories \u2014 agents in different worktrees would be\n * unable to see or message each other.\n *\n * Project-local paths still use the caller's actual checkout. Only global\n * state identity is canonicalized. Non-Git projects, normal checkouts, Git\n * submodules, and separate-git-dir layouts keep their existing identity.\n */\nexport function canonicalProjectRoot(absRoot: string): string {\n const checkoutRoot = path.resolve(absRoot);\n const dotGit = path.join(checkoutRoot, '.git');\n\n try {\n if (!fs.statSync(dotGit).isFile()) return checkoutRoot;\n\n const gitDirLine = fs.readFileSync(dotGit, 'utf8').trim();\n const match = /^gitdir:\\s*(.+)$/i.exec(gitDirLine);\n if (!match?.[1]) return checkoutRoot;\n\n const gitDir = path.resolve(checkoutRoot, match[1].trim());\n const commonDirFile = path.join(gitDir, 'commondir');\n if (!fs.statSync(commonDirFile).isFile()) return checkoutRoot;\n\n const commonDir = path.resolve(gitDir, fs.readFileSync(commonDirFile, 'utf8').trim());\n // Linked worktrees created by Git share the main checkout's `.git` dir.\n // A submodule or --separate-git-dir layout may point elsewhere; do not\n // guess a working-tree root for those shapes.\n if (path.basename(commonDir).toLowerCase() !== '.git') return checkoutRoot;\n return path.dirname(commonDir);\n } catch {\n // Missing/malformed administrative files must never make path resolution\n // fail. Falling back preserves the pre-canonicalization behavior.\n return checkoutRoot;\n }\n}\n\nexport function projectHash(absRoot: string): string {\n return createHash('sha256').update(canonicalProjectRoot(absRoot)).digest('hex').slice(0, 12);\n}\n\n/**\n * Human-readable project directory name: slugified folder name + short hash\n * suffix for uniqueness. e.g. `wrongstack-a1b2c3` instead of `3024e5e6fa58`.\n */\nexport function projectSlug(absRoot: string): string {\n const identityRoot = canonicalProjectRoot(absRoot);\n const base = slugify(path.basename(identityRoot));\n const hash = createHash('sha256').update(identityRoot).digest('hex').slice(0, 6);\n return `${base}-${hash}`;\n}\n\n/** Turn a folder name into a filesystem-safe lowercase slug. */\nfunction slugify(name: string): string {\n return (\n name\n .toLowerCase()\n // Collapse any run of non-alphanumeric chars into a single hyphen.\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40) || 'project'\n );\n}\n\nexport interface WstackPathOptions {\n userHome?: string | undefined;\n projectRoot: string;\n /** Override the global root (e.g. for tests). Default: `${userHome}/.wrongstack`. */\n globalRoot?: string | undefined;\n}\n\n/**\n * The global `~/.wrongstack` root, honoring the `WRONGSTACK_HOME` env\n * override. The override exists so tests (and sandboxed runs) can redirect\n * ALL global state \u2014 config, secrets, logs, projects/, mailboxes \u2014 away from\n * the real user home. Before it existed, `pnpm test` booted runtimes against\n * the real `~/.wrongstack`: it read the user's real config.json (starting a\n * second live Telegram poller), appended to the real wrongstack.log, and left\n * ~20k orphaned fixture dirs under projects/.\n *\n * Every code path that wants the global dir must come through here (or\n * through `resolveWstackPaths`) instead of `path.join(os.homedir(), '.wrongstack')`.\n */\nexport function wstackGlobalRoot(): string {\n const fromEnv = process.env['WRONGSTACK_HOME'];\n if (fromEnv && fromEnv.trim().length > 0) return path.resolve(fromEnv);\n return path.join(os.homedir(), '.wrongstack');\n}\n\nexport function resolveWstackPaths(opts: WstackPathOptions): WstackPaths {\n // Precedence: explicit globalRoot > explicit userHome (callers/tests that\n // pass one expect paths under it) > WRONGSTACK_HOME env > real home dir.\n const globalRoot =\n opts.globalRoot ?? (opts.userHome ? path.join(opts.userHome, '.wrongstack') : wstackGlobalRoot());\n // Home dir for FOREIGN tool state (Claude Code's ~/.claude). Independent of\n // WRONGSTACK_HOME, which redirects only WrongStack state: a real user's\n // Claude skills live in their real home, but tests pass `userHome` to keep\n // both `.wrongstack` and `.claude` under a temp dir.\n const homeDir = opts.userHome ?? os.homedir();\n const hash = projectHash(opts.projectRoot);\n const slug = projectSlug(opts.projectRoot);\n const projectDir = path.join(globalRoot, 'projects', slug);\n return {\n globalRoot,\n projectRoot: opts.projectRoot,\n homeDir,\n configDir: globalRoot,\n globalConfig: path.join(globalRoot, 'config.json'),\n secretsKey: path.join(globalRoot, '.key'),\n globalMemory: path.join(globalRoot, 'memory.md'),\n globalSkills: path.join(globalRoot, 'skills'),\n globalClaudeSkills: path.join(homeDir, '.claude', 'skills'),\n globalDesignKits: path.join(globalRoot, 'design-kits'),\n globalPrompts: path.join(globalRoot, 'prompts'),\n globalInstructions: path.join(globalRoot, 'instructions'),\n promptUsage: path.join(globalRoot, 'prompt-usage.json'),\n cacheDir: path.join(globalRoot, 'cache'),\n modelsCache: path.join(globalRoot, 'cache', 'models.dev.json'),\n modelsOverlayCache: path.join(globalRoot, 'cache', 'models-overlay.json'),\n historyFile: path.join(globalRoot, 'history'),\n logFile: path.join(globalRoot, 'logs', 'wrongstack.log'),\n projectDir,\n projectCodebaseIndex: path.join(projectDir, 'codebase-index'),\n projectMemory: path.join(projectDir, 'memory.md'),\n projectSessions: path.join(projectDir, 'sessions'),\n projectTrust: path.join(projectDir, 'trust.json'),\n projectMeta: path.join(projectDir, 'meta.json'),\n projectLocalConfig: path.join(projectDir, 'config.local.json'),\n inProjectConfig: path.join(opts.projectRoot, '.wrongstack', 'config.json'),\n inProjectAgentsFile: path.join(opts.projectRoot, '.wrongstack', 'AGENTS.md'),\n inProjectSkills: path.join(opts.projectRoot, '.wrongstack', 'skills'),\n inProjectClaudeSkills: path.join(opts.projectRoot, '.claude', 'skills'),\n inProjectPrompts: path.join(opts.projectRoot, '.wrongstack', 'prompts'),\n inProjectInstructions: path.join(opts.projectRoot, '.wrongstack', 'instructions'),\n inProjectDesignKits: path.join(opts.projectRoot, '.wrongstack', 'design-kits'),\n inProjectWorktrees: path.join(opts.projectRoot, '.wrongstack', 'worktrees'),\n projectHash: hash,\n projectSlug: slug,\n projectGoal: path.join(projectDir, 'goal.json'),\n projectInputHistory: path.join(projectDir, 'input-history.json'),\n projectSpecs: path.join(projectDir, 'specs'),\n projectTaskGraphs: path.join(projectDir, 'task-graphs'),\n projectSddSession: path.join(projectDir, 'sdd-session.json'),\n projectPlan: path.join(projectDir, 'plan.json'),\n projectAutophase: path.join(projectDir, 'autophase'),\n projectSddBoards: path.join(projectDir, 'sdd-boards'),\n syncConfig: path.join(globalRoot, 'sync.json'),\n projectStatus: (projectHash: string) => path.join(globalRoot, 'projects', projectHash, 'status.json'),\n };\n}\n", "import { toErrorMessage } from '../utils/index.js';\n\n/**\n * WrongStack error hierarchy.\n *\n * Every error thrown by the framework is a `WrongStackError` with a\n * machine-readable `code`, a `subsystem` tag, and a `severity` level.\n * This lets consumers (CLI, TUI, plugins, tests) branch on structured\n * data instead of parsing error messages.\n */\n\n// \u2500\u2500 Error codes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Machine-readable error codes as frozen constants.\n *\n * Use `ERROR_CODES.X` instead of raw string literals for:\n * - IDE autocomplete and compile-time validation\n * - Safe refactoring (rename updates all usages)\n * - Plugin extensibility (extend the object to add custom codes)\n *\n * The `ErrorCode` type is derived from this object, so adding a new\n * code here automatically updates the type without extra changes.\n */\nexport const ERROR_CODES = {\n // Provider\n PROVIDER_RATE_LIMITED: 'PROVIDER_RATE_LIMITED',\n PROVIDER_AUTH_FAILED: 'PROVIDER_AUTH_FAILED',\n PROVIDER_OVERLOADED: 'PROVIDER_OVERLOADED',\n PROVIDER_INVALID_REQUEST: 'PROVIDER_INVALID_REQUEST',\n PROVIDER_SERVER_ERROR: 'PROVIDER_SERVER_ERROR',\n PROVIDER_NETWORK_ERROR: 'PROVIDER_NETWORK_ERROR',\n PROVIDER_CONTEXT_OVERFLOW: 'PROVIDER_CONTEXT_OVERFLOW',\n // Tool\n TOOL_NOT_FOUND: 'TOOL_NOT_FOUND',\n TOOL_PERMISSION_DENIED: 'TOOL_PERMISSION_DENIED',\n TOOL_EXECUTION_FAILED: 'TOOL_EXECUTION_FAILED',\n TOOL_TIMEOUT: 'TOOL_TIMEOUT',\n TOOL_INPUT_INVALID: 'TOOL_INPUT_INVALID',\n // Config\n CONFIG_INVALID: 'CONFIG_INVALID',\n CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',\n CONFIG_PARSE_FAILED: 'CONFIG_PARSE_FAILED',\n CONFIG_MIGRATION_NEEDED: 'CONFIG_MIGRATION_NEEDED',\n // Plugin\n PLUGIN_LOAD_FAILED: 'PLUGIN_LOAD_FAILED',\n PLUGIN_API_MISMATCH: 'PLUGIN_API_MISMATCH',\n PLUGIN_MISSING_DEPENDENCY: 'PLUGIN_MISSING_DEPENDENCY',\n // Agent\n AGENT_ITERATION_LIMIT: 'AGENT_ITERATION_LIMIT',\n AGENT_CONTEXT_OVERFLOW: 'AGENT_CONTEXT_OVERFLOW',\n AGENT_ABORTED: 'AGENT_ABORTED',\n AGENT_RUN_FAILED: 'AGENT_RUN_FAILED',\n // Session\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\n SESSION_CORRUPTED: 'SESSION_CORRUPTED',\n SESSION_WRITE_FAILED: 'SESSION_WRITE_FAILED',\n // Container / Registry\n CONTAINER_TOKEN_ALREADY_BOUND: 'CONTAINER_TOKEN_ALREADY_BOUND',\n CONTAINER_TOKEN_NOT_BOUND: 'CONTAINER_TOKEN_NOT_BOUND',\n CONTAINER_CIRCULAR_DEPENDENCY: 'CONTAINER_CIRCULAR_DEPENDENCY',\n REGISTRY_DUPLICATE: 'REGISTRY_DUPLICATE',\n REGISTRY_NOT_FOUND: 'REGISTRY_NOT_FOUND',\n REGISTRY_INVALID: 'REGISTRY_INVALID',\n // File system\n FS_READ_FAILED: 'FS_READ_FAILED',\n FS_WRITE_FAILED: 'FS_WRITE_FAILED',\n FS_MKDIR_FAILED: 'FS_MKDIR_FAILED',\n FS_DELETE_FAILED: 'FS_DELETE_FAILED',\n FS_ATOMIC_WRITE_FAILED: 'FS_ATOMIC_WRITE_FAILED',\n // SDD (Spec-Driven Development)\n SDD_VALIDATION_FAILED: 'SDD_VALIDATION_FAILED',\n SDD_PARSE_FAILED: 'SDD_PARSE_FAILED',\n SDD_INVALID_STATE: 'SDD_INVALID_STATE',\n SDD_NOT_READY: 'SDD_NOT_READY',\n // General\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n PARSE_FAILED: 'PARSE_FAILED',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\n/**\n * Union type derived from `ERROR_CODES`. Using `typeof ERROR_CODES[keyof typeof ERROR_CODES]`\n * instead of a string literal union means TypeScript auto-updates the type whenever\n * a new code is added to `ERROR_CODES` \u2014 no need to keep two lists in sync.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];\n\nexport type ErrorSubsystem =\n | 'provider'\n | 'tool'\n | 'config'\n | 'plugin'\n | 'agent'\n | 'session'\n | 'sdd'\n | 'container'\n | 'fs'\n | 'general';\nexport type ErrorSeverity = 'fatal' | 'error' | 'warning';\n\n// \u2500\u2500 Base error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class WrongStackError extends Error {\n readonly code: ErrorCode;\n readonly subsystem: ErrorSubsystem;\n readonly severity: ErrorSeverity;\n readonly recoverable: boolean;\n readonly context?: Record<string, unknown> | undefined;\n\n constructor(opts: {\n message: string;\n code: ErrorCode;\n subsystem: ErrorSubsystem;\n severity?: ErrorSeverity | undefined;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super(opts.message, { cause: opts.cause });\n this.name = 'WrongStackError';\n this.code = opts.code;\n this.subsystem = opts.subsystem;\n this.severity = opts.severity ?? 'error';\n this.recoverable = opts.recoverable ?? false;\n this.context = opts.context;\n }\n\n /**\n * Render a one-line user-facing description.\n * Subclasses should override for domain-specific formatting.\n */\n describe(): string {\n const ctx = this.context ? ` ${formatContext(this.context)}` : '';\n return `${this.code}: ${this.message}${ctx}`;\n }\n}\n\nfunction formatContext(ctx: Record<string, unknown>): string {\n const parts = Object.entries(ctx)\n .filter(([, v]) => v !== undefined)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${String(v)}`);\n return parts.length > 0 ? `[${parts.join(' ')}]` : '';\n}\n\n// \u2500\u2500 Specific error classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Tool execution errors \u2014 thrown by ToolExecutor and individual tools.\n */\nexport class ToolError extends WrongStackError {\n readonly toolName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n | 'TOOL_NOT_FOUND'\n | 'TOOL_PERMISSION_DENIED'\n | 'TOOL_EXECUTION_FAILED'\n | 'TOOL_TIMEOUT'\n | 'TOOL_INPUT_INVALID'\n >;\n toolName: string;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'tool',\n recoverable: opts.recoverable,\n context: { tool: opts.toolName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolError';\n this.toolName = opts.toolName;\n }\n}\n\n/**\n * Config loading / validation errors.\n */\nexport class ConfigError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'CONFIG_INVALID' | 'CONFIG_NOT_FOUND' | 'CONFIG_PARSE_FAILED' | 'CONFIG_MIGRATION_NEEDED'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'config',\n severity: 'fatal',\n recoverable: false,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Plugin loading / lifecycle errors.\n */\nexport class PluginError extends WrongStackError {\n readonly pluginName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'PLUGIN_LOAD_FAILED' | 'PLUGIN_API_MISMATCH' | 'PLUGIN_MISSING_DEPENDENCY'\n >;\n pluginName: string;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'plugin',\n severity: 'error',\n recoverable: opts.code === ERROR_CODES.PLUGIN_MISSING_DEPENDENCY,\n context: { plugin: opts.pluginName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'PluginError';\n this.pluginName = opts.pluginName;\n }\n}\n\n/**\n * Agent runtime errors \u2014 thrown by Agent.run when a non-WrongStackError\n * escapes the inner loop, so callers always see a structured error.\n */\nexport class AgentError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'AGENT_ITERATION_LIMIT' | 'AGENT_CONTEXT_OVERFLOW' | 'AGENT_ABORTED' | 'AGENT_RUN_FAILED'\n >;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'agent',\n severity: opts.code === ERROR_CODES.AGENT_ABORTED ? 'warning' : 'error',\n recoverable: opts.recoverable ?? opts.code === ERROR_CODES.AGENT_ITERATION_LIMIT,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'AgentError';\n }\n}\n\n/**\n * Wrap an arbitrary thrown value into a `WrongStackError` so the caller\n * always gets a structured error. Pass-throughs WrongStackError instances\n * unchanged; raw `Error`s and primitives get an `AGENT_RUN_FAILED` wrapper\n * with the original preserved as `cause`.\n */\nexport function toWrongStackError(\n err: unknown,\n code: Extract<ErrorCode, 'AGENT_RUN_FAILED' | 'AGENT_ABORTED' | 'UNKNOWN'> = ERROR_CODES.AGENT_RUN_FAILED,\n): WrongStackError {\n if (err instanceof WrongStackError) return err;\n const message = toErrorMessage(err);\n return new AgentError({\n message,\n code: code === 'UNKNOWN' ? ERROR_CODES.AGENT_RUN_FAILED : code,\n cause: err,\n });\n}\n\n/**\n * Session storage errors.\n */\nexport class SessionError extends WrongStackError {\n readonly sessionId?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<ErrorCode, 'SESSION_NOT_FOUND' | 'SESSION_CORRUPTED' | 'SESSION_WRITE_FAILED'>;\n sessionId?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'session',\n severity: opts.code === ERROR_CODES.SESSION_WRITE_FAILED ? 'error' : 'warning',\n recoverable: opts.code !== ERROR_CODES.SESSION_CORRUPTED,\n context: { sessionId: opts.sessionId, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'SessionError';\n this.sessionId = opts.sessionId;\n }\n}\n\n/**\n * SDD (Spec-Driven Development) errors \u2014 spec validation, parsing, and\n * state machine violations in the AISpecBuilder, TaskFlow, and TaskTracker.\n */\nexport class SddError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'SDD_VALIDATION_FAILED' | 'SDD_PARSE_FAILED' | 'SDD_INVALID_STATE' | 'SDD_NOT_READY'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'sdd',\n severity: opts.code === ERROR_CODES.SDD_PARSE_FAILED ? 'warning' : 'error',\n recoverable: opts.code === ERROR_CODES.SDD_NOT_READY,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'SddError';\n }\n}\n\n/**\n * File system operation errors.\n */\nexport class FsError extends WrongStackError {\n readonly path?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'FS_READ_FAILED' | 'FS_WRITE_FAILED' | 'FS_MKDIR_FAILED' | 'FS_DELETE_FAILED' | 'FS_ATOMIC_WRITE_FAILED'\n >;\n path?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'fs',\n severity: 'error',\n recoverable: opts.code !== ERROR_CODES.FS_READ_FAILED,\n context: { path: opts.path, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FsError';\n this.path = opts.path;\n }\n}\n\n/**\n * HTTP fetch error \u2014 thrown when a network request returns a non-OK status.\n * Carries the response status so {@link classifyToolError} can branch on it\n * (429 \u2192 transient, 404 \u2192 not_found, 401 \u2192 permission) without duck-typing\n * the error via `'response' in err`.\n *\n * P3 #18 (before-release.md): the previous `'response' in err` check caught\n * any Error with a `response` property, including custom errors, proxy\n * objects, or mocked errors in tests. `instanceof FetchError` is reliable.\n *\n * Tools and providers that make HTTP requests and need the executor to\n * classify their failures should throw `new FetchError({ status, message })`\n * instead of a bare `Error` with an ad-hoc `response` field.\n */\nexport class FetchError extends WrongStackError {\n readonly status: number;\n\n constructor(opts: {\n message: string;\n status: number;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: opts.status === 429 || opts.status >= 500,\n context: { status: opts.status, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FetchError';\n this.status = opts.status;\n }\n}\n\n/**\n * Tool input validation error \u2014 thrown when a tool's input fails a validation\n * check that the JSON Schema cannot express (e.g. `old_string === new_string`\n * in edit, or a cross-field invariant). Use this instead of a bare\n * `throw new Error('...validation...')` so {@link classifyToolError} can\n * match on `instanceof` rather than a locale-dependent message substring.\n *\n * P2 #6 (before-release.md): the previous `err.message.includes('validation')`\n * check misclassified any error whose message happened to contain \"validation\"\n * (e.g. a third-party \"input validation timeout\") as a VALIDATION error.\n *\n * Named `ToolValidationError` (not `ValidationError`) to avoid colliding with\n * the existing `ValidationError` interface exported by json-schema-validate.ts\n * (a validation-result shape, not an Error subclass).\n */\nexport class ToolValidationError extends WrongStackError {\n constructor(opts: {\n message: string;\n /** Field path or tool name that failed validation, for diagnostics. */\n field?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { field: opts.field, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolValidationError';\n }\n}\n\n/**\n * Response / payload parse error \u2014 thrown when an upstream HTTP response,\n * file, or data structure is well-formed at the transport layer (HTTP 200,\n * valid JSON) but is missing required fields or has an unexpected shape.\n *\n * Distinct from `ConfigError(CONFIG_PARSE_FAILED)` (which is specifically\n * for config-file parsing) and `FetchError` (which covers HTTP non-OK\n * responses). `ParseError` fills the gap: the request succeeded but the\n * response body couldn't be interpreted.\n *\n * Common sites: OAuth token responses missing `access_token`, device-code\n * responses missing `device_code`, registry responses with unexpected\n * schemas.\n */\nexport class ParseError extends WrongStackError {\n readonly source?: string | undefined;\n\n constructor(opts: {\n message: string;\n /**\n * What was being parsed \u2014 e.g. `'oauth-token-response'`,\n * `'device-code-response'`. Lets consumers distinguish parse failures\n * from different upstream APIs without parsing the message.\n */\n source?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.PARSE_FAILED,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { source: opts.source, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ParseError';\n this.source = opts.source;\n }\n}\n\n// \u2500\u2500 Type guards \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function isWrongStackError(err: unknown): err is WrongStackError {\n return err instanceof WrongStackError;\n}\n\nexport function isToolError(err: unknown): err is ToolError {\n return err instanceof ToolError;\n}\n\nexport function isConfigError(err: unknown): err is ConfigError {\n return err instanceof ConfigError;\n}\n\nexport function isPluginError(err: unknown): err is PluginError {\n return err instanceof PluginError;\n}\n\nexport function isSessionError(err: unknown): err is SessionError {\n return err instanceof SessionError;\n}\n\nexport function isAgentError(err: unknown): err is AgentError {\n return err instanceof AgentError;\n}\n\nexport function isFsError(err: unknown): err is FsError {\n return err instanceof FsError;\n}\n\nexport function isToolValidationError(err: unknown): err is ToolValidationError {\n return err instanceof ToolValidationError;\n}\n\nexport function isFetchError(err: unknown): err is FetchError {\n return err instanceof FetchError;\n}\n\nexport function isParseError(err: unknown): err is ParseError {\n return err instanceof ParseError;\n}\n\nexport function isSddError(err: unknown): err is SddError {\n return err instanceof SddError;\n}\n", "/**\n * Centralized constants for the mailbox system.\n *\n * Previously these magic numbers were scattered across global-mailbox.ts,\n * mailbox-attach.ts, mailbox-hooks.ts, and mailbox-health.ts. Keeping them\n * in one place ensures every surface agrees on timeouts, intervals, and\n * thresholds \u2014 and makes tuning a single-file change.\n *\n * @module mailbox-constants\n */\n\n/**\n * Agents without a heartbeat for this long are no longer live and are removed\n * from the registry. Presence registries are not history stores: retaining an\n * offline row makes dead agents and shadow workers look actionable in HQ.\n */\nexport const AGENT_STALE_MS = 60_000;\n\n/** Clients without a heartbeat for this long are considered offline. */\nexport const CLIENT_STALE_MS = 60_000;\n\n/** Heartbeat updates are throttled to at most this interval (per agent/client). */\nexport const HEARTBEAT_THROTTLE_MS = 5_000;\n\n/**\n * How long a read may be served from the in-process registry cache before\n * re-reading the shared file. Kept well below HEARTBEAT_THROTTLE_MS so\n * cross-process registrations become visible promptly.\n */\nexport const REGISTRY_CACHE_TTL_MS = 2_000;\n\n/** JSONL line separator. */\nexport const LINE_SEPARATOR = '\\n';\n\n/**\n * Soft cap on the in-memory message cache. The cache mirrors the JSONL\n * message file; under normal load it stays well under this. If a pathological\n * mailbox exceeds the cap we fall back to reading from disk rather than\n * holding an unbounded buffer in memory.\n */\nexport const MESSAGE_CACHE_MAX_ENTRIES = 10_000;\n\n// \u2500\u2500 Polling / heartbeat intervals (used by mailbox-attach.ts) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Background mailbox awareness polling interval (cross-process fallback). */\nexport const MAILBOX_AWARENESS_INTERVAL_MS = 30_000;\n\n/** Agent heartbeat interval in the attach layer. */\nexport const MAILBOX_HEARTBEAT_INTERVAL_MS = 30_000;\n\n/** Min interval between registry reads for the fleet pulse digest. */\nexport const PULSE_MIN_READ_INTERVAL_MS = 30_000;\n\n// \u2500\u2500 Auto-cleanup / compaction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Interval at which the background auto-compaction sweep runs.\n * Default: every 5 minutes.\n */\nexport const AUTO_COMPACT_INTERVAL_MS = 300_000;\n\n/**\n * Messages that have been read by ALL currently-online agents are eligible\n * for auto-removal after this many milliseconds since the last read.\n * Default: 10 minutes.\n */\nexport const AUTO_COMPACT_READ_MAX_AGE_MS = 600_000;\n\n/**\n * Messages whose TTL (time-to-live) has expired are eligible for auto-removal.\n * When a message has `expiresAt` set and that timestamp is in the past, the\n * next compaction sweep drops it. Default TTL for messages without an explicit\n * `expiresAt`: 24 hours.\n */\nexport const AUTO_COMPACT_DEFAULT_TTL_MS = 86_400_000; // 24h\n\n// \u2500\u2500 HTTP bridge rate limiting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Maximum requests per minute from a single external agent (bearer token). */\nexport const HTTP_RATE_LIMIT_PER_MINUTE = 120;\n\n/** Window size for the sliding-window rate limiter. */\nexport const HTTP_RATE_LIMIT_WINDOW_MS = 60_000;\n", "import type {\n AckRecord,\n MailboxMessage,\n MailboxMessageType,\n MailboxTaskContext,\n ReadReceipts,\n} from './mailbox-types.js';\n\nconst MESSAGE_TYPES = new Set<MailboxMessageType>([\n 'note',\n 'ask',\n 'assign',\n 'steer',\n 'btw',\n 'broadcast',\n 'status',\n 'result',\n 'review',\n 'control',\n]);\n\nconst PRIORITIES = new Set<MailboxMessage['priority']>(['low', 'normal', 'high']);\nconst TASK_STATUSES = new Set([\n 'pending',\n 'in_progress',\n 'completed',\n 'failed',\n 'idle',\n 'running',\n 'streaming',\n 'waiting_user',\n 'error',\n 'offline',\n 'busy',\n]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction requiredString(record: Record<string, unknown>, key: string): string {\n const value = record[key];\n if (typeof value !== 'string') {\n throw new TypeError(`mailbox message field \"${key}\" must be a string`);\n }\n return value;\n}\n\nfunction optionalString(record: Record<string, unknown>, key: string): Record<string, string> {\n const value = record[key];\n if (value === undefined) return {};\n if (typeof value !== 'string') {\n throw new TypeError(`mailbox message field \"${key}\" must be a string when present`);\n }\n return { [key]: value };\n}\n\nfunction parseMessageType(value: unknown): MailboxMessageType {\n if (value === 'info') return 'note';\n if (value === 'task') return 'assign';\n if (typeof value === 'string' && MESSAGE_TYPES.has(value as MailboxMessageType)) {\n return value as MailboxMessageType;\n }\n throw new TypeError('mailbox message field \"type\" is invalid');\n}\n\n/** Normalize message types emitted by pre-union mailbox builds. */\nexport function normalizeMailboxMessageType(value: unknown): MailboxMessageType {\n return parseMessageType(value);\n}\n\nfunction parsePriority(value: unknown): MailboxMessage['priority'] {\n if (typeof value === 'string' && PRIORITIES.has(value as MailboxMessage['priority'])) {\n return value as MailboxMessage['priority'];\n }\n // Older callers were intentionally tolerant here and ranked unknown values\n // as normal. Normalize rather than dropping an otherwise valid message.\n if (typeof value === 'string') return 'normal';\n throw new TypeError('mailbox message field \"priority\" must be a string');\n}\n\nfunction parseReadReceipts(record: Record<string, unknown>, to: string): ReadReceipts {\n const value = record['readBy'];\n if (value === undefined) {\n const legacyReadAt = record['readAt'];\n return record['read'] === true && typeof legacyReadAt === 'string'\n ? { [to || 'unknown']: legacyReadAt }\n : {};\n }\n if (!isRecord(value)) {\n throw new TypeError('mailbox message field \"readBy\" must be an object');\n }\n\n const receipts: ReadReceipts = {};\n for (const [agentId, timestamp] of Object.entries(value)) {\n if (typeof timestamp !== 'string') {\n throw new TypeError('mailbox message read receipt timestamps must be strings');\n }\n receipts[agentId] = timestamp;\n }\n return receipts;\n}\n\nfunction parseTaskContext(value: unknown): MailboxTaskContext | undefined {\n if (value === undefined) return undefined;\n if (!isRecord(value)) {\n throw new TypeError('mailbox message field \"taskContext\" must be an object');\n }\n\n const status = value['status'];\n if (\n status !== undefined &&\n (typeof status !== 'string' ||\n !TASK_STATUSES.has(status as NonNullable<MailboxTaskContext['status']>))\n ) {\n throw new TypeError('mailbox message taskContext status is invalid');\n }\n\n return {\n ...optionalString(value, 'agentRole'),\n ...optionalString(value, 'agentName'),\n ...optionalString(value, 'taskId'),\n ...(status === undefined\n ? {}\n : { status: status as NonNullable<MailboxTaskContext['status']> }),\n };\n}\n\n/** Parse, migrate, and structurally validate one persisted mailbox message. */\nexport function parseMailboxMessage(value: unknown): MailboxMessage {\n if (!isRecord(value)) throw new TypeError('mailbox message must be an object');\n\n const to = value['to'] === undefined ? '' : requiredString(value, 'to');\n const completed = value['completed'];\n if (typeof completed !== 'boolean') {\n throw new TypeError('mailbox message field \"completed\" must be a boolean');\n }\n\n const taskContext = parseTaskContext(value['taskContext']);\n return {\n id: requiredString(value, 'id'),\n from: requiredString(value, 'from'),\n to,\n type: parseMessageType(value['type']),\n subject: requiredString(value, 'subject'),\n body: requiredString(value, 'body'),\n priority: parsePriority(value['priority']),\n readBy: parseReadReceipts(value, to),\n completed,\n timestamp: requiredString(value, 'timestamp'),\n ...optionalString(value, 'completedBy'),\n ...optionalString(value, 'outcome'),\n ...optionalString(value, 'completedAt'),\n ...optionalString(value, 'deletedAt'),\n ...optionalString(value, 'deletedBy'),\n ...optionalString(value, 'replyTo'),\n ...optionalString(value, 'senderSessionId'),\n ...optionalString(value, 'expiresAt'),\n ...(taskContext === undefined ? {} : { taskContext }),\n };\n}\n\n/** Parse one JSONL line and validate the decoded mailbox message. */\nexport function parseMailboxMessageLine(line: string): MailboxMessage {\n return parseMailboxMessage(JSON.parse(line) as unknown);\n}\n\n// \u2500\u2500 Ack record helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Check if a parsed JSONL value is an append-only ack record (not a message).\n * Ack records carry a `__ack: true` discriminator.\n */\nexport function isAckRecord(value: unknown): value is AckRecord {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n (value as Record<string, unknown>)['__ack'] === true\n );\n}\n\n/**\n * Parse one JSONL line, returning either a MailboxMessage or an AckRecord.\n * Returns null when the line is neither (corrupt/malformed).\n */\nexport function parseMailboxLine(line: string): MailboxMessage | AckRecord | null {\n try {\n const parsed = JSON.parse(line) as unknown;\n if (isAckRecord(parsed)) return parsed;\n return parseMailboxMessage(parsed);\n } catch {\n return null;\n }\n}\n\n/**\n * Apply an ack record's effects to a MailboxMessage in-place.\n * This mutates the message object (readBy, completed, completedBy, completedAt,\n * outcome, deletedAt, deletedBy).\n */\nexport function applyAckToMessage(msg: MailboxMessage, ack: AckRecord): void {\n if (ack.read && !(ack.readerId in msg.readBy)) {\n msg.readBy[ack.readerId] = ack.timestamp;\n }\n if (ack.completed && !msg.completed) {\n msg.completed = true;\n msg.completedBy = ack.completedBy ?? ack.readerId;\n msg.completedAt = ack.timestamp;\n }\n if (ack.outcome !== undefined && msg.outcome !== ack.outcome) {\n msg.outcome = ack.outcome;\n }\n // Soft-delete: set deletedAt/deletedBy.\n if (ack.deleted === true) {\n msg.deletedAt = ack.timestamp;\n msg.deletedBy = ack.deletedBy ?? ack.readerId;\n }\n // Restore: clear deletedAt/deletedBy.\n if (ack.deleted === false) {\n delete msg.deletedAt;\n delete msg.deletedBy;\n }\n}\n\n/**\n * Serialize an ack record to a JSONL line.\n */\nexport function serializeAckRecord(ack: AckRecord): string {\n return JSON.stringify(ack) + '\\n';\n}\n", "/**\n * Mailbox \u2014 persistent inter-agent messaging system with cross-session support.\n *\n * Agents can leave notes for specific agents or broadcast to all. Each agent\n * periodically checks the mailbox or retrieves messages via tool calls.\n *\n * ## Cross-session communication\n *\n * The mailbox is stored at **project level** (`~/.wrongstack/projects/<slug>/_mailbox.jsonl`),\n * so agents in different terminal sessions / WebUI tabs working on the same\n * canonical project can communicate live, even when they run in different\n * processes, clients, branches, or linked Git worktrees.\n *\n * ## Agent registration\n *\n * Every agent that uses the mailbox registers itself with a heartbeat.\n * Other agents can discover online agents via `getOnlineAgents()`.\n * Stale agents (no heartbeat > 60s) are pruned automatically.\n *\n * ## Read receipts\n *\n * Each message tracks per-recipient read status via a `readBy` map:\n * `{ \"agentId\": \"ISO8601\" }`. When agent X reads a message, its entry\n * is added. The WebUI shows who read what and when.\n *\n * @module mailbox-types\n */\n\n// \u2500\u2500 Message type discriminator \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type MailboxMessageType =\n | 'note' // informational message\n | 'ask' // question / request for advice\n | 'assign' // task assignment\n | 'steer' // steering instruction (change behavior mid-task)\n | 'btw' // \"by the way\" \u2014 non-urgent info\n | 'broadcast' // sent to all agents\n | 'status' // agent status update\n | 'result' // task result / completion notice\n | 'review' // review request (code/doc/PR) \u2014 passive ask, no reply required\n | 'control'; // out-of-band control signal (e.g. interrupt) \u2014 handled by\n// the agent loop, NOT folded into the conversation as content\n\n// \u2500\u2500 Read receipt \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Per-recipient read status. `readBy` maps agentId \u2192 ISO8601 timestamp of\n * when that agent first read the message. An empty map means unread by all.\n */\nexport interface ReadReceipts {\n [agentId: string]: string; // ISO8601 timestamp\n}\n\n// \u2500\u2500 Core message \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxMessage {\n /** Unique message id (UUID). */\n id: string;\n /** Sender agent id. */\n from: string;\n /** Recipient agent id, or '*' for broadcast. */\n to: string;\n /** Message category. */\n type: MailboxMessageType;\n /** Short subject line \u2014 one sentence. */\n subject: string;\n /** Full message content. */\n body: string;\n /** Priority \u2014 high priority messages surface first. */\n priority: 'low' | 'normal' | 'high';\n /**\n * Per-recipient read receipts. agentId \u2192 ISO8601 when they first read it.\n * Replaces the old single `read: boolean` + `readAt` fields.\n */\n readBy: ReadReceipts;\n /** Has any recipient acted on / completed this? */\n completed: boolean;\n /** Who completed it (agentId). */\n completedBy?: string | undefined;\n /** Optional summary of what happened after handling. */\n outcome?: string | undefined;\n /** ISO8601 \u2014 when the message was sent. */\n timestamp: string;\n /** ISO8601 \u2014 when the message was marked complete. */\n completedAt?: string | undefined;\n /**\n * ISO8601 \u2014 when the message was soft-deleted. When present, the\n * default `Mailbox.query()` filter excludes the message from the\n * normal inbox view; {@link GlobalMailbox.restore} clears the\n * field to undo the delete. Hard deletes (removing the line from\n * the JSONL) are reserved for the CLI and never happen via the\n * server route handlers.\n */\n deletedAt?: string | undefined;\n /** When the soft-delete happened, the agentId that issued it. */\n deletedBy?: string | undefined;\n /** If this is a reply, the id of the parent message. */\n replyTo?: string | undefined;\n /** For assign-type messages \u2014 task context for agent discovery. */\n taskContext?: MailboxTaskContext | undefined;\n /** Session id of the sender. Enables cross-session communication. */\n senderSessionId?: string | undefined;\n /**\n * ISO8601 \u2014 when the message expires. Set at send time from `ttlMs`\n * (default: 24h via AUTO_COMPACT_DEFAULT_TTL_MS). The auto-compaction\n * sweep removes messages whose `expiresAt` is in the past. When\n * undefined, the compaction sweep uses the default TTL from the\n * caller's options.\n */\n expiresAt?: string | undefined;\n}\n\n// \u2500\u2500 Task context for agent discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxTaskContext {\n /** The role that should handle this task (e.g. \"tech-stack\", \"audit-log\"). */\n agentRole?: string | undefined;\n /** Human-readable agent name (e.g. \"Tesla (Executor)\"). */\n agentName?: string | undefined;\n /** Task id if already assigned via coordinator. */\n taskId?: string | undefined;\n /** Current task status. */\n status?: 'pending' | 'in_progress' | 'completed' | 'failed' | undefined;\n}\n\n// \u2500\u2500 Agent registration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface RegisteredAgent {\n /** Unique agent id. */\n agentId: string;\n /** Session id this agent belongs to. */\n sessionId: string;\n /** Human-readable name. */\n name: string;\n /** Role (e.g. \"leader\", \"tech-stack\", \"bug-hunter\"). */\n role?: string | undefined;\n /** Current status. */\n status: 'idle' | 'running' | 'streaming' | 'waiting_user' | 'error';\n /** Current tool being executed, if any. */\n currentTool?: string | undefined;\n /** Current task description. */\n currentTask?: string | undefined;\n /** Iteration count so far. */\n iterations: number;\n /** Tool calls so far. */\n toolCalls: number;\n /** ISO8601 \u2014 registered at. */\n registeredAt: string;\n /** ISO8601 \u2014 last heartbeat (updated on every mailbox op). */\n lastSeenAt: string;\n /** Which process registered this agent (PID). */\n pid: number;\n /** Where the agent is running (e.g. \"cli\", \"webui\"). */\n source?: 'cli' | 'webui' | 'mcp' | 'acp' | 'http' | undefined;\n}\n\n// \u2500\u2500 Agent status entry (for discovery) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxAgentStatus {\n /** Agent id. */\n agentId: string;\n /** Human-readable name. */\n name: string;\n /** Role. */\n role?: string | undefined;\n /** Session id. */\n sessionId: string;\n /** Current status. */\n status: 'idle' | 'running' | 'streaming' | 'waiting_user' | 'error' | 'offline';\n /** Current tool being executed, if any. */\n currentTool?: string | undefined;\n /** Current task description. */\n currentTask?: string | undefined;\n /** Iteration count so far. */\n iterations: number;\n /** Tool calls so far. */\n toolCalls: number;\n /** ISO8601 \u2014 last activity timestamp. */\n lastActivityAt: string;\n /** ISO8601 \u2014 last heartbeat. */\n lastSeenAt: string;\n /** Whether this agent is currently online (heartbeat within threshold). */\n online: boolean;\n /** Which process. */\n pid: number;\n /** Source. */\n source?: 'cli' | 'webui' | 'mcp' | 'acp' | 'http' | undefined;\n}\n\n// \u2500\u2500 Mailbox query \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxQuery {\n /** Filter by recipient agent id. */\n to?: string | undefined;\n /** Filter by sender agent id. */\n from?: string | undefined;\n /** Only messages unread by this agent. */\n unreadBy?: string | undefined;\n /** Only incomplete messages. */\n incompleteOnly?: boolean | undefined;\n /** Filter by message type. */\n type?: MailboxMessageType | undefined;\n /** Filter by priority (>= this level). */\n minPriority?: 'low' | 'normal' | 'high' | undefined;\n /** Maximum number of messages to return. */\n limit?: number | undefined;\n /** ISO8601 \u2014 only messages after this timestamp. */\n since?: string | undefined;\n /**\n * Include soft-deleted messages (where `deletedAt` is set). When\n * `false` (the default), soft-deleted messages are filtered out so\n * the normal inbox view stays clean. The \"trash\" view passes\n * `true` to surface them.\n */\n includeDeleted?: boolean | undefined;\n}\n\n// \u2500\u2500 Mailbox operations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Normalize a recipient address. `\"all\"` (any casing) is an accepted\n * spelling of the broadcast address and is canonicalized to `'*'` at send\n * time \u2014 both agents and humans reach for \"all\" naturally, and a literal\n * \"all\" recipient would otherwise be deliverable to nobody. The word is\n * therefore RESERVED: no agent may register under the base id \"all\".\n */\nexport function normalizeRecipient(to: string): string {\n return to.trim().toLowerCase() === 'all' ? '*' : to.trim();\n}\n\nexport interface MailboxSendInput {\n /** Sender agent id. */\n from: string;\n /** Recipient agent id, '*' for broadcast (alias: \"all\"). */\n to: string;\n /** Message category. */\n type: MailboxMessageType;\n /** Short subject line. */\n subject: string;\n /** Full message content. */\n body: string;\n /** Priority. Default: 'normal'. */\n priority?: 'low' | 'normal' | 'high' | undefined;\n /** If replying, the id of the parent message. */\n replyTo?: string | undefined;\n /** Task context for assign-type messages. */\n taskContext?: MailboxTaskContext | undefined;\n /**\n * Time-to-live in milliseconds. When set, the message's `expiresAt` is\n * computed as `now + ttlMs` at send time. The auto-compaction sweep\n * removes expired messages. Default: none (use compaction sweep default).\n */\n ttlMs?: number | undefined;\n}\n\n/**\n * Append-only ack record stored in the JSONL alongside messages.\n *\n * Instead of rewriting the entire mailbox file to mark a message as read or\n * completed, we append a small ack record. At read time, ack records are\n * folded into their target messages. The `__ack` discriminator distinguishes\n * ack records from regular messages.\n *\n * Compaction (autoCompact / purgeStale) folds these into the messages and\n * removes the ack lines from the file, keeping the file bounded.\n */\nexport interface AckRecord {\n /** Discriminator \u2014 always `true` to distinguish from MailboxMessage. */\n __ack: true;\n /** The message this ack applies to. */\n messageId: string;\n /** Agent acknowledging the message. */\n readerId: string;\n /** ISO8601 timestamp of the ack. */\n timestamp: string;\n /** Was the message read? */\n read: boolean;\n /** Was the message marked completed? */\n completed?: boolean | undefined;\n /** Who completed it (when completed === true). */\n completedBy?: string | undefined;\n /** Optional outcome summary. */\n outcome?: string | undefined;\n /**\n * Soft-delete or restore the target message.\n * - `true`: set `deletedAt`/`deletedBy` on the message\n * - `false`: clear `deletedAt`/`deletedBy` on the message\n * - `undefined`: not a delete/restore operation (backward-compat default)\n *\n * When `deleted` is `true`, `deletedBy` records who performed the delete.\n */\n deleted?: boolean | undefined;\n /** Who deleted the message (set when `deleted === true`). */\n deletedBy?: string | undefined;\n}\n\nexport interface MailboxAckInput {\n /** Message id to acknowledge. */\n messageId: string;\n /** Agent id of who is reading/acking. */\n readerId: string;\n /** Mark as read by this agent? Defaults to true if not specified. */\n read?: boolean | undefined;\n /** Mark as completed? */\n completed?: boolean | undefined;\n /** Optional outcome summary. */\n outcome?: string | undefined;\n}\n\n/**\n * Batch acknowledgment input \u2014 applies a batch of acks under a single file\n * lock + single file rewrite. Each entry has the same shape as\n * {@link MailboxAckInput} minus the per-batch defaults documented on\n * `ackMany`. Use this when an agent is acking several fresh messages at\n * once (the common case in the mailbox loop) \u2014 it collapses N full-file\n * rewrites into one.\n */\nexport interface MailboxAckBatchInput {\n /** Ack entries to apply. */\n acks: MailboxAckInput[];\n}\n\n// \u2500\u2500 Agent registration input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface AgentRegistrationInput {\n agentId: string;\n sessionId: string;\n name: string;\n role?: string | undefined;\n pid: number;\n source?: 'cli' | 'webui' | 'mcp' | 'acp' | 'http' | undefined;\n}\n\n// \u2500\u2500 Client (REPL/TUI/WebUI) registration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type ClientSource = 'repl' | 'tui' | 'webui' | 'http';\n\nexport interface RegisteredClient {\n /** Unique client id. */\n clientId: string;\n /** Session/project context id. */\n sessionId: string;\n /** Human-readable name (e.g. \"TUI [main]\", \"WebUI [chrome]\"). */\n name: string;\n /** Client type. */\n source: ClientSource;\n /** ISO8601 \u2014 registered at. */\n registeredAt: string;\n /** ISO8601 \u2014 last heartbeat. */\n lastSeenAt: string;\n /** Which process. */\n pid: number;\n}\n\nexport interface ClientStatus {\n /** Client id. */\n clientId: string;\n /** Human-readable name. */\n name: string;\n /** Client type. */\n source: ClientSource;\n /** Session id. */\n sessionId: string;\n /** ISO8601 \u2014 last activity timestamp. */\n lastSeenAt: string;\n /** Whether this client is currently online (heartbeat within threshold). */\n online: boolean;\n /** Which process. */\n pid: number;\n}\n\nexport interface ClientRegistrationInput {\n clientId: string;\n sessionId: string;\n name: string;\n source: ClientSource;\n pid: number;\n}\n\nexport interface ClientHeartbeatInput {\n clientId: string;\n /** Active session id for this client. When present, updates the registry entry. */\n sessionId?: string | undefined;\n}\n\n// \u2500\u2500 Agent heartbeat input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface AgentHeartbeatInput {\n agentId: string;\n status?: RegisteredAgent['status'] | undefined;\n currentTool?: string | undefined;\n currentTask?: string | undefined;\n iterations?: number | undefined;\n toolCalls?: number | undefined;\n}\n\n// \u2500\u2500 Purge options & result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface PurgeOptions {\n /**\n * Purge completed messages older than this many milliseconds.\n * Default: 1 day (86_400_000 ms)\n */\n completedMaxAgeMs?: number | undefined;\n /**\n * Purge incomplete messages older than this many milliseconds.\n * Default: 7 days (604_800_000 ms)\n */\n incompleteMaxAgeMs?: number | undefined;\n}\n\nexport interface PurgeResult {\n /** Messages removed because they were completed and too old. */\n completedPurged: number;\n /** Messages removed because they were incomplete and too old. */\n incompletePurged: number;\n /** Total messages removed. */\n totalPurged: number;\n /** Messages remaining in the mailbox after purge. */\n remaining: number;\n}\n\n// \u2500\u2500 Auto-compact options & result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface AutoCompactOptions {\n /**\n * Remove messages read by ALL currently-online agents that are older\n * than this many milliseconds since the last read receipt was stamped.\n * Default: 10 minutes (AUTO_COMPACT_READ_MAX_AGE_MS).\n */\n readMaxAgeMs?: number | undefined;\n /**\n * Default TTL for messages without an explicit `expiresAt`. Messages\n * whose `timestamp` is older than `now - defaultTtlMs` are removed.\n * Default: 24 hours (AUTO_COMPACT_DEFAULT_TTL_MS).\n */\n defaultTtlMs?: number | undefined;\n /**\n * Also run `purgeStale` logic in the same pass \u2014 purge completed\n * messages older than this many ms. Default: 1 day.\n */\n completedMaxAgeMs?: number | undefined;\n /**\n * Also run `purgeStale` logic in the same pass \u2014 purge incomplete\n * messages older than this many ms. Default: 7 days.\n */\n incompleteMaxAgeMs?: number | undefined;\n /**\n * Interval for the background auto-compact timer.\n * Default: 5 minutes (AUTO_COMPACT_INTERVAL_MS).\n */\n intervalMs?: number | undefined;\n /**\n * Also run `purgeStale` logic in the same pass (completed > 1 day,\n * incomplete > 7 days). Default: true.\n */\n includePurgeStale?: boolean | undefined;\n}\n\nexport interface AutoCompactResult {\n /** Messages removed because they were read by all online agents. */\n readByAllRemoved: number;\n /** Messages removed because their TTL expired (explicit or default). */\n expiredRemoved: number;\n /** Messages removed by the purgeStale pass (if enabled). */\n stalePurged: number;\n /** Total messages removed. */\n totalRemoved: number;\n /** Messages remaining in the mailbox after compaction. */\n remaining: number;\n}\n\n// \u2500\u2500 Mailbox interface \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface Mailbox {\n /** Send a message. Returns the created message. */\n send(input: MailboxSendInput): Promise<MailboxMessage>;\n\n /** Query messages matching criteria. */\n query(query: MailboxQuery): Promise<MailboxMessage[]>;\n\n /** Acknowledge a message (read/complete). Returns updated message. */\n ack(input: MailboxAckInput): Promise<MailboxMessage | null>;\n\n /**\n * Acknowledge many messages in one shot. Acquires the file lock once and\n * rewrites the message file once, regardless of how many acks are in the\n * batch. Returns the messages that were actually updated (messages whose\n * ids are not in the file are skipped silently).\n *\n * This is the preferred path when an agent has multiple fresh messages\n * to receipt at once \u2014 the per-message {@link ack} path does a full\n * read-modify-rewrite of the mailbox file for every call.\n */\n ackMany(input: MailboxAckBatchInput): Promise<MailboxMessage[]>;\n\n /**\n * Soft-delete a message. Sets `deletedAt` to the current timestamp\n * and records the acting agent in `deletedBy`. Reversible via\n * {@link restore}. The default `query()` filter hides the message\n * once `deletedAt` is set; pass `includeDeleted: true` to see the\n * trash.\n */\n softDelete(mailId: string, by: string): Promise<MailboxMessage | null>;\n\n /**\n * Undo a {@link softDelete}. Clears `deletedAt` and `deletedBy` on\n * the message. No-op (returns the message as-is) if the message is\n * not soft-deleted.\n */\n restore(mailId: string): Promise<MailboxMessage | null>;\n\n /** Get a snapshot of online/offline agents and their current tasks. */\n getAgentStatuses(): Promise<MailboxAgentStatus[]>;\n\n /**\n * Get only online agents (heartbeat within 60s).\n * Useful for \"who can I talk to right now?\" queries.\n */\n getOnlineAgents(): Promise<MailboxAgentStatus[]>;\n\n /**\n * Register an agent. Called once per agent on first mailbox use.\n * Subsequent calls are idempotent \u2014 they update lastSeenAt.\n */\n registerAgent(input: AgentRegistrationInput): Promise<void>;\n /** Remove an agent from the registry entirely. Called on session shutdown. */\n deregisterAgent(agentId: string): Promise<void>;\n\n /**\n * Update agent heartbeat and optional status fields.\n * Called periodically (every tool call / iteration).\n */\n heartbeat(input: AgentHeartbeatInput): Promise<void>;\n\n /**\n * Count unread messages for a specific agent.\n * Used for \"new mail\" notifications without pulling full message bodies.\n */\n unreadCount(forAgentId: string): Promise<number>;\n\n /** Close and flush any pending writes. */\n close(): Promise<void>;\n\n /**\n * Delete all messages from the mailbox file.\n * Agents and read receipts are preserved; only messages are cleared.\n */\n clearAll(): Promise<void>;\n\n /**\n * Purge orphaned and stale messages from the mailbox.\n *\n * Stale messages are:\n * - Completed messages older than `completedMaxAgeMs` (default: 1 day)\n * - Incomplete messages older than `incompleteMaxAgeMs` (default: 7 days)\n *\n * This does NOT touch agent registrations or client registry.\n */\n purgeStale(opts?: PurgeOptions): Promise<PurgeResult>;\n\n /**\n * Auto-compact: remove messages that are no longer needed.\n *\n * Two cleanup passes run in a single file rewrite:\n * 1. **Read-by-all**: Messages read by every currently-online agent,\n * older than `readMaxAgeMs` (default 10 min).\n * 2. **Expired**: Messages whose `expiresAt` is in the past, or whose\n * `timestamp` is older than `defaultTtlMs` (default 24h) when no\n * explicit `expiresAt` is set.\n *\n * Also runs `purgeStale` logic (completed > 1 day, incomplete > 7 days)\n * in the same pass to avoid a second rewrite.\n */\n autoCompact(opts?: AutoCompactOptions): Promise<AutoCompactResult>;\n\n /**\n * Start a background timer that periodically calls `autoCompact`.\n * Returns a dispose function that stops the timer. Idempotent \u2014\n * calling start twice replaces the prior timer.\n */\n startAutoCompactTimer(opts?: AutoCompactOptions): () => void;\n\n // \u2500\u2500 Client (REPL/TUI/WebUI) registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Register a client (REPL/TUI/WebUI). Called once per client on startup.\n * Subsequent calls are idempotent \u2014 they update lastSeenAt.\n */\n registerClient(input: ClientRegistrationInput): Promise<void>;\n\n /**\n * Update client heartbeat. Called periodically (every 15s for clients).\n */\n clientHeartbeat(input: ClientHeartbeatInput): Promise<void>;\n\n /** Remove a client immediately on clean shutdown. */\n deregisterClient(clientId: string): Promise<void>;\n\n /**\n * Get snapshot of online/offline clients and their last activity.\n */\n getClientStatuses(): Promise<ClientStatus[]>;\n\n /**\n * Explicitly purge stale clients from the registry.\n * Removes client entries whose lastSeenAt is older than CLIENT_STALE_MS.\n * Returns the number of entries purged.\n */\n purgeClients(): Promise<number>;\n}\n", "/**\n * HQ auth-store \u2014 persistent `auth.json` for the HQ command center.\n *\n * Holds:\n * - Operator-configured redaction policy override (applied server-side\n * even when a publisher claims rawContent:true).\n * - Browser tokens + client tokens. Separate lists so a browser-only token\n * cannot be replayed on /ws/client and vice versa.\n * - Operator-configured alert-rule thresholds (`alertRules`), live-reloaded.\n * - Live reload hook: callers can `watchHqAuthFile()` to re-read on change.\n *\n * Storage layout (under the HQ data directory, default `~/.wrongstack/hq/`):\n * <dataDir>/auth.json \u2014 this file (atomic write, mode 0o600)\n * <dataDir>/events.jsonl \u2014 persistent event log (rotated)\n * <dataDir>/snapshot.json \u2014 persisted latest snapshot (cache)\n *\n * The file is written atomically (tmp + rename) with mode 0o600 so a\n * shared host cannot read issued tokens or the redaction policy. Reads\n * are lenient: a missing file yields an empty document; a corrupt file\n * yields an empty document plus a warning so the operator can recover.\n *\n * @module hq/auth-store\n */\nimport { randomBytes, randomUUID, scrypt, timingSafeEqual } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as syncFs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { atomicWrite } from '../utils/atomic-write.js';\nimport { wstackGlobalRoot } from '../utils/wstack-paths.js';\nimport type { HqAlertRuleConfig } from './alerts.js';\nimport type { HqRedactionPolicy } from './protocol.js';\n\n/** Current auth-file schema version. Bump on breaking shape changes. */\nexport const HQ_AUTH_FILE_VERSION = 1 as const;\n\n/** Default HQ data directory: `~/.wrongstack/hq` (honors WRONGSTACK_HOME). */\nexport function defaultHqDataDir(): string {\n return path.join(wstackGlobalRoot(), 'hq');\n}\n\n/**\n * Resolve an HQ data directory from an optional override.\n *\n * Resolution order:\n * 1. Explicit `override` (from `--data-dir`) \u2014 resolved against\n * `process.cwd()` if relative.\n * 2. `WRONGSTACK_HQ_DATA_DIR` env var (same resolution rules).\n * 3. `defaultHqDataDir()` \u2014 `~/.wrongstack/hq`.\n *\n * The env var exists so tests (and sandboxed runs) can redirect HQ state\n * away from the real user home without threading a CLI flag everywhere.\n */\nexport function resolveHqDataDir(override?: string, env: NodeJS.ProcessEnv = process.env): string {\n const raw = override ?? env['WRONGSTACK_HQ_DATA_DIR']?.trim();\n if (!raw) return defaultHqDataDir();\n return path.isAbsolute(raw) ? path.resolve(raw) : path.resolve(process.cwd(), raw);\n}\n\n/**\n * A generic HQ-issued token. Used for both browser tokens (validated on\n * `/ws/browser`) and client tokens (validated on `/ws/client`). The two\n * are stored in separate lists so a browser-only token cannot be replayed\n * against the client channel and vice versa.\n *\n * `capabilities` scopes what a token may do. When absent the token is\n * unrestricted (backward-compat with tokens minted before Phase 3). Known\n * capability strings:\n * - `control.enqueue` \u2014 browser token may enqueue commands to clients\n * - `control.execute` \u2014 client token may execute `run-command` commands\n * - `telemetry.publish` \u2014 client token may publish telemetry\n */\nexport interface HqToken {\n id: string;\n token: string;\n label?: string;\n createdAt: string;\n lastUsedAt?: string;\n /**\n * Optional capability scope. When absent, the token is unrestricted\n * (backward-compat). When present, only the listed capabilities are\n * granted.\n */\n capabilities?: string[];\n}\n\n/**\n * Check whether a token grants a capability. A token with no `capabilities`\n * field is unrestricted (backward-compat). Otherwise the capability must be\n * explicitly listed.\n */\nexport function tokenHasCapability(token: HqToken | undefined, capability: string): boolean {\n if (token === undefined) return false;\n if (token.capabilities === undefined) return true;\n return token.capabilities.includes(capability);\n}\n\n/**\n * Alias kept for backward-compat with Phase 3 callers/tests. New code\n * should prefer `HqToken`.\n */\nexport type HqBrowserToken = HqToken;\n\n/** On-disk shape of `<dataDir>/auth.json`. */\nexport interface HqRuntimeFile {\n url: string;\n updatedAt: string;\n pid?: number;\n}\n\nexport interface HqAuthFile {\n version: typeof HQ_AUTH_FILE_VERSION;\n updatedAt: string;\n /**\n * Operator-configured redaction policy override. When present, the HQ\n * server applies these settings AFTER any publisher-declared policy \u2014\n * i.e. the operator can always tighten, never loosen.\n */\n redactionPolicy?: Partial<HqRedactionPolicy>;\n /** Browser tokens \u2014 validated on `/ws/browser` upgrades (Phase 3). */\n browserTokens?: HqToken[];\n /** Client tokens \u2014 validated on `/ws/client` upgrades (Phase 4). */\n clientTokens?: HqToken[];\n /** scrypt hash of the optional browser password login. */\n passwordHash?: string;\n /** Secret used to sign browser session cookies. */\n cookieSecret?: string;\n /**\n * Operator-configured alert-rule thresholds. When present, these override\n * the built-in defaults for the alert engine (cost ceiling, stale-machine\n * window, concurrency limit). Live-reloaded with the rest of the file.\n */\n alertRules?: HqAlertRuleConfig;\n}\n\n/** An empty auth file \u2014 what a brand-new HQ install starts with. */\nexport function emptyHqAuthFile(): HqAuthFile {\n return {\n version: HQ_AUTH_FILE_VERSION,\n updatedAt: new Date().toISOString(),\n };\n}\n\n/** Path to `auth.json` under the given data directory. */\nexport function hqAuthFilePath(dataDir: string): string {\n return path.join(dataDir, 'auth.json');\n}\n\n/** Path to the best-effort runtime endpoint marker under the given data directory. */\nexport function hqRuntimeFilePath(dataDir: string): string {\n return path.join(dataDir, 'runtime.json');\n}\n\nexport async function writeHqRuntimeFile(dataDir: string, file: Omit<HqRuntimeFile, 'updatedAt'>): Promise<void> {\n const payload: HqRuntimeFile = {\n ...file,\n updatedAt: new Date().toISOString(),\n };\n await atomicWrite(hqRuntimeFilePath(dataDir), `${JSON.stringify(payload, null, 2)}\\n`, { mode: 0o600 });\n}\n\nfunction isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readHqRuntimeFileSync(dataDir: string): HqRuntimeFile | undefined {\n try {\n const parsed = JSON.parse(syncFs.readFileSync(hqRuntimeFilePath(dataDir), 'utf8')) as Partial<HqRuntimeFile>;\n if (typeof parsed.url !== 'string' || parsed.url.trim().length === 0) return undefined;\n if (typeof parsed.pid === 'number' && !isProcessAlive(parsed.pid)) return undefined;\n return {\n url: parsed.url,\n updatedAt: typeof parsed.updatedAt === 'string' ? parsed.updatedAt : '',\n ...(typeof parsed.pid === 'number' ? { pid: parsed.pid } : {}),\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Read `auth.json` from disk. Returns `emptyHqAuthFile()` when the file does\n * NOT exist (ENOENT) \u2014 the only case treated as intentional open mode.\n *\n * Throws for all other read failures (EACCES, EIO, etc.), malformed JSON,\n * and unsupported schema versions. A corrupt or unreadable auth file must\n * never silently open the server.\n *\n * Callers that want to handle errors gracefully (e.g. the live-reload\n * watcher which should preserve the last-known-good state) should catch\n * the thrown error.\n */\nexport async function readHqAuthFile(\n dataDir: string,\n _opts: { warn?: (msg: string) => void } = {},\n): Promise<HqAuthFile> {\n const file = hqAuthFilePath(dataDir);\n let raw: string;\n try {\n raw = await fs.readFile(file, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return emptyHqAuthFile();\n // Non-ENOENT (EACCES, EIO, \u2026) \u2014 fail closed.\n throw new Error(\n `HQ auth file at ${file} cannot be read: ${(err as Error).message}. ` +\n 'Fix the file permissions or delete it to start with an empty auth state.',\n );\n }\n let parsed: HqAuthFile;\n try {\n parsed = JSON.parse(raw) as HqAuthFile;\n } catch (err) {\n throw new Error(\n `HQ auth file at ${file} is not valid JSON: ${(err as Error).message}. ` +\n 'Fix the file or delete it to start with an empty auth state.',\n );\n }\n if (parsed.version !== HQ_AUTH_FILE_VERSION) {\n throw new Error(\n `HQ auth file at ${file} has unsupported version ${String(parsed.version)} ` +\n `(expected ${String(HQ_AUTH_FILE_VERSION)}). ` +\n 'Remove or update the file to match the current schema version.',\n );\n }\n return parsed;\n}\n\n/**\n * Write `auth.json` atomically with mode 0o600. Creates the data directory\n * if needed. Throws on I/O failure \u2014 callers (CLI commands) should surface\n * the error to the operator.\n */\nexport async function writeHqAuthFile(dataDir: string, file: HqAuthFile): Promise<void> {\n const target = hqAuthFilePath(dataDir);\n const payload: HqAuthFile = {\n ...file,\n version: HQ_AUTH_FILE_VERSION,\n updatedAt: new Date().toISOString(),\n };\n await atomicWrite(target, `${JSON.stringify(payload, null, 2)}\\n`, { mode: 0o600 });\n}\n\nexport interface EnsureHqFirstRunAuthOptions {\n warn?: (msg: string) => void;\n /** Optional browser password login. Hashed with scrypt before storage. */\n password?: string;\n}\n\nexport interface EnsureHqFirstRunAuthResult {\n authFile: HqAuthFile;\n created: boolean;\n browserToken?: HqToken;\n clientToken?: HqToken;\n}\n\n/**\n * Ensure a brand-new HQ data directory has the auth required for safe\n * first-run operation. Only a missing auth.json is bootstrapped; an existing\n * file, including one with empty token arrays, is treated as operator intent.\n */\nexport async function ensureHqFirstRunAuthFile(\n dataDir: string,\n opts: EnsureHqFirstRunAuthOptions = {},\n): Promise<EnsureHqFirstRunAuthResult> {\n const file = hqAuthFilePath(dataDir);\n try {\n await fs.access(file);\n return { authFile: await readHqAuthFile(dataDir, opts), created: false };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n opts.warn?.(`HQ auth file access failed at ${file}: ${(err as Error).message}`);\n return { authFile: await readHqAuthFile(dataDir, opts), created: false };\n }\n }\n\n // First-run credentials are deliberately least-privilege. Operators can\n // mint an execution-capable client token explicitly when remote command\n // execution is required; a freshly started HQ must never grant it by\n // accident.\n const browserToken = { ...mintHqToken('first-run browser'), capabilities: ['control.enqueue'] };\n const clientToken = { ...mintHqToken('first-run client'), capabilities: ['telemetry.publish'] };\n const authFile: HqAuthFile = {\n version: HQ_AUTH_FILE_VERSION,\n updatedAt: new Date().toISOString(),\n browserTokens: [browserToken],\n clientTokens: [clientToken],\n };\n if (opts.password) {\n authFile.passwordHash = await hashHqPassword(opts.password);\n authFile.cookieSecret = mintHqCookieSecret();\n }\n await writeHqAuthFile(dataDir, authFile);\n return { authFile: await readHqAuthFile(dataDir, opts), created: true, browserToken, clientToken };\n}\n\n/**\n * Load \u2192 mutate \u2192 write. The mutator receives the current file (or an empty\n * one) and returns the next file. Use this for any read-modify-write cycle\n * to avoid clobbering concurrent edits from another CLI invocation.\n *\n * Note: this does NOT take a file lock. HQ auth edits are rare (operator\n * running `wstack --hq-token add` etc.) and the atomic rename protects\n * against torn writes; a race between two concurrent edits would be\n * last-write-wins, which is acceptable for this low-frequency file.\n */\nexport async function mutateHqAuthFile(\n dataDir: string,\n mutator: (current: HqAuthFile) => HqAuthFile | Promise<HqAuthFile>,\n opts: { warn?: (msg: string) => void } = {},\n): Promise<HqAuthFile> {\n const current = await readHqAuthFile(dataDir, opts);\n const next = await mutator(current);\n await writeHqAuthFile(dataDir, next);\n return next;\n}\n\nconst HQ_PASSWORD_SALT_BYTES = 16;\nconst HQ_PASSWORD_HASH_BYTES = 32;\nconst HQ_PASSWORD_SCRYPT_PARAMS = { N: 16384, r: 8, p: 1 };\n\n/**\n * Hash a browser password for storage in `auth.json`. Uses scrypt with a\n * random salt; the returned string is `scrypt$<salt>$<hash>` in base64url.\n */\nexport function hashHqPassword(password: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const salt = randomBytes(HQ_PASSWORD_SALT_BYTES);\n scrypt(password, salt, HQ_PASSWORD_HASH_BYTES, HQ_PASSWORD_SCRYPT_PARAMS, (err, derivedKey) => {\n if (err) return reject(err);\n const payload = `scrypt$${salt.toString('base64url')}$${derivedKey.toString('base64url')}`;\n resolve(payload);\n });\n });\n}\n\n/**\n * Verify a browser password against a stored scrypt hash.\n */\nexport async function verifyHqPassword(password: string, hash: string): Promise<boolean> {\n const parts = hash.split('$');\n if (parts.length !== 3 || parts[0] !== 'scrypt' || !parts[1] || !parts[2]) return false;\n let salt: Buffer;\n let expected: Buffer;\n try {\n salt = Buffer.from(parts[1], 'base64url');\n expected = Buffer.from(parts[2], 'base64url');\n } catch {\n return false;\n }\n if (salt.length === 0 || expected.length === 0) return false;\n const derived = await new Promise<Buffer>((resolve, reject) => {\n scrypt(password, salt, expected.length, HQ_PASSWORD_SCRYPT_PARAMS, (err, key) => {\n if (err) reject(err);\n else resolve(key);\n });\n });\n return timingSafeEqual(derived, expected);\n}\n\n/** Mint a secret used to sign browser session cookies. */\nexport function mintHqCookieSecret(): string {\n return randomBytes(32).toString('base64url');\n}\n\n/**\n * Mint a fresh token. Used for both browser and client tokens; the caller\n * decides which list to append to.\n */\nexport function mintHqToken(label?: string): HqToken {\n const now = new Date().toISOString();\n return {\n id: randomUUID(),\n token: randomUUID().replace(/-/g, '') + randomUUID().replace(/-/g, ''),\n ...(label ? { label } : {}),\n createdAt: now,\n };\n}\n\n/**\n * Backward-compat alias for `mintHqToken`. Phase 3 callers/tests use this.\n */\nexport const mintHqBrowserToken = mintHqToken;\n\n/**\n * Watch `auth.json` for changes and invoke `onChange` with the freshly-read\n * file. Returns a `close()` function that stops watching.\n *\n * The watcher debounces events (default 200ms) because most editors do a\n * tmp+rename dance that emits multiple events. On any read failure (file\n * deleted, corrupt, etc.) the `warn` callback is invoked with the same\n * semantics as `readHqAuthFile`; the watcher stays active so a future\n * valid write re-triggers the callback.\n *\n * Notes:\n * - `fs.watch` is best-effort across platforms. On some network\n * filesystems events may not fire; the operator must restart the server\n * to pick up changes in that case.\n * - The watcher polls the parent directory (not the file itself) so that\n * atomic rename events surface reliably.\n */\nexport function watchHqAuthFile(\n dataDir: string,\n onChange: (file: HqAuthFile) => void,\n opts: { warn?: (msg: string) => void; debounceMs?: number } = {},\n): { close: () => void } {\n const file = hqAuthFilePath(dataDir);\n const debounceMs = opts.debounceMs ?? 200;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let closed = false;\n\n let watcher: syncFs.FSWatcher;\n try {\n // Watch the directory (not the file) so atomic-rename events surface\n // reliably. `fs.watch` is best-effort across platforms \u2014 on some\n // network filesystems events may not fire; the operator must restart\n // the server in that case.\n watcher = syncFs.watch(path.dirname(file), { recursive: false });\n } catch (err) {\n opts.warn?.(`HQ auth watcher could not start: ${(err as Error).message}`);\n return { close: () => {} };\n }\n\n const trigger = (): void => {\n if (closed) return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = undefined;\n const readOpts = opts.warn ? { warn: opts.warn } : {};\n void readHqAuthFile(dataDir, readOpts).then(\n (next) => {\n if (!closed) onChange(next);\n },\n () => {\n // readHqAuthFile never throws for routine I/O \u2014 this is a\n // belt-and-braces guard.\n },\n );\n }, debounceMs);\n };\n\n watcher.on('change', (eventType: string, filename: string | Buffer | null) => {\n const name = typeof filename === 'string' ? filename : '';\n // Only react to events that touch auth.json (rename, change).\n if (eventType === 'rename' || eventType === 'change') {\n if (!name || name === 'auth.json' || name === path.basename(file)) {\n trigger();\n }\n }\n });\n\n watcher.on('error', (err: Error) => {\n opts.warn?.(`HQ auth watcher error: ${err.message}`);\n });\n\n return {\n close: () => {\n closed = true;\n if (timer) clearTimeout(timer);\n watcher.close();\n },\n };\n}\n", "/**\n * SessionTelemetryBridge \u2014 streams a surface's own live session state and full\n * chat transcript to HQ over the `/ws/client` plane, so the command center can\n * render every machine \u2192 terminal \u2192 agent \u2192 full-history across all connected\n * machines (not only the one HQ runs on).\n *\n * Two streams, both best-effort and self-contained:\n * 1. `session.snapshot` \u2014 the terminal's live state + agents, sourced from the\n * in-process `session.agents_updated` bus event (no registry file reads).\n * 2. `session.transcript` \u2014 incremental conversation turns, tailed cheaply\n * from this process's own session JSONL by byte offset.\n *\n * @module hq/session-bridge\n */\nimport * as fs from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport type { EventBus, TrackedAgentSnapshot } from '../kernel/events.js';\nimport { sessionScopedPath } from '../utils/session-scoped-path.js';\nimport { resolveWstackPaths } from '../utils/wstack-paths.js';\nimport type {\n HqSessionAgentLiveStatus,\n HqSessionAgentSummary,\n HqSessionLiveStatus,\n HqSessionSnapshotPayload,\n HqTranscriptEntry,\n} from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\nimport { mapSessionEventToEntries } from './transcript-mapper.js';\n\nexport interface SessionTelemetryBridgeOptions {\n publisher: HqPublisher;\n /** Local bus carrying `session.agents_updated`. When omitted, snapshots\n * still publish (with empty/last-known agents) and the transcript still\n * streams from disk. */\n events?: EventBus | undefined;\n sessionId: string;\n projectRoot: string;\n projectName?: string | undefined;\n /** Override the global root used to resolve the session JSONL path. */\n globalRoot?: string | undefined;\n /** Last-known agents to publish immediately before the next bus update. */\n initialAgents?: readonly TrackedAgentSnapshot[] | undefined;\n gitBranch?: string | undefined;\n startedAt?: string | undefined;\n /** Snapshot republish interval (also refreshes lastActivity). Default 2500ms. */\n snapshotIntervalMs?: number | undefined;\n /** Transcript tail poll interval. Default 1200ms. */\n transcriptIntervalMs?: number | undefined;\n now?: (() => string) | undefined;\n}\n\nconst VALID_AGENT_STATUS = new Set<HqSessionAgentLiveStatus>([\n 'idle',\n 'running',\n 'streaming',\n 'waiting_user',\n 'error',\n]);\nconst MAX_TRANSCRIPT_BATCH_ENTRIES = 32;\nconst MAX_TRANSCRIPT_BATCH_BYTES = 512 * 1024;\n\nfunction toAgentSummary(a: TrackedAgentSnapshot): HqSessionAgentSummary {\n const status = (\n VALID_AGENT_STATUS.has(a.status as HqSessionAgentLiveStatus) ? a.status : 'idle'\n ) as HqSessionAgentLiveStatus;\n return {\n id: a.id,\n name: a.name,\n status,\n iterations: a.iterations,\n toolCalls: a.toolCalls,\n lastActivityAt: a.lastActivityAt,\n ...(a.startedAt !== undefined ? { startedAt: a.startedAt } : {}),\n ...(a.currentTool !== undefined ? { currentTool: a.currentTool } : {}),\n ...(a.costUsd !== undefined ? { costUsd: a.costUsd } : {}),\n ...(a.tokensIn !== undefined ? { tokensIn: a.tokensIn } : {}),\n ...(a.tokensOut !== undefined ? { tokensOut: a.tokensOut } : {}),\n ...(a.ctxPct !== undefined ? { ctxPct: a.ctxPct } : {}),\n ...(a.model !== undefined ? { model: a.model } : {}),\n ...(a.partialText !== undefined ? { partialText: a.partialText } : {}),\n };\n}\n\nfunction deriveSessionStatus(agents: readonly HqSessionAgentSummary[]): HqSessionLiveStatus {\n return agents.some(\n (a) => a.status === 'running' || a.status === 'streaming' || a.status === 'waiting_user',\n )\n ? 'active'\n : 'idle';\n}\n\n/**\n * Start streaming this surface's session telemetry to HQ. Returns a disposer\n * that stops both streams and publishes a final `session.ended`.\n */\nexport function startSessionTelemetryBridge(opts: SessionTelemetryBridgeOptions): () => void {\n const now = opts.now ?? (() => new Date().toISOString());\n const publisher = opts.publisher;\n const identity = publisher.identity;\n const project = publisher.project;\n const startedAt = opts.startedAt ?? now();\n\n const wpaths = resolveWstackPaths({\n projectRoot: opts.projectRoot,\n ...(opts.globalRoot !== undefined ? { globalRoot: opts.globalRoot } : {}),\n });\n const sessionFile = sessionScopedPath(wpaths.projectSessions, opts.sessionId, '.jsonl');\n\n let agents: HqSessionAgentSummary[] = (opts.initialAgents ?? []).map(toAgentSummary);\n let lastActivityAt = agents.reduce(\n (latest, agent) => agent.lastActivityAt > latest ? agent.lastActivityAt : latest,\n startedAt,\n );\n let lastSnapshotHash = '';\n let disposed = false;\n\n function buildSnapshot(): HqSessionSnapshotPayload {\n return {\n sessionId: opts.sessionId,\n clientKind: identity.kind,\n machineId: identity.machineId,\n projectId: project.projectId,\n projectName: opts.projectName ?? project.projectName,\n projectRoot: opts.projectRoot,\n status: deriveSessionStatus(agents),\n startedAt,\n lastActivityAt,\n agentCount: agents.length,\n agents,\n ...(identity.hostname !== undefined ? { hostname: identity.hostname } : {}),\n ...(identity.pid !== undefined ? { pid: identity.pid } : {}),\n ...(opts.gitBranch !== undefined ? { gitBranch: opts.gitBranch } : {}),\n };\n }\n\n function publishSnapshot(force = false): void {\n if (disposed) return;\n const snap = buildSnapshot();\n // Hash on everything except lastActivityAt so identical state isn't\n // republished by the heartbeat tick, but real changes always go out.\n const hash = JSON.stringify({ ...snap, lastActivityAt: '' });\n if (!force && hash === lastSnapshotHash) return;\n lastSnapshotHash = hash;\n try {\n publisher.publishSessionSnapshot(snap);\n } catch {\n /* best-effort */\n }\n }\n\n function publishTranscriptEntries(entries: HqTranscriptEntry[]): void {\n let batch: HqTranscriptEntry[] = [];\n let batchFromSeq = seqEmitted;\n\n const publishBatch = (): void => {\n if (batch.length === 0) return;\n try {\n publisher.publishTranscriptAppend({\n sessionId: opts.sessionId,\n fromSeq: batchFromSeq,\n entries: batch,\n });\n } catch {\n /* best-effort */\n }\n seqEmitted += batch.length;\n batch = [];\n batchFromSeq = seqEmitted;\n };\n\n for (const entry of entries) {\n const candidate = [...batch, entry];\n const candidatePayload = {\n sessionId: opts.sessionId,\n fromSeq: batchFromSeq,\n entries: candidate,\n };\n const tooManyEntries = candidate.length > MAX_TRANSCRIPT_BATCH_ENTRIES;\n const tooLarge =\n batch.length > 0 &&\n Buffer.byteLength(JSON.stringify(candidatePayload), 'utf8') >\n MAX_TRANSCRIPT_BATCH_BYTES;\n if (tooManyEntries || tooLarge) publishBatch();\n batch.push(entry);\n }\n\n publishBatch();\n }\n\n const offAgents = opts.events?.on('session.agents_updated', (payload) => {\n agents = payload.agents.map(toAgentSummary);\n lastActivityAt = now();\n publishSnapshot();\n });\n\n // Announce the terminal immediately so its node appears even before any\n // agent activity.\n publishSnapshot(true);\n\n // \u2500\u2500 Transcript tail \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let offset = 0;\n let partial = '';\n let seqEmitted = 0;\n let tailing = false;\n let watcher: fs.FSWatcher | null = null;\n let watchPending = false;\n\n // Once the session file exists, watch it so new turns are streamed within\n // milliseconds of being written \u2014 the interval poll is only a safety net.\n function setupWatcher(): void {\n if (disposed || watcher) return;\n try {\n const nextWatcher = fs.watch(sessionFile, () => {\n if (watchPending || disposed) return;\n watchPending = true;\n setTimeout(() => {\n watchPending = false;\n void tail();\n }, 25);\n });\n // fs.watch surfaces transient failures (EPERM/ENOENT on rename/delete,\n // common on Windows) as async 'error' events \u2014 swallow them so they\n // never become uncaught exceptions. The interval poll keeps us live.\n nextWatcher.on('error', () => {\n try {\n nextWatcher.close();\n } catch {\n /* ignore */\n }\n if (watcher === nextWatcher) watcher = null;\n });\n watcher = nextWatcher;\n } catch {\n watcher = null;\n }\n }\n\n async function tail(): Promise<void> {\n if (disposed || tailing) return;\n tailing = true;\n try {\n const stat = await fsp.stat(sessionFile).catch(() => null);\n if (disposed) return;\n if (!stat) return;\n setupWatcher();\n if (stat.size <= offset) return;\n const fd = await fsp.open(sessionFile, 'r');\n try {\n if (disposed) return;\n const len = stat.size - offset;\n const buf = Buffer.allocUnsafe(len);\n await fd.read(buf, 0, len, offset);\n offset = stat.size;\n partial += buf.toString('utf8');\n const lines = partial.split('\\n');\n partial = lines.pop() ?? '';\n const entries: HqTranscriptEntry[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n let obj: Record<string, unknown>;\n try {\n obj = JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n continue;\n }\n for (const entry of mapSessionEventToEntries(obj)) entries.push(entry);\n }\n if (entries.length > 0) {\n publishTranscriptEntries(entries);\n lastActivityAt = now();\n }\n } finally {\n await fd.close();\n }\n } catch {\n /* best-effort */\n } finally {\n tailing = false;\n }\n }\n\n const snapshotTimer = setInterval(() => publishSnapshot(true), opts.snapshotIntervalMs ?? 2500);\n const tailTimer = setInterval(() => void tail(), opts.transcriptIntervalMs ?? 500);\n snapshotTimer.unref?.();\n tailTimer.unref?.();\n void tail();\n\n return () => {\n if (disposed) return;\n disposed = true;\n offAgents?.();\n if (watcher) {\n try {\n watcher.close();\n } catch {\n /* ignore */\n }\n watcher = null;\n }\n clearInterval(snapshotTimer);\n clearInterval(tailTimer);\n try {\n publisher.publishSessionEnded({ sessionId: opts.sessionId, endedAt: now() });\n } catch {\n /* best-effort */\n }\n };\n}\n", "/**\n * Transcript mapper \u2014 converts raw session JSONL events into the canonical\n * {@link HqTranscriptEntry} shape used by HQ for full chat-history rendering.\n *\n * On-disk reality (see `types/session.ts` + `core/agent-tools.ts`):\n * - A tool CALL (with its arguments) is NOT a standalone event \u2014 it is a\n * `tool_use` content block inside the assistant's `llm_response`.\n * - The tool RESULT is a separate `tool_result` event carrying the matching\n * `id`.\n * So we extract each `tool_use` block as a tool entry (args) at the assistant's\n * position, then merge the later `tool_result` (matched by `id`) INTO that same\n * entry \u2014 giving one box per tool (args + result) in strict chronological order.\n *\n * @module hq/transcript-mapper\n */\nimport type { HqTranscriptEntry, HqTranscriptRole } from './protocol.js';\n\nfunction blocksToText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .filter(\n (b): b is { type: string; text: string } =>\n !!b &&\n typeof b === 'object' &&\n (b as { type?: unknown }).type === 'text' &&\n typeof (b as { text?: unknown }).text === 'string',\n )\n .map((b) => b.text)\n .join('\\n');\n }\n return '';\n}\n\nfunction asString(v: unknown): string {\n if (typeof v === 'string') return v;\n try {\n return JSON.stringify(v, null, 2);\n } catch {\n return String(v);\n }\n}\n\nfunction argsEntry(ts: string, name: unknown, input: unknown, id: unknown): HqTranscriptEntry {\n return {\n ts,\n role: 'tool',\n tool: String(name ?? 'tool'),\n toolInput: input !== undefined && input !== null ? asString(input) : '{}',\n text: '',\n ...(typeof id === 'string' ? { toolUseId: id } : {}),\n };\n}\n\n/**\n * Map a single raw JSONL session event to zero or more transcript entries.\n * An `llm_response` can yield an assistant text entry PLUS one tool entry per\n * embedded `tool_use` block.\n */\nexport function mapSessionEventToEntries(ev: Record<string, unknown>): HqTranscriptEntry[] {\n const ts = typeof ev['ts'] === 'string' ? (ev['ts'] as string) : '';\n const make = (\n role: HqTranscriptRole,\n text: string,\n extra?: Partial<HqTranscriptEntry>,\n ): HqTranscriptEntry => ({\n ts,\n role,\n text,\n ...extra,\n });\n\n switch (ev['type']) {\n case 'user_input': {\n const t = blocksToText(ev['content']);\n return t.trim() ? [make('user', t)] : [];\n }\n case 'llm_response': {\n const out: HqTranscriptEntry[] = [];\n const content = ev['content'];\n // Thinking blocks precede text/tool_use in an assistant message (provider\n // contract) \u2014 surface them first so the transcript preserves that order.\n if (Array.isArray(content)) {\n const thinking = content\n .filter(\n (b): b is { type: string; thinking: string } =>\n !!b &&\n typeof b === 'object' &&\n (b as { type?: unknown }).type === 'thinking' &&\n typeof (b as { thinking?: unknown }).thinking === 'string',\n )\n .map((b) => b.thinking)\n .join('\\n');\n if (thinking.trim()) out.push(make('thinking', thinking));\n }\n const t = blocksToText(content);\n if (t.trim()) out.push(make('assistant', t));\n if (Array.isArray(content)) {\n for (const b of content) {\n if (b && typeof b === 'object' && (b as { type?: unknown }).type === 'tool_use') {\n const block = b as { id?: unknown; name?: unknown; input?: unknown };\n out.push(argsEntry(ts, block.name, block.input, block.id));\n }\n }\n }\n return out;\n }\n case 'tool_use':\n return [argsEntry(ts, ev['name'], ev['input'], ev['id'])];\n case 'tool_call_start':\n return [argsEntry(ts, ev['name'], ev['input'] ?? ev['args'], ev['id'])];\n case 'tool_result': {\n const isError = ev['isError'] === true;\n const content = ev['content'] ?? ev['output'];\n const outStr = content !== undefined && content !== null ? asString(content) : '';\n return [\n make(isError ? 'error' : 'tool', outStr, {\n tool: '\u21B3 result',\n ...(isError ? { isError: true } : {}),\n ...(typeof ev['id'] === 'string' ? { toolUseId: ev['id'] } : {}),\n }),\n ];\n }\n case 'tool_call_end': {\n const isError = ev['isError'] === true;\n const content = ev['output'] ?? ev['content'];\n const outStr = content !== undefined && content !== null ? asString(content) : '';\n if (!outStr.trim() && !isError && typeof ev['durationMs'] !== 'number') return [];\n return [\n make(isError ? 'error' : 'tool', outStr, {\n tool: typeof ev['name'] === 'string' ? String(ev['name']) : '\u21B3 result',\n ...(typeof ev['durationMs'] === 'number' ? { durationMs: ev['durationMs'] } : {}),\n ...(isError ? { isError: true } : {}),\n ...(typeof ev['id'] === 'string' ? { toolUseId: ev['id'] } : {}),\n }),\n ];\n }\n case 'error':\n case 'provider_error':\n return [make('error', String(ev['message'] ?? 'error'))];\n case 'agent_spawned':\n return [make('system', `spawned ${String(ev['role'] ?? 'agent')}`)];\n case 'task_completed':\n return [make('system', `task done: ${String(ev['title'] ?? '')}`)];\n case 'task_failed':\n return [make('system', `task failed: ${String(ev['title'] ?? '')}`)];\n default:\n return [];\n }\n}\n\n/**\n * Identify a \"result\" entry \u2014 a tool/error entry that carries a tool-use id but\n * no args (it's the output half of a tool call, to be merged into the args\n * half).\n */\nfunction isResultEntry(e: HqTranscriptEntry): boolean {\n return (\n (e.role === 'tool' || e.role === 'error') &&\n e.toolUseId !== undefined &&\n e.toolInput === undefined\n );\n}\n\n/**\n * Merge each tool result into its matching args entry (by `toolUseId`),\n * keeping the args entry's chronological position. Results with no matching\n * args entry are kept as their own entries. Mutates/keeps order; pure w.r.t.\n * input ordering.\n */\nexport function mergeToolResults(flat: readonly HqTranscriptEntry[]): HqTranscriptEntry[] {\n const out: HqTranscriptEntry[] = [];\n const argsById = new Map<string, HqTranscriptEntry>();\n for (const src of flat) {\n const e: HqTranscriptEntry = { ...src };\n if (isResultEntry(e) && e.toolUseId !== undefined) {\n const tgt = argsById.get(e.toolUseId);\n if (tgt) {\n tgt.text = e.text || '';\n if (e.durationMs !== undefined) tgt.durationMs = e.durationMs;\n if (e.isError) {\n tgt.role = 'error';\n tgt.isError = true;\n }\n continue; // merged into the existing args box \u2014 no new entry\n }\n }\n out.push(e);\n if (e.role === 'tool' && e.toolUseId !== undefined && e.toolInput !== undefined) {\n argsById.set(e.toolUseId, e);\n }\n }\n return out;\n}\n\n/**\n * Map + merge an array of raw JSONL events into the final transcript-entry\n * list: strict chronological order, with each tool's args and result combined\n * into a single entry.\n */\nexport function buildTranscriptFromEvents(\n events: Iterable<Record<string, unknown>>,\n): HqTranscriptEntry[] {\n const flat: HqTranscriptEntry[] = [];\n for (const ev of events) {\n for (const e of mapSessionEventToEntries(ev)) flat.push(e);\n }\n return mergeToolResults(flat);\n}\n", "/**\n * FleetTelemetryBridge \u2014 forwards local multi-agent coordinator stats to the\n * HQ publisher as `fleet.snapshot` envelopes, so the command center can render\n * a global fleet roll-up (queued/completed/failed tasks, per-subagent status,\n * fleet cost) across every connected machine.\n *\n * Source: the `coordinator.stats` EventBus event (originating on the FleetBus\n * and re-emitted onto the host EventBus by `fleet/host.ts`). All payload\n * fields are plain serializable data \u2014 no closures, no decoupled relay needed.\n *\n * The snapshot is republished on every `coordinator.stats` change (hash-dedup,\n * mirroring {@link startSessionTelemetryBridge}) so the HQ browser sees live\n * fleet counters without polling.\n *\n * @module hq/fleet-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport type { HqEventEnvelope, HqFleetSnapshotPayload, HqSubagentSummary } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface FleetTelemetryBridgeOptions {\n /** Local EventBus emitting `coordinator.stats` (host EventBus after the FleetBus hop). */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Coordinator run id \u2014 identifies this fleet instance. Falls back to a stable per-session id. */\n runId: string;\n /** Optional sessionId to tag envelopes with. */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\n/**\n * Start forwarding coordinator stats to HQ. Returns a disposer that\n * unsubscribes the listener \u2014 call on shutdown.\n */\nexport function startFleetTelemetryBridge(opts: FleetTelemetryBridgeOptions): () => void {\n const { events, publisher, runId } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n let lastHash = '';\n\n function buildPayload(stats: {\n total: number;\n running: number;\n idle: number;\n stopped: number;\n inFlight: number;\n pending: number;\n completed: number;\n totalCostUsd?: number | undefined;\n subagentStatuses: {\n subagentId: string;\n taskId: string;\n status: string;\n assigned: boolean;\n model?: string | undefined;\n costUsd?: number | undefined;\n runtimeMs?: number | undefined;\n lastActivityAt?: string | undefined;\n iterations?: number | undefined;\n toolCalls?: number | undefined;\n }[];\n }): HqFleetSnapshotPayload {\n const subagents: HqSubagentSummary[] = stats.subagentStatuses.map((s) => ({\n subagentId: s.subagentId,\n ...(s.taskId ? { task: s.taskId } : {}),\n status: normalizeSubagentStatus(s.status),\n ...(s.model !== undefined ? { model: s.model } : {}),\n ...(s.costUsd !== undefined ? { costUsd: s.costUsd } : {}),\n ...(s.runtimeMs !== undefined ? { runtimeMs: s.runtimeMs } : {}),\n ...(s.lastActivityAt !== undefined ? { lastActivityAt: s.lastActivityAt } : {}),\n }));\n return {\n runId,\n activeSubagents: stats.running + stats.idle,\n queuedTasks: stats.pending,\n completedTasks: stats.completed,\n failedTasks: stats.stopped,\n ...(stats.totalCostUsd !== undefined ? { totalCostUsd: stats.totalCostUsd } : {}),\n subagents,\n };\n }\n\n const off = events.on('coordinator.stats', (stats) => {\n try {\n const payload = buildPayload(stats);\n // Hash-dedup so identical fleet state isn't republished.\n const hash = JSON.stringify(payload);\n if (hash === lastHash) return;\n lastHash = hash;\n publisher.publishFleetSnapshot(payload, {\n ...(opts.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n timestamp: now(),\n });\n } catch {\n /* best-effort \u2014 HQ telemetry must never break the host */\n }\n });\n\n return () => {\n off();\n };\n}\n\nconst FLEET_STATUS_MAP: Record<string, HqSubagentSummary['status']> = {\n running: 'running',\n idle: 'idle',\n pending: 'pending',\n completed: 'completed',\n failed: 'failed',\n stopped: 'stopped',\n timeout: 'stopped',\n budget_exhausted: 'stopped',\n};\n\nfunction normalizeSubagentStatus(raw: string): HqSubagentSummary['status'] {\n return FLEET_STATUS_MAP[raw] ?? 'idle';\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * BrainTelemetryBridge \u2014 forwards local Brain (decision layer) events to the\n * HQ publisher as `brain.event` envelopes, so the command center can observe\n * decision requests, answers, denials, ask-human escalations, and\n * self-activated interventions across every connected machine.\n *\n * Source: the `brain.*` EventBus events emitted by `ObservableBrainArbiter`\n * (`coordination/brain.ts`) and `BrainMonitor` (`coordination/brain-monitor.ts`).\n * All payloads are plain serializable data (request id, question, source, risk,\n * decision kind, rationale) \u2014 no closures, no decoupled relay needed.\n *\n * The webui `setup-events.ts` already forwards these verbatim to its browser;\n * this bridge does the same for the cross-machine HQ plane.\n *\n * @module hq/brain-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport type { BrainDecision, BrainDecisionRequest } from '../coordination/brain.js';\nimport type { HqBrainEventKind, HqBrainEventPayload, HqEventEnvelope } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface BrainTelemetryBridgeOptions {\n /** Local EventBus emitting `brain.*` events. */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Optional sessionId to tag envelopes with. */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\nfunction extractRequestFields(req: BrainDecisionRequest | undefined): {\n requestId?: string;\n question?: string;\n source?: string;\n risk?: string;\n} {\n if (req === undefined) return {};\n const out: { requestId?: string; question?: string; source?: string; risk?: string } = {};\n if (typeof req.id === 'string') out.requestId = req.id;\n if (typeof req.question === 'string') out.question = req.question;\n if (typeof req.source === 'string') out.source = req.source;\n if (typeof req.risk === 'string') out.risk = req.risk;\n return out;\n}\n\nfunction extractDecisionFields(dec: BrainDecision | undefined): { decision?: string; detail?: string } {\n if (dec === undefined) return {};\n const out: { decision?: string; detail?: string } = {};\n // BrainDecision is a discriminated union on `type` (answer | ask_human | deny).\n out.decision = dec.type;\n if (dec.type === 'answer') {\n out.detail = dec.text;\n } else if (dec.type === 'ask_human') {\n out.detail = dec.prompt;\n } else if (dec.type === 'deny') {\n out.detail = dec.reason;\n }\n return out;\n}\n\n/**\n * Start forwarding brain events to HQ. Returns a disposer that unsubscribes\n * all listeners \u2014 call on shutdown.\n */\nexport function startBrainTelemetryBridge(opts: BrainTelemetryBridgeOptions): () => void {\n const { events, publisher } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n\n function publish(kind: HqBrainEventKind, payload: Partial<HqBrainEventPayload>, at: number): void {\n try {\n const full: HqBrainEventPayload = { kind, at, ...payload } as HqBrainEventPayload;\n publisher.publishEvent({\n type: 'brain.event',\n payload: full,\n ...(opts.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n }\n\n const offs: Array<() => void> = [];\n\n offs.push(\n events.on('brain.decision_requested', (p) => {\n publish('decision_requested', extractRequestFields(p.request), p.at);\n }),\n );\n offs.push(\n events.on('brain.decision_answered', (p) => {\n publish('decision_answered', {\n ...extractRequestFields(p.request),\n ...extractDecisionFields(p.decision),\n }, p.at);\n }),\n );\n offs.push(\n events.on('brain.decision_ask_human', (p) => {\n publish('decision_ask_human', {\n ...extractRequestFields(p.request),\n ...extractDecisionFields(p.decision),\n }, p.at);\n }),\n );\n offs.push(\n events.on('brain.decision_denied', (p) => {\n publish('decision_denied', {\n ...extractRequestFields(p.request),\n ...extractDecisionFields(p.decision),\n }, p.at);\n }),\n );\n offs.push(\n events.on('brain.human_answered', (p) => {\n const detail = typeof p.text === 'string' ? p.text : p.optionId;\n publish('human_answered', {\n requestId: p.id,\n ...(detail !== undefined ? { detail } : {}),\n ...(p.deny === true ? { decision: 'deny' } : {}),\n }, p.at);\n }),\n );\n offs.push(\n events.on('brain.intervention', (p) => {\n publish('intervention', {\n ...extractRequestFields(p.request),\n ...extractDecisionFields(p.decision),\n interventionKind: p.kind,\n intervened: p.intervened,\n }, p.at);\n }),\n );\n\n return () => {\n for (const off of offs) off();\n };\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * WorktreeTelemetryBridge \u2014 forwards local git-worktree lifecycle events to\n * the HQ publisher as `worktree.event` envelopes, so the command center can\n * render live build phase swim-lanes / DAG across every connected machine.\n *\n * Source: the `worktree.*` EventBus events emitted by `WorktreeManager`\n * (`worktree/worktree-manager.ts`): allocated, committed, merged, conflict,\n * released, failed. All payload fields are plain serializable data\n * (handleId, ownerId, branch, diff stats, conflict files) \u2014 no closures, no\n * decoupled relay needed.\n *\n * @module hq/worktree-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport type { HqEventEnvelope, HqWorktreeEventPayload } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface WorktreeTelemetryBridgeOptions {\n /** Local EventBus emitting `worktree.*` events. */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Optional sessionId to tag envelopes with. */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\ntype WorktreeAllocated = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n ownerLabel: string;\n slug: string;\n dir: string;\n branch: string;\n baseBranch: string;\n};\ntype WorktreeCommitted = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch: string;\n committed: boolean;\n insertions: number;\n deletions: number;\n files: number;\n sha?: string | undefined;\n};\ntype WorktreeMerged = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch: string;\n baseBranch: string;\n squash: boolean;\n};\ntype WorktreeConflict = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch: string;\n conflictFiles: string[];\n};\ntype WorktreeReleased = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch: string;\n kept: boolean;\n};\ntype WorktreeFailed = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch?: string | undefined;\n error: string;\n};\n\n/**\n * Start forwarding worktree lifecycle events to HQ. Returns a disposer that\n * unsubscribes all listeners \u2014 call on shutdown.\n */\nexport function startWorktreeTelemetryBridge(opts: WorktreeTelemetryBridgeOptions): () => void {\n const { events, publisher } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n\n function publish(payload: HqWorktreeEventPayload, sessionId?: string): void {\n try {\n publisher.publishEvent({\n type: 'worktree.event',\n payload,\n ...(sessionId !== undefined && sessionId !== '' ? { sessionId } : {}),\n ...(opts.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n }\n\n const offs: Array<() => void> = [];\n\n offs.push(\n events.on('worktree.allocated', (p: WorktreeAllocated) => {\n publish(\n {\n kind: 'allocated',\n handleId: p.handleId,\n ownerId: p.ownerId,\n ownerLabel: p.ownerLabel,\n slug: p.slug,\n branch: p.branch,\n baseBranch: p.baseBranch,\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.committed', (p: WorktreeCommitted) => {\n publish(\n {\n kind: 'committed',\n handleId: p.handleId,\n ownerId: p.ownerId,\n branch: p.branch,\n insertions: p.insertions,\n deletions: p.deletions,\n files: p.files,\n ...(p.sha !== undefined ? { sha: p.sha } : {}),\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.merged', (p: WorktreeMerged) => {\n publish(\n {\n kind: 'merged',\n handleId: p.handleId,\n ownerId: p.ownerId,\n branch: p.branch,\n baseBranch: p.baseBranch,\n squash: p.squash,\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.conflict', (p: WorktreeConflict) => {\n publish(\n {\n kind: 'conflict',\n handleId: p.handleId,\n ownerId: p.ownerId,\n branch: p.branch,\n conflictFiles: p.conflictFiles,\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.released', (p: WorktreeReleased) => {\n publish(\n {\n kind: 'released',\n handleId: p.handleId,\n ownerId: p.ownerId,\n branch: p.branch,\n kept: p.kept,\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.failed', (p: WorktreeFailed) => {\n publish(\n {\n kind: 'failed',\n handleId: p.handleId,\n ownerId: p.ownerId,\n ...(p.branch !== undefined ? { branch: p.branch } : {}),\n error: p.error,\n },\n p.sessionId,\n );\n }),\n );\n\n return () => {\n for (const off of offs) off();\n };\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * ToolTelemetryBridge \u2014 forwards local tool execution events to the HQ\n * publisher as `tool.started` and `tool.completed` envelopes, so the command\n * center can surface live tool activity (what's running, durations, success\n * rates) across every connected machine.\n *\n * Sources:\n * - `tool.started` (EventBus) \u2192 `tool.started` envelope. Raw tool input is\n * shaped via {@link summarizeHqToolArgs} according to the active HQ policy.\n * - `tool.executed` (EventBus) \u2192 `tool.completed` envelope (carries the\n * richer post-execution signal: duration, ok/error, output bytes).\n *\n * All payload fields are plain serializable data \u2014 no closures. The\n * `tool.started.input` raw args follow the publisher redaction policy before\n * publishing.\n *\n * @module hq/tool-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport { resolveHqRedactionPolicy, scrubAndTruncateHqPreview, summarizeHqToolArgs } from './redaction.js';\nimport type { HqEventEnvelope, HqRedactionPolicy, HqToolCompletedPayload, HqToolStartedPayload } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface ToolTelemetryBridgeOptions {\n /** Local EventBus emitting `tool.started` and `tool.executed` events. */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Project root for path redaction in tool input summaries. */\n projectRoot?: string;\n /** Optional sessionId to tag envelopes with. */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\ninterface ToolStartedEvent {\n sessionId?: string | undefined;\n name: string;\n id: string;\n input?: unknown | undefined;\n}\n\ninterface ToolExecutedEvent {\n sessionId?: string | undefined;\n id?: string | undefined;\n name: string;\n durationMs: number;\n ok: boolean;\n input?: unknown | undefined;\n output?: string | undefined;\n outputBytes?: number | undefined;\n}\n\n/** Track in-flight tool calls so we can attach start info to completion. */\ninterface InFlightTool {\n name: string;\n startedAt: number;\n}\n\n/**\n * Start forwarding tool execution events to HQ. Returns a disposer that\n * unsubscribes all listeners \u2014 call on shutdown.\n */\nexport function startToolTelemetryBridge(opts: ToolTelemetryBridgeOptions): () => void {\n const { events, publisher } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n const inFlight = new Map<string, InFlightTool>();\n\n function sessionIdTag(sessionId?: string): { sessionId?: string } {\n const tag = sessionId ?? opts.sessionId;\n return tag !== undefined ? { sessionId: tag } : {};\n }\n\n const offStarted = events.on('tool.started', (p: ToolStartedEvent) => {\n inFlight.set(p.id, { name: p.name, startedAt: Date.now() });\n try {\n const payload: HqToolStartedPayload = {\n toolName: p.name,\n ...(p.input !== undefined\n ? {\n inputSummary: summarizeHqToolArgs(p.input, {\n policy: publisher.redactionPolicy,\n ...(opts.projectRoot !== undefined ? { projectRoot: opts.projectRoot } : {}),\n }),\n }\n : {}),\n };\n publisher.publishEvent({\n type: 'tool.started',\n payload,\n ...sessionIdTag(p.sessionId),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n });\n\n const offExecuted = events.on('tool.executed', (p: ToolExecutedEvent) => {\n const id = p.id;\n if (id !== undefined) inFlight.delete(id);\n try {\n const payload: HqToolCompletedPayload = {\n toolName: p.name,\n status: p.ok ? 'success' : 'error',\n durationMs: p.durationMs,\n ...(p.output !== undefined && p.output.length > 0\n ? { outputSummary: truncateForSummary(p.output, publisher.redactionPolicy) }\n : {}),\n };\n publisher.publishEvent({\n type: 'tool.completed',\n payload,\n ...sessionIdTag(p.sessionId),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n });\n\n return () => {\n offStarted();\n offExecuted();\n inFlight.clear();\n };\n}\n\nfunction truncateForSummary(output: string, policy?: Partial<HqRedactionPolicy>, max = 280): unknown {\n const resolved = resolveHqRedactionPolicy(policy);\n if (resolved.rawContent) {\n if (output.length <= max) return output;\n return `${output.slice(0, max)}\u2026[truncated:${output.length - max}]`;\n }\n return scrubAndTruncateHqPreview(output, max) ?? '';\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * CostTelemetryBridge \u2014 forwards local token/cost accounting events to the HQ\n * publisher as `session.usage` envelopes, giving the command center the\n * granular per-call cost signal it needs to render live cost trends and\n * roll-ups across every connected machine.\n *\n * Source: the `token.accounted` EventBus event, emitted by the TokenCounter\n * (`infrastructure/token-counter.ts`) after every provider call. The payload\n * is plain serializable data (usage counts + a cost breakdown, plus the\n * provider/model that priced it and cache token counts) \u2014 no closures.\n *\n * This is the high-frequency cost feed; HQ's persistence layer time-buckets\n * these into trend series (per-bucket totals + per-model/per-provider\n * breakdowns).\n *\n * @module hq/cost-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport type { Usage } from '../types/provider.js';\nimport type { HqEventEnvelope, HqUsagePayload } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface CostTelemetryBridgeOptions {\n /** Local EventBus emitting `token.accounted`. */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Optional sessionId to tag envelopes with (overrides the event's, when set). */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\ninterface TokenAccountedEvent {\n sessionId?: string | undefined;\n usage: Usage;\n cost: { input: number; output: number; total: number };\n /** Provider id that produced this usage (e.g. 'anthropic'), when known. */\n provider?: string | undefined;\n /** Model id the cost was priced against, when known. */\n model?: string | undefined;\n}\n\n/**\n * Start forwarding token/cost events to HQ. Returns a disposer that\n * unsubscribes the listener \u2014 call on shutdown.\n */\nexport function startCostTelemetryBridge(opts: CostTelemetryBridgeOptions): () => void {\n const { events, publisher } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n\n const off = events.on('token.accounted', (p: TokenAccountedEvent) => {\n try {\n const payload: HqUsagePayload = {\n inputTokens: p.usage.input,\n outputTokens: p.usage.output,\n totalTokens: p.usage.input + p.usage.output,\n costUsd: p.cost.total,\n };\n // Forward the dimensions HQ needs for per-model/per-provider cost charts\n // and cache-hit-ratio cards. All optional \u2014 older counters omit them.\n if (p.provider !== undefined) payload.provider = p.provider;\n if (p.model !== undefined) payload.model = p.model;\n if (p.usage.cacheRead !== undefined) payload.cacheRead = p.usage.cacheRead;\n if (p.usage.cacheWrite !== undefined) payload.cacheWrite = p.usage.cacheWrite;\n const sessionId = opts.sessionId ?? p.sessionId;\n publisher.publishEvent({\n type: 'session.usage',\n payload,\n ...(sessionId !== undefined ? { sessionId } : {}),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n });\n\n return () => {\n off();\n };\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * HQ persistence layer \u2014 survives HQ server restarts so the command center\n * keeps its event history, snapshot state, cost/activity trends, and (later)\n * alert + command-audit logs across reboots.\n *\n * Three stores, all file-backed under the HQ dataDir\n * (`~/.wrongstack/hq/` by default \u2014 see {@link resolveHqDataDir}):\n *\n * - {@link HqEventLog} \u2014 append-only JSONL of every received event\n * envelope, rotated when it exceeds a cap.\n * - {@link HqSnapshotStore} \u2014 atomic checkpoint of the latest snapshot,\n * written on every debounced broadcast.\n * - {@link HqTimeseriesStore}\u2014 time-bucketed cost + activity samples for\n * trend charts.\n *\n * Design constraints (mirrors the codebase conventions):\n * - All disk writes go through {@link withFileLock} + {@link atomicWrite}\n * (shared primitives from `utils/atomic-write.ts`) for cross-process safety.\n * - Every write is best-effort and never throws into the HQ server hot path \u2014\n * callers wrap in try/catch and degrade to in-memory-only on failure.\n * - Appends use a FIFO write chain (single in-flight writer) so concurrent\n * event arrivals don't interleave lines.\n *\n * @module hq/persistence\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite, withFileLock } from '../utils/atomic-write.js';\nimport type { HqEventEnvelope, HqSnapshot } from './protocol.js';\n\n/** Maximum event-log lines before a rotation compacts it down to the tail. */\nconst DEFAULT_EVENT_LOG_MAX_LINES = 50_000;\n/** How many lines to retain after a rotation. */\nconst DEFAULT_EVENT_LOG_ROTATE_KEEP = 20_000;\n\n// \u2500\u2500 HqEventLog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqEventLogOptions {\n dataDir: string;\n maxLines?: number;\n rotateKeep?: number;\n}\n\n/**\n * Append-only JSONL event log. Every received event envelope is appended to\n * `events.jsonl`; when the file exceeds `maxLines` it is rotated under a file\n * lock to keep only the most recent `rotateKeep` lines.\n *\n * Writes are serialized through a FIFO chain so concurrent appends never\n * interleave. All operations are best-effort: a rejected append resolves\n * (never rejects) and the caller's `await` never breaks the server loop.\n */\nexport class HqEventLog {\n private readonly filePath: string;\n private readonly maxLines: number;\n private readonly rotateKeep: number;\n private writeChain: Promise<void> = Promise.resolve();\n private lineCount = 0;\n private counted = false;\n\n constructor(opts: HqEventLogOptions) {\n this.filePath = path.join(opts.dataDir, 'events.jsonl');\n this.maxLines = opts.maxLines ?? DEFAULT_EVENT_LOG_MAX_LINES;\n this.rotateKeep = opts.rotateKeep ?? DEFAULT_EVENT_LOG_ROTATE_KEEP;\n }\n\n /** Append an event envelope as one JSON line. Best-effort, never rejects. */\n append(event: HqEventEnvelope): void {\n this.writeChain = this.writeChain\n .then(() => this.appendInternal(event))\n .catch(() => {\n /* best-effort: a failed append must not break the write chain */\n });\n }\n\n /** Resolves once all queued appends have settled. For tests. */\n async drain(): Promise<void> {\n await this.writeChain.catch(() => {\n /* best-effort */\n });\n }\n\n private async appendInternal(event: HqEventEnvelope): Promise<void> {\n if (!this.counted) {\n this.lineCount = await this.countLines();\n this.counted = true;\n }\n const line = JSON.stringify(event) + '\\n';\n await fs.appendFile(this.filePath, line, { encoding: 'utf8' });\n this.lineCount += 1;\n if (this.lineCount >= this.maxLines) {\n await this.rotate();\n }\n }\n\n private async rotate(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n try {\n const content = await fs.readFile(this.filePath, 'utf8');\n const lines = content.split('\\n').filter((l) => l.length > 0);\n if (lines.length <= this.rotateKeep) {\n this.lineCount = lines.length;\n return;\n }\n const kept = lines.slice(lines.length - this.rotateKeep);\n await atomicWrite(this.filePath, kept.join('\\n') + '\\n');\n this.lineCount = kept.length;\n } catch {\n /* best-effort */\n }\n });\n }\n\n private async countLines(): Promise<number> {\n try {\n const content = await fs.readFile(this.filePath, 'utf8');\n return content.split('\\n').filter((l) => l.length > 0).length;\n } catch {\n return 0;\n }\n }\n\n /**\n * Read the most recent `limit` events, optionally filtered by envelope\n * `type`. Newest first. Returns `[]` if the file doesn't exist yet.\n */\n async recent(limit: number, typeFilter?: string): Promise<HqEventEnvelope[]> {\n let content: string;\n try {\n content = await fs.readFile(this.filePath, 'utf8');\n } catch {\n return [];\n }\n const lines = content.split('\\n').filter((l) => l.length > 0);\n const out: HqEventEnvelope[] = [];\n // Walk newest-first so we can stop early once we have `limit` matches.\n for (let i = lines.length - 1; i >= 0 && out.length < limit; i--) {\n try {\n const env = JSON.parse(lines[i]!) as HqEventEnvelope;\n if (typeFilter === undefined || env.type === typeFilter) {\n out.push(env);\n }\n } catch {\n /* skip malformed lines */\n }\n }\n return out;\n }\n\n /** Initialize the line count cache from disk (call once at boot). */\n async hydrate(): Promise<void> {\n this.lineCount = await this.countLines();\n this.counted = true;\n }\n}\n\n// \u2500\u2500 HqSnapshotStore \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqSnapshotStoreOptions {\n dataDir: string;\n}\n\n/**\n * Atomic checkpoint of the latest snapshot, written to `snapshot.json`.\n * The HQ server writes on every debounced broadcast and reads on boot to\n * re-seed its in-memory state. Best-effort, never rejects.\n */\nexport class HqSnapshotStore {\n private readonly filePath: string;\n private writeChain: Promise<void> = Promise.resolve();\n\n constructor(opts: HqSnapshotStoreOptions) {\n this.filePath = path.join(opts.dataDir, 'snapshot.json');\n }\n\n /** Persist a snapshot. Best-effort, never rejects. */\n save(snapshot: HqSnapshot): void {\n this.writeChain = this.writeChain\n .then(() => atomicWrite(this.filePath, JSON.stringify(snapshot), { mode: 0o600 }))\n .catch(() => {\n /* best-effort */\n });\n }\n\n /** Resolves once all queued saves have settled. For tests. */\n async drain(): Promise<void> {\n await this.writeChain.catch(() => {\n /* best-effort */\n });\n }\n\n /** Read the last persisted snapshot, or `null` if none. */\n async load(): Promise<HqSnapshot | null> {\n try {\n const content = await fs.readFile(this.filePath, 'utf8');\n return JSON.parse(content) as HqSnapshot;\n } catch {\n return null;\n }\n }\n}\n\n// \u2500\u2500 HqTimeseriesStore \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqTimeseriesSample {\n /** Bucket start (epoch ms, floored to the bucket width). */\n ts: number;\n /** Total cost (USD) accumulated in this bucket. */\n costUsd: number;\n /** Total input tokens in this bucket. */\n inputTokens: number;\n /** Total output tokens in this bucket. */\n outputTokens: number;\n /** Number of tool executions in this bucket. */\n toolCalls: number;\n /** Snapshot of active agents at bucket close (last-write per bucket). */\n activeAgents?: number;\n /** Per-dimension cost/token breakdowns for richer trend charts. */\n byModel?: Record<string, HqTimeseriesBreakdownEntry>;\n byProvider?: Record<string, HqTimeseriesBreakdownEntry>;\n}\n\n/**\n * One row of a per-dimension breakdown inside a {@link HqTimeseriesSample}\n * (e.g. the cost + tokens attributed to a single model or provider within the\n * bucket). Sums of these across a dimension equal the bucket's totals when\n * every cost signal carried that dimension.\n */\nexport interface HqTimeseriesBreakdownEntry {\n costUsd: number;\n inputTokens: number;\n outputTokens: number;\n cacheRead?: number | undefined;\n cacheWrite?: number | undefined;\n}\n\nexport interface HqTimeseriesStoreOptions {\n dataDir: string;\n /** Bucket width in ms. Default 5 minutes. */\n bucketMs?: number;\n /** How many buckets to retain. Default 2016 (1 week of 5-min buckets). */\n maxBuckets?: number;\n}\n\n/**\n * Time-bucketed cost + activity samples for trend charts. Each {@link record}\n * call folds a cost/tool signal into the current bucket; {@link flush} writes\n * the accumulated buckets to `timeseries.jsonl` (append under lock) and prunes\n * to `maxBuckets`.\n *\n * The store keeps an in-memory ring of buckets for cheap reads; {@link load}\n * rehydrates them on boot.\n */\nexport class HqTimeseriesStore {\n private readonly filePath: string;\n private readonly bucketMs: number;\n private readonly maxBuckets: number;\n private readonly buckets = new Map<number, HqTimeseriesSample>();\n private flushChain: Promise<void> = Promise.resolve();\n\n constructor(opts: HqTimeseriesStoreOptions) {\n this.filePath = path.join(opts.dataDir, 'timeseries.jsonl');\n this.bucketMs = opts.bucketMs ?? 5 * 60 * 1000;\n this.maxBuckets = opts.maxBuckets ?? 2016;\n }\n\n private bucketStart(ts: number): number {\n return Math.floor(ts / this.bucketMs) * this.bucketMs;\n }\n\n /** Fold a cost/tool signal into the current bucket. Best-effort. */\n record(signal: {\n ts?: number;\n costUsd?: number;\n inputTokens?: number;\n outputTokens?: number;\n toolCalls?: number;\n activeAgents?: number;\n /** When present, this signal is also attributed to a model dimension. */\n model?: string;\n /** When present, this signal is also attributed to a provider dimension. */\n provider?: string;\n cacheRead?: number;\n cacheWrite?: number;\n }): void {\n const start = this.bucketStart(signal.ts ?? Date.now());\n let bucket = this.buckets.get(start);\n if (!bucket) {\n bucket = { ts: start, costUsd: 0, inputTokens: 0, outputTokens: 0, toolCalls: 0 };\n this.buckets.set(start, bucket);\n }\n if (signal.costUsd !== undefined) bucket.costUsd += signal.costUsd;\n if (signal.inputTokens !== undefined) bucket.inputTokens += signal.inputTokens;\n if (signal.outputTokens !== undefined) bucket.outputTokens += signal.outputTokens;\n if (signal.toolCalls !== undefined) bucket.toolCalls += signal.toolCalls;\n if (signal.activeAgents !== undefined) bucket.activeAgents = signal.activeAgents;\n // Attribute this cost signal to its model / provider dimension when known,\n // so trend charts can break spend down without scraping the event log.\n if (signal.model !== undefined || signal.provider !== undefined) {\n const entry: HqTimeseriesBreakdownEntry = {\n costUsd: signal.costUsd ?? 0,\n inputTokens: signal.inputTokens ?? 0,\n outputTokens: signal.outputTokens ?? 0,\n ...(signal.cacheRead !== undefined ? { cacheRead: signal.cacheRead } : {}),\n ...(signal.cacheWrite !== undefined ? { cacheWrite: signal.cacheWrite } : {}),\n };\n if (signal.model !== undefined) {\n bucket.byModel = foldBreakdown(bucket.byModel, signal.model, entry);\n }\n if (signal.provider !== undefined) {\n bucket.byProvider = foldBreakdown(bucket.byProvider, signal.provider, entry);\n }\n }\n // Prune in-memory buckets beyond retention so a long-lived HQ doesn't\n // accumulate unbounded history. Keep the most-recent maxBuckets.\n if (this.buckets.size > this.maxBuckets) {\n const sorted = Array.from(this.buckets.keys()).sort((a, b) => a - b);\n while (this.buckets.size > this.maxBuckets && sorted.length > 0) {\n const oldest = sorted.shift();\n if (oldest === undefined) break;\n this.buckets.delete(oldest);\n }\n }\n }\n\n /** Persist accumulated buckets to disk (append under lock), prune to maxBuckets. */\n flush(): void {\n const snapshot = Array.from(this.buckets.values()).sort((a, b) => a.ts - b.ts);\n if (snapshot.length === 0) return;\n this.flushChain = this.flushChain\n .then(() => this.flushInternal(snapshot))\n .catch(() => {\n /* best-effort */\n });\n }\n\n /** Resolves once all queued flushes have settled. For tests. */\n async drain(): Promise<void> {\n await this.flushChain.catch(() => {\n /* best-effort */\n });\n }\n\n private async flushInternal(toWrite: HqTimeseriesSample[]): Promise<void> {\n const lines = toWrite.map((b) => JSON.stringify(b)).join('\\n') + '\\n';\n await withFileLock(this.filePath, async () => {\n await fs.appendFile(this.filePath, lines, { encoding: 'utf8' });\n });\n // Prune in-memory buckets beyond retention.\n const sorted = Array.from(this.buckets.keys()).sort((a, b) => a - b);\n while (this.buckets.size > this.maxBuckets) {\n const oldest = sorted.shift();\n if (oldest === undefined) break;\n this.buckets.delete(oldest);\n }\n }\n\n /** Read buckets within `[since, now]`, oldest-first. */\n async read(sinceMs?: number): Promise<HqTimeseriesSample[]> {\n // Prefer in-memory (always most current); supplement from disk on first call.\n if (this.buckets.size === 0) await this.load();\n const since = sinceMs ?? 0;\n return Array.from(this.buckets.values())\n .filter((b) => b.ts >= since)\n .sort((a, b) => a.ts - b.ts);\n }\n\n /** Rehydrate buckets from disk (deduped, latest-per-bucket wins). */\n async load(): Promise<void> {\n let content: string;\n try {\n content = await fs.readFile(this.filePath, 'utf8');\n } catch {\n return;\n }\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const sample = JSON.parse(trimmed) as HqTimeseriesSample;\n // Last-write-wins per bucket (file is append-only, so later lines win).\n this.buckets.set(sample.ts, sample);\n } catch {\n /* skip malformed */\n }\n }\n // Prune to retention.\n const sorted = Array.from(this.buckets.keys()).sort((a, b) => a - b);\n while (this.buckets.size > this.maxBuckets) {\n const oldest = sorted.shift();\n if (oldest === undefined) break;\n this.buckets.delete(oldest);\n }\n }\n}\n\n/**\n * Fold a breakdown entry into a per-dimension map (model or provider), summing\n * cost/token fields and merging cache counts. Returns a new map so the caller\n * can assign it back immutably.\n */\nfunction foldBreakdown(\n map: Record<string, HqTimeseriesBreakdownEntry> | undefined,\n key: string,\n entry: HqTimeseriesBreakdownEntry,\n): Record<string, HqTimeseriesBreakdownEntry> {\n const next: Record<string, HqTimeseriesBreakdownEntry> = { ...map };\n const existing = next[key];\n if (existing === undefined) {\n next[key] = { ...entry };\n } else {\n next[key] = {\n costUsd: existing.costUsd + entry.costUsd,\n inputTokens: existing.inputTokens + entry.inputTokens,\n outputTokens: existing.outputTokens + entry.outputTokens,\n cacheRead:\n existing.cacheRead !== undefined || entry.cacheRead !== undefined\n ? (existing.cacheRead ?? 0) + (entry.cacheRead ?? 0)\n : undefined,\n cacheWrite:\n existing.cacheWrite !== undefined || entry.cacheWrite !== undefined\n ? (existing.cacheWrite ?? 0) + (entry.cacheWrite ?? 0)\n : undefined,\n };\n }\n return next;\n}\n\n// \u2500\u2500 HqSimpleLog (generic append-only JSONL for audit/alert records) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * A minimal append-only JSONL log used for records that don't need rotation\n * compaction \u2014 command-audit entries and fired alerts. Each record is one\n * JSON line appended under a FIFO write chain; {@link readAll} parses them\n * oldest-first. Best-effort: a rejected append resolves (never rejects) so the\n * HQ server hot path is never broken.\n */\nexport class HqSimpleLog<T> {\n private readonly filePath: string;\n private writeChain: Promise<void> = Promise.resolve();\n\n constructor(dataDir: string, filename: string) {\n this.filePath = path.join(dataDir, filename);\n }\n\n /** Append one record as a JSON line. Best-effort, never rejects. */\n append(record: T): void {\n this.writeChain = this.writeChain\n .then(() => fs.appendFile(this.filePath, `${JSON.stringify(record)}\\n`, { encoding: 'utf8' }))\n .catch(() => {\n /* best-effort: a failed append must not break the write chain */\n });\n }\n\n /** Resolves once all queued appends have settled. For tests. */\n async drain(): Promise<void> {\n await this.writeChain.catch(() => {\n /* best-effort */\n });\n }\n\n /** Read all records oldest-first. Returns `[]` if the file doesn't exist. */\n async readAll(): Promise<T[]> {\n let content: string;\n try {\n content = await fs.readFile(this.filePath, 'utf8');\n } catch {\n return [];\n }\n const out: T[] = [];\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n out.push(JSON.parse(trimmed) as T);\n } catch {\n /* skip malformed lines */\n }\n }\n return out;\n }\n}\n\n// \u2500\u2500 Aggregate persistence facade \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqPersistence {\n eventLog: HqEventLog;\n snapshotStore: HqSnapshotStore;\n timeseries: HqTimeseriesStore;\n commandLog: HqSimpleLog<unknown>;\n alertLog: HqSimpleLog<unknown>;\n}\n\nexport function createHqPersistence(dataDir: string): HqPersistence {\n return {\n eventLog: new HqEventLog({ dataDir }),\n snapshotStore: new HqSnapshotStore({ dataDir }),\n timeseries: new HqTimeseriesStore({ dataDir }),\n commandLog: new HqSimpleLog(dataDir, 'commands.jsonl'),\n alertLog: new HqSimpleLog(dataDir, 'alerts.jsonl'),\n };\n}\n", "/**\n * HQ control-plane command definitions \u2014 typed payloads for the commands the\n * HQ dashboard can enqueue to connected machines (Phase 3+ of the HQ command\n * center). These are carried over the existing `HqQueuedCommand` wire shape\n * (`{commandId, type, payload, \u2026}`) whose `type`/`payload` were previously\n * type-erased. This module gives them a discriminated union for type-safe\n * dispatch on the client side (Phase 4).\n *\n * Security model: `run-command` (raw shell) is gated by a per-token\n * `control.execute` capability AND an operator opt-in; the other four commands\n * route through the agent's own decision loop / mailbox and inherit their\n * existing guardrails. See `docs/plans/hq-command-center-2026-07.md`.\n *\n * @module hq/commands\n */\nimport type { HqQueuedCommand } from './protocol.js';\n\n// \u2500\u2500 Command types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** HQ_COMMAND_TYPES \u2014 the full set of recognized command `type` strings. */\nexport const HQ_COMMAND_TYPES = [\n 'steer',\n 'btw',\n 'queue',\n 'abort',\n 'spawn',\n 'broadcast',\n 'run-command',\n] as const;\n\nexport type HqCommandType = (typeof HQ_COMMAND_TYPES)[number];\n\n/** Inject a steer text into a target agent's conversation. */\nexport interface HqSteerCommand {\n type: 'steer';\n /** Target agent address: a unique id (`leader@<tag>`), an alias (`leader`), or `*` for all. */\n to: string;\n subject: string;\n body: string;\n priority?: 'low' | 'normal' | 'high';\n}\n\n/**\n * Post a non-urgent FYI (`btw`) into a target agent's mailbox. Unlike a steer,\n * a btw is absorbed as context \u2014 it does not demand the agent change course.\n * Same wire shape as steer; only the emitted mailbox `type` differs.\n */\nexport interface HqBtwCommand {\n type: 'btw';\n /** Target agent address: a unique id (`leader@<tag>`), an alias (`leader`), or `*` for all. */\n to: string;\n subject: string;\n body: string;\n priority?: 'low' | 'normal' | 'high';\n}\n\n/**\n * Queue a prompt/note (`queue`) for a target agent. Delivered as a plain\n * `note` mailbox message the agent picks up before its next step \u2014 used when\n * the prompt should wait its turn rather than steer the current operation.\n */\nexport interface HqQueueCommand {\n type: 'queue';\n /** Target agent address: a unique id (`leader@<tag>`), an alias (`leader`), or `*` for all. */\n to: string;\n subject: string;\n body: string;\n priority?: 'low' | 'normal' | 'high';\n}\n\n/** Abort a running agent run or fleet. */\nexport interface HqAbortCommand {\n type: 'abort';\n /** `'leader'` aborts the session leader; a subagentId aborts one agent; `'fleet'` stops all. */\n target: 'leader' | 'fleet' | string;\n}\n\n/** Spawn a subagent of the given role. */\nexport interface HqSpawnCommand {\n type: 'spawn';\n role: string;\n /** Optional task description for dispatch routing. */\n task?: string;\n maxIterations?: number;\n}\n\n/** Broadcast a mailbox message to all agents on the target's project. */\nexport interface HqBroadcastCommand {\n type: 'broadcast';\n subject: string;\n body: string;\n priority?: 'low' | 'normal' | 'high';\n}\n\n/** Run a shell command on the target machine. GATED by `control.execute`. */\nexport interface HqRunCommandCommand {\n type: 'run-command';\n command: string;\n /** Optional working directory (defaults to the agent's project root). */\n cwd?: string;\n}\n\nexport type HqCommand =\n | HqSteerCommand\n | HqBtwCommand\n | HqQueueCommand\n | HqAbortCommand\n | HqSpawnCommand\n | HqBroadcastCommand\n | HqRunCommandCommand;\n\n// \u2500\u2500 Validation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst HQ_COMMAND_TYPE_SET = new Set<string>(HQ_COMMAND_TYPES);\n\n/**\n * Validate that an inbound `HqQueuedCommand` has a recognized `type` and a\n * minimally well-formed payload. Returns the narrowed command on success, or\n * `null` when the command should be rejected.\n *\n * This is a shape check, not a security gate \u2014 capability enforcement happens\n * at enqueue time (browser token must have `control.enqueue`) and at execute\n * time (`run-command` requires `control.execute`).\n */\nexport function validateHqCommand(queued: HqQueuedCommand): HqCommand | null {\n if (!HQ_COMMAND_TYPE_SET.has(queued.type)) return null;\n const p = queued.payload as Record<string, unknown>;\n if (p === null || typeof p !== 'object') return null;\n switch (queued.type as HqCommandType) {\n case 'steer': {\n if (typeof p['to'] !== 'string' || typeof p['subject'] !== 'string' || typeof p['body'] !== 'string') {\n return null;\n }\n const result: HqSteerCommand = { type: 'steer', to: p['to'], subject: p['subject'], body: p['body'] };\n if (p['priority'] === 'low' || p['priority'] === 'normal' || p['priority'] === 'high') {\n result.priority = p['priority'];\n }\n return result;\n }\n case 'btw': {\n if (typeof p['to'] !== 'string' || typeof p['subject'] !== 'string' || typeof p['body'] !== 'string') {\n return null;\n }\n const result: HqBtwCommand = { type: 'btw', to: p['to'], subject: p['subject'], body: p['body'] };\n if (p['priority'] === 'low' || p['priority'] === 'normal' || p['priority'] === 'high') {\n result.priority = p['priority'];\n }\n return result;\n }\n case 'queue': {\n if (typeof p['to'] !== 'string' || typeof p['subject'] !== 'string' || typeof p['body'] !== 'string') {\n return null;\n }\n const result: HqQueueCommand = { type: 'queue', to: p['to'], subject: p['subject'], body: p['body'] };\n if (p['priority'] === 'low' || p['priority'] === 'normal' || p['priority'] === 'high') {\n result.priority = p['priority'];\n }\n return result;\n }\n case 'abort':\n if (typeof p['target'] !== 'string') return null;\n return { type: 'abort', target: p['target'] };\n case 'spawn': {\n if (typeof p['role'] !== 'string') return null;\n const result: HqSpawnCommand = { type: 'spawn', role: p['role'] };\n if (typeof p['task'] === 'string') result.task = p['task'];\n if (typeof p['maxIterations'] === 'number') result.maxIterations = p['maxIterations'];\n return result;\n }\n case 'broadcast': {\n if (typeof p['subject'] !== 'string' || typeof p['body'] !== 'string') return null;\n const result: HqBroadcastCommand = { type: 'broadcast', subject: p['subject'], body: p['body'] };\n if (p['priority'] === 'low' || p['priority'] === 'normal' || p['priority'] === 'high') {\n result.priority = p['priority'];\n }\n return result;\n }\n case 'run-command': {\n if (typeof p['command'] !== 'string') return null;\n const result: HqRunCommandCommand = { type: 'run-command', command: p['command'] };\n if (typeof p['cwd'] === 'string') result.cwd = p['cwd'];\n return result;\n }\n default:\n return null;\n }\n}\n\n// \u2500\u2500 Audit log \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqCommandAuditEntry {\n commandId: string;\n type: HqCommandType;\n clientId: string;\n /** Who enqueued the command (browser token id, or 'anonymous' in open mode). */\n enqueuedBy: string;\n enqueuedAt: string;\n status: 'queued' | 'delivered' | 'acked';\n /** Ack status when the client has responded. */\n ackStatus?: 'accepted' | 'completed' | 'failed' | 'rejected';\n ackMessage?: string;\n ackedAt?: string;\n}\n\n/**\n * In-memory command audit ring. Capped for cheap reads. When an `onPersist`\n * callback is wired, every record/update also sinks a snapshot of the entry to\n * the caller's durable store (e.g. HQ's `commands.jsonl`) so history survives\n * restarts. The ring remains the read path for `/api/commands`.\n */\nexport class HqCommandAuditLog {\n private readonly entries: HqCommandAuditEntry[] = [];\n private readonly max: number;\n private readonly onPersist?: ((entry: HqCommandAuditEntry) => void) | undefined;\n\n constructor(max = 1000, onPersist?: ((entry: HqCommandAuditEntry) => void) | undefined) {\n this.max = max;\n this.onPersist = onPersist;\n }\n\n record(entry: HqCommandAuditEntry): void {\n this.entries.push(entry);\n if (this.entries.length > this.max) {\n this.entries.splice(0, this.entries.length - this.max);\n }\n this.onPersist?.(entry);\n }\n\n update(commandId: string, patch: Partial<HqCommandAuditEntry>): void {\n const entry = this.entries.find((e) => e.commandId === commandId);\n if (entry) {\n Object.assign(entry, patch);\n this.onPersist?.(entry);\n }\n }\n\n /** Update only when the command belongs to the authenticated client. */\n updateForClient(\n commandId: string,\n clientId: string,\n patch: Partial<HqCommandAuditEntry>,\n ): boolean {\n const entry = this.entries.find(\n (candidate) => candidate.commandId === commandId && candidate.clientId === clientId,\n );\n if (!entry) return false;\n Object.assign(entry, patch);\n this.onPersist?.(entry);\n return true;\n }\n\n /** Seed the ring from a durable store on boot (no persist callback fired). */\n seed(entries: readonly HqCommandAuditEntry[]): void {\n for (const entry of entries) {\n this.entries.push(entry);\n }\n if (this.entries.length > this.max) {\n this.entries.splice(0, this.entries.length - this.max);\n }\n }\n\n recent(limit = 200): HqCommandAuditEntry[] {\n return this.entries.slice(-limit);\n }\n}\n", "/**\n * HQ alerting engine \u2014 evaluates the current snapshot against a set of\n * operator-configurable rules and emits `hq.alert` messages when a threshold\n * is crossed. Mirrors the BrainMonitor's self-activation logic (tool-failure\n * streaks, error storms) but at the fleet-wide command-center scope.\n *\n * Rules are evaluated on a periodic tick (default 15s, unref'd) against the\n * latest in-memory snapshot. Deduplication prevents alert storms: a rule that\n * is still firing is not re-emitted until it clears (state machine per rule).\n *\n * @module hq/alerts\n */\nimport type { HqAlertMessage, HqSnapshot } from './protocol.js';\n\n/** Severity levels for alerts, mirroring {@link HqAlertMessage}. */\nexport type HqAlertSeverity = HqAlertMessage['severity'];\n\nexport interface HqAlert {\n id: string;\n ruleId: string;\n severity: HqAlertSeverity;\n message: string;\n /** Epoch ms when the alert first fired in its current episode. */\n firstFiredAt: number;\n /** Epoch ms of the most recent evaluation that confirmed the alert. */\n lastFiredAt: number;\n}\n\nexport interface HqAlertRuleConfig {\n /** Maximum cost (USD) across the whole fleet before alerting. Default 50. */\n costThresholdUsd?: number;\n /** Seconds of silence from ALL machines before a stale alert fires. Default 120. */\n staleMachineSeconds?: number;\n /** Minimum number of active agents before concurrency alert fires. Default: disabled (0). */\n maxAgents?: number;\n}\n\n/** The fully-resolved config passed to rule.evaluate (no optional fields). */\ntype ResolvedAlertConfig = Required<Pick<HqAlertRuleConfig, 'costThresholdUsd' | 'staleMachineSeconds' | 'maxAgents'>>;\n\n/** A rule is a pure function: snapshot + config \u2192 optional firing. */\ninterface HqAlertRule {\n id: string;\n severity: HqAlertSeverity;\n evaluate: (snapshot: HqSnapshot | null, config: ResolvedAlertConfig, now: number) => string | null;\n}\n\nconst DEFAULT_CONFIG: ResolvedAlertConfig = {\n costThresholdUsd: 50,\n staleMachineSeconds: 120,\n maxAgents: 0,\n};\n\nfunction resolveConfig(config?: HqAlertRuleConfig): ResolvedAlertConfig {\n return { ...DEFAULT_CONFIG, ...(config ?? {}) };\n}\n\nconst RULES: readonly HqAlertRule[] = [\n {\n id: 'fleet-cost-threshold',\n severity: 'warn',\n evaluate: (snapshot, config) => {\n if (snapshot === null) return null;\n const cost = snapshot.totals.totalCostUsd ?? 0;\n if (cost >= config.costThresholdUsd) {\n return `Fleet cost $${cost.toFixed(2)} exceeded threshold $${config.costThresholdUsd.toFixed(2)}`;\n }\n return null;\n },\n },\n {\n id: 'all-machines-stale',\n severity: 'warn',\n evaluate: (snapshot, config, now) => {\n if (snapshot === null) return null;\n const machines = snapshot.machines ?? [];\n if (machines.length === 0) return null;\n const cutoff = now - config.staleMachineSeconds * 1000;\n const stale = machines.filter((m) => Date.parse(m.lastActivityAt) < cutoff);\n if (stale.length === machines.length) {\n return `All ${machines.length} machine(s) silent for ${config.staleMachineSeconds}s`;\n }\n return null;\n },\n },\n {\n id: 'high-concurrency',\n severity: 'info',\n evaluate: (snapshot, config) => {\n if (snapshot === null || config.maxAgents <= 0) return null;\n const agents = snapshot.totals.activeAgents ?? 0;\n if (agents >= config.maxAgents) {\n return `High fleet concurrency: ${agents} active agents (limit ${config.maxAgents})`;\n }\n return null;\n },\n },\n {\n id: 'fleet-failure-spike',\n severity: 'warn',\n evaluate: (snapshot) => {\n if (snapshot === null) return null;\n // Aggregate failed tasks across all reported fleets.\n const fleets = snapshot.fleets ?? [];\n const failed = fleets.reduce((sum, f) => sum + f.failedTasks, 0);\n if (failed >= 5) {\n return `${failed} failed task(s) across the fleet`;\n }\n return null;\n },\n },\n];\n\n/**\n * In-memory alert state. Tracks which rules are currently firing so the same\n * alert is not re-emitted every tick \u2014 only state transitions (cleared \u2192\n * firing) emit. Optionally persists to disk via a callback.\n */\nexport class HqAlertEngine {\n private readonly active = new Map<string, HqAlert>();\n private readonly history: HqAlert[] = [];\n private readonly maxHistory: number;\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly onAlert: (alert: HqAlert) => void;\n private readonly onPersist?: ((alert: HqAlert) => void) | undefined;\n\n constructor(opts: {\n onAlert: (alert: HqAlert) => void;\n maxHistory?: number;\n /** Optional durable sink \u2014 fires when an alert transitions to firing. */\n onPersist?: ((alert: HqAlert) => void) | undefined;\n }) {\n this.onAlert = opts.onAlert;\n this.maxHistory = opts.maxHistory ?? 500;\n this.onPersist = opts.onPersist;\n }\n\n /**\n * Evaluate all rules against the snapshot. Emits (via the `onAlert`\n * callback) only for rules that newly transition to firing. Clears rules\n * that are no longer firing. Returns the list of newly-fired alerts.\n */\n evaluate(snapshot: HqSnapshot | null, config?: HqAlertRuleConfig, now: number = Date.now()): HqAlert[] {\n const resolved = resolveConfig(config);\n const fired: HqAlert[] = [];\n const firingIds = new Set<string>();\n\n for (const rule of RULES) {\n const message = rule.evaluate(snapshot, resolved, now);\n if (message !== null) {\n firingIds.add(rule.id);\n const existing = this.active.get(rule.id);\n if (existing === undefined) {\n // New transition \u2192 emit.\n const alert: HqAlert = {\n id: `${rule.id}-${now}`,\n ruleId: rule.id,\n severity: rule.severity,\n message,\n firstFiredAt: now,\n lastFiredAt: now,\n };\n this.active.set(rule.id, alert);\n this.history.push(alert);\n if (this.history.length > this.maxHistory) this.history.splice(0, this.history.length - this.maxHistory);\n fired.push(alert);\n this.onAlert(alert);\n this.onPersist?.(alert);\n } else {\n // Already firing \u2014 refresh timestamp, don't re-emit.\n existing.lastFiredAt = now;\n }\n }\n }\n\n // Clear rules no longer firing.\n for (const id of Array.from(this.active.keys())) {\n if (!firingIds.has(id)) {\n this.active.delete(id);\n }\n }\n\n return fired;\n }\n\n /** Currently-active (firing) alerts. */\n activeAlerts(): HqAlert[] {\n return Array.from(this.active.values());\n }\n\n /** Historical alerts (newest-last), capped at maxHistory. */\n recentAlerts(limit = 100): HqAlert[] {\n return this.history.slice(-limit);\n }\n\n /** Seed the history from a durable store on boot (no alert callbacks fired). */\n seed(alerts: readonly HqAlert[]): void {\n for (const alert of alerts) {\n this.history.push(alert);\n }\n if (this.history.length > this.maxHistory) {\n this.history.splice(0, this.history.length - this.maxHistory);\n }\n }\n\n /**\n * Start periodic evaluation against a snapshot getter. The timer is\n * unref'd so it never keeps the process alive. Returns a disposer.\n */\n startPeriodic(\n getSnapshot: () => HqSnapshot | null,\n config?: HqAlertRuleConfig | (() => HqAlertRuleConfig | undefined),\n intervalMs = 15_000,\n ): () => void {\n if (this.timer !== null) return () => undefined;\n const tick = (): void => {\n try {\n const cfg = typeof config === 'function' ? config() : config;\n this.evaluate(getSnapshot(), cfg);\n } catch {\n /* best-effort \u2014 alert evaluation must never crash the server */\n }\n };\n this.timer = setInterval(tick, intervalMs);\n this.timer.unref?.();\n return () => {\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n };\n }\n}\n\n/** Map an internal {@link HqAlert} to the wire {@link HqAlertMessage}. */\nexport function toAlertMessage(alert: HqAlert): HqAlertMessage {\n return {\n type: 'hq.alert',\n severity: alert.severity,\n message: `[${alert.ruleId}] ${alert.message}`,\n timestamp: new Date(alert.lastFiredAt).toISOString(),\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["redacted", "out", "createHash", "randomUUID", "fs", "basename", "randomUUID", "path", "fs", "path", "path", "projectHash", "stat", "stat", "resolve", "randomUUID", "randomBytes", "randomUUID", "fs", "path", "resolve", "randomBytes", "randomUUID", "createHash", "basename", "randomUUID", "fs", "fsp", "stat", "fs", "path"]
|
|
3
|
+
"sources": ["../../src/hq/protocol/tool.ts", "../../src/hq/protocol/core.ts", "../../src/security/secret-scrubber.ts", "../../src/hq/redaction.ts", "../../src/coordination/mailbox-types.ts", "../../src/hq/mailbox-mapper.ts", "../../src/hq/publisher.ts", "../../src/hq/factory.ts", "../../src/coordination/global-mailbox.ts", "../../src/utils/atomic-write.ts", "../../src/utils/session-scoped-path.ts", "../../src/utils/wstack-paths.ts", "../../src/types/errors.ts", "../../src/coordination/mailbox-constants.ts", "../../src/coordination/mailbox-message-codec.ts", "../../src/hq/auth-store.ts", "../../src/hq/exposure.ts", "../../src/hq/session-bridge.ts", "../../src/hq/transcript-mapper.ts", "../../src/hq/fleet-bridge.ts", "../../src/hq/brain-bridge.ts", "../../src/hq/worktree-bridge.ts", "../../src/hq/tool-bridge.ts", "../../src/hq/cost-bridge.ts", "../../src/hq/persistence.ts", "../../src/hq/commands.ts", "../../src/hq/alerts.ts"],
|
|
4
|
+
"sourcesContent": ["import type { HqPathPolicy } from './project.js';\n\nexport type HqToolArgsPolicy = 'none' | 'summary' | 'redacted' | 'full';\n\nexport interface HqRedactionPolicy {\n rawContent: boolean;\n toolArgs: HqToolArgsPolicy;\n paths: HqPathPolicy;\n}\n\nexport const DEFAULT_HQ_REDACTION_POLICY: HqRedactionPolicy = {\n rawContent: true,\n toolArgs: 'full',\n paths: 'full',\n};\n\n/**\n * Per-string cap applied when redacting chat-transcript events\n * (`session.transcript` / `agent.message`). The generic 500-char summary cap\n * is right for telemetry rollups but would mangle full chat-history rendering\n * in the HQ Console once `rawContent` is enabled \u2014 messages and tool outputs\n * routinely exceed it. Applied publisher-side AND at the server's re-redaction\n * so both hops agree.\n */\nexport const HQ_TRANSCRIPT_TEXT_CAP = 16_000;\n\nexport interface HqToolStartedPayload {\n toolName: string;\n capabilities?: readonly string[];\n risk?: string;\n inputSummary?: unknown;\n}\n\nexport interface HqToolCompletedPayload {\n toolName: string;\n status: 'success' | 'error' | 'timeout' | 'cancelled';\n durationMs: number;\n outputSummary?: unknown;\n errorClass?: string;\n}\n", "import type {\n HqClientCapability,\n HqClientCommandAckMessage,\n HqClientCommandPollMessage,\n HqClientHelloPayload,\n HqClientHeartbeatPayload,\n HqClientIdentity,\n HqClientKind,\n HqClientMessage,\n} from './client.js';\nimport type { HqBrainEventPayload } from './brain.js';\nimport type {\n HqFleetEventPayload,\n HqFleetSnapshotPayload,\n HqQueuedCommand,\n HqWorktreeEventPayload,\n} from './fleet.js';\nimport type {\n HqMailboxAgentSummary,\n HqMailboxEventPayload,\n HqMailboxMessageSummary,\n HqMailboxSnapshotPayload,\n} from './mailbox.js';\nimport type {\n HqMcpFailureCounts,\n HqMcpHealthCheck,\n HqMcpHealthSnapshotPayload,\n HqMcpLatencySummary,\n HqMcpOperationPayload,\n HqMcpServerHealth,\n} from './mcp.js';\nimport type { HqProjectIdentity, HqWorkspaceKind } from './project.js';\nimport type {\n HqSessionAgentSummary,\n HqSessionEndedPayload,\n HqSessionSnapshotPayload,\n HqSubagentSummary,\n HqTranscriptAppendPayload,\n HqTranscriptEntry,\n} from './session.js';\nimport type {\n HqRedactionPolicy,\n HqToolCompletedPayload,\n HqToolStartedPayload,\n} from './tool.js';\n\nexport const HQ_PROTOCOL_VERSION = 1 as const;\n\nexport type HqProtocolVersion = typeof HQ_PROTOCOL_VERSION;\n\nexport interface HqWelcomePayload {\n type: 'hq.welcome';\n protocolVersion: HqProtocolVersion;\n serverTime: string;\n acceptedCapabilities: readonly HqClientCapability[];\n redactionPolicy: HqRedactionPolicy;\n}\n\nexport interface HqEventEnvelope<TPayload = unknown> {\n id: string;\n type: HqEventType | (string & {});\n schemaVersion: HqProtocolVersion;\n timestamp: string;\n clientId: string;\n projectId: string;\n sessionId?: string;\n runId?: string;\n seq: number;\n payload: TPayload;\n}\n\nexport type HqEventType =\n | 'client.hello'\n | 'client.heartbeat'\n | 'session.started'\n | 'session.status'\n | 'session.usage'\n | 'tool.started'\n | 'tool.completed'\n | 'fleet.snapshot'\n | 'fleet.event'\n | 'mailbox.snapshot'\n | 'mailbox.event'\n | 'worklist.snapshot'\n | 'git.snapshot'\n | 'agent.message'\n | 'agent.status'\n | 'session.snapshot'\n | 'session.transcript'\n | 'session.ended'\n | 'brain.event'\n | 'worktree.event'\n | 'mcp.health.snapshot'\n | 'mcp.operation';\n\nexport interface HqUsagePayload {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n costUsd?: number;\n durationMs?: number;\n /** Provider id that produced this usage (e.g. 'anthropic'), when known. */\n provider?: string;\n /** Model id the cost was priced against, when known. */\n model?: string;\n /** Cache-read (prompt-cache hit) tokens, when reported. */\n cacheRead?: number;\n /** Cache-write tokens, when reported. */\n cacheWrite?: number;\n}\n\n/** A physical machine, aggregated by HQ from connected clients' machineId. */\nexport interface HqMachineRecord {\n machineId: string;\n hostname?: string;\n clientCount: number;\n sessionCount: number;\n agentCount: number;\n projectIds: readonly string[];\n lastActivityAt: string;\n}\n\nexport interface HqGitSnapshotPayload {\n branch?: string;\n dirtyFiles?: number;\n stagedFiles?: number;\n ahead?: number;\n behind?: number;\n}\n\nexport interface HqAlertMessage {\n type: 'hq.alert';\n severity: 'info' | 'warn' | 'error';\n message: string;\n timestamp: string;\n}\n\nexport interface HqHeartbeatMessage {\n type: 'hq.heartbeat';\n serverTime: string;\n}\n\nexport interface HqServerCommandBatchMessage {\n type: 'hq.command_batch';\n commands: readonly HqQueuedCommand[];\n}\n\nexport type HqServerMessage = HqServerCommandBatchMessage | HqWelcomePayload;\n\n/**\n * Discriminated parse result for {@link parseHqFrame}. The `reason` field\n * is only present when `ok` is `false`; consumers should narrow on `ok`\n * before accessing `frame` or `reason`.\n */\nexport type HqParseResult =\n | { ok: true; frame: HqClientMessage }\n | { ok: false; reason: 'invalid-json' | 'unknown-type' | 'malformed' };\n\n/** Known client \u2192 server frame `type` discriminators. */\nconst KNOWN_HQ_CLIENT_FRAME_TYPES = new Set<HqClientMessage['type']>([\n 'client.hello',\n 'client.event',\n 'client.command_poll',\n 'client.command_ack',\n]);\n\nconst HQ_CLIENT_KINDS = new Set<HqClientKind>([\n 'tui',\n 'repl',\n 'webui',\n 'cli',\n 'mailbox',\n 'unknown',\n]);\nconst HQ_WORKSPACE_KINDS = new Set<HqWorkspaceKind>(['git', 'directory', 'unknown']);\nconst HQ_CLIENT_CAPABILITIES = new Set<HqClientCapability>([\n 'telemetry.publish',\n 'session.summary',\n 'fleet.summary',\n 'mailbox.summary',\n 'mailbox.serve',\n 'control.receive',\n]);\nconst HQ_COMMAND_ACK_STATUSES = new Set<HqClientCommandAckMessage['status']>([\n 'accepted',\n 'completed',\n 'failed',\n 'rejected',\n]);\n\n/** Top-level object + string `type` guard. */\nfunction hasStringType(x: unknown): x is { type: string } {\n return typeof x === 'object' && x !== null && typeof (x as { type?: unknown }).type === 'string';\n}\n\nfunction isHqClientIdentity(x: unknown): x is HqClientIdentity {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.clientId === 'string' &&\n typeof v.kind === 'string' &&\n HQ_CLIENT_KINDS.has(v.kind as HqClientKind) &&\n typeof v.machineId === 'string' &&\n typeof v.startedAt === 'string'\n );\n}\n\nfunction isHqProjectIdentity(x: unknown): x is HqProjectIdentity {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.projectId === 'string' &&\n typeof v.projectRoot === 'string' &&\n typeof v.projectName === 'string' &&\n typeof v.machineId === 'string' &&\n typeof v.workspaceKind === 'string' &&\n HQ_WORKSPACE_KINDS.has(v.workspaceKind as HqWorkspaceKind)\n );\n}\n\nfunction isHqRedactionPolicy(x: unknown): x is HqRedactionPolicy {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.rawContent === 'boolean' &&\n (v.toolArgs === 'none' || v.toolArgs === 'summary' || v.toolArgs === 'redacted' || v.toolArgs === 'full') &&\n (v.paths === 'none' ||\n v.paths === 'project-relative' ||\n v.paths === 'redacted' ||\n v.paths === 'full')\n );\n}\n\nfunction isHqClientHelloPayload(x: unknown): x is HqClientHelloPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.protocolVersion === 'number' &&\n isHqClientIdentity(v.client) &&\n isHqProjectIdentity(v.project) &&\n Array.isArray(v.capabilities) &&\n v.capabilities.every(\n (capability) =>\n typeof capability === 'string' &&\n HQ_CLIENT_CAPABILITIES.has(capability as HqClientCapability),\n ) &&\n (v.redactionPolicy === undefined || isHqRedactionPolicy(v.redactionPolicy))\n );\n}\n\nfunction isHqEventEnvelope(x: unknown): x is HqEventEnvelope {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.id === 'string' &&\n typeof v.type === 'string' &&\n v.schemaVersion === HQ_PROTOCOL_VERSION &&\n typeof v.timestamp === 'string' &&\n typeof v.clientId === 'string' &&\n typeof v.projectId === 'string' &&\n Number.isSafeInteger(v.seq) &&\n (v.seq as number) >= 0 &&\n Object.hasOwn(v, 'payload')\n );\n}\n\nfunction isHqClientCommandPollMessage(x: unknown): x is HqClientCommandPollMessage {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.clientId === 'string' &&\n typeof v.projectId === 'string' &&\n (v.afterCommandId === undefined || typeof v.afterCommandId === 'string') &&\n (v.limit === undefined ||\n (Number.isSafeInteger(v.limit) && (v.limit as number) > 0 && (v.limit as number) <= 200))\n );\n}\n\nfunction isHqClientCommandAckMessage(x: unknown): x is HqClientCommandAckMessage {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.clientId === 'string' &&\n typeof v.projectId === 'string' &&\n typeof v.commandId === 'string' &&\n typeof v.status === 'string' &&\n HQ_COMMAND_ACK_STATUSES.has(v.status as HqClientCommandAckMessage['status']) &&\n (v.message === undefined || typeof v.message === 'string')\n );\n}\n\n/**\n * Strictly parse a raw client \u2192 server frame into a {@link HqParseResult}.\n *\n * Validates, in order:\n * 1. JSON syntax (`invalid-json` on failure)\n * 2. Top-level object with string `type` discriminator\n * 3. `type` is one of {@link HqClientMessage} union members (`unknown-type`)\n * 4. Per-type field-shape presence checks (`malformed` on failure)\n *\n * On success, `frame` is narrowed to {@link HqClientMessage} and consumers\n * can switch on `frame.type` for type-safe access to per-union-member\n * fields without `as` casts.\n */\nexport function parseHqFrame(raw: string | Buffer): HqParseResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(typeof raw === 'string' ? raw : raw.toString('utf8'));\n } catch {\n return { ok: false, reason: 'invalid-json' };\n }\n\n if (!hasStringType(parsed)) {\n return { ok: false, reason: 'malformed' };\n }\n const obj = parsed as { type: string } & Record<string, unknown>;\n\n if (!KNOWN_HQ_CLIENT_FRAME_TYPES.has(obj.type as HqClientMessage['type'])) {\n return { ok: false, reason: 'unknown-type' };\n }\n\n switch (obj.type as HqClientMessage['type']) {\n case 'client.hello':\n if (!isHqClientHelloPayload(obj.payload)) {\n return { ok: false, reason: 'malformed' };\n }\n return { ok: true, frame: { type: 'client.hello', payload: obj.payload } };\n case 'client.event':\n if (!isHqEventEnvelope(obj.event)) {\n return { ok: false, reason: 'malformed' };\n }\n return { ok: true, frame: { type: 'client.event', event: obj.event } };\n case 'client.command_poll':\n if (!isHqClientCommandPollMessage(obj)) {\n return { ok: false, reason: 'malformed' };\n }\n return {\n ok: true,\n frame: {\n type: 'client.command_poll',\n clientId: obj.clientId,\n projectId: obj.projectId,\n ...(typeof obj.afterCommandId === 'string'\n ? { afterCommandId: obj.afterCommandId }\n : {}),\n ...(typeof obj.limit === 'number' ? { limit: obj.limit } : {}),\n },\n };\n case 'client.command_ack':\n if (!isHqClientCommandAckMessage(obj)) {\n return { ok: false, reason: 'malformed' };\n }\n return {\n ok: true,\n frame: {\n type: 'client.command_ack',\n clientId: obj.clientId,\n projectId: obj.projectId,\n commandId: obj.commandId,\n status: obj.status as HqClientCommandAckMessage['status'],\n ...(typeof obj.message === 'string' ? { message: obj.message } : {}),\n },\n };\n default: {\n // Unreachable: KNOWN_HQ_CLIENT_FRAME_TYPES membership guarantees\n // `obj.type` is one of the cases above. Return `unknown-type` defensively\n // to satisfy the return type if a future HqClientMessage union member\n // is added without updating this switch.\n const _exhaustive: never = obj.type as never;\n return _exhaustive;\n }\n }\n}\n\n/** Known `client.event` envelope event types whose payload shape we validate. */\nconst KNOWN_HQ_EVENT_PAYLOAD_TYPES = new Set<string>([\n 'mailbox.snapshot',\n 'mailbox.event',\n 'session.snapshot',\n 'session.transcript',\n 'session.ended',\n 'fleet.snapshot',\n 'fleet.event',\n 'brain.event',\n 'worktree.event',\n 'tool.started',\n 'tool.completed',\n 'session.usage',\n 'client.heartbeat',\n 'mcp.health.snapshot',\n 'mcp.operation',\n]);\n\nfunction isHqMcpLatencySummary(x: unknown): x is HqMcpLatencySummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.count === 'number' &&\n (v.lastMs === undefined || typeof v.lastMs === 'number') &&\n (v.minMs === undefined || typeof v.minMs === 'number') &&\n (v.maxMs === undefined || typeof v.maxMs === 'number') &&\n (v.p50Ms === undefined || typeof v.p50Ms === 'number') &&\n (v.p95Ms === undefined || typeof v.p95Ms === 'number')\n );\n}\n\nfunction isHqMcpFailureCounts(x: unknown): x is HqMcpFailureCounts {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.transport === 'number' &&\n typeof v.protocol === 'number' &&\n typeof v.tool === 'number'\n );\n}\n\nfunction isHqMcpHealthCheck(x: unknown): x is HqMcpHealthCheck {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.name === 'string' &&\n typeof v.passed === 'boolean' &&\n (v.value === undefined || typeof v.value === 'number') &&\n (v.threshold === undefined || typeof v.threshold === 'number')\n );\n}\n\nconst HQ_MCP_HEALTH_STATES = new Set<string>([\n 'disabled',\n 'dormant',\n 'connecting',\n 'healthy',\n 'degraded',\n 'failed',\n]);\n\nconst HQ_MCP_CONNECTION_STATES = new Set<string>([\n 'idle',\n 'dormant',\n 'connecting',\n 'connected',\n 'reconnecting',\n 'disconnected',\n 'failed',\n]);\n\nfunction isHqMcpServerHealth(x: unknown): x is HqMcpServerHealth {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.name === 'string' &&\n typeof v.projectId === 'string' &&\n typeof v.clientId === 'string' &&\n typeof v.connectionState === 'string' &&\n HQ_MCP_CONNECTION_STATES.has(v.connectionState) &&\n typeof v.healthState === 'string' &&\n HQ_MCP_HEALTH_STATES.has(v.healthState) &&\n (v.lastSuccessAt === undefined || typeof v.lastSuccessAt === 'string') &&\n (v.lastFailureAt === undefined || typeof v.lastFailureAt === 'string') &&\n (v.lastFailureKind === undefined ||\n v.lastFailureKind === 'transport' ||\n v.lastFailureKind === 'protocol' ||\n v.lastFailureKind === 'tool') &&\n typeof v.consecutiveFailures === 'number' &&\n isHqMcpFailureCounts(v.failures) &&\n typeof v.reconnectCount === 'number' &&\n typeof v.wakeCount === 'number' &&\n typeof v.sleepCount === 'number' &&\n typeof v.restartCount === 'number' &&\n isHqMcpLatencySummary(v.connectionLatency) &&\n isHqMcpLatencySummary(v.discoveryLatency) &&\n isHqMcpLatencySummary(v.callLatency) &&\n typeof v.inFlightCalls === 'number' &&\n typeof v.peakInFlightCalls === 'number' &&\n Array.isArray(v.healthChecks) &&\n v.healthChecks.every(isHqMcpHealthCheck)\n );\n}\n\nfunction isHqMcpHealthSnapshotPayload(x: unknown): x is HqMcpHealthSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return Array.isArray(v.servers) && v.servers.every(isHqMcpServerHealth);\n}\n\nfunction isHqMcpOperationPayload(x: unknown): x is HqMcpOperationPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.operation === 'object' &&\n v.operation !== null &&\n Array.isArray(v.servers) &&\n v.servers.every(isHqMcpServerHealth)\n );\n}\n\nfunction isHqMailboxMessageSummary(x: unknown): x is HqMailboxMessageSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.messageId === 'string' &&\n typeof v.from === 'string' &&\n typeof v.to === 'string' &&\n typeof v.subject === 'string' &&\n typeof v.priority === 'string' &&\n typeof v.timestamp === 'string' &&\n typeof v.completed === 'boolean' &&\n typeof v.hasBody === 'boolean'\n );\n}\n\nfunction isHqMailboxAgentSummary(x: unknown): x is HqMailboxAgentSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.agentId === 'string' &&\n typeof v.name === 'string' &&\n typeof v.sessionId === 'string' &&\n typeof v.status === 'string' &&\n typeof v.iterations === 'number' &&\n typeof v.toolCalls === 'number' &&\n typeof v.lastActivityAt === 'string' &&\n typeof v.lastSeenAt === 'string' &&\n typeof v.online === 'boolean'\n );\n}\n\nfunction isHqMailboxSnapshotPayload(x: unknown): x is HqMailboxSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.mailboxId !== 'string' ||\n (v.scope !== 'project' && v.scope !== 'global') ||\n !Array.isArray(v.messages) ||\n !Array.isArray(v.agents) ||\n typeof v.totals !== 'object' ||\n v.totals === null\n ) {\n return false;\n }\n const totals = v.totals as Record<string, unknown>;\n if (\n typeof totals.messages !== 'number' ||\n typeof totals.unread !== 'number' ||\n typeof totals.incomplete !== 'number' ||\n typeof totals.highPriority !== 'number' ||\n typeof totals.onlineAgents !== 'number'\n ) {\n return false;\n }\n for (const message of v.messages) {\n if (!isHqMailboxMessageSummary(message)) return false;\n }\n for (const agent of v.agents) {\n if (!isHqMailboxAgentSummary(agent)) return false;\n }\n return true;\n}\n\nconst HQ_MAILBOX_EVENT_ACTIONS = new Set<string>([\n 'message.sent',\n 'message.read',\n 'message.completed',\n 'message.updated',\n 'agent.registered',\n 'agent.heartbeat',\n 'agent.offline',\n 'agent.deregistered',\n]);\n\nfunction isHqMailboxEventPayload(x: unknown): x is HqMailboxEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.mailboxId !== 'string') return false;\n if (typeof v.action !== 'string' || !HQ_MAILBOX_EVENT_ACTIONS.has(v.action)) return false;\n // `message` and `agent` are optional but, when present, must satisfy\n // their respective shape guard so a downstream consumer can rely on\n // the typed fields.\n if (v.message !== undefined && !isHqMailboxMessageSummary(v.message)) return false;\n if (v.agent !== undefined && !isHqMailboxAgentSummary(v.agent)) return false;\n return true;\n}\n\nconst HQ_SESSION_AGENT_STATUSES = new Set<string>([\n 'idle',\n 'running',\n 'streaming',\n 'waiting_user',\n 'error',\n]);\n\nfunction isHqSessionAgentSummary(x: unknown): x is HqSessionAgentSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.id === 'string' &&\n typeof v.name === 'string' &&\n typeof v.status === 'string' &&\n HQ_SESSION_AGENT_STATUSES.has(v.status) &&\n typeof v.iterations === 'number' &&\n typeof v.toolCalls === 'number' &&\n typeof v.lastActivityAt === 'string'\n );\n}\n\nconst HQ_SESSION_STATUSES = new Set<string>(['active', 'idle', 'closing', 'stale']);\n\nfunction isHqSessionSnapshotPayload(x: unknown): x is HqSessionSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.sessionId !== 'string' ||\n typeof v.clientKind !== 'string' ||\n typeof v.machineId !== 'string' ||\n typeof v.projectId !== 'string' ||\n typeof v.projectName !== 'string' ||\n typeof v.projectRoot !== 'string' ||\n typeof v.status !== 'string' ||\n !HQ_SESSION_STATUSES.has(v.status) ||\n typeof v.startedAt !== 'string' ||\n typeof v.lastActivityAt !== 'string' ||\n typeof v.agentCount !== 'number' ||\n !Array.isArray(v.agents)\n ) {\n return false;\n }\n for (const agent of v.agents) {\n if (!isHqSessionAgentSummary(agent)) return false;\n }\n return true;\n}\n\nconst HQ_TRANSCRIPT_ROLES = new Set<string>([\n 'user',\n 'assistant',\n 'thinking',\n 'tool',\n 'system',\n 'error',\n]);\n\nfunction isHqTranscriptEntry(x: unknown): x is HqTranscriptEntry {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.ts === 'string' &&\n typeof v.role === 'string' &&\n HQ_TRANSCRIPT_ROLES.has(v.role) &&\n typeof v.text === 'string'\n );\n}\n\nfunction isHqTranscriptAppendPayload(x: unknown): x is HqTranscriptAppendPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.sessionId !== 'string' ||\n typeof v.fromSeq !== 'number' ||\n !Array.isArray(v.entries)\n ) {\n return false;\n }\n for (const entry of v.entries) {\n if (!isHqTranscriptEntry(entry)) return false;\n }\n return true;\n}\n\nfunction isHqSessionEndedPayload(x: unknown): x is HqSessionEndedPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return typeof v.sessionId === 'string' && typeof v.endedAt === 'string';\n}\n\nconst HQ_FLEET_SUBAGENT_STATUS = new Set<string>([\n 'pending',\n 'running',\n 'idle',\n 'completed',\n 'failed',\n 'stopped',\n]);\n\nfunction isHqSubagentSummary(x: unknown): x is HqSubagentSummary {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.subagentId === 'string' &&\n typeof v.status === 'string' &&\n HQ_FLEET_SUBAGENT_STATUS.has(v.status)\n );\n}\n\nfunction isHqFleetSnapshotPayload(x: unknown): x is HqFleetSnapshotPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (\n typeof v.runId !== 'string' ||\n typeof v.activeSubagents !== 'number' ||\n typeof v.queuedTasks !== 'number' ||\n typeof v.completedTasks !== 'number' ||\n typeof v.failedTasks !== 'number' ||\n !Array.isArray(v.subagents)\n ) {\n return false;\n }\n for (const s of v.subagents) {\n if (!isHqSubagentSummary(s)) return false;\n }\n return true;\n}\n\nfunction isHqFleetEventPayload(x: unknown): x is HqFleetEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return typeof v.runId === 'string' && typeof v.event === 'string';\n}\n\nconst HQ_BRAIN_EVENT_KINDS = new Set<string>([\n 'decision_requested',\n 'decision_answered',\n 'decision_ask_human',\n 'human_answered',\n 'decision_denied',\n 'intervention',\n]);\n\nfunction isHqBrainEventPayload(x: unknown): x is HqBrainEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.kind !== 'string' || !HQ_BRAIN_EVENT_KINDS.has(v.kind)) return false;\n if (typeof v.at !== 'number') return false;\n return true;\n}\n\nconst HQ_WORKTREE_EVENT_KINDS = new Set<string>([\n 'allocated',\n 'committed',\n 'merged',\n 'conflict',\n 'released',\n 'failed',\n]);\n\nfunction isHqWorktreeEventPayload(x: unknown): x is HqWorktreeEventPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n if (typeof v.kind !== 'string' || !HQ_WORKTREE_EVENT_KINDS.has(v.kind)) return false;\n if (typeof v.handleId !== 'string' || typeof v.ownerId !== 'string') return false;\n return true;\n}\n\nfunction isHqToolStartedPayload(x: unknown): x is HqToolStartedPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return typeof v.toolName === 'string';\n}\n\nfunction isHqToolCompletedPayload(x: unknown): x is HqToolCompletedPayload {\n if (typeof x !== 'object' || x === null) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.toolName === 'string' &&\n typeof v.status === 'string' &&\n typeof v.durationMs === 'number'\n );\n}\n\nfunction isHqUsagePayload(x: unknown): x is HqUsagePayload {\n if (typeof x !== 'object' || x === null) return false;\n // HqUsagePayload has all-optional numeric fields; accept any object so the\n // cost signal is never dropped on a partial payload, but require it be a\n // plain object (not array/null) to keep the downstream typed.\n return !Array.isArray(x);\n}\n\nfunction isHqClientHeartbeatPayload(x: unknown): x is HqClientHeartbeatPayload {\n if (typeof x !== 'object' || x === null || Array.isArray(x)) return false;\n const v = x as Record<string, unknown>;\n return (\n typeof v.uptimeMs === 'number' &&\n (v.activeSessionId === undefined || typeof v.activeSessionId === 'string') &&\n (v.activeRunId === undefined || typeof v.activeRunId === 'string') &&\n typeof v.status === 'string' &&\n (v.status === 'active' ||\n v.status === 'idle' ||\n v.status === 'stale' ||\n v.status === 'error') &&\n (v.activeSubagents === undefined || typeof v.activeSubagents === 'number') &&\n (v.queuedTasks === undefined || typeof v.queuedTasks === 'number')\n );\n}\n\n/**\n * Validate the `payload` field of a {@link HqEventEnvelope} for known\n * event types. Returns `{ ok: true, payload }` with a narrowed payload\n * type when the event type has a registered shape guard and the payload\n * matches it; `{ ok: true, payload: unknown }` for event types that the\n * server does not yet validate; or `{ ok: false, reason }` when the\n * payload fails the registered guard.\n *\n * Use this after {@link parseHqFrame} has produced a valid frame, when\n * the frame is `client.event` and the server is about to consume the\n * event payload.\n */\nexport type HqEventPayloadResult<T> =\n | { ok: true; payload: T }\n | { ok: false; reason: 'unknown-event-type' | 'malformed-payload' };\n\nexport function parseHqEventPayload(\n eventType: string,\n payload: unknown,\n): HqEventPayloadResult<unknown> {\n if (!KNOWN_HQ_EVENT_PAYLOAD_TYPES.has(eventType)) {\n // Server does not validate this event type yet \u2014 pass it through\n // untyped so the publish pipeline is not blocked. Future events\n // can opt-in by adding their type + guard here.\n return { ok: true, payload };\n }\n switch (eventType) {\n case 'mailbox.snapshot':\n return isHqMailboxSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'mailbox.event':\n return isHqMailboxEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.snapshot':\n return isHqSessionSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.transcript':\n return isHqTranscriptAppendPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.ended':\n return isHqSessionEndedPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'fleet.snapshot':\n return isHqFleetSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'fleet.event':\n return isHqFleetEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'brain.event':\n return isHqBrainEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'worktree.event':\n return isHqWorktreeEventPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'tool.started':\n return isHqToolStartedPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'tool.completed':\n return isHqToolCompletedPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'session.usage':\n return isHqUsagePayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'client.heartbeat':\n return isHqClientHeartbeatPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'mcp.health.snapshot':\n return isHqMcpHealthSnapshotPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n case 'mcp.operation':\n return isHqMcpOperationPayload(payload)\n ? { ok: true, payload }\n : { ok: false, reason: 'malformed-payload' };\n default: {\n const _exhaustive: never = eventType as never;\n return _exhaustive;\n }\n }\n}\n\nexport function createHqEventEnvelope<TPayload>(input: {\n id: string;\n type: HqEventType | (string & {});\n timestamp: string;\n clientId: string;\n projectId: string;\n seq: number;\n payload: TPayload;\n sessionId?: string;\n runId?: string;\n}): HqEventEnvelope<TPayload> {\n return {\n id: input.id,\n type: input.type,\n schemaVersion: HQ_PROTOCOL_VERSION,\n timestamp: input.timestamp,\n clientId: input.clientId,\n projectId: input.projectId,\n seq: input.seq,\n payload: input.payload,\n ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),\n ...(input.runId !== undefined ? { runId: input.runId } : {}),\n };\n}\n", "import type { SecretScrubber } from '../types/secret-scrubber.js';\n\ninterface Pattern {\n type: string;\n regex: RegExp;\n}\n\nconst PATTERNS: Pattern[] = [\n // Anchored at the start where possible so partial matches inside larger\n // strings don't trigger false positives.\n {\n type: 'anthropic_key',\n regex: /(?<![A-Za-z0-9])sk-ant-api\\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g,\n },\n { type: 'openai_key', regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },\n { type: 'github_pat', regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g },\n { type: 'github_pat_v2', regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g },\n { type: 'aws_access_key', regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g },\n { type: 'gcp_key', regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g },\n { type: 'slack_token', regex: /(?<![A-Za-z0-9-])xox[abpos]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g },\n {\n type: 'stripe_key',\n regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'twilio_sid', regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g,\n },\n {\n type: 'telegram_bot_token',\n // Telegram tokens are of the form bot<digits>:<alphanum> in URL paths\n regex: /\\/bot\\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,\n },\n {\n type: 'jwt',\n // Anchored: look for literal \"eyJ\" which is unambiguous for JWT header\n regex:\n /(?<![A-Za-z0-9/+=])eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9/+=])/g,\n },\n {\n type: 'private_key',\n // Anchored: start must be BEGIN, end must be END with no extra dashes after END\n regex:\n /(?:^|\\n)-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----[\\s\\S]*?-----END[^-]*-----(?:\\n|$)/g,\n },\n { type: 'mongodb_uri', regex: /mongodb(?:\\+srv)?:\\/\\/[^\\s\"'`]+/g },\n { type: 'postgres_uri', regex: /postgres(?:ql)?:\\/\\/[^\\s\"'`]+/g },\n { type: 'mysql_uri', regex: /mysql:\\/\\/[^\\s\"'`]+/g },\n { type: 'redis_uri', regex: /redis:\\/\\/[^\\s\"'`]+/g },\n // AI/ML provider keys \u2014 modern LLM services with well-known prefixes\n {\n type: 'huggingface_token',\n // HuggingFace tokens: hf_ followed by 34 alphanumeric chars\n regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g,\n },\n {\n type: 'replicate_token',\n // Replicate tokens: r8_ followed by 40+ alphanumeric chars\n regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'perplexity_key',\n // Perplexity API keys: pplx- followed by 40+ alphanumeric chars\n regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'groq_key',\n // Groq API keys: gsk_ followed by 40+ alphanumeric chars\n regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g,\n },\n {\n type: 'bearer_token',\n // Anchored with alternation instead of negative lookahead \u2014 avoids V8\n // backtracking risk on adversarial input. Bounded at 512 chars.\n // Min 12 chars: some OAuth providers issue shorter-lived tokens (< 20\n // chars). A 12-char base64 string has ~71 bits of entropy \u2014 above the\n // threshold where random strings are unlikely to produce false matches.\n // The trailing boundary is a NON-consuming lookahead: two adjacent bearer\n // tokens sharing a single delimiter (`Bearer a\u2026 Bearer b\u2026`) must both be\n // redacted. A consuming trailing delimiter would eat the separator the\n // next match needs for its leading anchor, leaking the second token.\n regex: /(?:^|[^A-Za-z0-9_.~+/-])Bearer\\s+[A-Za-z0-9._~+/-]{12,512}=*(?=$|[^A-Za-z0-9_.~+/-])/g,\n },\n {\n type: 'high_entropy_env',\n // Anchored with alternation instead of lookbehind to avoid backtracking.\n // Value bounded at 512 chars.\n // The trailing boundary is a NON-consuming lookahead so two secrets\n // separated by a single delimiter (one space OR one newline, e.g.\n // `printenv` / `.env` dumps: `API_KEY=\u2026 \\n SESSION_TOKEN=\u2026`) are BOTH\n // redacted. A consuming trailing `\\s` would swallow the separator the\n // next match needs for its leading anchor, so every other secret would\n // leak in plaintext.\n // The leading delimiter is CAPTURED (group 1) and re-emitted by the\n // replacement so the separator between adjacent secrets is preserved\n // rather than collapsed. Capture groups are therefore: 1=leading\n // delimiter, 2=key name, 3=value.\n regex: /(^|\\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\\s*[:=]\\s*['\"]?([A-Za-z0-9_/+=-]{20,512})['\"]?(?=\\s|$)/g,\n },\n];\n\n/**\n * `high_entropy_env` is the one pattern that needs special replacement logic\n * (it preserves the key name), so it runs in its own pass. Every other pattern\n * is folded into a single combined regex. Derive the split by type rather than\n * by hard-coded indices so adding/removing a pattern can't silently drop one.\n */\nconst SIMPLE_PATTERNS = PATTERNS.filter((p) => p.type !== 'high_entropy_env');\n\n/**\n * Combined single-pass regex for all simple patterns. Each alternative is a\n * capturing group so the callback can determine which original pattern fired\n * (only one group is non-undefined at match time). Order matches SIMPLE_PATTERNS\n * (longer/more-specific prefixes first). Relies on each simple pattern source\n * containing no internal capturing groups \u2014 only `(?:...)` and lookarounds.\n */\nconst COMBINED_REGEX = new RegExp(SIMPLE_PATTERNS.map((p) => `(${p.regex.source})`).join('|'), 'g');\n\n/** Separate pattern for high_entropy_env (different replacement logic). */\nconst HIGH_ENTROPY_REGEX = PATTERNS.find((p) => p.type === 'high_entropy_env')!.regex;\n\n/**\n * Replacements for the combined patterns, parallel to SIMPLE_PATTERNS. The\n * combined-regex callback indexes into this with the matched group's position.\n */\nconst COMBINED_REPLACEMENTS = SIMPLE_PATTERNS.map((p) => `[REDACTED:${p.type}]`);\n\n/**\n * Per-chunk cap. Splits long inputs into 64 KB chunks to keep scrub() memory\n * bounded. Real scrub() inputs (LLM responses, tool outputs) are typically\n * much smaller; this cap handles edge cases without impacting normal usage.\n */\nconst SCRUB_CHUNK_BYTES = 64 * 1024;\n\n/**\n * Overlap window used to nudge a chunk boundary onto a safe separator so a\n * secret straddling the 64 KB cut isn't split in half (which would leave\n * neither half matching, leaking the secret verbatim).\n *\n * Sized above the longest BOUNDED credential pattern: `high_entropy_env`\n * caps its value at 512 chars (+ key name + quotes \u2248 560) and `bearer_token`\n * at 512; every prefix-keyed pattern is far shorter. Because all of these\n * patterns are whitespace-free, the first whitespace at/after the nominal cut\n * is guaranteed to sit *past the end* of any such secret \u2014 so snapping the\n * boundary forward to it keeps every bounded secret wholly inside one chunk.\n * 1 KB gives comfortable headroom over the 560-char worst case.\n */\nconst SCRUB_OVERLAP_BYTES = 1024;\n\n/**\n * Quick pre-scan: check if the text contains any substring that MUST be\n * present for a credential pattern to match. If none are found, the text\n * is guaranteed clean \u2014 skip all regex passes (2 total: 16-pattern combined + high_entropy_env).\n *\n * Each anchor is the shortest unique substring from the corresponding pattern.\n * V8's `String.includes()` is hand-tuned C++ \u2014 O(n) with near-zero overhead\n * for typical tool-output lengths (100\u20135000 chars). A single combined regex\n * via `text.search()` is consistently slower for this many alternatives.\n */\nfunction hasCredentialAnchors(text: string): boolean {\n return (\n text.includes('-----BEGIN') || // Private keys (most unique \u2192 cheap reject)\n text.includes('sk-') || // Anthropic + OpenAI keys\n text.includes('sk_') || // Stripe live/test keys\n text.includes('ghp_') || // GitHub PAT v1\n text.includes('github_pat_') || // GitHub PAT v2\n text.includes('eyJ') || // JWT\n text.includes('AKIA') || // AWS access key\n text.includes('AIza') || // GCP service key\n text.includes('xox') || // Slack token (xoxa/xoxb/xoxp/xoxo/xoxs)\n text.includes('Bearer ') || // Bearer token (space suffix reduces false positives)\n text.includes('/bot') || // Telegram bot token (URL path pattern)\n text.includes('hf_') || // HuggingFace token\n text.includes('r8_') || // Replicate token\n text.includes('pplx-') || // Perplexity API key\n text.includes('gsk_') || // Groq API key\n text.includes('_KEY=') || // High-entropy env vars: API_KEY=, SECRET_KEY=, ...\n text.includes('_TOKEN=') || // ACCESS_TOKEN=, AUTH_TOKEN=, ...\n text.includes('_SECRET=') || // API_SECRET=, CLIENT_SECRET=, ...\n text.includes('_PASSWORD=') || // DB_PASSWORD=, ROOT_PASSWORD=, ...\n text.includes('mongodb://') ||\n text.includes('mongodb+srv://') ||\n text.includes('postgres://') ||\n text.includes('postgresql://') ||\n text.includes('mysql://') ||\n text.includes('redis://') ||\n // JSON-style credential keys: tool outputs often serialise objects as\n // raw JSON strings rather than parsed objects. The value may not start\n // with a recognisable prefix (sk-, ghp_, etc.), so we anchor on common\n // key names. The `\"` prefix avoids matching prose that happens to mention\n // these words \u2014 JSON serialisation always quotes string keys.\n text.includes('\"apiKey\"') ||\n text.includes('\"api_key\"') ||\n text.includes('\"token\"') ||\n text.includes('\"secret\"') ||\n text.includes('\"password\"') ||\n text.includes('\"authorization\"') ||\n text.includes('\"bearer\"') ||\n text.includes('\"private_key\"') ||\n text.includes('\"access_token\"') ||\n text.includes('\"refresh_token\"') ||\n text.includes('\"client_secret\"')\n );\n}\n\nexport class DefaultSecretScrubber implements SecretScrubber {\n scrub(text: string): string {\n if (!text) return text;\n\n // Fast path: if no credential anchor substrings exist in the text,\n // none of the 17 regex patterns can match. Skip all regex work.\n // This covers the vast majority of tool outputs (~95% of calls on\n // typical sessions are file paths, status messages, diffs, etc.).\n if (!hasCredentialAnchors(text)) return text;\n\n // For oversize inputs, scrub in fixed chunks to keep memory bounded.\n // The boundary is snapped FORWARD to the next whitespace within an\n // overlap window so a secret straddling the nominal 64 KB cut is never\n // split in half. Every bounded credential pattern is whitespace-free, so\n // the next whitespace at/after the cut necessarily falls past the end of\n // any such secret \u2014 guaranteeing it stays wholly inside the current chunk.\n if (text.length <= SCRUB_CHUNK_BYTES) {\n return this.scrubOne(text);\n }\n const out: string[] = [];\n let i = 0;\n while (i < text.length) {\n let end = Math.min(i + SCRUB_CHUNK_BYTES, text.length);\n if (end < text.length) {\n // Look for the first whitespace at/after the nominal cut, bounded by\n // the overlap window. Extending forward (not backward) ensures any\n // secret that began before `end` finishes before the new boundary.\n const limit = Math.min(end + SCRUB_OVERLAP_BYTES, text.length);\n let safe = -1;\n for (let j = end; j < limit; j++) {\n const ch = text.charCodeAt(j);\n // space, \\t, \\n, \\r\n if (ch === 32 || ch === 9 || ch === 10 || ch === 13) {\n safe = j;\n break;\n }\n }\n // Snap onto the whitespace if found; otherwise fall back to the hard\n // cut (an unbroken >1 KB run with no whitespace can't be a bounded\n // secret anyway \u2014 those are all \u2264 ~560 chars and whitespace-free).\n end = safe === -1 ? end : safe + 1;\n }\n out.push(this.scrubOne(text.slice(i, end)));\n i = end;\n }\n return out.join('');\n }\n\n private scrubOne(text: string): string {\n // Redundant guard: if we reached scrubOne via the chunked path, the\n // chunk may have been small enough to anchor-skip independently.\n if (!hasCredentialAnchors(text)) return text;\n\n // Pass 1: combined single-pass regex for all simple patterns. Each\n // alternative is a capturing group; only the group that matched is\n // non-undefined. The trailing offset/string args replace() appends are\n // always defined, so the matched group (which precedes them) is found first.\n let out = text.replace(\n COMBINED_REGEX,\n (match, ...groups) => {\n // groups[i] corresponds to SIMPLE_PATTERNS[i]; find which one fired.\n const idx = groups.findIndex((g) => g !== undefined);\n if (idx < 0) return match;\n const replacement = COMBINED_REPLACEMENTS[idx];\n return replacement !== undefined ? replacement : match;\n },\n );\n\n // Pass 2: high_entropy_env needs special handling \u2014 preserve the key name.\n // Groups: 1=leading delimiter (re-emitted so adjacent-secret separators\n // aren't collapsed), 2=key name, 3=value (redacted).\n out = out.replace(HIGH_ENTROPY_REGEX, (_match, lead, key, _value) => {\n return `${lead}${key}=[REDACTED:high_entropy_env]`;\n });\n\n return out;\n }\n\n /**\n * Recursively scrub every string value in an object/array graph. Secrets can\n * appear under any key \u2014 a URL query param, an `authorization` header, an\n * arbitrarily-named nested field \u2014 so we don't gate recursion on key names.\n * The per-string `scrub()` fast-path (anchor pre-scan) keeps this cheap: any\n * value without a credential anchor returns immediately without regex work.\n */\n scrubObject<T>(obj: T): T {\n const seen = new WeakSet();\n const visit = (v: unknown): unknown => {\n if (typeof v === 'string') return this.scrub(v);\n if (v === null || typeof v !== 'object') return v;\n if (seen.has(v as object)) return v;\n seen.add(v as object);\n if (Array.isArray(v)) return v.map(visit);\n const out: Record<string, unknown> = {};\n for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n out[k] = visit(val);\n }\n return out;\n };\n return visit(obj) as T;\n }\n}\n", "import { DefaultSecretScrubber } from '../security/secret-scrubber.js';\nimport {\n DEFAULT_HQ_REDACTION_POLICY,\n type HqEventEnvelope,\n type HqRedactionPolicy,\n} from './protocol.js';\n\nconst RAW_CONTENT_REPLACEMENT = '[REDACTED:hq_raw_content]';\nconst SENSITIVE_FIELD_REPLACEMENT = '[REDACTED:hq_sensitive_field]';\nconst REDACTED_PATH_REPLACEMENT = '[REDACTED:hq_path]';\n\nconst RAW_CONTENT_KEYS = new Set([\n 'content',\n 'contents',\n 'raw',\n 'rawContent',\n 'body',\n 'message',\n 'messages',\n 'prompt',\n 'prompts',\n 'completion',\n 'response',\n 'text',\n 'partialText',\n 'assistantMessage',\n 'userMessage',\n 'stdout',\n 'stderr',\n 'output',\n 'toolInput',\n 'toolOutput',\n 'outputSummary',\n 'body',\n 'mailboxBody',\n 'messageBody',\n 'outcome',\n 'fileContent',\n 'diff',\n 'patch',\n 'transcript',\n 'logs',\n]);\n\nconst SENSITIVE_KEYS = new Set([\n 'authorization',\n 'cookie',\n 'password',\n 'passwd',\n 'pwd',\n 'secret',\n 'token',\n 'accessToken',\n 'refreshToken',\n 'apiKey',\n 'apikey',\n 'clientSecret',\n 'privateKey',\n]);\n\nconst PATH_KEYS = new Set([\n 'path',\n 'paths',\n 'file',\n 'files',\n 'filepath',\n 'filePath',\n 'filename',\n 'projectRoot',\n 'projectRootDisplay',\n 'cwd',\n 'workingDir',\n 'workingDirectory',\n]);\n\nexport interface HqRedactOptions {\n policy?: Partial<HqRedactionPolicy>;\n projectRoot?: string;\n maxSummaryLength?: number;\n}\n\nexport interface HqRedactionResult<T> {\n value: T;\n redacted: boolean;\n}\n\nconst defaultScrubber = new DefaultSecretScrubber();\n\nexport function resolveHqRedactionPolicy(\n policy?: Partial<HqRedactionPolicy>,\n): HqRedactionPolicy {\n return {\n ...DEFAULT_HQ_REDACTION_POLICY,\n ...policy,\n };\n}\n\n/**\n * Apply an operator policy as a one-way privacy clamp. An override can make a\n * publisher policy stricter, but can never enable raw content or broader path\n * / tool-argument disclosure than the publisher selected.\n */\nexport function tightenHqRedactionPolicy(\n publisherPolicy: HqRedactionPolicy,\n operatorPolicy?: Partial<HqRedactionPolicy>,\n): HqRedactionPolicy {\n if (operatorPolicy === undefined) return publisherPolicy;\n const toolRank: Record<HqRedactionPolicy['toolArgs'], number> = {\n none: 0,\n summary: 1,\n redacted: 2,\n full: 3,\n };\n const pathRank: Record<HqRedactionPolicy['paths'], number> = {\n none: 0,\n redacted: 0,\n 'project-relative': 1,\n full: 2,\n };\n const requestedToolArgs = operatorPolicy.toolArgs;\n const requestedPaths = operatorPolicy.paths;\n return {\n rawContent:\n publisherPolicy.rawContent &&\n (operatorPolicy.rawContent === undefined || operatorPolicy.rawContent),\n toolArgs:\n requestedToolArgs !== undefined &&\n toolRank[requestedToolArgs] < toolRank[publisherPolicy.toolArgs]\n ? requestedToolArgs\n : publisherPolicy.toolArgs,\n paths:\n requestedPaths !== undefined && pathRank[requestedPaths] < pathRank[publisherPolicy.paths]\n ? requestedPaths\n : publisherPolicy.paths,\n };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]';\n}\n\nfunction isSensitiveKey(key: string): boolean {\n const lower = key.toLowerCase();\n return (\n SENSITIVE_KEYS.has(key) ||\n lower.includes('authorization') ||\n lower.includes('password') ||\n lower.includes('secret') ||\n lower.endsWith('token') ||\n lower.endsWith('apikey') ||\n lower.endsWith('api_key')\n );\n}\n\nfunction isRawContentKey(key: string): boolean {\n return RAW_CONTENT_KEYS.has(key) || RAW_CONTENT_KEYS.has(key.toLowerCase());\n}\n\nfunction isPathKey(key: string): boolean {\n return PATH_KEYS.has(key) || PATH_KEYS.has(key.toLowerCase());\n}\n\nfunction normalizePathForCompare(value: string): string {\n return value.replace(/\\\\/g, '/').replace(/\\/+$/g, '');\n}\n\nfunction redactPath(\n value: string,\n projectRoot: string | undefined,\n policy: HqRedactionPolicy,\n): string {\n if (policy.paths === 'full') return value;\n if (policy.paths === 'none' || policy.paths === 'redacted') return REDACTED_PATH_REPLACEMENT;\n\n const normalizedValue = normalizePathForCompare(value);\n if (!projectRoot) return normalizedValue.split('/').at(-1) ?? REDACTED_PATH_REPLACEMENT;\n\n const normalizedRoot = normalizePathForCompare(projectRoot);\n if (normalizedValue === normalizedRoot) return '.';\n if (normalizedValue.startsWith(`${normalizedRoot}/`)) {\n return normalizedValue.slice(normalizedRoot.length + 1) || '.';\n }\n return normalizedValue.split('/').at(-1) ?? REDACTED_PATH_REPLACEMENT;\n}\n\nfunction summarizeString(value: string, maxSummaryLength: number, scrub: boolean): string {\n const scrubbed = scrub ? defaultScrubber.scrub(value) : value;\n if (scrubbed.length <= maxSummaryLength) return scrubbed;\n return `${scrubbed.slice(0, maxSummaryLength)}\u2026[truncated:${scrubbed.length - maxSummaryLength}]`;\n}\n\n/**\n * Scrub a free-text preview field and truncate it to a maximum length so\n * it is safe to embed in HQ event envelopes and broadcast to browsers\n * without leaking secrets or running away on unbounded input.\n *\n * Returns `undefined` when the input is empty or non-string. Truncation\n * suffix is `\"\u2026[truncated:N]\"` where N is the number of dropped chars.\n */\nexport function scrubAndTruncateHqPreview(\n value: unknown,\n maxLength: number = 280,\n): string | undefined {\n if (typeof value !== 'string' || value.length === 0) return undefined;\n return summarizeString(value, maxLength, true);\n}\n\nfunction visitValue(\n value: unknown,\n options: {\n policy: HqRedactionPolicy;\n projectRoot?: string;\n maxSummaryLength: number;\n seen: WeakSet<object>;\n },\n key?: string,\n): { value: unknown; redacted: boolean } {\n if (!options.policy.rawContent && key !== undefined && isSensitiveKey(key)) {\n return { value: SENSITIVE_FIELD_REPLACEMENT, redacted: true };\n }\n\n if (typeof value === 'string') {\n if (key !== undefined && isPathKey(key)) {\n const redactedPath = redactPath(value, options.projectRoot, options.policy);\n return { value: redactedPath, redacted: redactedPath !== value };\n }\n\n if (!options.policy.rawContent && key !== undefined && isRawContentKey(key)) {\n return { value: RAW_CONTENT_REPLACEMENT, redacted: true };\n }\n\n const scrubbed = summarizeString(value, options.maxSummaryLength, !options.policy.rawContent);\n return { value: scrubbed, redacted: scrubbed !== value };\n }\n\n if (value === null || typeof value !== 'object') return { value, redacted: false };\n\n if (options.seen.has(value)) return { value: '[REDACTED:hq_circular]', redacted: true };\n options.seen.add(value);\n\n if (Array.isArray(value)) {\n let redacted = false;\n const out = value.map((item) => {\n const next = visitValue(item, options, key);\n redacted ||= next.redacted;\n return next.value;\n });\n return { value: out, redacted };\n }\n\n if (!isPlainObject(value)) return { value: String(value), redacted: true };\n\n let redacted = false;\n const out: Record<string, unknown> = {};\n for (const [childKey, childValue] of Object.entries(value)) {\n const next = visitValue(childValue, options, childKey);\n redacted ||= next.redacted;\n out[childKey] = next.value;\n }\n return { value: out, redacted };\n}\n\nexport function redactHqValue<T>(value: T, options: HqRedactOptions = {}): HqRedactionResult<T> {\n const result = visitValue(value, {\n policy: resolveHqRedactionPolicy(options.policy),\n ...(options.projectRoot !== undefined ? { projectRoot: options.projectRoot } : {}),\n maxSummaryLength: options.maxSummaryLength ?? 500,\n seen: new WeakSet<object>(),\n });\n return { value: result.value as T, redacted: result.redacted };\n}\n\nexport function redactHqEvent<TPayload>(\n event: HqEventEnvelope<TPayload>,\n options: HqRedactOptions = {},\n): HqRedactionResult<HqEventEnvelope<TPayload>> {\n const payload = redactHqValue(event.payload, options);\n const nextEvent = {\n ...event,\n payload: payload.value,\n };\n return { value: nextEvent, redacted: payload.redacted };\n}\n\nexport function summarizeHqToolArgs(value: unknown, options: HqRedactOptions = {}): unknown {\n const policy = resolveHqRedactionPolicy(options.policy);\n if (policy.toolArgs === 'full') return value;\n if (policy.toolArgs === 'none') return '[REDACTED:hq_tool_args]';\n if (policy.toolArgs === 'redacted') return redactHqValue(value, options).value;\n\n if (value === null || typeof value !== 'object') return redactHqValue(value, options).value;\n if (Array.isArray(value)) return `[array:${value.length}]`;\n\n const entries = Object.entries(value as Record<string, unknown>);\n const summary: Record<string, unknown> = {};\n for (const [key, item] of entries.slice(0, 20)) {\n if (isSensitiveKey(key)) {\n summary[key] = SENSITIVE_FIELD_REPLACEMENT;\n } else if (typeof item === 'string') {\n summary[key] = isPathKey(key)\n ? redactPath(item, options.projectRoot, policy)\n : summarizeString(item, 120, true);\n } else if (Array.isArray(item)) {\n summary[key] = `[array:${item.length}]`;\n } else if (item !== null && typeof item === 'object') {\n summary[key] = '[object]';\n } else {\n summary[key] = item;\n }\n }\n if (entries.length > 20) summary.__truncatedKeys = entries.length - 20;\n return summary;\n}\n", "/**\n * Mailbox \u2014 persistent inter-agent messaging system with cross-session support.\n *\n * Agents can leave notes for specific agents or broadcast to all. Each agent\n * periodically checks the mailbox or retrieves messages via tool calls.\n *\n * ## Cross-session communication\n *\n * The mailbox is stored at **project level** (`~/.wrongstack/projects/<slug>/_mailbox.jsonl`),\n * so agents in different terminal sessions / WebUI tabs working on the same\n * canonical project can communicate live, even when they run in different\n * processes, clients, branches, or linked Git worktrees.\n *\n * ## Agent registration\n *\n * Every agent that uses the mailbox registers itself with a heartbeat.\n * Other agents can discover online agents via `getOnlineAgents()`.\n * Stale agents (no heartbeat > 60s) are pruned automatically.\n *\n * ## Read receipts\n *\n * Each message tracks per-recipient read status via a `readBy` map:\n * `{ \"agentId\": \"ISO8601\" }`. When agent X reads a message, its entry\n * is added. The WebUI shows who read what and when.\n *\n * @module mailbox-types\n */\n\n// \u2500\u2500 Message type discriminator \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * The ten mail types each carry a distinct **semantic category**, a **sender\n * contract** (when the sender must use it), and a **recipient contract** (how\n * the runtime dispatches it and what the recipient agent must do).\n *\n * \u2500\u2500\u2500\u2500\u2500 Type semantics \u2014 decision matrix for senders \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * ## Categories\n *\n * | Category | Types | Purpose |\n * |--------------|---------------------------------------|--------------------------------|\n * | Actionable | `ask`, `assign`, `steer`, `review` | Require a substantive response |\n * | Informational| `note`, `btw`, `result`, `status` | Consume for context, no action |\n * | Routing | `broadcast` | Multi-recipient envelope |\n * | Control | `control` | Out-of-band signal (no render) |\n *\n * ## Per-type contract\n *\n * ### Actionable types\n *\n * | Type | When to send | Recipient must |\n * |----------|-----------------------------------------------------|----------------------------------------------------|\n * | `ask` | Blocking question \u2014 you need an answer to proceed | Answer as soon as possible; the sender is waiting. |\n * | `assign` | Delegating a task | Accept or decline; act on it when current op allows. |\n * | `steer` | Mid-task direction change \u2014 the recipient is | Pause current approach, adjust per instruction, |\n * | | already working on something and you need them | then resume. Rendered first in the mailbox block. |\n * | | to change course NOW | |\n * | `review` | Requesting a code/doc/PR review (passive) | Inspect when convenient; no immediate reply needed.|\n *\n * ### Informational types\n *\n * | Type | When to send | Recipient must |\n * |----------|-----------------------------------------------------|----------------------------------------------------|\n * | `note` | General-purpose FYI \u2014 a message that isn't any | Read for context; no reply needed. The untyped |\n * | | of the more specific types | default for directed messages. |\n * | `btw` | Low-priority aside \u2014 \"by the way\" | Absorb the information and stay on current task; |\n * | | | no reply needed. Injected via BTW block (separate |\n * | | | from the main mailbox fold) to minimise disruption.|\n * | `result` | Subagent/task completion notice \u2014 share the | Factor into next decision; treat as evidence, not |\n * | | outcome of finished work | a new task. |\n * | `status` | Agent or system status update (heartbeat, spawn, | Use to avoid redundant work; never act on it as |\n * | | task progress, error). Machine-generated. | a task or question. |\n * | `broadcast` | Multi-recipient envelope \u2014 the same message for | Read if addressed to you (direct, alias, session, |\n * | | every agent on the project. Auto-selected when | or `*`). The `*` recipient means \"everyone\". |\n * | | `to` is `\"*\"` or `\"@session\"` in `mail_send`. | |\n *\n * ### Control type\n *\n * | Type | When to send | Recipient must |\n * |----------|-----------------------------------------------------|----------------------------------------------------|\n * | `control`| Out-of-band signal (interrupt, halt, redirect). | NEVER folded into conversation content. The agent |\n * | | Machine-generated by the runtime, not by agents. | loop intercepts it separately. `control:interrupt` |\n * | | | causes a cooperative halt at the next iteration |\n * | | | boundary. |\n *\n * \u2500\u2500\u2500\u2500\u2500 Dispatch behavior (runtime contract) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * The mailbox system enforces these dispatch rules:\n *\n * 1. **Send-side**: `mail_send` auto-defaults the type: `broadcast` when\n * `to` is `\"*\"` or `\"@session::...\"`, otherwise `note`.\n * 2. **Send-side validation**: `assign` always requires a specific `to`\n * (not `\"*\"`). `control` is reserved for runtime use \u2014 agents passing it\n * via the tool surface will be rejected.\n * 3. **Render-order guarantee**: `steer` messages are ALWAYS rendered first\n * in `buildMailboxBlock()`, before any other type, to ensure mid-task\n * direction changes are seen before other action items.\n * 4. **Control isolation**: `control`-type messages are filtered by\n * `injectPendingMailboxMessages()` and NEVER enter the folded\n * conversation block \u2014 they are out-of-band signals only.\n * 5. **Background routing**: in `background` delivery mode, only\n * `ACTIONABLE_BACKGROUND_TYPES` (`steer`, `ask`, `assign`, `result`,\n * `review`) are escalated; `note`, `btw`, `status`, and `broadcast`\n * are suppressed to minimise disruption during tool work.\n * 6. **Awareness polling**: `btw` messages intercepted by background\n * polling are queued via `setBtwNote()` for injection at a safe loop\n * boundary, not folded inline.\n * 7. **Agent registry**: `getAgentStatuses()` reads the dedicated agent\n * registry (`_mailbox.registry.json`), not mailbox message content. The\n * registry is populated by agent heartbeat calls (not by `status`-type\n * messages). `DefaultMailbox.getAgentStatuses()` (per-session) derives\n * a registry snapshot from `status`-type messages as a fallback when no\n * shared registry file exists.\n *\n * When a type is missing from any dispatch table, the fallback is:\n * - Render with `\uD83D\uDCE8 <TYPE>` label (generic emoji prefix)\n * - Route inline (not background)\n * - No special instruction added\n */\n\nexport type MailboxMessageType =\n | 'note' // General informational message (untyped default for directed sends)\n | 'ask' // Blocking question \u2014 sender is waiting for an answer\n | 'assign' // Task delegation \u2014 act on it when current op allows\n | 'steer' // Mid-course direction change \u2014 render first, pause current approach\n | 'btw' // Low-priority \"by the way\" \u2014 absorb info, stay on task\n | 'broadcast' // Multi-recipient envelope \u2014 auto-selected for `*` / `@session`\n | 'status' // Agent/system status update \u2014 never treated as a task\n | 'result' // Task completion notice \u2014 evidence for next decision\n | 'review' // Passive review request \u2014 inspect when convenient\n | 'control'; // Out-of-band signal \u2014 never folded into conversation content\n\n/**\n * Semantic category a mail type belongs to \u2014 determines its handling\n * priority, delivery guarantees, and interaction with the agent loop.\n */\nexport type MailboxTypeCategory =\n /** Requires a substantive response from the recipient. */\n | 'actionable'\n /** Consumed for context; no action required. */\n | 'informational'\n /** Multi-recipient envelope \u2014 routing metadata only. */\n | 'routing'\n /** Out-of-band signal handled by the runtime, not the agent. */\n | 'control_signal';\n\n/**\n * Explicit per-type properties used for programmatic dispatch decisions.\n * This is the single source of truth \u2014 every type in the union appears\n * here, so adding a new type requires a corresponding entry.\n */\nexport const MAILBOX_TYPE_PROPERTIES: Record<MailboxMessageType, {\n category: MailboxTypeCategory;\n /** Is the sender expected to get a substantive response? */\n expectsReply: boolean;\n /**\n * Should this message type trigger the \"Action required\" acknowledgement\n * footer in the rendered mailbox block?\n *\n * This is SEPARATE from `expectsReply`:\n * - `review` expects no reply but still requires inspection \u2192 `requiresAction: true`\n * - `ask` requires both a reply AND action \u2192 `requiresAction: true, expectsReply: true`\n * - `result` provides evidence but expects nothing back \u2192 both false\n */\n requiresAction: boolean;\n /** Should this type be injected inline in background delivery mode? */\n backgroundEligible: boolean;\n /** Should this type be excluded from the folded conversation block? */\n outOfBand: boolean;\n /** Render priority (lower = rendered first). */\n renderPriority: number;\n /** Human-readable description of the recipient's obligation. */\n recipientObligation: string;\n /** Human-readable description of when a sender should use this type. */\n senderGuidance: string;\n}> = {\n note: {\n category: 'informational',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: false,\n renderPriority: 20,\n recipientObligation: 'Read for context; no reply needed.',\n senderGuidance: 'General-purpose FYI. Use when no more specific type applies.',\n },\n ask: {\n category: 'actionable',\n expectsReply: true,\n requiresAction: true,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 10,\n recipientObligation: 'Answer as soon as possible \u2014 the sender is waiting.',\n senderGuidance: 'Blocking question. Only use when you need an answer to proceed.',\n },\n assign: {\n category: 'actionable',\n expectsReply: false,\n requiresAction: true,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 10,\n recipientObligation: 'Accept or decline; act on it when current operation allows.',\n senderGuidance: 'Task delegation. Must be directed to a specific recipient (not \"*\").',\n },\n steer: {\n category: 'actionable',\n expectsReply: false,\n requiresAction: true,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 0, // Always rendered first\n recipientObligation: 'Pause current approach, adjust per instruction, then resume.',\n senderGuidance: 'Mid-task direction change. The recipient is already working on something.',\n },\n btw: {\n category: 'informational',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: false,\n renderPriority: 30,\n recipientObligation: 'Absorb the information and stay on current task; no reply needed.',\n senderGuidance: 'Low-priority aside. Non-urgent info that can wait.',\n },\n broadcast: {\n category: 'routing',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: false,\n renderPriority: 20,\n recipientObligation: 'Read if addressed to you (direct recipient, alias, or \"*\").',\n senderGuidance: 'Multi-recipient envelope. Auto-selected when to is \"*\" or \"@session\".',\n },\n status: {\n category: 'informational',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: false,\n renderPriority: 40,\n recipientObligation: 'Use to avoid redundant work; never act on as a task or question.',\n senderGuidance: 'Agent/system status update. Machine-generated, not for human-originated messages.',\n },\n result: {\n category: 'informational',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 10,\n recipientObligation: 'Factor into next decision; treat as evidence, not a new task.',\n senderGuidance: 'Task completion notice. Share the outcome of finished work.',\n },\n review: {\n category: 'actionable',\n expectsReply: false,\n requiresAction: true,\n backgroundEligible: true,\n outOfBand: false,\n renderPriority: 10,\n recipientObligation: 'Inspect when convenient; no immediate reply required.',\n senderGuidance: 'Passive review request (code/doc/PR). No reply required.',\n },\n control: {\n category: 'control_signal',\n expectsReply: false,\n requiresAction: false,\n backgroundEligible: false,\n outOfBand: true,\n renderPriority: 999, // Never rendered\n recipientObligation: 'Handled by the agent loop, NOT folded into conversation. \"interrupt\" causes cooperative halt.',\n senderGuidance: 'RESERVED for runtime use. Agents must NOT send control messages.',\n },\n};\n\n/**\n * The set of types that are escalated in background delivery mode.\n * Defined here for import reuse so every dispatch site agrees.\n */\nexport const ACTIONABLE_BACKGROUND_TYPES = new Set<MailboxMessage['type']>([\n 'steer',\n 'ask',\n 'assign',\n 'result',\n 'review',\n]);\n\n/**\n * Return the semantic category for the given type. Every valid\n * `MailboxMessageType` maps to exactly one category.\n */\nexport function mailboxTypeCategory(type: MailboxMessageType): MailboxTypeCategory {\n return MAILBOX_TYPE_PROPERTIES[type].category;\n}\n\n/**\n * Is this type an action item that requires a substantive response?\n */\nexport function mailboxTypeExpectsReply(type: MailboxMessageType): boolean {\n return MAILBOX_TYPE_PROPERTIES[type].expectsReply;\n}\n\n/**\n * Validate that a given (type, to) pair is internally consistent.\n * Throws when the combination breaks a fundamental rule.\n */\nexport function validateSendType(type: MailboxMessageType, to: string): void {\n if (type === 'control') {\n throw new TypeError(\n 'Type \"control\" is reserved for runtime use and cannot be set by agents',\n );\n }\n const isMultiRecipient = to === '*' || to.startsWith('@session:');\n if (type === 'assign' && isMultiRecipient) {\n throw new TypeError(\n `Type \"assign\" requires a specific recipient \u2014 multi-recipient target \"${to}\" is ambiguous`,\n );\n }\n if (type === 'steer' && isMultiRecipient) {\n throw new TypeError(\n `Type \"steer\" requires a specific recipient \u2014 multi-recipient target \"${to}\" is ambiguous`,\n );\n }\n}\n\n// \u2500\u2500 Read receipt \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Per-recipient read status. `readBy` maps agentId \u2192 ISO8601 timestamp of\n * when that agent first read the message. An empty map means unread by all.\n */\nexport interface ReadReceipts {\n [agentId: string]: string; // ISO8601 timestamp\n}\n\n// \u2500\u2500 Core message \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxMessage {\n /** Unique message id (UUID). */\n id: string;\n /** Sender agent id. */\n from: string;\n /** Recipient agent id, or '*' for broadcast. */\n to: string;\n /** Message category. */\n type: MailboxMessageType;\n /** Short subject line \u2014 one sentence. */\n subject: string;\n /** Full message content. */\n body: string;\n /** Priority \u2014 high priority messages surface first. */\n priority: 'low' | 'normal' | 'high';\n /**\n * Per-recipient read receipts. agentId \u2192 ISO8601 when they first read it.\n * Replaces the old single `read: boolean` + `readAt` fields.\n */\n readBy: ReadReceipts;\n /** Has any recipient acted on / completed this? */\n completed: boolean;\n /** Who completed it (agentId). */\n completedBy?: string | undefined;\n /** Optional summary of what happened after handling. */\n outcome?: string | undefined;\n /** ISO8601 \u2014 when the message was sent. */\n timestamp: string;\n /** ISO8601 \u2014 when the message was marked complete. */\n completedAt?: string | undefined;\n /**\n * ISO8601 \u2014 when the message was soft-deleted. When present, the\n * default `Mailbox.query()` filter excludes the message from the\n * normal inbox view; {@link GlobalMailbox.restore} clears the\n * field to undo the delete. Hard deletes (removing the line from\n * the JSONL) are reserved for the CLI and never happen via the\n * server route handlers.\n */\n deletedAt?: string | undefined;\n /** When the soft-delete happened, the agentId that issued it. */\n deletedBy?: string | undefined;\n /** If this is a reply, the id of the parent message. */\n replyTo?: string | undefined;\n /** For assign-type messages \u2014 task context for agent discovery. */\n taskContext?: MailboxTaskContext | undefined;\n /** Session id of the sender. Enables cross-session communication. */\n senderSessionId?: string | undefined;\n /**\n * ISO8601 \u2014 when the message expires. Set at send time from `ttlMs`\n * (default: 24h via AUTO_COMPACT_DEFAULT_TTL_MS). The auto-compaction\n * sweep removes messages whose `expiresAt` is in the past. When\n * undefined, the compaction sweep uses the default TTL from the\n * caller's options.\n */\n expiresAt?: string | undefined;\n}\n\n// \u2500\u2500 Task context for agent discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxTaskContext {\n /** The role that should handle this task (e.g. \"tech-stack\", \"audit-log\"). */\n agentRole?: string | undefined;\n /** Human-readable agent name (e.g. \"Tesla (Executor)\"). */\n agentName?: string | undefined;\n /** Task id if already assigned via coordinator. */\n taskId?: string | undefined;\n /** Current task status. */\n status?: 'pending' | 'in_progress' | 'completed' | 'failed' | undefined;\n}\n\n// \u2500\u2500 Agent registration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface RegisteredAgent {\n /** Unique agent id. */\n agentId: string;\n /** Session id this agent belongs to. */\n sessionId: string;\n /** Human-readable name. */\n name: string;\n /** Role (e.g. \"leader\", \"tech-stack\", \"bug-hunter\"). */\n role?: string | undefined;\n /** Current status. */\n status: 'idle' | 'running' | 'streaming' | 'waiting_user' | 'error';\n /** Current tool being executed, if any. */\n currentTool?: string | undefined;\n /** Current task description. */\n currentTask?: string | undefined;\n /** Iteration count so far. */\n iterations: number;\n /** Tool calls so far. */\n toolCalls: number;\n /** ISO8601 \u2014 registered at. */\n registeredAt: string;\n /** ISO8601 \u2014 last heartbeat (updated on every mailbox op). */\n lastSeenAt: string;\n /** Which process registered this agent (PID). */\n pid: number;\n /** Where the agent is running (e.g. \"cli\", \"webui\"). */\n source?: 'cli' | 'webui' | 'mcp' | 'acp' | 'http' | undefined;\n}\n\n// \u2500\u2500 Agent status entry (for discovery) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxAgentStatus {\n /** Agent id. */\n agentId: string;\n /** Human-readable name. */\n name: string;\n /** Role. */\n role?: string | undefined;\n /** Session id. */\n sessionId: string;\n /** Current status. */\n status: 'idle' | 'running' | 'streaming' | 'waiting_user' | 'error' | 'offline';\n /** Current tool being executed, if any. */\n currentTool?: string | undefined;\n /** Current task description. */\n currentTask?: string | undefined;\n /** Iteration count so far. */\n iterations: number;\n /** Tool calls so far. */\n toolCalls: number;\n /** ISO8601 \u2014 last activity timestamp. */\n lastActivityAt: string;\n /** ISO8601 \u2014 last heartbeat. */\n lastSeenAt: string;\n /** Whether this agent is currently online (heartbeat within threshold). */\n online: boolean;\n /** Which process. */\n pid: number;\n /** Source. */\n source?: 'cli' | 'webui' | 'mcp' | 'acp' | 'http' | undefined;\n}\n\n// \u2500\u2500 Mailbox query \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MailboxQuery {\n /** Filter by recipient agent id. */\n to?: string | undefined;\n /** Filter by sender agent id. */\n from?: string | undefined;\n /** Only messages unread by this agent. */\n unreadBy?: string | undefined;\n /** Only incomplete messages. */\n incompleteOnly?: boolean | undefined;\n /** Filter by message type. */\n type?: MailboxMessageType | undefined;\n /** Filter by priority (>= this level). */\n minPriority?: 'low' | 'normal' | 'high' | undefined;\n /** Maximum number of messages to return. */\n limit?: number | undefined;\n /** ISO8601 \u2014 only messages after this timestamp. */\n since?: string | undefined;\n /** Filter by the sender's session id (`MailboxMessage.senderSessionId`). */\n sessionId?: string | undefined;\n /**\n * Include soft-deleted messages (where `deletedAt` is set). When\n * `false` (the default), soft-deleted messages are filtered out so\n * the normal inbox view stays clean. The \"trash\" view passes\n * `true` to surface them.\n */\n includeDeleted?: boolean | undefined;\n}\n\n// \u2500\u2500 Mailbox operations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Canonical prefix for mail addressed to every agent in one session. */\nexport const SESSION_RECIPIENT_PREFIX = '@session:';\n\n/** Build the canonical recipient address for a session-scoped broadcast. */\nexport function sessionRecipient(sessionId: string): string {\n const normalizedSessionId = sessionId.trim();\n if (!normalizedSessionId) {\n throw new TypeError('sessionId is required for the \"@session\" recipient');\n }\n return `${SESSION_RECIPIENT_PREFIX}${normalizedSessionId}`;\n}\n\n/**\n * Normalize a recipient address.\n *\n * - `\"all\"` (any casing) is canonicalized to `'*'`.\n * - `\"@session\"` (any casing) is canonicalized to\n * `\"@session:<sessionId>\"`; callers must provide the sender's session id.\n * - Already-canonical `\"@session:<sessionId>\"` addresses are preserved.\n */\nexport function normalizeRecipient(to: string, sessionId?: string): string {\n const trimmed = to.trim();\n const normalized = trimmed.toLowerCase();\n if (normalized === 'all') return '*';\n if (normalized === '@session') return sessionRecipient(sessionId ?? '');\n return trimmed;\n}\n\nexport interface MailboxSendInput {\n /** Sender agent id. */\n from: string;\n /** Recipient agent id, '*' / \"all\" for project broadcast, or \"@session\" for the sender's session. */\n to: string;\n /** Message category. */\n type: MailboxMessageType;\n /** Short subject line. */\n subject: string;\n /** Full message content. */\n body: string;\n /** Priority. Default: 'normal'. */\n priority?: 'low' | 'normal' | 'high' | undefined;\n /** If replying, the id of the parent message. */\n replyTo?: string | undefined;\n /** Task context for assign-type messages. */\n taskContext?: MailboxTaskContext | undefined;\n /** Sender session id. Required when `to` is the `\"@session\"` alias. */\n senderSessionId?: string | undefined;\n /**\n * Time-to-live in milliseconds. When set, the message's `expiresAt` is\n * computed as `now + ttlMs` at send time. The auto-compaction sweep\n * removes expired messages. Default: none (use compaction sweep default).\n */\n ttlMs?: number | undefined;\n}\n\n/**\n * Append-only ack record stored in the JSONL alongside messages.\n *\n * Instead of rewriting the entire mailbox file to mark a message as read or\n * completed, we append a small ack record. At read time, ack records are\n * folded into their target messages. The `__ack` discriminator distinguishes\n * ack records from regular messages.\n *\n * Compaction (autoCompact / purgeStale) folds these into the messages and\n * removes the ack lines from the file, keeping the file bounded.\n */\nexport interface AckRecord {\n /** Discriminator \u2014 always `true` to distinguish from MailboxMessage. */\n __ack: true;\n /** The message this ack applies to. */\n messageId: string;\n /** Agent acknowledging the message. */\n readerId: string;\n /** ISO8601 timestamp of the ack. */\n timestamp: string;\n /** Was the message read? */\n read: boolean;\n /** Was the message marked completed? */\n completed?: boolean | undefined;\n /** Who completed it (when completed === true). */\n completedBy?: string | undefined;\n /** Optional outcome summary. */\n outcome?: string | undefined;\n /**\n * Soft-delete or restore the target message.\n * - `true`: set `deletedAt`/`deletedBy` on the message\n * - `false`: clear `deletedAt`/`deletedBy` on the message\n * - `undefined`: not a delete/restore operation (backward-compat default)\n *\n * When `deleted` is `true`, `deletedBy` records who performed the delete.\n */\n deleted?: boolean | undefined;\n /** Who deleted the message (set when `deleted === true`). */\n deletedBy?: string | undefined;\n}\n\nexport interface MailboxAckInput {\n /** Message id to acknowledge. */\n messageId: string;\n /** Agent id of who is reading/acking. */\n readerId: string;\n /** Mark as read by this agent? Defaults to true if not specified. */\n read?: boolean | undefined;\n /** Mark as completed? */\n completed?: boolean | undefined;\n /** Optional outcome summary. */\n outcome?: string | undefined;\n}\n\n/**\n * Batch acknowledgment input \u2014 applies a batch of acks under a single file\n * lock + single file rewrite. Each entry has the same shape as\n * {@link MailboxAckInput} minus the per-batch defaults documented on\n * `ackMany`. Use this when an agent is acking several fresh messages at\n * once (the common case in the mailbox loop) \u2014 it collapses N full-file\n * rewrites into one.\n */\nexport interface MailboxAckBatchInput {\n /** Ack entries to apply. */\n acks: MailboxAckInput[];\n}\n\n// \u2500\u2500 Agent registration input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface AgentRegistrationInput {\n agentId: string;\n sessionId: string;\n name: string;\n role?: string | undefined;\n pid?: number | undefined;\n source?: 'cli' | 'webui' | 'mcp' | 'acp' | 'http' | undefined;\n}\n\n// \u2500\u2500 Client (REPL/TUI/WebUI) registration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type ClientSource = 'repl' | 'tui' | 'webui' | 'http';\n\nexport interface RegisteredClient {\n /** Unique client id. */\n clientId: string;\n /** Session/project context id. */\n sessionId: string;\n /** Human-readable name (e.g. \"TUI [main]\", \"WebUI [chrome]\"). */\n name: string;\n /** Client type. */\n source: ClientSource;\n /** ISO8601 \u2014 registered at. */\n registeredAt: string;\n /** ISO8601 \u2014 last heartbeat. */\n lastSeenAt: string;\n /** Which process. */\n pid: number;\n}\n\nexport interface ClientStatus {\n /** Client id. */\n clientId: string;\n /** Human-readable name. */\n name: string;\n /** Client type. */\n source: ClientSource;\n /** Session id. */\n sessionId: string;\n /** ISO8601 \u2014 last activity timestamp. */\n lastSeenAt: string;\n /** Whether this client is currently online (heartbeat within threshold). */\n online: boolean;\n /** Which process. */\n pid: number;\n}\n\nexport interface ClientRegistrationInput {\n clientId: string;\n sessionId: string;\n name: string;\n source: ClientSource;\n pid?: number | undefined;\n}\n\nexport interface ClientHeartbeatInput {\n clientId: string;\n /** Active session id for this client. When present, updates the registry entry. */\n sessionId?: string | undefined;\n}\n\n// \u2500\u2500 Agent heartbeat input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface AgentHeartbeatInput {\n agentId: string;\n status?: RegisteredAgent['status'] | undefined;\n currentTool?: string | undefined;\n currentTask?: string | undefined;\n iterations?: number | undefined;\n toolCalls?: number | undefined;\n}\n\n// \u2500\u2500 Purge options & result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface PurgeOptions {\n /**\n * Purge completed messages older than this many milliseconds.\n * Default: 1 day (86_400_000 ms)\n */\n completedMaxAgeMs?: number | undefined;\n /**\n * Purge incomplete messages older than this many milliseconds.\n * Default: 7 days (604_800_000 ms)\n */\n incompleteMaxAgeMs?: number | undefined;\n}\n\nexport interface PurgeResult {\n /** Messages removed because they were completed and too old. */\n completedPurged: number;\n /** Messages removed because they were incomplete and too old. */\n incompletePurged: number;\n /** Total messages removed. */\n totalPurged: number;\n /** Messages remaining in the mailbox after purge. */\n remaining: number;\n}\n\n// \u2500\u2500 Auto-compact options & result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface AutoCompactOptions {\n /**\n * Remove messages read by ALL currently-online agents that are older\n * than this many milliseconds since the last read receipt was stamped.\n * Default: 10 minutes (AUTO_COMPACT_READ_MAX_AGE_MS).\n */\n readMaxAgeMs?: number | undefined;\n /**\n * Default TTL for messages without an explicit `expiresAt`. Messages\n * whose `timestamp` is older than `now - defaultTtlMs` are removed.\n * Default: 24 hours (AUTO_COMPACT_DEFAULT_TTL_MS).\n */\n defaultTtlMs?: number | undefined;\n /**\n * Also run `purgeStale` logic in the same pass \u2014 purge completed\n * messages older than this many ms. Default: 1 day.\n */\n completedMaxAgeMs?: number | undefined;\n /**\n * Also run `purgeStale` logic in the same pass \u2014 purge incomplete\n * messages older than this many ms. Default: 7 days.\n */\n incompleteMaxAgeMs?: number | undefined;\n /**\n * Interval for the background auto-compact timer.\n * Default: 5 minutes (AUTO_COMPACT_INTERVAL_MS).\n */\n intervalMs?: number | undefined;\n /**\n * Also run `purgeStale` logic in the same pass (completed > 1 day,\n * incomplete > 7 days). Default: true.\n */\n includePurgeStale?: boolean | undefined;\n}\n\nexport interface AutoCompactResult {\n /** Messages removed because they were read by all online agents. */\n readByAllRemoved: number;\n /** Messages removed because their TTL expired (explicit or default). */\n expiredRemoved: number;\n /** Messages removed by the purgeStale pass (if enabled). */\n stalePurged: number;\n /** Total messages removed. */\n totalRemoved: number;\n /** Messages remaining in the mailbox after compaction. */\n remaining: number;\n}\n\n// \u2500\u2500 Mailbox interface \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface Mailbox {\n /** Send a message. Returns the created message. */\n send(input: MailboxSendInput): Promise<MailboxMessage>;\n\n /** Query messages matching criteria. */\n query(query: MailboxQuery): Promise<MailboxMessage[]>;\n\n /** Acknowledge a message (read/complete). Returns updated message. */\n ack(input: MailboxAckInput): Promise<MailboxMessage | null>;\n\n /**\n * Acknowledge many messages in one shot. Acquires the file lock once and\n * rewrites the message file once, regardless of how many acks are in the\n * batch. Returns the messages that were actually updated (messages whose\n * ids are not in the file are skipped silently).\n *\n * This is the preferred path when an agent has multiple fresh messages\n * to receipt at once \u2014 the per-message {@link ack} path does a full\n * read-modify-rewrite of the mailbox file for every call.\n */\n ackMany(input: MailboxAckBatchInput): Promise<MailboxMessage[]>;\n\n /**\n * Soft-delete a message. Sets `deletedAt` to the current timestamp\n * and records the acting agent in `deletedBy`. Reversible via\n * {@link restore}. The default `query()` filter hides the message\n * once `deletedAt` is set; pass `includeDeleted: true` to see the\n * trash.\n */\n softDelete(mailId: string, by: string): Promise<MailboxMessage | null>;\n\n /**\n * Undo a {@link softDelete}. Clears `deletedAt` and `deletedBy` on\n * the message. No-op (returns the message as-is) if the message is\n * not soft-deleted.\n */\n restore(mailId: string): Promise<MailboxMessage | null>;\n\n /** Get a snapshot of online/offline agents and their current tasks. */\n getAgentStatuses(): Promise<MailboxAgentStatus[]>;\n\n /**\n * Get only online agents (heartbeat within 60s).\n * Useful for \"who can I talk to right now?\" queries.\n */\n getOnlineAgents(): Promise<MailboxAgentStatus[]>;\n\n /**\n * Register an agent. Called once per agent on first mailbox use.\n * Subsequent calls are idempotent \u2014 they update lastSeenAt.\n */\n registerAgent(input: AgentRegistrationInput): Promise<void>;\n /** Remove an agent from the registry entirely. Called on session shutdown. */\n deregisterAgent(agentId: string): Promise<void>;\n\n /**\n * Update agent heartbeat and optional status fields.\n * Called periodically (every tool call / iteration).\n */\n heartbeat(input: AgentHeartbeatInput): Promise<void>;\n\n /**\n * Count unread messages for a specific agent.\n * Used for \"new mail\" notifications without pulling full message bodies.\n */\n unreadCount(forAgentId: string, sessionId?: string): Promise<number>;\n\n /** Close and flush any pending writes. */\n close(): Promise<void>;\n\n /**\n * Delete all messages from the mailbox file.\n * Agents and read receipts are preserved; only messages are cleared.\n */\n clearAll(): Promise<void>;\n\n /**\n * Purge orphaned and stale messages from the mailbox.\n *\n * Stale messages are:\n * - Completed messages older than `completedMaxAgeMs` (default: 1 day)\n * - Incomplete messages older than `incompleteMaxAgeMs` (default: 7 days)\n *\n * This does NOT touch agent registrations or client registry.\n */\n purgeStale(opts?: PurgeOptions): Promise<PurgeResult>;\n\n /**\n * Auto-compact: remove messages that are no longer needed.\n *\n * Two cleanup passes run in a single file rewrite:\n * 1. **Read-by-all**: Messages read by every currently-online agent,\n * older than `readMaxAgeMs` (default 10 min).\n * 2. **Expired**: Messages whose `expiresAt` is in the past, or whose\n * `timestamp` is older than `defaultTtlMs` (default 24h) when no\n * explicit `expiresAt` is set.\n *\n * Also runs `purgeStale` logic (completed > 1 day, incomplete > 7 days)\n * in the same pass to avoid a second rewrite.\n */\n autoCompact(opts?: AutoCompactOptions): Promise<AutoCompactResult>;\n\n /**\n * Start a background timer that periodically calls `autoCompact`.\n * Returns a dispose function that stops the timer. Idempotent \u2014\n * calling start twice replaces the prior timer.\n */\n startAutoCompactTimer(opts?: AutoCompactOptions): () => void;\n\n // \u2500\u2500 Client (REPL/TUI/WebUI) registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Register a client (REPL/TUI/WebUI). Called once per client on startup.\n * Subsequent calls are idempotent \u2014 they update lastSeenAt.\n */\n registerClient(input: ClientRegistrationInput): Promise<void>;\n\n /**\n * Update client heartbeat. Called periodically (every 15s for clients).\n */\n clientHeartbeat(input: ClientHeartbeatInput): Promise<void>;\n\n /** Remove a client immediately on clean shutdown. */\n deregisterClient(clientId: string): Promise<void>;\n\n /**\n * Get snapshot of online/offline clients and their last activity.\n */\n getClientStatuses(): Promise<ClientStatus[]>;\n\n /**\n * Explicitly purge stale clients from the registry.\n * Removes client entries whose lastSeenAt is older than CLIENT_STALE_MS.\n * Returns the number of entries purged.\n */\n purgeClients(): Promise<number>;\n}\n", "import type { Mailbox, MailboxAgentStatus, MailboxMessage } from '../coordination/mailbox-types.js';\nimport { SESSION_RECIPIENT_PREFIX } from '../coordination/mailbox-types.js';\nimport type {\n HqMailboxAgentSummary,\n HqMailboxEventPayload,\n HqMailboxMessageScope,\n HqMailboxMessageSummary,\n HqMailboxSnapshotPayload,\n HqRedactionPolicy,\n} from './protocol.js';\nimport { scrubAndTruncateHqPreview } from './redaction.js';\n\nexport interface HqMailboxMappingOptions {\n mailboxId: string;\n scope?: 'project' | 'global';\n limit?: number;\n previewLength?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n}\n\nexport interface HqMailboxSnapshotOptions extends HqMailboxMappingOptions {\n includeCompleted?: boolean;\n}\n\nexport type HqMailboxEventAction = HqMailboxEventPayload['action'];\n\nfunction previewText(value: string | undefined, maxLength: number, policy?: Partial<HqRedactionPolicy>): string | undefined {\n if (value === undefined || value.length === 0) return undefined;\n if (policy?.rawContent === false) return '[REDACTED:hq_raw_content]';\n if (policy?.rawContent === true) {\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength)}\u2026`;\n }\n return scrubAndTruncateHqPreview(value, maxLength);\n}\n\nfunction readCount(message: MailboxMessage): number {\n return Object.keys(message.readBy).length;\n}\n\n/**\n * Classify a mailbox recipient address for UI labeling.\n *\n * - `'*'` (project broadcast) \u2192 `'project'`\n * - `@session:<id>` \u2192 `'session'` (returns the session id)\n * - everything else \u2192 `'agent'`\n */\nexport interface HqMailboxRecipientScope {\n scope: HqMailboxMessageScope;\n recipientSessionId?: string;\n}\n\nexport function classifyMailboxRecipient(to: string): HqMailboxRecipientScope {\n if (to === '*' || to === 'all') return { scope: 'project' };\n if (to.startsWith(SESSION_RECIPIENT_PREFIX)) {\n const recipientSessionId = to.slice(SESSION_RECIPIENT_PREFIX.length);\n if (recipientSessionId.length === 0) return { scope: 'agent' };\n return { scope: 'session', recipientSessionId };\n }\n return { scope: 'agent' };\n}\n\nfunction taskSummary(message: MailboxMessage): HqMailboxMessageSummary['task'] {\n if (message.taskContext === undefined) return undefined;\n const task = {\n ...(message.taskContext.taskId !== undefined ? { taskId: message.taskContext.taskId } : {}),\n ...(message.taskContext.agentRole !== undefined ? { agentRole: message.taskContext.agentRole } : {}),\n ...(message.taskContext.agentName !== undefined ? { agentName: message.taskContext.agentName } : {}),\n ...(message.taskContext.status !== undefined ? { status: message.taskContext.status } : {}),\n } satisfies HqMailboxMessageSummary['task'];\n return Object.keys(task).length > 0 ? task : undefined;\n}\n\nexport function mapMailboxMessageToHqSummary(\n message: MailboxMessage,\n options: Pick<HqMailboxMappingOptions, 'previewLength' | 'redactionPolicy'> = {},\n): HqMailboxMessageSummary {\n const previewLength = options.previewLength ?? 500;\n const bodyPreview = previewText(message.body, previewLength, options.redactionPolicy);\n const outcomePreview = previewText(message.outcome, previewLength, options.redactionPolicy);\n const task = taskSummary(message);\n const recipient = classifyMailboxRecipient(message.to);\n\n return {\n mailId: message.id, // unique UUID per message record, used for deduplication\n messageId: message.id,\n from: message.from,\n to: message.to,\n scope: recipient.scope,\n ...(recipient.recipientSessionId !== undefined ? { recipientSessionId: recipient.recipientSessionId } : {}),\n type: message.type,\n subject: previewText(message.subject, previewLength, options.redactionPolicy) ?? '',\n priority: message.priority,\n timestamp: message.timestamp,\n ...(message.replyTo !== undefined ? { replyTo: message.replyTo } : {}),\n ...(message.senderSessionId !== undefined ? { senderSessionId: message.senderSessionId } : {}),\n completed: message.completed,\n ...(message.completedBy !== undefined ? { completedBy: message.completedBy } : {}),\n ...(message.completedAt !== undefined ? { completedAt: message.completedAt } : {}),\n readCount: readCount(message),\n hasBody: message.body.length > 0,\n ...(bodyPreview !== undefined ? { bodyPreview } : {}),\n ...(outcomePreview !== undefined ? { outcomePreview } : {}),\n ...(task !== undefined ? { task } : {}),\n };\n}\n\nexport function mapMailboxAgentToHqSummary(agent: MailboxAgentStatus): HqMailboxAgentSummary {\n return {\n agentId: agent.agentId,\n name: agent.name,\n ...(agent.role !== undefined ? { role: agent.role } : {}),\n sessionId: agent.sessionId,\n status: agent.status,\n ...(agent.currentTool !== undefined ? { currentTool: agent.currentTool } : {}),\n ...(agent.currentTask !== undefined ? { currentTask: agent.currentTask } : {}),\n iterations: agent.iterations,\n toolCalls: agent.toolCalls,\n lastActivityAt: agent.lastActivityAt,\n lastSeenAt: agent.lastSeenAt,\n online: agent.online,\n ...(agent.source !== undefined ? { source: agent.source } : {}),\n };\n}\n\nexport function createMailboxSnapshotPayload(\n messages: readonly MailboxMessage[],\n agents: readonly MailboxAgentStatus[],\n options: HqMailboxSnapshotOptions,\n): HqMailboxSnapshotPayload {\n const includeCompleted = options.includeCompleted ?? true;\n const filteredMessages = includeCompleted ? messages : messages.filter((message) => !message.completed);\n const limit = options.limit ?? 50;\n const sortedMessages = [...filteredMessages].sort((a, b) => b.timestamp.localeCompare(a.timestamp)).slice(0, limit);\n const summaries = sortedMessages.map((message) => mapMailboxMessageToHqSummary(message, options));\n const agentSummaries = agents.map(mapMailboxAgentToHqSummary);\n\n return {\n mailboxId: options.mailboxId,\n scope: options.scope ?? 'project',\n messages: summaries,\n agents: agentSummaries,\n totals: {\n messages: messages.length,\n unread: messages.filter((message) => !message.completed && readCount(message) === 0).length,\n incomplete: messages.filter((message) => !message.completed).length,\n highPriority: messages.filter((message) => message.priority === 'high').length,\n onlineAgents: agents.filter((agent) => agent.online).length,\n },\n };\n}\n\nexport async function createMailboxSnapshotPayloadFromMailbox(\n mailbox: Pick<Mailbox, 'query' | 'getAgentStatuses'>,\n options: HqMailboxSnapshotOptions,\n): Promise<HqMailboxSnapshotPayload> {\n const limit = options.limit ?? 50;\n const [messages, agents] = await Promise.all([\n mailbox.query({ limit }),\n mailbox.getAgentStatuses(),\n ]);\n return createMailboxSnapshotPayload(messages, agents, options);\n}\n\nexport function createMailboxEventPayload(input: {\n mailboxId: string;\n action: HqMailboxEventAction;\n message?: MailboxMessage;\n agent?: MailboxAgentStatus;\n summary?: string;\n previewLength?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n}): HqMailboxEventPayload {\n const summaryOptions: Pick<HqMailboxMappingOptions, 'previewLength' | 'redactionPolicy'> = {\n ...(input.previewLength !== undefined ? { previewLength: input.previewLength } : {}),\n ...(input.redactionPolicy !== undefined ? { redactionPolicy: input.redactionPolicy } : {}),\n };\n\n return {\n mailboxId: input.mailboxId,\n action: input.action,\n ...(input.message !== undefined ? { message: mapMailboxMessageToHqSummary(input.message, summaryOptions) } : {}),\n ...(input.agent !== undefined ? { agent: mapMailboxAgentToHqSummary(input.agent) } : {}),\n ...(input.summary !== undefined\n ? { summary: previewText(input.summary, input.previewLength ?? 160, input.redactionPolicy) ?? '' }\n : {}),\n };\n}\n", "import { randomUUID } from 'node:crypto';\nimport type { Logger } from '../types/logger.js';\nimport type { Mailbox, MailboxAgentStatus, MailboxMessage } from '../coordination/mailbox-types.js';\nimport {\n createMailboxEventPayload,\n createMailboxSnapshotPayloadFromMailbox,\n type HqMailboxEventAction,\n type HqMailboxSnapshotOptions,\n} from './mailbox-mapper.js';\nimport { redactHqEvent, resolveHqRedactionPolicy } from './redaction.js';\nimport {\n createHqEventEnvelope,\n HQ_PROTOCOL_VERSION,\n HQ_TRANSCRIPT_TEXT_CAP,\n type HqClientCapability,\n type HqClientCommandAckMessage,\n type HqClientCommandPollMessage,\n type HqClientEventMessage,\n type HqClientHelloMessage,\n type HqClientIdentity,\n type HqEventEnvelope,\n type HqEventType,\n type HqFleetSnapshotPayload,\n type HqMailboxEventPayload,\n type HqMailboxSnapshotPayload,\n type HqProjectIdentity,\n type HqQueuedCommand,\n type HqRedactionPolicy,\n type HqServerCommandBatchMessage,\n type HqSessionEndedPayload,\n type HqSessionSnapshotPayload,\n type HqTranscriptAppendPayload,\n} from './protocol.js';\n\nexport interface HqSocketLike {\n readyState: number;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n addEventListener?(\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n ): void;\n removeEventListener?(\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n ): void;\n on?(type: 'open' | 'close' | 'error' | 'message', listener: (event: unknown) => void): void;\n off?(type: 'open' | 'close' | 'error' | 'message', listener: (event: unknown) => void): void;\n}\n\nexport type HqSocketFactory = (url: string, init: { token?: string }) => HqSocketLike;\n\nexport interface HqPublisherCommandResult {\n commandId: string;\n status: 'accepted' | 'completed' | 'failed' | 'rejected';\n message?: string;\n}\n\nexport type HqPublisherCommandHandler = (\n command: HqQueuedCommand,\n) => void | HqPublisherCommandResult | Promise<void | HqPublisherCommandResult>;\n\nexport interface HqPublisherOptions {\n url: string;\n token?: string;\n client: HqClientIdentity;\n project: HqProjectIdentity;\n capabilities?: readonly HqClientCapability[];\n socketFactory?: HqSocketFactory;\n now?: () => string;\n idFactory?: () => string;\n reconnect?: boolean;\n reconnectBaseMs?: number;\n reconnectMaxMs?: number;\n maxQueuedMessages?: number;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n commandPollIntervalMs?: number;\n commandPollLimit?: number;\n onCommand?: HqPublisherCommandHandler;\n /**\n * Local auto-discovery hook: re-resolve the HQ endpoint before EVERY\n * connect attempt (e.g. by reading `<hq dataDir>/runtime.json`). Returning\n * `undefined` means no HQ is currently discoverable \u2014 the publisher stays\n * dormant (events keep queueing, bounded) and re-checks every\n * {@link HqPublisherOptions.discoveryPollMs}. Because the endpoint is\n * re-resolved per attempt, an HQ started AFTER this client \u2014 or restarted\n * on a different port, or one that minted its first client token on boot \u2014\n * is picked up automatically.\n */\n resolveEndpoint?: () => { url: string; token?: string | undefined } | undefined;\n /** Dormant re-check interval while `resolveEndpoint` yields nothing. Default 5s. */\n discoveryPollMs?: number;\n /**\n * Application-level heartbeat interval for the `/ws/client` connection.\n * The HQ server evicts silent sockets, so this must be comfortably below\n * the server-side client TTL even when no command handler is installed.\n */\n heartbeatIntervalMs?: number;\n /**\n * Diagnostic sink for the one-time consecutive-connect-failure warning.\n * The publisher is otherwise deliberately silent (dormant queueing), which\n * made auth failures invisible: a token the server rejects \u2014 e.g. a wrong\n * `WRONGSTACK_HQ_TOKEN` against a remote HQ \u2014 looked exactly like \"HQ not\n * running\". Defaults to a single structured `console.warn` line.\n */\n warn?: (message: string) => void;\n /** Logger for structured events. When provided, the `warn` callback is derived from it. */\n logger?: Logger | undefined;\n}\n\nexport interface HqPublishEventOptions {\n type: HqEventType | (string & {});\n payload: unknown;\n sessionId?: string;\n runId?: string;\n timestamp?: string;\n /**\n * Per-string redaction cap override. Defaults to the generic 500-char\n * summary cap; chat-transcript event types (`session.transcript`,\n * `agent.message`) automatically get {@link HQ_TRANSCRIPT_TEXT_CAP} so\n * full chat history survives when `rawContent` is enabled.\n */\n maxSummaryLength?: number;\n}\n\n/** Event types that carry full chat turns rather than telemetry summaries. */\nconst TRANSCRIPT_EVENT_TYPES = new Set<string>(['session.transcript', 'agent.message']);\n\nconst OPEN_STATE = 1;\n/**\n * After this many consecutive failed connects (never reaching `open`), emit\n * ONE diagnostic warning. The WS handshake gives the browser-style socket no\n * HTTP status, so a 401 (token mismatch) is indistinguishable from a dead\n * server at this layer \u2014 the warning names both possibilities.\n */\nconst CONNECT_WARN_AFTER_FAILURES = 5;\nconst DEFAULT_RECONNECT_BASE_MS = 1_000;\nconst DEFAULT_RECONNECT_MAX_MS = 30_000;\nconst DEFAULT_DISCOVERY_POLL_MS = 5_000;\nconst DEFAULT_MAX_QUEUED_MESSAGES = 2000;\n// Commands originate from an interactive operator console. Keep delivery\n// close to WebSocket-real-time while retaining the existing bounded poll\n// protocol (which also provides replay after a brief disconnect).\nconst DEFAULT_COMMAND_POLL_INTERVAL_MS = 500;\nconst DEFAULT_COMMAND_POLL_LIMIT = 25;\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 25_000;\n\nfunction defaultSocketFactory(url: string): HqSocketLike {\n const WebSocketCtor = globalThis.WebSocket;\n if (WebSocketCtor === undefined) {\n throw new Error(\n 'No global WebSocket implementation is available; provide HqPublisherOptions.socketFactory.',\n );\n }\n return new WebSocketCtor(url) as HqSocketLike;\n}\n\nfunction toClientUrl(baseUrl: string, token: string | undefined): string {\n const url = new URL(baseUrl);\n url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';\n if (url.pathname === '/' || url.pathname === '') url.pathname = '/ws/client';\n if (token !== undefined && token.length > 0) url.searchParams.set('token', token);\n return url.toString();\n}\n\nfunction addSocketListener(\n socket: HqSocketLike,\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n): void {\n if (socket.addEventListener !== undefined) {\n socket.addEventListener(type, listener);\n return;\n }\n socket.on?.(type, listener);\n}\n\nfunction removeSocketListener(\n socket: HqSocketLike,\n type: 'open' | 'close' | 'error' | 'message',\n listener: (event: unknown) => void,\n): void {\n if (socket.removeEventListener !== undefined) {\n socket.removeEventListener(type, listener);\n return;\n }\n socket.off?.(type, listener);\n}\n\nexport class HqPublisher {\n private readonly socketFactory: HqSocketFactory;\n private readonly now: () => string;\n private readonly idFactory: () => string;\n private readonly capabilities: readonly HqClientCapability[];\n private readonly reconnect: boolean;\n private readonly reconnectBaseMs: number;\n private readonly reconnectMaxMs: number;\n private readonly maxQueuedMessages: number;\n private readonly resolvedRedactionPolicy: HqRedactionPolicy;\n private readonly logger: Logger | undefined;\n private socket: HqSocketLike | null = null;\n private seq = 0;\n private queue: string[] = [];\n private stopped = false;\n private reconnectAttempt = 0;\n private connectWarningEmitted = false;\n private lastAttempt: { url: string; hadToken: boolean } | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private commandPollTimer: ReturnType<typeof setInterval> | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private lastCommandId: string | undefined;\n\n constructor(private readonly options: HqPublisherOptions) {\n this.socketFactory = options.socketFactory ?? defaultSocketFactory;\n this.now = options.now ?? (() => new Date().toISOString());\n this.idFactory = options.idFactory ?? randomUUID;\n this.capabilities = options.capabilities ?? [\n 'telemetry.publish',\n 'mailbox.summary',\n 'fleet.summary',\n 'session.summary',\n ];\n this.reconnect = options.reconnect ?? true;\n this.reconnectBaseMs = options.reconnectBaseMs ?? DEFAULT_RECONNECT_BASE_MS;\n this.reconnectMaxMs = options.reconnectMaxMs ?? DEFAULT_RECONNECT_MAX_MS;\n this.maxQueuedMessages = options.maxQueuedMessages ?? DEFAULT_MAX_QUEUED_MESSAGES;\n this.resolvedRedactionPolicy = resolveHqRedactionPolicy(options.redactionPolicy);\n this.logger = options.logger;\n }\n\n connect(): void {\n if (this.socket !== null || this.stopped) return;\n // A retry / discovery poll is already scheduled \u2014 let it fire instead of\n // dialing (and re-resolving the endpoint) on every publish while offline.\n if (this.reconnectTimer !== null) return;\n\n let url = this.options.url;\n let token = this.options.token;\n if (this.options.resolveEndpoint !== undefined) {\n const endpoint = this.options.resolveEndpoint();\n if (endpoint === undefined) {\n this.scheduleDiscoveryPoll();\n return;\n }\n url = endpoint.url;\n token = endpoint.token ?? token;\n }\n this.lastAttempt = { url, hadToken: token !== undefined };\n\n let socket: HqSocketLike;\n try {\n socket = this.socketFactory(toClientUrl(url, token), {\n ...(token !== undefined ? { token } : {}),\n });\n } catch {\n this.scheduleReconnect();\n return;\n }\n this.socket = socket;\n\n const onOpen = () => {\n this.reconnectAttempt = 0;\n this.sendHelloNow();\n this.flushQueue();\n this.startHeartbeat();\n if (this.options.onCommand !== undefined) {\n this.startCommandPolling();\n this.pollCommands();\n }\n };\n const onMessage = (event: unknown) => {\n void this.handleServerMessage(event);\n };\n const onCloseOrError = () => {\n removeSocketListener(socket, 'open', onOpen);\n removeSocketListener(socket, 'message', onMessage);\n removeSocketListener(socket, 'close', onCloseOrError);\n removeSocketListener(socket, 'error', onCloseOrError);\n this.stopCommandPolling();\n this.stopHeartbeat();\n if (this.socket === socket) this.socket = null;\n this.scheduleReconnect();\n };\n\n addSocketListener(socket, 'open', onOpen);\n addSocketListener(socket, 'message', onMessage);\n addSocketListener(socket, 'close', onCloseOrError);\n addSocketListener(socket, 'error', onCloseOrError);\n\n if (socket.readyState === OPEN_STATE) onOpen();\n }\n\n close(): void {\n this.stopped = true;\n if (this.reconnectTimer !== null) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.stopCommandPolling();\n this.stopHeartbeat();\n this.queue = [];\n const socket = this.socket;\n this.socket = null;\n socket?.close(1000, 'hq publisher closed');\n }\n\n publishEvent<TPayload>(\n options: HqPublishEventOptions & { payload: TPayload },\n ): HqEventEnvelope<TPayload> {\n const event = createHqEventEnvelope({\n id: this.idFactory(),\n type: options.type,\n timestamp: options.timestamp ?? this.now(),\n clientId: this.options.client.clientId,\n projectId: this.options.project.projectId,\n seq: ++this.seq,\n payload: options.payload,\n ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),\n ...(options.runId !== undefined ? { runId: options.runId } : {}),\n });\n const maxSummaryLength =\n options.maxSummaryLength ??\n (TRANSCRIPT_EVENT_TYPES.has(options.type) ? HQ_TRANSCRIPT_TEXT_CAP : undefined);\n const redacted = redactHqEvent(event, {\n policy: this.resolvedRedactionPolicy,\n projectRoot: this.options.project.projectRoot,\n ...(maxSummaryLength !== undefined ? { maxSummaryLength } : {}),\n }).value;\n this.sendFrame({ type: 'client.event', event: redacted });\n return redacted;\n }\n\n async publishMailboxSnapshot(\n mailbox: Pick<Mailbox, 'query' | 'getAgentStatuses'>,\n options: Omit<HqMailboxSnapshotOptions, 'redactionPolicy'> & {\n sessionId?: string;\n timestamp?: string;\n },\n ): Promise<HqEventEnvelope<HqMailboxSnapshotPayload>> {\n const payload = await createMailboxSnapshotPayloadFromMailbox(mailbox, {\n ...options,\n redactionPolicy: this.resolvedRedactionPolicy,\n });\n return this.publishEvent({\n type: 'mailbox.snapshot',\n payload,\n ...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),\n ...(options.timestamp !== undefined ? { timestamp: options.timestamp } : {}),\n });\n }\n\n publishMailboxEvent(input: {\n mailboxId: string;\n action: HqMailboxEventAction;\n message?: MailboxMessage;\n agent?: MailboxAgentStatus;\n summary?: string;\n previewLength?: number;\n sessionId?: string;\n timestamp?: string;\n }): HqEventEnvelope<HqMailboxEventPayload> {\n const payload = createMailboxEventPayload({\n mailboxId: input.mailboxId,\n action: input.action,\n ...(input.message !== undefined ? { message: input.message } : {}),\n ...(input.agent !== undefined ? { agent: input.agent } : {}),\n ...(input.summary !== undefined ? { summary: input.summary } : {}),\n ...(input.previewLength !== undefined ? { previewLength: input.previewLength } : {}),\n redactionPolicy: this.resolvedRedactionPolicy,\n });\n return this.publishEvent({\n type: 'mailbox.event',\n payload,\n ...(input.sessionId !== undefined ? { sessionId: input.sessionId } : {}),\n ...(input.timestamp !== undefined ? { timestamp: input.timestamp } : {}),\n });\n }\n\n /** The client identity this publisher announced (clientId, kind, machineId, \u2026). */\n get identity(): HqClientIdentity {\n return this.options.client;\n }\n\n /** The project identity this publisher is bound to. */\n get project(): HqProjectIdentity {\n return this.options.project;\n }\n\n /** Effective publisher-side policy applied before any event leaves this process. */\n get redactionPolicy(): HqRedactionPolicy {\n return this.resolvedRedactionPolicy;\n }\n\n /** Publish a live session/terminal snapshot (state + agents). */\n publishSessionSnapshot(\n payload: HqSessionSnapshotPayload,\n opts?: { timestamp?: string },\n ): HqEventEnvelope<HqSessionSnapshotPayload> {\n return this.publishEvent({\n type: 'session.snapshot',\n payload,\n sessionId: payload.sessionId,\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n /** Publish an incremental batch of transcript turns for a session. */\n publishTranscriptAppend(\n payload: HqTranscriptAppendPayload,\n opts?: { timestamp?: string },\n ): HqEventEnvelope<HqTranscriptAppendPayload> {\n return this.publishEvent({\n type: 'session.transcript',\n payload,\n sessionId: payload.sessionId,\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n /** Mark a session/terminal as ended. */\n publishSessionEnded(\n payload: HqSessionEndedPayload,\n opts?: { timestamp?: string },\n ): HqEventEnvelope<HqSessionEndedPayload> {\n return this.publishEvent({\n type: 'session.ended',\n payload,\n sessionId: payload.sessionId,\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n /** Publish a fleet (multi-agent coordinator) snapshot. */\n publishFleetSnapshot(\n payload: HqFleetSnapshotPayload,\n opts?: { sessionId?: string; timestamp?: string },\n ): HqEventEnvelope<HqFleetSnapshotPayload> {\n return this.publishEvent({\n type: 'fleet.snapshot',\n payload,\n runId: payload.runId,\n ...(opts?.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n ...(opts?.timestamp !== undefined ? { timestamp: opts.timestamp } : {}),\n });\n }\n\n pollCommands(): void {\n this.sendFrame({\n type: 'client.command_poll',\n clientId: this.options.client.clientId,\n projectId: this.options.project.projectId,\n ...(this.lastCommandId !== undefined ? { afterCommandId: this.lastCommandId } : {}),\n limit: this.options.commandPollLimit ?? DEFAULT_COMMAND_POLL_LIMIT,\n });\n }\n\n ackCommand(result: HqPublisherCommandResult): void {\n this.sendFrame({\n type: 'client.command_ack',\n clientId: this.options.client.clientId,\n projectId: this.options.project.projectId,\n commandId: result.commandId,\n status: result.status,\n ...(result.message !== undefined ? { message: result.message } : {}),\n });\n }\n\n private createHelloFrame(): HqClientHelloMessage {\n return {\n type: 'client.hello',\n payload: {\n protocolVersion: HQ_PROTOCOL_VERSION,\n client: this.options.client,\n project: this.options.project,\n capabilities: this.capabilities,\n redactionPolicy: this.resolvedRedactionPolicy,\n },\n };\n }\n\n private sendHelloNow(): void {\n const socket = this.socket;\n if (socket?.readyState !== OPEN_STATE) {\n this.sendFrame(this.createHelloFrame());\n return;\n }\n socket.send(JSON.stringify(this.createHelloFrame()));\n }\n\n private sendFrame(\n frame:\n | HqClientHelloMessage\n | HqClientEventMessage\n | HqClientCommandPollMessage\n | HqClientCommandAckMessage,\n ): void {\n const serialized = JSON.stringify(frame);\n const socket = this.socket;\n // Fast path: socket is open and nothing queued \u2014 send immediately.\n if (socket?.readyState === OPEN_STATE && this.queue.length === 0) {\n socket.send(serialized);\n return;\n }\n // Slow path: socket offline or queue already has pending frames \u2014 enqueue.\n this.enqueue(serialized);\n this.connect();\n }\n\n private enqueue(serialized: string): void {\n if (this.queue.length >= this.maxQueuedMessages) this.queue.shift();\n this.queue.push(serialized);\n }\n\n /** Batch-dequeue up to 50 frames at a time, yielding to the microtask\n * queue between batches so we don't starve the event loop on reconnect. */\n private flushQueue(): void {\n const socket = this.socket;\n if (socket?.readyState !== OPEN_STATE || this.queue.length === 0) return;\n const batch = this.queue.splice(0, 50);\n for (const frame of batch) socket.send(frame);\n if (this.queue.length > 0) setImmediate(() => this.flushQueue());\n }\n\n private startCommandPolling(): void {\n if (this.options.onCommand === undefined || this.commandPollTimer !== null) return;\n this.commandPollTimer = setInterval(\n () => this.pollCommands(),\n this.options.commandPollIntervalMs ?? DEFAULT_COMMAND_POLL_INTERVAL_MS,\n );\n this.commandPollTimer.unref?.();\n }\n\n private stopCommandPolling(): void {\n if (this.commandPollTimer === null) return;\n clearInterval(this.commandPollTimer);\n this.commandPollTimer = null;\n }\n\n private startHeartbeat(): void {\n if (this.heartbeatTimer !== null) return;\n this.heartbeatTimer = setInterval(\n () => this.publishHeartbeat(),\n this.options.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS,\n );\n this.heartbeatTimer.unref?.();\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer === null) return;\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n\n private publishHeartbeat(): void {\n const startedAt = Date.parse(this.options.client.startedAt);\n const now = Date.parse(this.now());\n this.publishEvent({\n type: 'client.heartbeat',\n payload: {\n uptimeMs:\n Number.isFinite(startedAt) && Number.isFinite(now) ? Math.max(0, now - startedAt) : 0,\n status: 'idle',\n },\n });\n }\n\n private async handleServerMessage(event: unknown): Promise<void> {\n const message = this.parseServerMessage(event);\n if (message?.type !== 'hq.command_batch') return;\n await this.handleCommandBatch(message);\n }\n\n private parseServerMessage(event: unknown): HqServerCommandBatchMessage | null {\n const data = this.extractMessageData(event);\n if (data === null) return null;\n try {\n const parsed = JSON.parse(data) as Partial<HqServerCommandBatchMessage>;\n if (parsed.type !== 'hq.command_batch' || !Array.isArray(parsed.commands)) return null;\n return parsed as HqServerCommandBatchMessage;\n } catch {\n return null;\n }\n }\n\n private extractMessageData(event: unknown): string | null {\n const value =\n typeof event === 'object' && event !== null && 'data' in event\n ? (event as { data?: unknown }).data\n : event;\n if (typeof value === 'string') return value;\n if (value instanceof ArrayBuffer) return new TextDecoder().decode(value);\n if (ArrayBuffer.isView(value)) {\n const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n return new TextDecoder().decode(bytes);\n }\n return null;\n }\n\n private async handleCommandBatch(message: HqServerCommandBatchMessage): Promise<void> {\n const handler = this.options.onCommand;\n if (handler === undefined) return;\n\n for (const command of message.commands) {\n this.lastCommandId = command.commandId;\n try {\n const result = await handler(command);\n if (result !== undefined) this.ackCommand(result);\n else if (command.requiresAck)\n this.ackCommand({ commandId: command.commandId, status: 'accepted' });\n } catch (err) {\n this.ackCommand({\n commandId: command.commandId,\n status: 'failed',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.stopped || !this.reconnect || this.reconnectTimer !== null) return;\n const delay = Math.min(this.reconnectMaxMs, this.reconnectBaseMs * 2 ** this.reconnectAttempt);\n this.reconnectAttempt += 1;\n // One-time visibility for persistent failures. `reconnectAttempt` resets\n // on every successful open, so reaching the threshold means the endpoint\n // has NEVER accepted us in this streak \u2014 dead server or rejected token.\n if (!this.connectWarningEmitted && this.reconnectAttempt >= CONNECT_WARN_AFTER_FAILURES) {\n this.connectWarningEmitted = true;\n this.emitConnectWarning();\n }\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, delay);\n this.reconnectTimer.unref?.();\n }\n\n private emitConnectWarning(): void {\n const attempt = this.lastAttempt;\n const message =\n `WrongStack HQ publisher: ${this.reconnectAttempt} consecutive connection failures` +\n `${attempt !== null ? ` to ${attempt.url} (client token ${attempt.hadToken ? 'present' : 'absent'})` : ''}. ` +\n 'Either the HQ server is unreachable or it rejected the token (401). ' +\n 'If HQ runs in client-token mode, verify WRONGSTACK_HQ_TOKEN / auth.json. Retries continue with backoff.';\n if (this.logger) {\n this.logger.warn(message, { event: 'hq.publisher.connect_failed' });\n return;\n }\n const warn =\n this.options.warn ??\n ((msg: string) =>\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.publisher.connect_failed',\n message: msg,\n timestamp: this.now(),\n }),\n ));\n try {\n warn(message);\n } catch {\n /* diagnostics must never break publishing */\n }\n }\n\n /**\n * Dormant re-check while no HQ endpoint is discoverable. Uses a FIXED\n * interval (not the exponential reconnect backoff): the check is a cheap\n * local file read, and backing off would delay attaching to an HQ the\n * user just started \u2014 the whole point of auto-discovery.\n */\n private scheduleDiscoveryPoll(): void {\n if (this.stopped || !this.reconnect || this.reconnectTimer !== null) return;\n this.reconnectAttempt = 0;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, this.options.discoveryPollMs ?? DEFAULT_DISCOVERY_POLL_MS);\n this.reconnectTimer.unref?.();\n }\n}\n", "import { createHash, randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport { hostname } from 'node:os';\nimport { basename } from 'node:path';\nimport { GlobalMailbox } from '../coordination/global-mailbox.js';\nimport type { EventBus } from '../kernel/events.js';\nimport type { HqClientConfig } from '../types/config.js';\nimport type { Logger } from '../types/logger.js';\nimport {\n type HqAuthFile,\n hqAuthFilePath,\n readHqRuntimeFileSync,\n resolveHqDataDir,\n} from './auth-store.js';\nimport type {\n HqClientCapability,\n HqClientIdentity,\n HqProjectIdentity,\n HqRedactionPolicy,\n} from './protocol.js';\nimport { HqPublisher, type HqPublisherCommandHandler, type HqSocketFactory } from './publisher.js';\n\nexport interface HqPublisherEnvConfig {\n url: string;\n token?: string;\n enabled?: boolean;\n rawContent?: boolean;\n projectAlias?: string;\n /**\n * Same-machine auto-discovery mode: no explicit URL was configured, so the\n * publisher should re-resolve the endpoint from `<dataDir>/runtime.json`\n * (+ the first client token in `auth.json`) before every connect attempt.\n * This lets every client on the machine attach to a `wstack --hq` that is\n * already running, starts later, or restarts on a different port.\n */\n discover?: boolean;\n /** Resolved HQ data dir the discovery reads from. */\n dataDir?: string;\n}\n\n/**\n * Discover a locally running `wstack --hq` endpoint: reads the runtime\n * marker (pid-liveness-checked) and the first client token. Returns\n * `undefined` when no live HQ is advertised on this machine.\n */\nexport function discoverLocalHqEndpoint(options: {\n dataDir?: string | undefined;\n env?: NodeJS.ProcessEnv | undefined;\n} = {}): { url: string; token?: string | undefined } | undefined {\n const dataDir = resolveHqDataDir(options.dataDir, options.env ?? process.env);\n const runtime = readHqRuntimeFileSync(dataDir);\n if (runtime === undefined) return undefined;\n const token = readFirstClientTokenFromAuthFile(dataDir);\n return { url: runtime.url, ...(token ? { token } : {}) };\n}\n\nfunction readFirstClientTokenFromAuthFile(dataDir: string): string | undefined {\n try {\n const raw = fs.readFileSync(hqAuthFilePath(dataDir), 'utf8');\n const parsed = JSON.parse(raw) as HqAuthFile;\n return parsed.clientTokens?.find((t) => t.token.trim().length > 0)?.token;\n } catch {\n return undefined;\n }\n}\n\n/**\n * True when an explicit HQ URL targets this machine. Falling back to the\n * LOCAL auth.json client token is only valid for same-machine servers \u2014 a\n * remote HQ has its own auth.json, and sending the local token would put the\n * publisher into a silent 401 reconnect loop.\n */\nfunction isLoopbackHqUrl(url: string): boolean {\n try {\n const host = new URL(url).hostname.toLowerCase();\n return host === '127.0.0.1' || host === 'localhost' || host === '::1' || host === '[::1]' || host === '0.0.0.0';\n } catch {\n return false;\n }\n}\n\nexport function resolveHqConfigFromEnv(env: NodeJS.ProcessEnv = process.env): HqPublisherEnvConfig | undefined {\n return resolveHqConfig({ env });\n}\n\nexport function resolveHqConfig(options: {\n env?: NodeJS.ProcessEnv | undefined;\n config?: HqClientConfig | undefined;\n} = {}): HqPublisherEnvConfig | undefined {\n const env = options.env ?? process.env;\n const fileConfig = options.config;\n const envUrl = env['WRONGSTACK_HQ_URL']?.trim();\n const envToken = env['WRONGSTACK_HQ_TOKEN']?.trim();\n const configUrl = fileConfig?.url?.trim();\n const configToken = fileConfig?.token?.trim();\n const envEnabledRaw = env['WRONGSTACK_HQ_ENABLED']?.trim();\n const enabled = envEnabledRaw !== undefined && envEnabledRaw.length > 0\n ? envEnabledRaw !== '0'\n : fileConfig?.enabled;\n const dataDir = resolveHqDataDir(fileConfig?.dataDir, env);\n const explicitToken = envToken || configToken;\n const runtimeUrl = readHqRuntimeFileSync(dataDir)?.url.trim();\n const url = envUrl || configUrl;\n // The local auth.json client token is only a valid fallback for\n // same-machine endpoints (discovery, or an explicit loopback URL). For a\n // remote URL without an explicit token, send NO token \u2014 the server's 401\n // is then an honest signal instead of a guaranteed-wrong local token.\n const localFallbackToken =\n !url || isLoopbackHqUrl(url) ? readFirstClientTokenFromAuthFile(dataDir) : undefined;\n const token = explicitToken || localFallbackToken;\n\n const rawContentEnv = env['WRONGSTACK_HQ_RAW_CONTENT']?.trim();\n const explicitRawContent = rawContentEnv ? rawContentEnv === '1' : fileConfig?.rawContent;\n const projectAliasEnv = env['WRONGSTACK_HQ_PROJECT_ALIAS']?.trim();\n const projectAlias = projectAliasEnv || fileConfig?.projectAlias;\n\n if (!url) {\n if (enabled === false) return undefined;\n // No explicit endpoint \u2192 same-machine auto-discovery (default ON).\n // The publisher re-resolves runtime.json + auth.json before every\n // connect attempt, so an HQ started AFTER this client \u2014 or restarted on\n // another port \u2014 is attached to automatically. While no HQ is running\n // the publisher stays dormant (bounded queue, cheap file poll).\n // Opt out with WRONGSTACK_HQ_ENABLED=0 or config `hq.enabled: false`.\n //\n // Same-machine HQ defaults to RAW content: the data never leaves this\n // machine and the operator watching HQ is the same user running the\n // sessions \u2014 a redacted chat history there is useless. Opt out with\n // WRONGSTACK_HQ_RAW_CONTENT=0 or `hq.rawContent: false` (/hq raw off).\n // Secret scrubbing + sensitive-field masking still always apply.\n return {\n url: runtimeUrl || 'http://127.0.0.1:3499',\n enabled: true,\n discover: true,\n dataDir,\n rawContent: explicitRawContent ?? true,\n ...(token ? { token } : {}),\n ...(projectAlias ? { projectAlias } : {}),\n };\n }\n\n // Explicit URL: raw content is the default for every HQ target. Operators\n // can still opt out with WRONGSTACK_HQ_RAW_CONTENT=0 or hq.rawContent=false,\n // and the HQ server can clamp disclosure with auth.json redactionPolicy.\n const rawContent = explicitRawContent ?? true;\n return {\n url,\n ...(token ? { token } : {}),\n ...(enabled !== undefined ? { enabled } : {}),\n ...(rawContent !== undefined ? { rawContent } : {}),\n ...(projectAlias ? { projectAlias } : {}),\n };\n}\n\nfunction stableMachineId(): string {\n // Stable per *physical machine*, NOT per process \u2014 every terminal on the\n // same computer must share one machineId so HQ groups them under a single\n // machine node. (Process identity already lives in clientId via the pid.)\n return createHash('sha256').update(hostname()).digest('hex').slice(0, 12);\n}\n\nfunction deriveProjectId(projectRoot: string): string {\n return createHash('sha256').update(projectRoot).digest('hex').slice(0, 12);\n}\n\nexport interface CreateHqPublisherOptions {\n clientKind: HqClientIdentity['kind'];\n projectRoot: string;\n projectName?: string;\n machineId?: string;\n hostnameOverride?: string;\n socketFactory?: HqSocketFactory;\n config?: HqPublisherEnvConfig;\n appConfig?: { hq?: HqClientConfig | undefined } | undefined;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n /** Forwarded to the HqPublisher constructor (Phase 4 control plane). */\n capabilities?: readonly HqClientCapability[];\n /** Forwarded to the HqPublisher constructor (Phase 4 control plane). */\n onCommand?: HqPublisherCommandHandler;\n /** Dormant discovery re-check interval override (tests / tight loops). */\n discoveryPollMs?: number;\n /** Logger for structured connect-failure diagnostics. */\n logger?: Logger | undefined;\n}\n\nexport function createHqPublisherFromEnv(options: CreateHqPublisherOptions): HqPublisher | undefined {\n const config = options.config ?? resolveHqConfig({ config: options.appConfig?.hq });\n if (!config || config.enabled === false) return undefined;\n\n const machineId = options.machineId ?? stableMachineId();\n const host = options.hostnameOverride ?? hostname();\n const projectName = options.projectName ?? config.projectAlias ?? (basename(options.projectRoot) || 'unknown');\n\n const client: HqClientIdentity = {\n clientId: `${machineId}:${options.clientKind}:${process.pid}:${randomUUID().slice(0, 8)}`,\n kind: options.clientKind,\n machineId,\n ...(host ? { hostname: host } : {}),\n pid: process.pid,\n startedAt: new Date().toISOString(),\n };\n\n const project: HqProjectIdentity = {\n projectId: deriveProjectId(options.projectRoot),\n projectRoot: options.projectRoot,\n projectName,\n machineId,\n workspaceKind: 'git',\n };\n\n const redactionPolicy: Partial<HqRedactionPolicy> | undefined =\n options.redactionPolicy || config.rawContent !== undefined\n ? {\n ...(config.rawContent !== undefined ? { rawContent: config.rawContent } : {}),\n ...(options.redactionPolicy ?? {}),\n }\n : undefined;\n\n const discoveryDataDir = config.dataDir;\n return new HqPublisher({\n url: config.url,\n ...(config.token ? { token: config.token } : {}),\n client,\n project,\n ...(options.socketFactory ? { socketFactory: options.socketFactory } : {}),\n ...(redactionPolicy !== undefined ? { redactionPolicy } : {}),\n ...(options.capabilities !== undefined ? { capabilities: options.capabilities } : {}),\n ...(options.onCommand !== undefined ? { onCommand: options.onCommand } : {}),\n // Auto-discovery: re-read the local HQ runtime marker + client token on\n // every connect attempt so late-started/restarted HQs are picked up.\n ...(config.discover\n ? { resolveEndpoint: () => discoverLocalHqEndpoint({ dataDir: discoveryDataDir }) }\n : {}),\n ...(options.discoveryPollMs !== undefined ? { discoveryPollMs: options.discoveryPollMs } : {}),\n ...(options.logger !== undefined ? { logger: options.logger } : {}),\n });\n}\n\nexport interface CreateGlobalMailboxOptions {\n projectDir: string;\n events?: EventBus;\n hqPublisher?: HqPublisher;\n}\n\nexport function createGlobalMailbox(options: CreateGlobalMailboxOptions): GlobalMailbox {\n return new GlobalMailbox(options.projectDir, options.events, options.hqPublisher);\n}\n", "/**\n * GlobalMailbox \u2014 project-level inter-agent mailbox with cross-session support.\n *\n * Stores messages at `~/.wrongstack/projects/<slug>/_mailbox.jsonl` so every\n * client and agent working on the same canonical project shares one inbox,\n * including agents in different processes, sessions, branches, and linked Git\n * worktrees.\n *\n * Features:\n * - Agent registration + heartbeat (agents go stale after 60s without heartbeat)\n * - Per-recipient read receipts (readBy[agentId] = ISO8601)\n * - Atomic file-locking for concurrent multi-process writes\n * - Unread count for new-mail notifications\n * - Online agent list\n *\n * @module GlobalMailbox\n */\n\nimport { randomUUID } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\n\nimport * as path from 'node:path';\nimport type { HqPublisher } from '../hq/publisher.js';\nimport type { EventBus } from '../kernel/events.js';\nimport { withFileLock } from '../utils/atomic-write.js';\nimport { projectSlug } from '../utils/wstack-paths.js';\nimport {\n AGENT_STALE_MS,\n AUTO_COMPACT_DEFAULT_TTL_MS,\n AUTO_COMPACT_INTERVAL_MS,\n AUTO_COMPACT_READ_MAX_AGE_MS,\n CLIENT_STALE_MS,\n HEARTBEAT_THROTTLE_MS,\n LINE_SEPARATOR,\n MESSAGE_CACHE_MAX_ENTRIES,\n REGISTRY_CACHE_TTL_MS,\n} from './mailbox-constants.js';\nimport type { MailboxEventEmitter } from './mailbox-events.js';\nimport {\n applyAckToMessage,\n isAckRecord,\n normalizeMailboxMessageType,\n parseMailboxLine,\n serializeAckRecord,\n} from './mailbox-message-codec.js';\nimport type {\n AckRecord,\n AgentHeartbeatInput,\n AgentRegistrationInput,\n AutoCompactOptions,\n AutoCompactResult,\n ClientHeartbeatInput,\n ClientRegistrationInput,\n ClientStatus,\n Mailbox,\n MailboxAckBatchInput,\n MailboxAckInput,\n MailboxAgentStatus,\n MailboxMessage,\n MailboxQuery,\n MailboxSendInput,\n PurgeOptions,\n PurgeResult,\n RegisteredAgent,\n RegisteredClient,\n} from './mailbox-types.js';\nimport { normalizeRecipient, sessionRecipient } from './mailbox-types.js';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst MAILBOX_FILE = '_mailbox.jsonl';\nconst CLIENT_REGISTRY_FILE = '_mailbox.clients.json';\n\ntype HqPublisherRef = HqPublisher | (() => HqPublisher | undefined);\n\n/**\n * Derive the project-level mailbox directory path.\n *\n * Delegates to the CANONICAL `projectSlug()` from wstack-paths so every\n * surface (CLI, TUI, WebUI, mailbox tool, loop checker) lands in the exact\n * same `~/.wrongstack/projects/<slug>/` directory. `projectSlug()` also folds\n * linked Git worktrees into their shared common project identity, preventing\n * branch/worktree isolation from accidentally becoming mailbox isolation.\n *\n * @param projectRoot \u2014 absolute path to the project root\n * @param globalRoot \u2014 `~/.wrongstack` (or custom global root)\n */\nexport function resolveProjectDir(projectRoot: string, globalRoot: string): string {\n return path.join(globalRoot, 'projects', projectSlug(projectRoot));\n}\n\n// \u2500\u2500 Singleton factory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Process-wide registry of GlobalMailbox instances, keyed by projectDir.\n *\n * Without this, `attachMailboxChecker` and `attachFleetPulse` each created\n * a SEPARATE GlobalMailbox for the same project directory \u2014 two independent\n * mtime caches, two read chains, two sets of heartbeat timers. The factory\n * ensures that within a single process there is at most one instance per\n * project directory, so cache hit ratio is maximized and I/O is minimized.\n *\n * Cross-process sharing still works as before (the JSONL file + file lock\n * is the source of truth); this is purely an in-process optimization.\n *\n * Pass `forceNew: true` to bypass the cache (used by tests that need an\n * isolated tmpdir instance without polluting the singleton).\n */\nconst _mailboxInstances = new Map<string, GlobalMailbox>();\n\nexport function getSharedMailbox(\n projectDir: string,\n events?: EventBus,\n hqPublisher?: HqPublisherRef,\n opts?: { forceNew?: boolean },\n): GlobalMailbox {\n if (opts?.forceNew) {\n return new GlobalMailbox(projectDir, events, hqPublisher);\n }\n const existing = _mailboxInstances.get(projectDir);\n if (existing !== undefined) return existing;\n const mb = new GlobalMailbox(projectDir, events, hqPublisher);\n _mailboxInstances.set(projectDir, mb);\n return mb;\n}\n\n/** Clear the singleton registry \u2014 used by tests to avoid cross-test leakage. */\nexport function _clearMailboxSingletons(): void {\n _mailboxInstances.clear();\n}\n\n// \u2500\u2500 GlobalMailbox \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class GlobalMailbox implements Mailbox {\n /** Path to the JSONL message file. */\n readonly messagePath: string;\n /** Path to the JSON agent registry file. */\n readonly registryPath: string;\n /** Path to the JSON client registry file. */\n readonly clientRegistryPath: string;\n /** Optional event bus for emitting agent registration/heartbeat events. */\n private readonly _events?: EventBus | undefined;\n /** Optional HQ publisher for cross-project command-center telemetry. */\n private readonly _hqPublisher?: HqPublisherRef | undefined;\n /**\n * Optional SSE event emitter for real-time push to HTTP bridge clients.\n * When present, `send`/`ack`/`softDelete`/`restore` emit events that\n * connected SSE subscribers receive instantly.\n */\n readonly eventEmitter?: MailboxEventEmitter | undefined;\n /**\n * Local cache of the agent registry to avoid re-reading on every call.\n * Time-bounded: the registry file is shared ACROSS PROCESSES (that's the\n * whole point of GlobalMailbox), so a cache served forever would never see\n * agents registered by other sessions. Writers always bypass it.\n */\n private _registryCache: Map<string, RegisteredAgent> | null = null;\n /** When the registry cache was last refreshed from disk (epoch ms). */\n private _registryCacheAt = 0;\n /**\n * Local cache of the client registry to avoid re-reading on every call.\n * Same reasoning as agent registry cache.\n */\n private _clientRegistryCache: Map<string, RegisteredClient> | null = null;\n /** When the client registry cache was last refreshed from disk (epoch ms). */\n private _clientRegistryCacheAt = 0;\n /** Last time each local agent sent a heartbeat (throttle). */\n private _lastHeartbeat = new Map<string, number>();\n /** Last time each local client sent a heartbeat (throttle). */\n private _lastClientHeartbeat = new Map<string, number>();\n /**\n * In-memory mirror of the JSONL message file. The mailbox is shared\n * ACROSS PROCESSES, so reads cannot trust the cache blindly \u2014 we pair it\n * with an mtime check. The file lock serializes every write, so a\n * changed mtimeMs is a definitive signal that another process (or this\n * one) wrote; an unchanged mtimeMs guarantees no write happened and the\n * cache is current. This collapses the per-iteration `query()` cost from\n * O(file_size) disk + parse to O(messages) in memory.\n */\n private _messageCache: MailboxMessage[] | null = null;\n /** mtimeMs of the file when `_messageCache` was populated. */\n private _messageCacheMtime = -1;\n /** Size of the file when `_messageCache` was populated (extra guard). */\n private _messageCacheSize = -1;\n /**\n * Serializes reads of the message file so overlapping concurrent\n * `_readMessagesCached()` calls don't both enter the incremental \"file\n * only grew\" branch against the same stale `_messageCacheSize` and\n * each push the same tail bytes onto the cache (duplicating every\n * appended message). The chain runs each read to completion before\n * the next starts, in issue order \u2014 readers are read-only and never\n * conflict with each other on content, only on the cache mutation\n * that follows the read. Pattern mirrors a serialized mutation chain.\n */\n private _readChain: Promise<MailboxMessage[]> = Promise.resolve([] as MailboxMessage[]);\n\n /**\n * Recipient \u2192 Set of indices into `_messageCache`. Maintained alongside\n * the cache so `query({ to })` and `unreadCount(agentId)` can skip the\n * O(N) full scan and iterate only the messages addressed to the target\n * recipient (plus broadcasts `*`).\n *\n * The index is rebuilt whenever the cache array is replaced\n * (`_setMessageCache`), extended when new messages are pushed\n * (`_pushToCache`), and cleared on `close()`.\n * It is `null` when the cache itself is null (> MESSAGE_CACHE_MAX_ENTRIES\n * or never populated).\n *\n * Safety: array indices are valid only as long as the cache array\n * reference hasn't changed. Since we rebuild the index in the same\n * synchronous step that replaces the cache, a reader that calls\n * `_readMessagesCached()` either gets the old array + old index, or\n * the new array + new index \u2014 never a mismatch.\n */\n private _recipientIndex: Map<string, Set<number>> | null = null;\n\n /**\n * Sender \u2192 Set of indices into `_messageCache`. Same lifecycle and\n * safety properties as `_recipientIndex`, but keyed on `msg.from`\n * so `query({ from })` can skip the full scan.\n */\n private _senderIndex: Map<string, Set<number>> | null = null;\n\n /**\n * @param projectDir \u2014 `~/.wrongstack/projects/<slug>/`\n * @param events \u2014 optional EventBus for real-time TUI/WebUI notifications\n * @param hqPublisher \u2014 optional HQ publisher, or getter, for cross-project telemetry\n * @param eventEmitter \u2014 optional SSE event emitter for HTTP bridge push\n */\n constructor(\n projectDir: string,\n events?: EventBus,\n hqPublisher?: HqPublisherRef,\n eventEmitter?: MailboxEventEmitter,\n ) {\n this.messagePath = path.join(projectDir, MAILBOX_FILE);\n this.registryPath = path.join(projectDir, '_mailbox.registry.json');\n this.clientRegistryPath = path.join(projectDir, CLIENT_REGISTRY_FILE);\n this._events = events;\n this._hqPublisher = hqPublisher;\n this.eventEmitter = eventEmitter;\n }\n\n private get hqMailboxId(): string {\n return `${path.basename(path.dirname(this.messagePath))}:mailbox`;\n }\n\n private get hqPublisher(): HqPublisher | undefined {\n return typeof this._hqPublisher === 'function' ? this._hqPublisher() : this._hqPublisher;\n }\n\n private publishHqMailboxEvent(input: Parameters<HqPublisher['publishMailboxEvent']>[0]): void {\n try {\n this.hqPublisher?.publishMailboxEvent(input);\n } catch {\n // HQ telemetry is best-effort and must never affect mailbox behavior.\n }\n }\n\n private publishHqMailboxSnapshot(): void {\n const publisher = this.hqPublisher;\n if (publisher === undefined) return;\n void publisher.publishMailboxSnapshot(this, { mailboxId: this.hqMailboxId }).catch(() => {\n // HQ telemetry is best-effort and must never affect mailbox behavior.\n });\n }\n\n // \u2500\u2500 Messages \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async send(input: MailboxSendInput): Promise<MailboxMessage> {\n const now = new Date().toISOString();\n const msg: MailboxMessage = {\n id: randomUUID(),\n from: input.from,\n // \"all\" maps to project broadcast; \"@session\" is resolved against the\n // sender's session before persistence so recipients can match it exactly.\n to: normalizeRecipient(input.to, input.senderSessionId),\n type: normalizeMailboxMessageType(input.type),\n subject: input.subject,\n body: input.body,\n priority: input.priority ?? 'normal',\n readBy: {},\n completed: false,\n timestamp: now,\n replyTo: input.replyTo,\n taskContext: input.taskContext,\n senderSessionId: input.senderSessionId,\n expiresAt:\n input.ttlMs !== undefined ? new Date(Date.now() + input.ttlMs).toISOString() : undefined,\n };\n\n const line = JSON.stringify(msg) + LINE_SEPARATOR;\n await fsp.mkdir(path.dirname(this.messagePath), { recursive: true });\n // The append must hold the same lock ack() rewrites under: an unlocked\n // append racing ack's read\u2192rewrite gets silently erased when the rewrite\n // lands. This file is shared ACROSS PROCESSES, so the window is real.\n await withFileLock(this.messagePath, async () => {\n await fsp.appendFile(this.messagePath, line, 'utf8');\n // Capture the post-append stat INSIDE the lock so the cache trackers\n // advance with the pushed content. A concurrent reader that lands\n // after we release but before a future stat would otherwise see the\n // file grew and re-append the just-sent tail, duplicating it.\n const { mtimeMs, size } = await this._statMessageFile();\n // Refresh the in-memory cache from the message we just appended \u2014\n // cheaper than re-reading the whole file, and correct because we\n // held the lock so nothing else changed underneath us.\n this._pushToCache(msg, mtimeMs, size);\n });\n\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'message.sent',\n message: msg,\n });\n this.publishHqMailboxSnapshot();\n\n // In-process push notification: same-process mailbox consumers (the\n // awareness poller, fleet pulse, TUI/WebUI) can listen on this event\n // to get real-time updates instead of polling on every iteration.\n this._events?.emitCustom('mailbox.message_sent', {\n messageId: msg.id,\n from: msg.from,\n to: msg.to,\n type: msg.type,\n subject: msg.subject,\n });\n // SSE push for external HTTP bridge clients.\n this.eventEmitter?.emit({\n type: 'message.sent' as const,\n messageId: msg.id,\n from: msg.from,\n to: msg.to,\n timestamp: now,\n });\n\n return msg;\n }\n\n async query(q: MailboxQuery): Promise<MailboxMessage[]> {\n const queryType = q.type === undefined ? undefined : normalizeMailboxMessageType(q.type);\n const all = await this._readMessagesCached();\n const limit = q.limit ?? 50;\n\n // Single-pass filter \u2014 previously 7 chained .filter() allocations each\n // producing a fresh array. Predicates are independent, so we can AND\n // them in one walk and short-circuit per element.\n const order = q.minPriority !== undefined ? ({ low: 0, normal: 1, high: 2 } as const) : null;\n const minPriorityRank = order && q.minPriority !== undefined ? order[q.minPriority] : 0;\n const out: MailboxMessage[] = [];\n\n // Recipient index fast-path: when the query filters by `to` AND no\n // other broad filter (from, type, etc.) would benefit from the index,\n // iterate only the messages addressed to the target recipient (plus\n // broadcasts `*`) instead of scanning the full cache. Falls back to\n // the full scan when the index is unavailable or when multiple\n // non-recipient filters are present (the index doesn't help there).\n //\n // Sender index fast-path: symmetric \u2014 when filtering ONLY by `from`\n // (no `to`, `type`, `minPriority`), iterate only messages from that\n // sender.\n let candidates: Iterable<MailboxMessage>;\n if (\n q.to !== undefined &&\n this._recipientIndex !== null &&\n q.from === undefined &&\n q.type === undefined &&\n q.minPriority === undefined\n ) {\n // Collect candidate indices: messages addressed to `q.to` + broadcasts.\n const indices = new Set<number>();\n const direct = this._recipientIndex.get(q.to);\n if (direct !== undefined) for (const i of direct) indices.add(i);\n const broadcasts = this._recipientIndex.get('*');\n if (broadcasts !== undefined) for (const i of broadcasts) indices.add(i);\n candidates = [...indices].sort((a, b) => a - b).map((i) => all[i]!);\n } else if (\n q.from !== undefined &&\n q.to === undefined &&\n this._senderIndex !== null &&\n q.type === undefined &&\n q.minPriority === undefined\n ) {\n // Sender index fast-path: iterate only messages from `q.from`.\n const indices = this._senderIndex.get(q.from);\n candidates =\n indices !== undefined ? [...indices].sort((a, b) => a - b).map((i) => all[i]!) : [];\n } else {\n candidates = all;\n }\n\n for (const m of candidates) {\n if (q.to !== undefined && m.to !== q.to && m.to !== '*') continue;\n if (q.from !== undefined && m.from !== q.from) continue;\n if (q.sessionId !== undefined && m.senderSessionId !== q.sessionId) continue;\n if (q.unreadBy !== undefined && q.unreadBy in m.readBy) continue;\n if (q.incompleteOnly && m.completed) continue;\n if (queryType !== undefined && m.type !== queryType) continue;\n if (order !== null && (order[m.priority as keyof typeof order] ?? 1) < minPriorityRank!) {\n continue;\n }\n if (q.since !== undefined && m.timestamp <= q.since) continue;\n // Default behavior: soft-deleted messages are hidden unless the\n // caller explicitly opts in via `includeDeleted: true` (used by\n // the WebUI's \"trash\" view).\n if (!q.includeDeleted && m.deletedAt !== undefined) continue;\n out.push(m);\n }\n\n out.sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n // Return defensive shallow copies so callers cannot mutate the shared\n // cache entries. Only the returned slice is copied \u2014 O(limit), not O(N).\n return out.slice(0, limit).map((m) => ({ ...m, readBy: { ...m.readBy } }));\n }\n\n async ack(input: MailboxAckInput): Promise<MailboxMessage | null> {\n const updated = await this.ackMany({ acks: [input] });\n return updated.length > 0 ? updated[0]! : null;\n }\n\n /** Diagnostic counters exposed for test/tool introspection. */\n readonly diag = {\n ackManyCacheDesync: 0,\n ackManyPreLockMtime: 0,\n ackManyPostLockMtime: 0,\n ackManyPreLockSize: 0,\n ackManyPostLockSize: 0,\n ackManyMessageCount: 0,\n ackManyAckCount: 0,\n cacheHitCount: 0,\n cacheMissCount: 0,\n cacheDesyncNoOp: 0,\n applyAckTargetMissing: 0,\n setMessageCacheCount: 0,\n pushToCacheCount: 0,\n };\n\n async ackMany(input: MailboxAckBatchInput): Promise<MailboxMessage[]> {\n // Append-only ack: instead of reading all messages, mutating them,\n // and rewriting the entire file (O(N) read + O(N) write), we append\n // small ack records (O(K) append where K = number of acks). At read\n // time, ack records are folded into their target messages.\n //\n // This is the #1 performance fix: every agent iteration calls ackMany\n // on the mailbox-loop hot path. Previously it was O(N) per iteration.\n if (input.acks.length === 0) return [];\n\n const now = new Date().toISOString();\n const ackRecords: AckRecord[] = [];\n const updated: MailboxMessage[] = [];\n const targetIds = new Set<string>();\n const byId = new Map<string, MailboxAckInput>();\n\n for (const a of input.acks) {\n byId.set(a.messageId, a);\n targetIds.add(a.messageId);\n }\n\n // \u2500\u2500 Pre-lock snapshot for cross-process desync detection \u2500\u2500\n const preLockMtime = this._messageCacheMtime;\n const preLockSize = this._messageCacheSize;\n this.diag.ackManyPreLockMtime = preLockMtime;\n this.diag.ackManyPreLockSize = preLockSize;\n\n // Build ack records and find target messages.\n // We need to find messages to return them; use cached view for speed.\n const all = await this._readMessagesCached();\n for (const msg of all) {\n const a = byId.get(msg.id);\n if (!a) continue;\n\n // Determine what this ack actually changes to avoid no-op appends.\n const needsRead = a.read !== false && !(a.readerId in msg.readBy);\n const needsComplete = a.completed && !msg.completed;\n const needsOutcome = a.outcome !== undefined && msg.outcome !== a.outcome;\n\n if (!needsRead && !needsComplete && !needsOutcome) {\n // No-op ack \u2014 return the pre-ack state (defensive copy matches\n // the original semantics: re-acking an already-read message\n // returns the message as it was).\n updated.push({ ...msg, readBy: { ...msg.readBy } });\n continue;\n }\n\n // Apply changes to a defensive copy for the return value.\n const copy = { ...msg, readBy: { ...msg.readBy } };\n if (needsRead) copy.readBy[a.readerId] = now;\n if (needsComplete) {\n copy.completed = true;\n copy.completedBy = a.readerId;\n copy.completedAt = now;\n }\n if (needsOutcome) copy.outcome = a.outcome;\n updated.push(copy);\n\n ackRecords.push({\n __ack: true,\n messageId: msg.id,\n readerId: a.readerId,\n timestamp: now,\n read: a.read !== false,\n completed: a.completed,\n completedBy: a.completed ? a.readerId : undefined,\n outcome: a.outcome,\n });\n }\n\n if (ackRecords.length === 0) {\n // All requested acks were no-ops (already read/completed).\n // Still return the messages that were found (updated may be empty if\n // none matched, which preserves prior silent-skip semantics).\n if (updated.length > 0) {\n for (const message of updated) {\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: message.completed ? 'message.completed' : 'message.read',\n message,\n });\n }\n }\n return updated;\n }\n\n // Append ack records to the file under the lock.\n const serialized = ackRecords.map((a) => serializeAckRecord(a)).join('');\n await withFileLock(this.messagePath, async () => {\n await fsp.appendFile(this.messagePath, serialized, 'utf8');\n // Capture the post-append stat inside the lock.\n const { mtimeMs, size } = await this._statMessageFile();\n // Apply ack effects directly to the in-memory cache.\n for (const ack of ackRecords) {\n this._applyAckToCache(ack);\n }\n // Advance cache trackers so the next read sees current size.\n this._messageCacheMtime = mtimeMs;\n this._messageCacheSize = size;\n\n // \u2500\u2500 Post-lock diagnostics \u2500\u2500\n this.diag.ackManyPostLockMtime = mtimeMs;\n this.diag.ackManyPostLockSize = size;\n this.diag.ackManyMessageCount = this._messageCache?.length ?? -1;\n this.diag.ackManyAckCount = ackRecords.length;\n\n // DETECT: cross-process cache desync\n // If the post-append stat jumped ahead more than our serialized ack\n // bytes alone, another process appended data between our cache read\n // and lock acquisition. The cache would then be missing those messages.\n const expectedMinSize = preLockSize + serialized.length;\n if (preLockSize > 0 && size > expectedMinSize) {\n const extraBytes = size - expectedMinSize;\n console.error(\n `[MAILBOX-DIAG] ackMany: post-lock size ${size} exceeds expected ${expectedMinSize} by ${extraBytes}B (mtime ${preLockMtime}->${mtimeMs}). ` +\n `Cache may be missing cross-process messages. diag.ackManyCacheDesync=${++this.diag.ackManyCacheDesync}`,\n );\n }\n });\n\n for (const message of updated) {\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: message.completed ? 'message.completed' : 'message.read',\n message,\n });\n this.eventEmitter?.emit({\n type: 'message.acked' as const,\n messageId: message.id,\n from: message.from,\n to: message.to,\n timestamp: new Date().toISOString(),\n });\n }\n if (updated.length > 0) this.publishHqMailboxSnapshot();\n return updated;\n }\n\n async unreadCount(forAgentId: string, sessionId?: string): Promise<number> {\n const all = await this._readMessagesCached();\n const scopedSessionRecipient =\n sessionId === undefined ? undefined : sessionRecipient(sessionId);\n let count = 0;\n\n // Recipient index fast-path: iterate direct + project broadcast + the\n // recipient's session broadcast, instead of the full cache.\n if (this._recipientIndex !== null) {\n const indices = new Set<number>();\n const direct = this._recipientIndex.get(forAgentId);\n if (direct !== undefined) for (const i of direct) indices.add(i);\n const broadcasts = this._recipientIndex.get('*');\n if (broadcasts !== undefined) for (const i of broadcasts) indices.add(i);\n if (scopedSessionRecipient !== undefined) {\n const sessionBroadcasts = this._recipientIndex.get(scopedSessionRecipient);\n if (sessionBroadcasts !== undefined) for (const i of sessionBroadcasts) indices.add(i);\n }\n for (const i of indices) {\n const m = all[i]!;\n if (!(forAgentId in m.readBy) && !m.completed) count++;\n }\n } else {\n for (let i = 0; i < all.length; i++) {\n const m = all[i]!;\n if (\n (m.to === forAgentId || m.to === '*' || m.to === scopedSessionRecipient) &&\n !(forAgentId in m.readBy) &&\n !m.completed\n ) count++;\n }\n }\n return count;\n }\n\n async softDelete(mailId: string, by: string): Promise<MailboxMessage | null> {\n // Append-only soft-delete: instead of reading all messages, mutating\n // one, and rewriting the entire file, we append a single ack record\n // with `deleted: true`. At read time, the delete is applied to the\n // target message via _parseLines / applyAckToMessage.\n // No-op when the message is already soft-deleted.\n\n const all = await this._readMessagesCached();\n const target = all.find((m) => m.id === mailId);\n if (target === undefined) return null;\n if (target.deletedAt !== undefined) {\n return { ...target, readBy: { ...target.readBy } };\n }\n\n const now = new Date().toISOString();\n const ack: AckRecord = {\n __ack: true,\n messageId: mailId,\n readerId: by,\n timestamp: now,\n read: true,\n deleted: true,\n deletedBy: by,\n };\n\n await withFileLock(this.messagePath, async () => {\n await fsp.appendFile(this.messagePath, serializeAckRecord(ack), 'utf8');\n const { mtimeMs, size } = await this._statMessageFile();\n this._applyAckToCache(ack);\n this._messageCacheMtime = mtimeMs;\n this._messageCacheSize = size;\n });\n\n const msg = { ...target, readBy: { ...target.readBy } };\n msg.deletedAt = now;\n msg.deletedBy = by;\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'message.updated',\n message: msg,\n });\n this.publishHqMailboxSnapshot();\n this.eventEmitter?.emit({\n type: 'message.deleted' as const,\n messageId: msg.id,\n from: msg.from,\n to: msg.to,\n timestamp: msg.deletedAt ?? now,\n });\n return msg;\n }\n\n async restore(mailId: string): Promise<MailboxMessage | null> {\n // Append-only restore (inverse of append-only softDelete). Same\n // pattern: put a `deleted: false` ack record on disk, apply it to\n // the cache. No-op when the message is not currently soft-deleted.\n\n const all = await this._readMessagesCached();\n const target = all.find((m) => m.id === mailId);\n if (target === undefined) return null;\n if (target.deletedAt === undefined && target.deletedBy === undefined) {\n return { ...target, readBy: { ...target.readBy } };\n }\n\n const now = new Date().toISOString();\n const ack: AckRecord = {\n __ack: true,\n messageId: mailId,\n readerId: '',\n timestamp: now,\n read: true,\n deleted: false,\n };\n\n await withFileLock(this.messagePath, async () => {\n await fsp.appendFile(this.messagePath, serializeAckRecord(ack), 'utf8');\n const { mtimeMs, size } = await this._statMessageFile();\n this._applyAckToCache(ack);\n this._messageCacheMtime = mtimeMs;\n this._messageCacheSize = size;\n });\n\n const msg = { ...target, readBy: { ...target.readBy } };\n delete msg.deletedAt;\n delete msg.deletedBy;\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'message.updated',\n message: msg,\n });\n this.publishHqMailboxSnapshot();\n this.eventEmitter?.emit({\n type: 'message.restored' as const,\n messageId: msg.id,\n from: msg.from,\n to: msg.to,\n timestamp: now,\n });\n return msg;\n }\n\n // \u2500\u2500 Agent registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async registerAgent(input: AgentRegistrationInput): Promise<void> {\n await this._ensureRegistry();\n const now = new Date().toISOString();\n const agent: RegisteredAgent = {\n agentId: input.agentId,\n sessionId: input.sessionId,\n name: input.name,\n role: input.role,\n status: 'idle',\n currentTool: undefined,\n currentTask: undefined,\n iterations: 0,\n toolCalls: 0,\n registeredAt: now,\n lastSeenAt: now,\n pid: input.pid ?? process.pid,\n source: input.source,\n };\n\n await withFileLock(this.registryPath, async () => {\n // fresh: read-modify-write must start from the on-disk state, not the\n // cache \u2014 other processes may have registered agents since.\n const registry = await this._readRegistry({ fresh: true });\n // Prune stale agents\n this._pruneStaleInPlace(registry);\n // Upsert\n registry.set(input.agentId, agent);\n // Update cache\n this._registryCache = registry;\n this._registryCacheAt = Date.now();\n await this._writeRegistry(registry);\n });\n\n // Emit event for TUI/WebUI to update online agent count\n this._events?.emitCustom('mailbox.agent_registered', {\n agentId: input.agentId,\n sessionId: input.sessionId,\n name: input.name,\n role: input.role,\n source: input.source,\n });\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'agent.registered',\n agent: {\n agentId: input.agentId,\n name: input.name,\n ...(input.role !== undefined ? { role: input.role } : {}),\n sessionId: input.sessionId,\n status: 'idle',\n iterations: 0,\n toolCalls: 0,\n lastActivityAt: now,\n lastSeenAt: now,\n online: true,\n pid: input.pid ?? process.pid,\n ...(input.source !== undefined ? { source: input.source } : {}),\n },\n });\n this.publishHqMailboxSnapshot();\n }\n\n async deregisterAgent(agentId: string): Promise<void> {\n await this._ensureRegistry();\n let removed: RegisteredAgent | undefined;\n await withFileLock(this.registryPath, async () => {\n const registry = await this._readRegistry({ fresh: true });\n this._pruneStaleInPlace(registry);\n // Capture the record before deletion so HQ telemetry can emit a full,\n // well-typed agent summary rather than a bare id.\n removed = registry.get(agentId);\n registry.delete(agentId);\n this._registryCache = registry;\n this._registryCacheAt = Date.now();\n await this._writeRegistry(registry);\n });\n this._events?.emitCustom('mailbox.agent_deregistered', {\n agentId,\n });\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'agent.deregistered',\n agent: {\n agentId,\n name: removed?.name ?? agentId,\n ...(removed?.role !== undefined ? { role: removed.role } : {}),\n sessionId: removed?.sessionId ?? '',\n status: 'offline',\n ...(removed?.currentTool !== undefined ? { currentTool: removed.currentTool } : {}),\n ...(removed?.currentTask !== undefined ? { currentTask: removed.currentTask } : {}),\n iterations: removed?.iterations ?? 0,\n toolCalls: removed?.toolCalls ?? 0,\n lastActivityAt: removed?.lastSeenAt ?? new Date().toISOString(),\n lastSeenAt: removed?.lastSeenAt ?? new Date().toISOString(),\n online: false,\n pid: removed?.pid ?? 0,\n ...(removed?.source !== undefined ? { source: removed.source } : {}),\n },\n });\n this.publishHqMailboxSnapshot();\n }\n\n async heartbeat(input: AgentHeartbeatInput): Promise<void> {\n // Throttle: at most one heartbeat per agent per HEARTBEAT_THROTTLE_MS\n const last = this._lastHeartbeat.get(input.agentId) ?? 0;\n const now = Date.now();\n if (now - last < HEARTBEAT_THROTTLE_MS) return;\n\n this._lastHeartbeat.set(input.agentId, now);\n\n await this._ensureRegistry();\n\n await withFileLock(this.registryPath, async () => {\n // fresh: see registerAgent \u2014 never read-modify-write from the cache.\n const registry = await this._readRegistry({ fresh: true });\n this._pruneStaleInPlace(registry);\n\n const agent = registry.get(input.agentId);\n if (agent) {\n const iso = new Date().toISOString();\n agent.lastSeenAt = iso;\n if (input.status !== undefined) agent.status = input.status;\n if (input.currentTool !== undefined) agent.currentTool = input.currentTool;\n if (input.currentTask !== undefined) agent.currentTask = input.currentTask;\n if (input.iterations !== undefined) agent.iterations = input.iterations;\n if (input.toolCalls !== undefined) agent.toolCalls = input.toolCalls;\n }\n // If agent not registered yet, silently skip \u2014 registerAgent first\n\n this._registryCache = registry;\n this._registryCacheAt = Date.now();\n await this._writeRegistry(registry);\n });\n\n // Emit event so TUI/WebUI can track online agents in real time\n this._events?.emitCustom('mailbox.agent_heartbeat', {\n agentId: input.agentId,\n status: input.status,\n currentTool: input.currentTool,\n currentTask: input.currentTask,\n });\n this.publishHqMailboxEvent({\n mailboxId: this.hqMailboxId,\n action: 'agent.heartbeat',\n summary: input.agentId,\n });\n this.publishHqMailboxSnapshot();\n }\n\n async getAgentStatuses(): Promise<MailboxAgentStatus[]> {\n await this._ensureRegistry();\n let registry = await this._readRegistry();\n const before = registry.size;\n this._pruneStaleInPlace(registry);\n\n // A read can be the only activity after every process in a project exits.\n // Persist expiry under the file lock so old agents do not survive forever\n // in `_mailbox.registry.json` (or race a concurrent registration).\n if (registry.size < before) {\n await withFileLock(this.registryPath, async () => {\n const fresh = await this._readRegistry({ fresh: true });\n this._pruneStaleInPlace(fresh);\n this._registryCache = fresh;\n this._registryCacheAt = Date.now();\n await this._writeRegistry(fresh);\n registry = fresh;\n });\n }\n\n const now = Date.now();\n return Array.from(registry.values())\n .map((a) => ({\n agentId: a.agentId,\n name: a.name,\n role: a.role,\n sessionId: a.sessionId,\n status: a.status,\n currentTool: a.currentTool,\n currentTask: a.currentTask,\n iterations: a.iterations,\n toolCalls: a.toolCalls,\n lastActivityAt: a.lastSeenAt,\n lastSeenAt: a.lastSeenAt,\n online: now - new Date(a.lastSeenAt).getTime() < AGENT_STALE_MS,\n pid: a.pid,\n source: a.source,\n }))\n .sort((a, b) => b.lastSeenAt.localeCompare(a.lastSeenAt));\n }\n\n async getOnlineAgents(): Promise<MailboxAgentStatus[]> {\n const all = await this.getAgentStatuses();\n return all.filter((a) => a.online);\n }\n\n // \u2500\u2500 Client registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async registerClient(input: ClientRegistrationInput): Promise<void> {\n await this._ensureClientRegistry();\n const now = new Date().toISOString();\n const client: RegisteredClient = {\n clientId: input.clientId,\n sessionId: input.sessionId,\n name: input.name,\n source: input.source,\n registeredAt: now,\n lastSeenAt: now,\n pid: input.pid ?? process.pid,\n };\n\n await withFileLock(this.clientRegistryPath, async () => {\n const registry = await this._readClientRegistry({ fresh: true });\n this._pruneStaleClientsInPlace(registry);\n registry.set(input.clientId, client);\n this._clientRegistryCache = registry;\n this._clientRegistryCacheAt = Date.now();\n await this._writeClientRegistry(registry);\n });\n\n // Emit event for TUI/WebUI to update online client count\n this._events?.emitCustom('mailbox.client_registered', {\n clientId: input.clientId,\n sessionId: input.sessionId,\n name: input.name,\n source: input.source,\n });\n this.publishHqMailboxSnapshot();\n }\n\n async deregisterClient(clientId: string): Promise<void> {\n await this._ensureClientRegistry();\n await withFileLock(this.clientRegistryPath, async () => {\n const registry = await this._readClientRegistry({ fresh: true });\n this._pruneStaleClientsInPlace(registry);\n registry.delete(clientId);\n this._clientRegistryCache = registry;\n this._clientRegistryCacheAt = Date.now();\n await this._writeClientRegistry(registry);\n });\n this._lastClientHeartbeat.delete(clientId);\n this._events?.emitCustom('mailbox.client_deregistered', { clientId });\n this.publishHqMailboxSnapshot();\n }\n\n async clientHeartbeat(input: ClientHeartbeatInput): Promise<void> {\n // Throttle: at most one heartbeat per client per HEARTBEAT_THROTTLE_MS\n const last = this._lastClientHeartbeat.get(input.clientId) ?? 0;\n const now = Date.now();\n if (now - last < HEARTBEAT_THROTTLE_MS) return;\n\n this._lastClientHeartbeat.set(input.clientId, now);\n\n await this._ensureClientRegistry();\n\n await withFileLock(this.clientRegistryPath, async () => {\n const registry = await this._readClientRegistry({ fresh: true });\n this._pruneStaleClientsInPlace(registry);\n\n const client = registry.get(input.clientId);\n if (client) {\n client.lastSeenAt = new Date().toISOString();\n if (typeof input.sessionId === 'string' && input.sessionId.length > 0) {\n client.sessionId = input.sessionId;\n }\n }\n\n this._clientRegistryCache = registry;\n this._clientRegistryCacheAt = Date.now();\n await this._writeClientRegistry(registry);\n });\n\n // Emit event so TUI/WebUI can track online clients in real time\n this._events?.emitCustom('mailbox.client_heartbeat', {\n clientId: input.clientId,\n ...(input.sessionId ? { sessionId: input.sessionId } : {}),\n });\n this.publishHqMailboxSnapshot();\n }\n\n async getClientStatuses(): Promise<ClientStatus[]> {\n await this._ensureClientRegistry();\n let registry = await this._readClientRegistry();\n const before = registry.size;\n this._pruneStaleClientsInPlace(registry);\n\n // Persist the pruning so stale entries in _mailbox.clients.json don't\n // accumulate indefinitely. Without this, `getClientStatuses` prunes in\n // memory only \u2014 the stale JSON records survive on disk until another\n // write happens (registerClient / clientHeartbeat), which may never\n // occur if all bridge clients are dead.\n //\n // Lock around the read-prune-write to prevent racing concurrent\n // registerClient / clientHeartbeat / deregisterClient calls, all of\n // which also acquire this lock.\n if (registry.size < before) {\n await withFileLock(this.clientRegistryPath, async () => {\n // Re-read under the lock so a concurrent write since our\n // initial read is not overwritten.\n registry = await this._readClientRegistry({ fresh: true });\n const postLockBefore = registry.size;\n this._pruneStaleClientsInPlace(registry);\n if (registry.size < postLockBefore) {\n await this._writeClientRegistry(registry);\n }\n });\n }\n\n const now = Date.now();\n return Array.from(registry.values())\n .map((c) => ({\n clientId: c.clientId,\n name: c.name,\n source: c.source,\n sessionId: c.sessionId,\n lastSeenAt: c.lastSeenAt,\n online: now - new Date(c.lastSeenAt).getTime() < CLIENT_STALE_MS,\n pid: c.pid,\n }))\n .sort((a, b) => b.lastSeenAt.localeCompare(a.lastSeenAt));\n }\n\n /**\n * Explicitly purge stale clients from the registry and write back to disk.\n * Removes client entries whose lastSeenAt is older than CLIENT_STALE_MS.\n * Returns the number of entries purged.\n *\n * Idempotent \u2014 safe to call regularly. The same pruning runs implicitly\n * inside registerClient, clientHeartbeat, and getClientStatuses, but if\n * no client registers or heartbeats for a long time, this public method\n * ensures the file gets cleaned up on demand.\n */\n async purgeClients(): Promise<number> {\n await this._ensureClientRegistry();\n let purged = 0;\n await withFileLock(this.clientRegistryPath, async () => {\n const registry = await this._readClientRegistry({ fresh: true });\n const before = registry.size;\n this._pruneStaleClientsInPlace(registry);\n purged = before - registry.size;\n if (purged > 0) {\n this._clientRegistryCache = registry;\n this._clientRegistryCacheAt = Date.now();\n await this._writeClientRegistry(registry);\n }\n });\n return purged;\n }\n\n // \u2500\u2500 Lifecycle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async close(): Promise<void> {\n // JSONL append-only \u2014 no flush needed\n this._registryCache = null;\n this._clientRegistryCache = null;\n this._messageCache = null;\n this._messageCacheMtime = -1;\n this._messageCacheSize = -1;\n this._recipientIndex = null;\n this._senderIndex = null;\n }\n\n async clearAll(): Promise<void> {\n // Truncate the mailbox file and promote the empty cache under the same\n // lock, with the post-truncate stat captured synchronously so a\n // concurrent reader doesn't misclassify the shrink as a \"file only\n // grew\" append.\n await withFileLock(this.messagePath, async () => {\n await fsp.writeFile(this.messagePath, '', 'utf8');\n const { mtimeMs, size } = await this._statMessageFile();\n this._setMessageCache([], mtimeMs, size);\n });\n }\n\n async purgeStale(opts?: PurgeOptions): Promise<PurgeResult> {\n const COMPLETED_MAX_AGE_MS = opts?.completedMaxAgeMs ?? 86_400_000; // 1 day\n const INCOMPLETE_MAX_AGE_MS = opts?.incompleteMaxAgeMs ?? 604_800_000; // 7 days\n\n let completedPurged = 0;\n let incompletePurged = 0;\n let remaining = 0;\n\n // Read-modify-write under the lock \u2014 same pattern as ack().\n await withFileLock(this.messagePath, async () => {\n const all = await this._readMessagesFresh();\n const now = Date.now();\n const cutoffCompleted = now - COMPLETED_MAX_AGE_MS;\n const cutoffIncomplete = now - INCOMPLETE_MAX_AGE_MS;\n\n const kept: MailboxMessage[] = [];\n\n for (const msg of all) {\n const msgTime = new Date(msg.timestamp).getTime();\n const completedTime = msg.completedAt ? new Date(msg.completedAt).getTime() : 0;\n\n if (msg.completed && completedTime < cutoffCompleted) {\n completedPurged++;\n continue; // drop\n }\n if (!msg.completed && msgTime < cutoffIncomplete) {\n incompletePurged++;\n continue; // drop\n }\n\n kept.push(msg);\n }\n remaining = kept.length;\n\n // Rewrite only if something changed\n if (kept.length < all.length) {\n const content = kept.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;\n await fsp.writeFile(this.messagePath, content, 'utf8');\n }\n // Capture the post-write (or post-read when nothing purged) stat\n // inside the lock so the cache trackers match the on-disk state.\n const { mtimeMs, size } = await this._statMessageFile();\n // Either way we just read fresh under the lock, so adopt the kept\n // snapshot (== all when nothing was purged) as the cache.\n this._setMessageCache(kept, mtimeMs, size);\n });\n\n return {\n completedPurged,\n incompletePurged,\n totalPurged: completedPurged + incompletePurged,\n remaining,\n };\n }\n\n // \u2500\u2500 Auto-compaction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _autoCompactTimer: NodeJS.Timeout | null = null;\n\n async autoCompact(opts?: AutoCompactOptions): Promise<AutoCompactResult> {\n const readMaxAgeMs = opts?.readMaxAgeMs ?? AUTO_COMPACT_READ_MAX_AGE_MS;\n const defaultTtlMs = opts?.defaultTtlMs ?? AUTO_COMPACT_DEFAULT_TTL_MS;\n const completedMaxAgeMs = opts?.completedMaxAgeMs ?? 86_400_000; // 1 day\n const incompleteMaxAgeMs = opts?.incompleteMaxAgeMs ?? 604_800_000; // 7 days\n\n let expiredPurged = 0;\n let readByAllPurged = 0;\n let completedPurged = 0;\n let incompletePurged = 0;\n let remaining = 0;\n\n // Resolve the set of currently-online agent ids so we can check\n // \"has every online agent read this?\" without a second file read.\n // Online set is advisory \u2014 if the registry is temporarily empty we\n // skip the read-by-all pass rather than purging everything.\n let onlineAgentIds: Set<string> | null = null;\n try {\n const statuses = await this.getAgentStatuses();\n const online = statuses.filter((s) => s.online);\n onlineAgentIds = online.length > 0 ? new Set(online.map((s) => s.agentId)) : null;\n } catch {\n onlineAgentIds = null;\n }\n\n await withFileLock(this.messagePath, async () => {\n const all = await this._readMessagesFresh();\n const now = Date.now();\n const cutoffReadAge = now - readMaxAgeMs;\n const cutoffCompleted = now - completedMaxAgeMs;\n const cutoffIncomplete = now - incompleteMaxAgeMs;\n const cutoffDefaultTtl = now - defaultTtlMs;\n\n const kept: MailboxMessage[] = [];\n\n for (const msg of all) {\n const msgTime = new Date(msg.timestamp).getTime();\n\n // Pass 1: Explicit expiry.\n if (msg.expiresAt !== undefined) {\n if (new Date(msg.expiresAt).getTime() < now) {\n expiredPurged++;\n continue;\n }\n } else if (msgTime < cutoffDefaultTtl) {\n // No explicit expiry; use default TTL from send time.\n expiredPurged++;\n continue;\n }\n\n // Pass 2: Read by ALL currently-online agents.\n if (onlineAgentIds !== null && !msg.completed) {\n const readByAll =\n onlineAgentIds.size > 0 && [...onlineAgentIds].every((id) => id in msg.readBy);\n if (readByAll) {\n // Check age of the most recent read receipt.\n const readTimes = Object.values(msg.readBy).map((t) => new Date(t).getTime());\n const latestRead = Math.max(...readTimes);\n if (latestRead < cutoffReadAge) {\n readByAllPurged++;\n continue;\n }\n }\n }\n\n // Pass 3: Standard purge-stale logic.\n const completedTime = msg.completedAt ? new Date(msg.completedAt).getTime() : 0;\n if (msg.completed && completedTime < cutoffCompleted) {\n completedPurged++;\n continue;\n }\n if (!msg.completed && msgTime < cutoffIncomplete) {\n incompletePurged++;\n continue;\n }\n\n kept.push(msg);\n }\n remaining = kept.length;\n\n if (kept.length < all.length) {\n const content = kept.map((m) => JSON.stringify(m)).join(LINE_SEPARATOR) + LINE_SEPARATOR;\n await fsp.writeFile(this.messagePath, content, 'utf8');\n }\n const { mtimeMs, size } = await this._statMessageFile();\n this._setMessageCache(kept, mtimeMs, size);\n });\n\n const totalRemoved = expiredPurged + readByAllPurged + completedPurged + incompletePurged;\n return {\n expiredRemoved: expiredPurged,\n readByAllRemoved: readByAllPurged,\n stalePurged: completedPurged + incompletePurged,\n totalRemoved,\n remaining,\n };\n }\n\n startAutoCompactTimer(opts?: AutoCompactOptions): () => void {\n // Replace any prior timer.\n if (this._autoCompactTimer !== null) {\n clearInterval(this._autoCompactTimer);\n }\n const intervalMs = opts?.intervalMs ?? AUTO_COMPACT_INTERVAL_MS;\n const timer = setInterval(() => {\n this.autoCompact(opts).catch(() => {\n // Best-effort \u2014 background compaction must never crash the process.\n });\n }, intervalMs);\n timer.unref?.();\n this._autoCompactTimer = timer;\n return () => {\n clearInterval(timer);\n this._autoCompactTimer = null;\n };\n }\n\n // \u2500\u2500 Internal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Read all messages from the JSONL file. Always reads + parses the file.\n * Callers that can tolerate a stale-by-mtime view should use\n * {@link _readMessagesCached}; writers that need the post-lock truth\n * should call this directly (it's what {@link _readMessagesFresh} aliases).\n */\n private async _readMessages(): Promise<MailboxMessage[]> {\n try {\n const raw = await fsp.readFile(this.messagePath, 'utf8');\n return this._parseLines(raw);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw err;\n }\n }\n\n /** Parse a JSONL string into MailboxMessage[], applying ack records. */\n private _parseLines(raw: string): MailboxMessage[] {\n const lines = raw.split(LINE_SEPARATOR).filter((l) => l.trim().length > 0);\n const messages: MailboxMessage[] = [];\n const acks: AckRecord[] = [];\n for (const line of lines) {\n const parsed = parseMailboxLine(line);\n if (isAckRecord(parsed)) {\n acks.push(parsed);\n } else if (parsed !== null) {\n messages.push(parsed);\n }\n }\n // Apply ack records to messages (event-sourcing fold).\n for (const ack of acks) {\n const target = messages.find((m) => m.id === ack.messageId);\n if (target) applyAckToMessage(target, ack);\n }\n return messages;\n }\n\n /**\n * Read messages, then adopt the result as the in-memory cache. Use this\n * from writers that just took the file lock \u2014 the read reflects the\n * authoritative post-lock state and should be served to subsequent\n * queries without re-reading.\n *\n * The mtime/size are captured from the stat at read time so the cache\n * trackers match exactly what was parsed. Writers that subsequently\n * rewrite the file MUST re-stat after the write and re-promote with the\n * post-write values (see ackMany / softDelete / restore / purgeStale /\n * clearAll) \u2014 otherwise a concurrent reader misclassifies the rewrite\n * as a \"file only grew\" append and corrupts the cache.\n */\n private async _readMessagesFresh(): Promise<MailboxMessage[]> {\n const all = await this._readMessages();\n const { mtimeMs, size } = await this._statMessageFile();\n this._setMessageCache(all, mtimeMs, size);\n return all;\n }\n\n /**\n * Stat the message file, returning its mtimeMs and size. Returns\n * `-1/-1` when the file does not yet exist (ENOENT) so callers can\n * still promote a cache snapshot \u2014 the next read will re-stat and\n * fall through to a full re-read. Call from inside the file lock so\n * the result reflects the post-write on-disk state, not a later\n * intermediate state from another process.\n */\n private async _statMessageFile(): Promise<{ mtimeMs: number; size: number }> {\n try {\n const st = await fsp.stat(this.messagePath);\n return { mtimeMs: st.mtimeMs, size: st.size };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { mtimeMs: -1, size: -1 };\n }\n throw err;\n }\n }\n\n /**\n * Read messages, consulting the mtime-bounded in-memory cache first,\n * serialized so concurrent callers don't both mutate the cache.\n *\n * The mailbox file is shared across processes; every `send`/`ack`/\n * `clearAll`/`purgeStale` takes the file lock, so writes are serialized\n * and a changed mtimeMs is a definitive freshness signal. When the\n * stat matches the cached mtime+size we return the cached array \u2014 no\n * file read and no JSON.parse \u2014 collapsing the per-iteration query\n * cost on the mailbox-loop hot path.\n *\n * When the file only grew (new messages appended by another process),\n * we read and parse just the tail bytes instead of the entire file.\n * This avoids re-parsing the full 10K-message history on every check.\n *\n * SERIALIZATION: the actual work is chained onto `_readChain` so two\n * overlapping calls can't both pass the `st.size > _messageCacheSize`\n * incremental check against the same stale tracker and each push the\n * same tail bytes onto the cache (duplicating every appended message).\n * Readers don't conflict on file content \u2014 only on the cache mutation\n * that follows the read \u2014 so we run them one at a time in issue order.\n * Errors in the chain are swallowed so a failed read never poisons\n * subsequent reads; each caller observes and re-throws its own error.\n */\n private _readMessagesCached(): Promise<MailboxMessage[]> {\n // Chain this read after the prior one settles. Catch-and-swallow the\n // prior's error so the chain stays alive for this call regardless.\n const run = this._readChain\n .catch(() => undefined as unknown as MailboxMessage[])\n .then(() => this._readMessagesCachedWork());\n this._readChain = run.catch(() => [] as MailboxMessage[]);\n return run;\n }\n\n /**\n * The un-serialized body of {@link _readMessagesCached}. Reads the\n * message file with the mtime-bounded cache + incremental-tail\n * optimization. Must only be called from `_readMessagesCached` so the\n * cache mutations here don't race a sibling read.\n */\n private async _readMessagesCachedWork(): Promise<MailboxMessage[]> {\n try {\n const st = await fsp.stat(this.messagePath);\n\n // Fast path: cache is current \u2014 no disk I/O beyond stat.\n if (\n this._messageCache !== null &&\n this._messageCacheMtime === st.mtimeMs &&\n this._messageCacheSize === st.size\n ) {\n return this._messageCache;\n }\n\n // Full re-read when the cache is stale. With append-only acks, the\n // file grows monotonously (no rewrites except compaction/purge/clear).\n // A simple incremental tail-read optimization could apply here for\n // cross-process scenarios, but the full re-read is correct and in the\n // common case (same-process) the cache stays current via `_pushToCache`\n // and `_applyAckToCache` which update the cache synchronously with\n // every send/ack. The full re-read also correctly handles ack records\n // via _parseLines which folds them into messages.\n\n // Full re-read: cache empty, file was rewritten (ack/purge), or\n // this is the first read.\n const all = await this._readMessages();\n this._setMessageCache(all, st.mtimeMs, st.size);\n return all;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n this._setMessageCache([], -1, -1);\n return [];\n }\n throw err;\n }\n }\n\n /**\n * Replace the in-memory cache, setting the mtime/size trackers\n * synchronously in the same step. Callers MUST pass the stat of the\n * on-disk file state that produced `messages`.\n *\n * Why both are required (not fire-and-forget): `_readMessagesCached()`\n * validates the cache against a fresh stat using these two trackers.\n * If the cache array is updated but the trackers lag behind (e.g. via\n * a deferred `stat().then(...)`), a concurrent reader landing in that\n * window sees a mismatched mtime and falls into the incremental\n * \"file only grew\" branch \u2014 parsing rewritten bytes as an appended\n * tail and corrupting the cache with duplicates/garbage. So both\n * values are captured under the file lock and applied synchronously\n * here, matching the fix already shipped in DefaultMailbox.\n */\n private _setMessageCache(messages: MailboxMessage[], mtime: number, size: number): void {\n // Bound the cache so a runaway mailbox can't balloon memory. The cap\n // is high enough that any realistic project mailbox fits; if it ever\n // exceeds the cap we just refuse to cache and the next read goes to\n // disk (the unoptimized but correct behavior).\n if (messages.length > MESSAGE_CACHE_MAX_ENTRIES) {\n this._messageCache = null;\n this._messageCacheMtime = -1;\n this._messageCacheSize = -1;\n this._recipientIndex = null;\n this._senderIndex = null;\n return;\n }\n this._messageCache = messages;\n this._messageCacheMtime = mtime;\n this._messageCacheSize = size;\n this._rebuildRecipientIndex();\n }\n\n /**\n * Fold a single ack record into the in-memory cache, mutating the target\n * message in place. Called from `ackMany` after appending the record to\n * disk so the cache reflects the ack without a full re-read + re-parse.\n *\n * An ack only touches `readBy`/`completed*`/`outcome` \u2014 none of which\n * affect the recipient/sender indexes \u2014 so no index rebuild is needed.\n * No-op when the cache is empty or the target message isn't cached.\n */\n private _applyAckToCache(ack: AckRecord): void {\n const cache = this._messageCache;\n if (cache === null) return;\n const target = cache.find((m) => m.id === ack.messageId);\n if (target !== undefined) applyAckToMessage(target, ack);\n }\n\n /**\n * Build the recipient AND sender indexes from the current `_messageCache`.\n * Called only from `_setMessageCache` so both indexes are always in sync\n * with a freshly-replaced cache array.\n */\n private _rebuildRecipientIndex(): void {\n const cache = this._messageCache;\n if (cache === null) {\n this._recipientIndex = null;\n this._senderIndex = null;\n return;\n }\n const recIdx = new Map<string, Set<number>>();\n const sndIdx = new Map<string, Set<number>>();\n for (let i = 0; i < cache.length; i++) {\n const msg = cache[i]!;\n let rSet = recIdx.get(msg.to);\n if (rSet === undefined) {\n rSet = new Set();\n recIdx.set(msg.to, rSet);\n }\n rSet.add(i);\n let sSet = sndIdx.get(msg.from);\n if (sSet === undefined) {\n sSet = new Set();\n sndIdx.set(msg.from, sSet);\n }\n sSet.add(i);\n }\n this._recipientIndex = recIdx;\n this._senderIndex = sndIdx;\n }\n\n /**\n * Append a single just-sent message to the in-memory cache without\n * re-reading the file. The caller must hold the file lock (or have\n * just released it after a successful append) and MUST pass the\n * post-append stat so the mtime/size trackers advance in lock-step\n * with the pushed content.\n *\n * Why the stat is required here: without it, `_messageCacheSize`\n * stays at the pre-append value. A concurrent `_readMessagesCached()`\n * then sees `st.size > _messageCacheSize` (the file did grow), takes\n * the incremental branch, and re-reads the just-appended tail \u2014\n * pushing the same message onto the cache a second time. Setting the\n * trackers here closes that window for the local-process append path.\n */\n private _pushToCache(msg: MailboxMessage, mtime: number, size: number): void {\n if (this._messageCache === null) {\n // No cache to extend \u2014 leave trackers at -1 so the next read does\n // a full re-read and rebuilds the cache from disk.\n return;\n }\n if (this._messageCache.length >= MESSAGE_CACHE_MAX_ENTRIES) {\n this._messageCache = null;\n this._messageCacheMtime = -1;\n this._messageCacheSize = -1;\n return;\n }\n // The cache holds shared message objects; we mirror the on-disk line\n // by storing the same reference. Callers of `query()` get defensive\n // copies, so this shared reference is safe.\n this._messageCache.push(msg);\n // Update the recipient index with the new message's position.\n const newIdx = this._messageCache.length - 1;\n if (this._recipientIndex !== null) {\n let set = this._recipientIndex.get(msg.to);\n if (set === undefined) {\n set = new Set();\n this._recipientIndex.set(msg.to, set);\n }\n set.add(newIdx);\n }\n // Update the sender index with the new message's position.\n if (this._senderIndex !== null) {\n let set = this._senderIndex.get(msg.from);\n if (set === undefined) {\n set = new Set();\n this._senderIndex.set(msg.from, set);\n }\n set.add(newIdx);\n }\n // Advance the trackers synchronously with the content push so a\n // concurrent reader does not re-append this same message.\n this._messageCacheMtime = mtime;\n this._messageCacheSize = size;\n }\n\n private async _ensureRegistry(): Promise<void> {\n await fsp.mkdir(path.dirname(this.registryPath), { recursive: true });\n }\n\n /** Minimal shape-check for a deserialized agent registry entry.\n * Logs a warning and returns `false` for structurally invalid data\n * so a single corrupted entry doesn't break the entire registry. */\n private _parseAgentEntry(value: unknown): RegisteredAgent | null {\n if (typeof value !== 'object' || value === null) return null;\n const v = value as Record<string, unknown>;\n // Identity fields are the only hard requirement \u2014 an entry without a usable\n // id/session is genuinely unusable and safe to drop. Everything else is\n // coerced to a safe default rather than rejected: this registry is shared\n // across processes and rewritten wholesale (read \u2192 modify \u2192 write-back), so\n // returning null for a merely UNRECOGNISED entry (e.g. a newer/mixed-version\n // CLI that adds a `status` value we don't know) would permanently ERASE\n // another live process's registration on the next write, not just skip it.\n if (typeof v.agentId !== 'string') return null;\n if (typeof v.sessionId !== 'string') return null;\n const statuses = ['idle', 'busy', 'running', 'streaming', 'waiting_user', 'error'] as const;\n const status =\n typeof v.status === 'string' && (statuses as readonly string[]).includes(v.status)\n ? v.status\n : 'idle';\n return {\n ...v,\n agentId: v.agentId,\n sessionId: v.sessionId,\n name: typeof v.name === 'string' ? v.name : v.agentId,\n registeredAt: typeof v.registeredAt === 'string' ? v.registeredAt : new Date(0).toISOString(),\n lastSeenAt: typeof v.lastSeenAt === 'string' ? v.lastSeenAt : new Date(0).toISOString(),\n iterations: typeof v.iterations === 'number' && Number.isFinite(v.iterations) ? v.iterations : 0,\n toolCalls: typeof v.toolCalls === 'number' && Number.isFinite(v.toolCalls) ? v.toolCalls : 0,\n pid: typeof v.pid === 'number' && Number.isFinite(v.pid) ? v.pid : 0,\n status,\n } as unknown as RegisteredAgent;\n }\n\n /** Minimal shape-check for a deserialized client registry entry. */\n private _parseClientEntry(value: unknown): RegisteredClient | null {\n if (typeof value !== 'object' || value === null) return null;\n const v = value as Record<string, unknown>;\n // See _parseAgentEntry: only identity is a hard requirement. Coerce the rest\n // so an unrecognised entry from another/newer process survives a shared\n // read-modify-write instead of being permanently evicted.\n if (typeof v.clientId !== 'string') return null;\n if (typeof v.sessionId !== 'string') return null;\n const sources = ['repl', 'tui', 'webui', 'http'] as const;\n const source =\n typeof v.source === 'string' && (sources as readonly string[]).includes(v.source)\n ? v.source\n : 'http';\n return {\n ...v,\n clientId: v.clientId,\n sessionId: v.sessionId,\n name: typeof v.name === 'string' ? v.name : v.clientId,\n registeredAt: typeof v.registeredAt === 'string' ? v.registeredAt : new Date(0).toISOString(),\n lastSeenAt: typeof v.lastSeenAt === 'string' ? v.lastSeenAt : new Date(0).toISOString(),\n pid: typeof v.pid === 'number' && Number.isFinite(v.pid) ? v.pid : 0,\n source,\n } as unknown as RegisteredClient;\n }\n\n private async _readRegistry(opts?: { fresh?: boolean }): Promise<Map<string, RegisteredAgent>> {\n // The registry file is shared across processes. Reads may use a short\n // TTL cache; writers (under the file lock) MUST pass { fresh: true } \u2014\n // a read-modify-write from a stale cache would silently erase agents\n // registered by other sessions.\n if (\n !opts?.fresh &&\n this._registryCache &&\n Date.now() - this._registryCacheAt < REGISTRY_CACHE_TTL_MS\n ) {\n return new Map(this._registryCache);\n }\n\n try {\n const raw = await fsp.readFile(this.registryPath, 'utf8');\n const data = JSON.parse(raw) as Record<string, unknown>;\n const map = new Map<string, RegisteredAgent>();\n for (const [id, agent] of Object.entries(data)) {\n const parsed = this._parseAgentEntry(agent);\n if (parsed) {\n map.set(id, parsed);\n } else {\n console.warn(JSON.stringify({ level: 'warn', event: 'mailbox.registry.invalid_agent', message: `Skipping malformed agent entry \"${id}\" in registry`, timestamp: new Date().toISOString() }));\n }\n }\n this._registryCache = map;\n this._registryCacheAt = Date.now();\n return new Map(map);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const empty = new Map<string, RegisteredAgent>();\n this._registryCache = empty;\n this._registryCacheAt = Date.now();\n return empty;\n }\n throw err;\n }\n }\n\n private _pruneStaleInPlace(registry: Map<string, RegisteredAgent>): void {\n const cutoff = Date.now() - AGENT_STALE_MS;\n for (const [id, agent] of registry) {\n const lastSeen = Date.parse(agent.lastSeenAt);\n // Missing/invalid heartbeat timestamps cannot establish liveness. Remove\n // them alongside expired entries instead of making malformed ghosts\n // immortal through NaN comparisons.\n if (!Number.isFinite(lastSeen) || lastSeen < cutoff) {\n registry.delete(id);\n }\n }\n }\n\n private async _writeRegistry(registry: Map<string, RegisteredAgent>): Promise<void> {\n const obj: Record<string, RegisteredAgent> = {};\n for (const [id, agent] of registry) {\n obj[id] = agent;\n }\n const tmp = `${this.registryPath}.${randomUUID().slice(0, 8)}.tmp`;\n await fsp.writeFile(tmp, JSON.stringify(obj), 'utf8');\n await fsp.rename(tmp, this.registryPath);\n }\n\n // \u2500\u2500 Client registry internals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async _ensureClientRegistry(): Promise<void> {\n await fsp.mkdir(path.dirname(this.clientRegistryPath), { recursive: true });\n }\n\n private async _readClientRegistry(opts?: {\n fresh?: boolean;\n }): Promise<Map<string, RegisteredClient>> {\n if (\n !opts?.fresh &&\n this._clientRegistryCache &&\n Date.now() - this._clientRegistryCacheAt < REGISTRY_CACHE_TTL_MS\n ) {\n return new Map(this._clientRegistryCache);\n }\n\n try {\n const raw = await fsp.readFile(this.clientRegistryPath, 'utf8');\n const data = JSON.parse(raw) as Record<string, unknown>;\n const map = new Map<string, RegisteredClient>();\n for (const [id, client] of Object.entries(data)) {\n const parsed = this._parseClientEntry(client);\n if (parsed) {\n map.set(id, parsed);\n } else {\n console.warn(JSON.stringify({ level: 'warn', event: 'mailbox.registry.invalid_client', message: `Skipping malformed client entry \"${id}\" in client registry`, timestamp: new Date().toISOString() }));\n }\n }\n this._clientRegistryCache = map;\n this._clientRegistryCacheAt = Date.now();\n return new Map(map);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const empty = new Map<string, RegisteredClient>();\n this._clientRegistryCache = empty;\n this._clientRegistryCacheAt = Date.now();\n return empty;\n }\n throw err;\n }\n }\n\n private _pruneStaleClientsInPlace(registry: Map<string, RegisteredClient>): void {\n const cutoff = Date.now() - CLIENT_STALE_MS;\n for (const [id, client] of registry) {\n const lastSeen = Date.parse(client.lastSeenAt);\n if (!Number.isFinite(lastSeen) || lastSeen < cutoff) {\n registry.delete(id);\n }\n }\n }\n\n private async _writeClientRegistry(registry: Map<string, RegisteredClient>): Promise<void> {\n const obj: Record<string, RegisteredClient> = {};\n for (const [id, client] of registry) {\n obj[id] = client;\n }\n const tmp = `${this.clientRegistryPath}.${randomUUID().slice(0, 8)}.tmp`;\n await fsp.writeFile(tmp, JSON.stringify(obj), 'utf8');\n await fsp.rename(tmp, this.clientRegistryPath);\n }\n}\n", "import { randomBytes } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport { watch as watchDir } from 'node:fs';\nimport type { FSWatcher } from 'node:fs';\nimport * as path from 'node:path';\nimport { FsError } from '../types/errors.js';\n\nexport interface AtomicWriteOptions {\n mode?: number | undefined;\n encoding?: BufferEncoding | undefined;\n}\n\nexport interface FileLockOptions {\n timeoutMs?: number | undefined;\n staleMs?: number | undefined;\n}\n\nexport async function atomicWrite(\n targetPath: string,\n content: string | Uint8Array,\n opts: AtomicWriteOptions = {},\n): Promise<void> {\n const dir = path.dirname(targetPath);\n await fs.mkdir(dir, { recursive: true });\n const tmp = path.join(dir, `.${path.basename(targetPath)}.${randomBytes(6).toString('hex')}.tmp`);\n\n // Write content to tmp first; 'wx' ensures exclusive creation (fails if\n // tmp already exists \u2014 extremely unlikely with 6-byte random suffix).\n try {\n if (typeof content === 'string') {\n await fs.writeFile(tmp, content, { flag: 'wx', encoding: opts.encoding ?? 'utf8' });\n } else {\n await fs.writeFile(tmp, content, { flag: 'wx' });\n }\n try {\n const fh = await fs.open(tmp, 'r+');\n try {\n await fh.sync();\n } finally {\n await fh.close();\n }\n } catch {\n // fsync best-effort\n }\n // Now safely read mode from target (if it exists) and apply to tmp before rename.\n // Prefer opts.mode for new files; for existing files preserve their mode.\n let mode: number | undefined;\n try {\n const stat = await fs.stat(targetPath);\n mode = stat.mode & 0o777;\n } catch {\n mode = opts.mode;\n }\n if (mode !== undefined) {\n await fs.chmod(tmp, mode);\n }\n await renameWithRetry(tmp, targetPath);\n // P3 #20 (before-release.md): on Windows, fs.rename (MoveFileExW) does\n // not preserve Unix permission bits \u2014 the chmod above applies to the tmp\n // file, but the rename may reset the destination's mode to the Windows\n // default. Re-apply the mode after rename on win32 so an edited file\n // keeps its executable bit (or any non-default permission). On POSIX,\n // rename preserves metadata so this is a no-op (chmod is idempotent and\n // cheap), but we gate it on win32 to avoid the extra stat+chmod on the\n // common path.\n if (mode !== undefined && process.platform === 'win32') {\n try {\n await fs.chmod(targetPath, mode);\n } catch {\n // Best-effort: a transient EPERM (antivirus lock) should not fail\n // the write \u2014 the content is already on disk.\n }\n }\n } catch (err) {\n try {\n await fs.unlink(tmp);\n } catch {\n // ignore cleanup error\n }\n throw err;\n }\n}\n\nexport async function ensureDir(dir: string): Promise<void> {\n await fs.mkdir(dir, { recursive: true });\n}\n\nexport async function withFileLock<T>(\n targetPath: string,\n fn: () => Promise<T>,\n opts: FileLockOptions = {},\n): Promise<T> {\n const dir = path.dirname(targetPath);\n await fs.mkdir(dir, { recursive: true });\n const lockPath = path.join(dir, `.${path.basename(targetPath)}.lock`);\n // A lock holder can be scheduled out for several seconds when the full test\n // suite (or a busy workstation) is spawning many child processes. Five\n // seconds was short enough to turn ordinary contention into a dropped\n // best-effort index write. Keep the wait bounded, but leave enough headroom\n // for the holder to resume and release before stale-lock recovery applies.\n const timeoutMs = opts.timeoutMs ?? 15_000;\n const staleMs = opts.staleMs ?? 30_000;\n const started = Date.now();\n let handle: fs.FileHandle | undefined;\n\n for (;;) {\n try {\n handle = await fs.open(lockPath, 'wx');\n await handle.writeFile(`${process.pid}:${Date.now()}`);\n break;\n } catch (err) {\n // If fs.open succeeded but handle.writeFile threw (e.g. ENOSPC, EIO),\n // `handle` owns an open exclusive lock file. Close the handle and remove\n // the orphan lock so the next iteration (or a peer) can acquire it\n // without timing out on the stale-lock window or dead-looping on EEXIST.\n if (handle) {\n await handle.close().catch(() => {});\n await fs.unlink(lockPath).catch(() => {});\n handle = undefined;\n }\n const code = (err as NodeJS.ErrnoException).code;\n // ENOENT means the directory was deleted (e.g. by concurrent cleanup).\n // Recreate it and retry acquiring the lock.\n if (code === 'ENOENT') {\n await fs.mkdir(dir, { recursive: true });\n continue;\n }\n if (code !== 'EEXIST' && code !== 'EPERM') throw err;\n try {\n const stat = await fs.stat(lockPath);\n if (Date.now() - stat.mtimeMs > staleMs) {\n await fs.unlink(lockPath);\n continue;\n }\n } catch {\n continue;\n }\n const elapsed = Date.now() - started;\n if (elapsed >= timeoutMs) {\n throw new FsError({\n message: `Timed out waiting for file lock: ${targetPath}`,\n code: 'FS_ATOMIC_WRITE_FAILED',\n path: targetPath,\n context: { timeoutMs },\n });\n }\n // Wait for the lock to be released, using a filesystem watcher for\n // nearly-instant wake-up instead of polling. The watcher is best-effort:\n // a safety timeout fires at most every 100ms so we don't busy-wait.\n await waitForLockRelease(lockPath, timeoutMs - elapsed);\n }\n }\n\n try {\n return await fn();\n } finally {\n try {\n await handle?.close();\n } catch {\n // ignore\n }\n try {\n await fs.unlink(lockPath);\n } catch {\n // ignore\n }\n }\n}\n\n/**\n * Watch a lock file's parent directory for the file being removed (unlinked),\n * which signals that the lock holder has released it. A safety timeout caps\n * the wait so the overall `withFileLock` timeout is always respected.\n *\n * Uses a bounded safety interval (up to 100ms) so even if `fs.watch` is\n * unavailable or misses the event, we never busy-wait at 25ms fixed polling.\n */\nasync function waitForLockRelease(lockPath: string, remainingMs: number): Promise<void> {\n const parentDir = path.dirname(lockPath);\n const lockName = path.basename(lockPath);\n const intervalMs = Math.min(remainingMs, 100);\n\n return new Promise<void>((resolve) => {\n let settled = false;\n let watcher: FSWatcher | null = null;\n\n // Safety timer \u2014 always fires, even if fs.watch is unavailable.\n const timer = setTimeout(() => {\n settled = true;\n watcher?.close();\n resolve();\n }, intervalMs);\n\n try {\n watcher = watchDir(parentDir, (eventType, filename) => {\n if (settled) return;\n // 'rename' fires on unlink on most platforms; 'change' is a\n // conservative fallback for environments that only emit 'change'.\n if (filename === lockName && (eventType === 'rename' || eventType === 'change')) {\n settled = true;\n clearTimeout(timer);\n watcher?.close();\n resolve();\n }\n });\n } catch {\n // fs.watch not supported (e.g. some container environments, network\n // filesystems). Clear the safety timer and fall back to a single\n // short delay \u2014 the caller's loop will retry on the next iteration.\n clearTimeout(timer);\n if (!settled) {\n settled = true;\n setTimeout(resolve, Math.min(remainingMs, 25));\n }\n return;\n }\n\n // Re-check lock existence after setting up the watch to close the race\n // where the lock was released between our last EEXIST check and now.\n fs.access(lockPath).then(\n () => {\n // Lock still exists \u2014 the watch (or safety timer) will resolve.\n },\n () => {\n // Lock was already released \u2014 respond immediately.\n if (!settled) {\n settled = true;\n clearTimeout(timer);\n watcher?.close();\n resolve();\n }\n },\n );\n });\n}\n\n// On Windows, fs.rename over an existing file can fail with EPERM/EBUSY/EACCES\n// when antivirus, file indexers, editor file watchers, or a concurrent writer\n// briefly hold a handle on the destination. These are transient \u2014 retry with a\n// short backoff before giving up. POSIX renames are atomic and won't hit this.\nconst TRANSIENT_RENAME_CODES = new Set(['EPERM', 'EBUSY', 'EACCES', 'ENOTEMPTY']);\n\nasync function renameWithRetry(from: string, to: string): Promise<void> {\n if (process.platform !== 'win32') {\n await fs.rename(from, to);\n return;\n }\n const delays = [10, 25, 60, 120, 250];\n let lastErr: unknown;\n for (let i = 0; i <= delays.length; i++) {\n try {\n await fs.rename(from, to);\n return;\n } catch (err) {\n lastErr = err;\n const code = (err as NodeJS.ErrnoException)?.code;\n if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {\n throw err;\n }\n await new Promise((resolve) => setTimeout(resolve, delays[i]));\n }\n }\n throw lastErr;\n}\n", "import * as path from 'node:path';\nimport { ERROR_CODES, FsError } from '../types/errors.js';\n\n/**\n * Resolve `<dir>/<sessionId><suffix>` for per-session sidecar files\n * (annotations, audit chain, replay log, the session JSONL itself).\n *\n * Modern session ids are date-sharded (\"2026-06-11/sess_<ULID>\"),\n * so a forward slash is a legitimate shard separator \u2014 NOT traversal.\n * Escape attempts are blocked two ways: an explicit ban on `..` and\n * backslashes, plus a resolved-path containment check that rejects any\n * id whose resolved target leaves `dir`. Character bans alone are how\n * several stores ended up throwing on every modern session id.\n */\nexport function sessionScopedPath(dir: string, sessionId: string, suffix: string): string {\n if (!sessionId || sessionId.includes('\\\\') || sessionId.includes('..')) {\n throw invalid(sessionId);\n }\n const resolved = path.resolve(dir, `${sessionId}${suffix}`);\n const rel = path.relative(path.resolve(dir), resolved);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw invalid(sessionId);\n }\n return resolved;\n}\n\nfunction invalid(sessionId: string): FsError {\n return new FsError({\n message: `Invalid sessionId: ${sessionId}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: sessionId,\n context: { reason: 'path_traversal' },\n });\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\n/**\n * Path layout. All developer-level state lives in ~/.wrongstack/.\n * Per-project state is keyed by the canonical project root under\n * ~/.wrongstack/projects/<slug>/. Linked Git worktrees resolve to their main\n * checkout so coordination and durable state are shared across worktrees.\n *\n * The ONLY thing inside the project tree is the optional\n * .wrongstack/AGENTS.md (committed) and .wrongstack/skills/ (committed).\n */\n\nexport interface WstackPaths {\n /** ~/.wrongstack \u2014 global root. */\n globalRoot: string;\n /** Absolute project root. */\n projectRoot: string;\n /** Home directory (~) \u2014 base for foreign tool state (~/.codex, ~/.agents, \u2026). */\n homeDir: string;\n /**\n * ~/.wrongstack \u2014 directory for user-global stateful config files\n * (mode.json, theme.json, \u2026). Currently an alias for `globalRoot`;\n * separate name lets us split out per-OS XDG_CONFIG_HOME later\n * without rewriting callers.\n */\n configDir: string;\n /** ~/.wrongstack/config.json \u2014 bootstrap config (activeProfile + version). */\n globalConfig: string;\n /**\n * ~/.wrongstack/profiles \u2014 directory containing per-profile configs.\n * Each profile has its own subdirectory with a config.json.\n */\n profilesDir: string;\n /**\n * Resolve the config path for a named profile.\n * Returns ~/.wrongstack/profiles/<name>/config.json.\n */\n profileConfig: (name: string) => string;\n /** ~/.wrongstack/.key \u2014 32 random bytes, mode 0600, AES-GCM key for the secret vault. */\n secretsKey: string;\n /** ~/.wrongstack/memory.md \u2014 user-global memory. */\n globalMemory: string;\n /** ~/.wrongstack/skills \u2014 user-global skills. */\n globalSkills: string;\n /** ~/.claude/skills \u2014 user-global skills from foreign coding agents (Claude Code, Codex, \u2026). Read-only. */\n globalClaudeSkills: string;\n /** ~/.wrongstack/design-kits \u2014 user-global Design Studio kits. */\n globalDesignKits: string;\n /** ~/.wrongstack/prompts \u2014 user-global prompt library. */\n globalPrompts: string;\n /** ~/.wrongstack/instructions \u2014 user-global system instruction overrides. */\n globalInstructions: string;\n /** ~/.wrongstack/prompt-usage.json \u2014 per-slug insert counts (recent/popular). */\n promptUsage: string;\n /** ~/.wrongstack/cache \u2014 fetched data (models.dev, etc.). */\n cacheDir: string;\n /** ~/.wrongstack/cache/models.dev.json */\n modelsCache: string;\n /** ~/.wrongstack/cache/models-overlay.json \u2014 cached curated overlay. */\n modelsOverlayCache: string;\n /**\n * Per-project codebase symbol index (SQLite). Lives under the global project\n * dir \u2014 NOT inside the repo \u2014 so it never clutters the working tree or needs\n * gitignoring. `~/.wrongstack/projects/<hash>/codebase-index`.\n */\n projectCodebaseIndex: string;\n /** ~/.wrongstack/history \u2014 REPL line history. */\n historyFile: string;\n /** ~/.wrongstack/logs/wrongstack.log */\n logFile: string;\n /** ~/.wrongstack/projects/<hash> */\n projectDir: string;\n /** ~/.wrongstack/projects/<hash>/memory.md */\n projectMemory: string;\n /** ~/.wrongstack/projects/<hash>/sessions */\n projectSessions: string;\n /** ~/.wrongstack/projects/<hash>/trust.json */\n projectTrust: string;\n /** ~/.wrongstack/projects/<hash>/meta.json */\n projectMeta: string;\n /** ~/.wrongstack/projects/<hash>/config.local.json \u2014 optional override */\n projectLocalConfig: string;\n /** <project>/.wrongstack/config.json \u2014 per-project settings (safe fields only).\n * This lives inside the project root so it can be gitignored or shared. */\n inProjectConfig: string;\n /** <project>/.wrongstack/AGENTS.md \u2014 committed project memory. */\n inProjectAgentsFile: string;\n /** <project>/.wrongstack/skills \u2014 committed project skills. */\n inProjectSkills: string;\n /** <project>/.claude/skills \u2014 project skills authored for foreign coding agents (Claude Code, \u2026). Read-only. */\n inProjectClaudeSkills: string;\n /** <project>/.wrongstack/prompts \u2014 committed project prompt library. */\n inProjectPrompts: string;\n /** <project>/.wrongstack/instructions \u2014 committed project instruction overrides. */\n inProjectInstructions: string;\n /** <project>/.wrongstack/design-kits \u2014 committed project Design Studio kits. */\n inProjectDesignKits: string;\n /** <project>/.wrongstack/worktrees \u2014 git worktrees for per-phase isolation (gitignored). */\n inProjectWorktrees: string;\n /** Stable hash for the canonical project root (shared by linked Git worktrees). */\n projectHash: string;\n /** Human-readable canonical project slug, shared by linked Git worktrees. */\n projectSlug: string;\n /** ~/.wrongstack/projects/<hash>/goal.json \u2014 goal persistence */\n projectGoal: string;\n /** ~/.wrongstack/projects/<hash>/input-history.json \u2014 TUI prompt input history */\n projectInputHistory: string;\n /** ~/.wrongstack/projects/<hash>/specs \u2014 SDD spec files */\n projectSpecs: string;\n /** ~/.wrongstack/projects/<hash>/task-graphs \u2014 SDD task graphs */\n projectTaskGraphs: string;\n /** ~/.wrongstack/projects/<hash>/sdd-session.json \u2014 SDD session state */\n projectSddSession: string;\n /** ~/.wrongstack/projects/<hash>/plan.json \u2014 plan persistence */\n projectPlan: string;\n /** ~/.wrongstack/projects/<hash>/autophase \u2014 Goal phase-graph JSON files (dir name kept for backward compat) */\n projectAutophase: string;\n /** ~/.wrongstack/projects/<hash>/sdd-boards \u2014 live SDD board snapshots + JSONL event logs */\n projectSddBoards: string;\n /** ~/.wrongstack/sync.json \u2014 CloudSync configuration */\n syncConfig: string;\n /** Function to get the status.json path for a project given its hash. */\n projectStatus: (projectHash: string) => string;\n}\n\n/**\n * Resolve the stable project identity root used by global WrongStack state.\n *\n * A linked Git worktree has its own checkout path and a `.git` *file* that\n * points into `<main>/.git/worktrees/<name>`. Its `commondir` points back to\n * the main checkout's `.git` directory. Treating the linked checkout path as\n * the project identity would split one repository into multiple session,\n * registry, and mailbox directories \u2014 agents in different worktrees would be\n * unable to see or message each other.\n *\n * Project-local paths still use the caller's actual checkout. Only global\n * state identity is canonicalized. Non-Git projects, normal checkouts, Git\n * submodules, and separate-git-dir layouts keep their existing identity.\n */\nexport function canonicalProjectRoot(absRoot: string): string {\n const checkoutRoot = path.resolve(absRoot);\n const dotGit = path.join(checkoutRoot, '.git');\n\n try {\n if (!fs.statSync(dotGit).isFile()) return checkoutRoot;\n\n const gitDirLine = fs.readFileSync(dotGit, 'utf8').trim();\n const match = /^gitdir:\\s*(.+)$/i.exec(gitDirLine);\n if (!match?.[1]) return checkoutRoot;\n\n const gitDir = path.resolve(checkoutRoot, match[1].trim());\n const commonDirFile = path.join(gitDir, 'commondir');\n if (!fs.statSync(commonDirFile).isFile()) return checkoutRoot;\n\n const commonDir = path.resolve(gitDir, fs.readFileSync(commonDirFile, 'utf8').trim());\n // Linked worktrees created by Git share the main checkout's `.git` dir.\n // A submodule or --separate-git-dir layout may point elsewhere; do not\n // guess a working-tree root for those shapes.\n if (path.basename(commonDir).toLowerCase() !== '.git') return checkoutRoot;\n return path.dirname(commonDir);\n } catch {\n // Missing/malformed administrative files must never make path resolution\n // fail. Falling back preserves the pre-canonicalization behavior.\n return checkoutRoot;\n }\n}\n\nexport function projectHash(absRoot: string): string {\n return createHash('sha256').update(canonicalProjectRoot(absRoot)).digest('hex').slice(0, 12);\n}\n\n/**\n * Human-readable project directory name: slugified folder name + short hash\n * suffix for uniqueness. e.g. `wrongstack-a1b2c3` instead of `3024e5e6fa58`.\n */\nexport function projectSlug(absRoot: string): string {\n const identityRoot = canonicalProjectRoot(absRoot);\n const base = slugify(path.basename(identityRoot));\n const hash = createHash('sha256').update(identityRoot).digest('hex').slice(0, 6);\n return `${base}-${hash}`;\n}\n\n/** Turn a folder name into a filesystem-safe lowercase slug. */\nfunction slugify(name: string): string {\n return (\n name\n .toLowerCase()\n // Collapse any run of non-alphanumeric chars into a single hyphen.\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40) || 'project'\n );\n}\n\nexport interface WstackPathOptions {\n userHome?: string | undefined;\n projectRoot: string;\n /** Override the global root (e.g. for tests). Default: `${userHome}/.wrongstack`. */\n globalRoot?: string | undefined;\n}\n\n/**\n * The global `~/.wrongstack` root, honoring the `WRONGSTACK_HOME` env\n * override. The override exists so tests (and sandboxed runs) can redirect\n * ALL global state \u2014 config, secrets, logs, projects/, mailboxes \u2014 away from\n * the real user home. Before it existed, `pnpm test` booted runtimes against\n * the real `~/.wrongstack`: it read the user's real config.json (starting a\n * second live Telegram poller), appended to the real wrongstack.log, and left\n * ~20k orphaned fixture dirs under projects/.\n *\n * Every code path that wants the global dir must come through here (or\n * through `resolveWstackPaths`) instead of `path.join(os.homedir(), '.wrongstack')`.\n */\nexport function wstackGlobalRoot(): string {\n const fromEnv = process.env['WRONGSTACK_HOME'];\n if (fromEnv && fromEnv.trim().length > 0) return path.resolve(fromEnv);\n return path.join(os.homedir(), '.wrongstack');\n}\n\nexport function resolveWstackPaths(opts: WstackPathOptions): WstackPaths {\n // Precedence: explicit globalRoot > explicit userHome (callers/tests that\n // pass one expect paths under it) > WRONGSTACK_HOME env > real home dir.\n const globalRoot =\n opts.globalRoot ?? (opts.userHome ? path.join(opts.userHome, '.wrongstack') : wstackGlobalRoot());\n // Home dir for FOREIGN tool state (Claude Code's ~/.claude). Independent of\n // WRONGSTACK_HOME, which redirects only WrongStack state: a real user's\n // Claude skills live in their real home, but tests pass `userHome` to keep\n // both `.wrongstack` and `.claude` under a temp dir.\n const homeDir = opts.userHome ?? os.homedir();\n const hash = projectHash(opts.projectRoot);\n const slug = projectSlug(opts.projectRoot);\n const projectDir = path.join(globalRoot, 'projects', slug);\n return {\n globalRoot,\n projectRoot: opts.projectRoot,\n homeDir,\n configDir: globalRoot,\n globalConfig: path.join(globalRoot, 'config.json'),\n profilesDir: path.join(globalRoot, 'profiles'),\n profileConfig: (name: string) => {\n // Prevent path traversal: only allow a single safe path segment.\n const safe = name.replace(/[/\\\\:]/g, '_').replace(/\\.\\./g, '_');\n return path.join(globalRoot, 'profiles', safe || 'default', 'config.json');\n },\n secretsKey: path.join(globalRoot, '.key'),\n globalMemory: path.join(globalRoot, 'memory.md'),\n globalSkills: path.join(globalRoot, 'skills'),\n globalClaudeSkills: path.join(homeDir, '.claude', 'skills'),\n globalDesignKits: path.join(globalRoot, 'design-kits'),\n globalPrompts: path.join(globalRoot, 'prompts'),\n globalInstructions: path.join(globalRoot, 'instructions'),\n promptUsage: path.join(globalRoot, 'prompt-usage.json'),\n cacheDir: path.join(globalRoot, 'cache'),\n modelsCache: path.join(globalRoot, 'cache', 'models.dev.json'),\n modelsOverlayCache: path.join(globalRoot, 'cache', 'models-overlay.json'),\n historyFile: path.join(globalRoot, 'history'),\n logFile: path.join(globalRoot, 'logs', 'wrongstack.log'),\n projectDir,\n projectCodebaseIndex: path.join(projectDir, 'codebase-index'),\n projectMemory: path.join(projectDir, 'memory.md'),\n projectSessions: path.join(projectDir, 'sessions'),\n projectTrust: path.join(projectDir, 'trust.json'),\n projectMeta: path.join(projectDir, 'meta.json'),\n projectLocalConfig: path.join(projectDir, 'config.local.json'),\n inProjectConfig: path.join(opts.projectRoot, '.wrongstack', 'config.json'),\n inProjectAgentsFile: path.join(opts.projectRoot, '.wrongstack', 'AGENTS.md'),\n inProjectSkills: path.join(opts.projectRoot, '.wrongstack', 'skills'),\n inProjectClaudeSkills: path.join(opts.projectRoot, '.claude', 'skills'),\n inProjectPrompts: path.join(opts.projectRoot, '.wrongstack', 'prompts'),\n inProjectInstructions: path.join(opts.projectRoot, '.wrongstack', 'instructions'),\n inProjectDesignKits: path.join(opts.projectRoot, '.wrongstack', 'design-kits'),\n inProjectWorktrees: path.join(opts.projectRoot, '.wrongstack', 'worktrees'),\n projectHash: hash,\n projectSlug: slug,\n projectGoal: path.join(projectDir, 'goal.json'),\n projectInputHistory: path.join(projectDir, 'input-history.json'),\n projectSpecs: path.join(projectDir, 'specs'),\n projectTaskGraphs: path.join(projectDir, 'task-graphs'),\n projectSddSession: path.join(projectDir, 'sdd-session.json'),\n projectPlan: path.join(projectDir, 'plan.json'),\n projectAutophase: path.join(projectDir, 'autophase'),\n projectSddBoards: path.join(projectDir, 'sdd-boards'),\n syncConfig: path.join(globalRoot, 'sync.json'),\n projectStatus: (projectHash: string) => path.join(globalRoot, 'projects', projectHash, 'status.json'),\n };\n}\n", "import { toErrorMessage } from '../utils/index.js';\n\n/**\n * WrongStack error hierarchy.\n *\n * Every error thrown by the framework is a `WrongStackError` with a\n * machine-readable `code`, a `subsystem` tag, and a `severity` level.\n * This lets consumers (CLI, TUI, plugins, tests) branch on structured\n * data instead of parsing error messages.\n */\n\n// \u2500\u2500 Error codes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Machine-readable error codes as frozen constants.\n *\n * Use `ERROR_CODES.X` instead of raw string literals for:\n * - IDE autocomplete and compile-time validation\n * - Safe refactoring (rename updates all usages)\n * - Plugin extensibility (extend the object to add custom codes)\n *\n * The `ErrorCode` type is derived from this object, so adding a new\n * code here automatically updates the type without extra changes.\n */\nexport const ERROR_CODES = {\n // Provider\n PROVIDER_RATE_LIMITED: 'PROVIDER_RATE_LIMITED',\n PROVIDER_AUTH_FAILED: 'PROVIDER_AUTH_FAILED',\n PROVIDER_OVERLOADED: 'PROVIDER_OVERLOADED',\n PROVIDER_INVALID_REQUEST: 'PROVIDER_INVALID_REQUEST',\n PROVIDER_SERVER_ERROR: 'PROVIDER_SERVER_ERROR',\n PROVIDER_NETWORK_ERROR: 'PROVIDER_NETWORK_ERROR',\n PROVIDER_CONTEXT_OVERFLOW: 'PROVIDER_CONTEXT_OVERFLOW',\n // Tool\n TOOL_NOT_FOUND: 'TOOL_NOT_FOUND',\n TOOL_PERMISSION_DENIED: 'TOOL_PERMISSION_DENIED',\n TOOL_EXECUTION_FAILED: 'TOOL_EXECUTION_FAILED',\n TOOL_TIMEOUT: 'TOOL_TIMEOUT',\n TOOL_INPUT_INVALID: 'TOOL_INPUT_INVALID',\n // Config\n CONFIG_INVALID: 'CONFIG_INVALID',\n CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',\n CONFIG_PARSE_FAILED: 'CONFIG_PARSE_FAILED',\n CONFIG_MIGRATION_NEEDED: 'CONFIG_MIGRATION_NEEDED',\n // Plugin\n PLUGIN_LOAD_FAILED: 'PLUGIN_LOAD_FAILED',\n PLUGIN_API_MISMATCH: 'PLUGIN_API_MISMATCH',\n PLUGIN_MISSING_DEPENDENCY: 'PLUGIN_MISSING_DEPENDENCY',\n // Agent\n AGENT_ITERATION_LIMIT: 'AGENT_ITERATION_LIMIT',\n AGENT_CONTEXT_OVERFLOW: 'AGENT_CONTEXT_OVERFLOW',\n AGENT_ABORTED: 'AGENT_ABORTED',\n AGENT_RUN_FAILED: 'AGENT_RUN_FAILED',\n // Session\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\n SESSION_CORRUPTED: 'SESSION_CORRUPTED',\n SESSION_WRITE_FAILED: 'SESSION_WRITE_FAILED',\n // Container / Registry\n CONTAINER_TOKEN_ALREADY_BOUND: 'CONTAINER_TOKEN_ALREADY_BOUND',\n CONTAINER_TOKEN_NOT_BOUND: 'CONTAINER_TOKEN_NOT_BOUND',\n CONTAINER_CIRCULAR_DEPENDENCY: 'CONTAINER_CIRCULAR_DEPENDENCY',\n REGISTRY_DUPLICATE: 'REGISTRY_DUPLICATE',\n REGISTRY_NOT_FOUND: 'REGISTRY_NOT_FOUND',\n REGISTRY_INVALID: 'REGISTRY_INVALID',\n // File system\n FS_READ_FAILED: 'FS_READ_FAILED',\n FS_WRITE_FAILED: 'FS_WRITE_FAILED',\n FS_MKDIR_FAILED: 'FS_MKDIR_FAILED',\n FS_DELETE_FAILED: 'FS_DELETE_FAILED',\n FS_ATOMIC_WRITE_FAILED: 'FS_ATOMIC_WRITE_FAILED',\n // SDD (Spec-Driven Development)\n SDD_VALIDATION_FAILED: 'SDD_VALIDATION_FAILED',\n SDD_PARSE_FAILED: 'SDD_PARSE_FAILED',\n SDD_INVALID_STATE: 'SDD_INVALID_STATE',\n SDD_NOT_READY: 'SDD_NOT_READY',\n // General\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n PARSE_FAILED: 'PARSE_FAILED',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\n/**\n * Union type derived from `ERROR_CODES`. Using `typeof ERROR_CODES[keyof typeof ERROR_CODES]`\n * instead of a string literal union means TypeScript auto-updates the type whenever\n * a new code is added to `ERROR_CODES` \u2014 no need to keep two lists in sync.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];\n\nexport type ErrorSubsystem =\n | 'provider'\n | 'tool'\n | 'config'\n | 'plugin'\n | 'agent'\n | 'session'\n | 'sdd'\n | 'container'\n | 'fs'\n | 'general';\nexport type ErrorSeverity = 'fatal' | 'error' | 'warning';\n\n// \u2500\u2500 Base error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class WrongStackError extends Error {\n readonly code: ErrorCode;\n readonly subsystem: ErrorSubsystem;\n readonly severity: ErrorSeverity;\n readonly recoverable: boolean;\n readonly context?: Record<string, unknown> | undefined;\n\n constructor(opts: {\n message: string;\n code: ErrorCode;\n subsystem: ErrorSubsystem;\n severity?: ErrorSeverity | undefined;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super(opts.message, { cause: opts.cause });\n this.name = 'WrongStackError';\n this.code = opts.code;\n this.subsystem = opts.subsystem;\n this.severity = opts.severity ?? 'error';\n this.recoverable = opts.recoverable ?? false;\n this.context = opts.context;\n }\n\n /**\n * Render a one-line user-facing description.\n * Subclasses should override for domain-specific formatting.\n */\n describe(): string {\n const ctx = this.context ? ` ${formatContext(this.context)}` : '';\n return `${this.code}: ${this.message}${ctx}`;\n }\n}\n\nfunction formatContext(ctx: Record<string, unknown>): string {\n const parts = Object.entries(ctx)\n .filter(([, v]) => v !== undefined)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${String(v)}`);\n return parts.length > 0 ? `[${parts.join(' ')}]` : '';\n}\n\n// \u2500\u2500 Specific error classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Tool execution errors \u2014 thrown by ToolExecutor and individual tools.\n */\nexport class ToolError extends WrongStackError {\n readonly toolName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n | 'TOOL_NOT_FOUND'\n | 'TOOL_PERMISSION_DENIED'\n | 'TOOL_EXECUTION_FAILED'\n | 'TOOL_TIMEOUT'\n | 'TOOL_INPUT_INVALID'\n >;\n toolName: string;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'tool',\n recoverable: opts.recoverable,\n context: { tool: opts.toolName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolError';\n this.toolName = opts.toolName;\n }\n}\n\n/**\n * Config loading / validation errors.\n */\nexport class ConfigError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'CONFIG_INVALID' | 'CONFIG_NOT_FOUND' | 'CONFIG_PARSE_FAILED' | 'CONFIG_MIGRATION_NEEDED'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'config',\n severity: 'fatal',\n recoverable: false,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Plugin loading / lifecycle errors.\n */\nexport class PluginError extends WrongStackError {\n readonly pluginName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'PLUGIN_LOAD_FAILED' | 'PLUGIN_API_MISMATCH' | 'PLUGIN_MISSING_DEPENDENCY'\n >;\n pluginName: string;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'plugin',\n severity: 'error',\n recoverable: opts.code === ERROR_CODES.PLUGIN_MISSING_DEPENDENCY,\n context: { plugin: opts.pluginName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'PluginError';\n this.pluginName = opts.pluginName;\n }\n}\n\n/**\n * Agent runtime errors \u2014 thrown by Agent.run when a non-WrongStackError\n * escapes the inner loop, so callers always see a structured error.\n */\nexport class AgentError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'AGENT_ITERATION_LIMIT' | 'AGENT_CONTEXT_OVERFLOW' | 'AGENT_ABORTED' | 'AGENT_RUN_FAILED'\n >;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'agent',\n severity: opts.code === ERROR_CODES.AGENT_ABORTED ? 'warning' : 'error',\n recoverable: opts.recoverable ?? opts.code === ERROR_CODES.AGENT_ITERATION_LIMIT,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'AgentError';\n }\n}\n\n/**\n * Wrap an arbitrary thrown value into a `WrongStackError` so the caller\n * always gets a structured error. Pass-throughs WrongStackError instances\n * unchanged; raw `Error`s and primitives get an `AGENT_RUN_FAILED` wrapper\n * with the original preserved as `cause`.\n */\nexport function toWrongStackError(\n err: unknown,\n code: Extract<ErrorCode, 'AGENT_RUN_FAILED' | 'AGENT_ABORTED' | 'UNKNOWN'> = ERROR_CODES.AGENT_RUN_FAILED,\n): WrongStackError {\n if (err instanceof WrongStackError) return err;\n const message = toErrorMessage(err);\n return new AgentError({\n message,\n code: code === 'UNKNOWN' ? ERROR_CODES.AGENT_RUN_FAILED : code,\n cause: err,\n });\n}\n\n/**\n * Session storage errors.\n */\nexport class SessionError extends WrongStackError {\n readonly sessionId?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<ErrorCode, 'SESSION_NOT_FOUND' | 'SESSION_CORRUPTED' | 'SESSION_WRITE_FAILED'>;\n sessionId?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'session',\n severity: opts.code === ERROR_CODES.SESSION_WRITE_FAILED ? 'error' : 'warning',\n recoverable: opts.code !== ERROR_CODES.SESSION_CORRUPTED,\n context: { sessionId: opts.sessionId, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'SessionError';\n this.sessionId = opts.sessionId;\n }\n}\n\n/**\n * SDD (Spec-Driven Development) errors \u2014 spec validation, parsing, and\n * state machine violations in the AISpecBuilder, TaskFlow, and TaskTracker.\n */\nexport class SddError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'SDD_VALIDATION_FAILED' | 'SDD_PARSE_FAILED' | 'SDD_INVALID_STATE' | 'SDD_NOT_READY'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'sdd',\n severity: opts.code === ERROR_CODES.SDD_PARSE_FAILED ? 'warning' : 'error',\n recoverable: opts.code === ERROR_CODES.SDD_NOT_READY,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'SddError';\n }\n}\n\n/**\n * File system operation errors.\n */\nexport class FsError extends WrongStackError {\n readonly path?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'FS_READ_FAILED' | 'FS_WRITE_FAILED' | 'FS_MKDIR_FAILED' | 'FS_DELETE_FAILED' | 'FS_ATOMIC_WRITE_FAILED'\n >;\n path?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'fs',\n severity: 'error',\n recoverable: opts.code !== ERROR_CODES.FS_READ_FAILED,\n context: { path: opts.path, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FsError';\n this.path = opts.path;\n }\n}\n\n/**\n * HTTP fetch error \u2014 thrown when a network request returns a non-OK status.\n * Carries the response status so {@link classifyToolError} can branch on it\n * (429 \u2192 transient, 404 \u2192 not_found, 401 \u2192 permission) without duck-typing\n * the error via `'response' in err`.\n *\n * P3 #18 (before-release.md): the previous `'response' in err` check caught\n * any Error with a `response` property, including custom errors, proxy\n * objects, or mocked errors in tests. `instanceof FetchError` is reliable.\n *\n * Tools and providers that make HTTP requests and need the executor to\n * classify their failures should throw `new FetchError({ status, message })`\n * instead of a bare `Error` with an ad-hoc `response` field.\n */\nexport class FetchError extends WrongStackError {\n readonly status: number;\n\n constructor(opts: {\n message: string;\n status: number;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: opts.status === 429 || opts.status >= 500,\n context: { status: opts.status, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FetchError';\n this.status = opts.status;\n }\n}\n\n/**\n * Tool input validation error \u2014 thrown when a tool's input fails a validation\n * check that the JSON Schema cannot express (e.g. `old_string === new_string`\n * in edit, or a cross-field invariant). Use this instead of a bare\n * `throw new Error('...validation...')` so {@link classifyToolError} can\n * match on `instanceof` rather than a locale-dependent message substring.\n *\n * P2 #6 (before-release.md): the previous `err.message.includes('validation')`\n * check misclassified any error whose message happened to contain \"validation\"\n * (e.g. a third-party \"input validation timeout\") as a VALIDATION error.\n *\n * Named `ToolValidationError` (not `ValidationError`) to avoid colliding with\n * the existing `ValidationError` interface exported by json-schema-validate.ts\n * (a validation-result shape, not an Error subclass).\n */\nexport class ToolValidationError extends WrongStackError {\n constructor(opts: {\n message: string;\n /** Field path or tool name that failed validation, for diagnostics. */\n field?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { field: opts.field, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolValidationError';\n }\n}\n\n/**\n * Response / payload parse error \u2014 thrown when an upstream HTTP response,\n * file, or data structure is well-formed at the transport layer (HTTP 200,\n * valid JSON) but is missing required fields or has an unexpected shape.\n *\n * Distinct from `ConfigError(CONFIG_PARSE_FAILED)` (which is specifically\n * for config-file parsing) and `FetchError` (which covers HTTP non-OK\n * responses). `ParseError` fills the gap: the request succeeded but the\n * response body couldn't be interpreted.\n *\n * Common sites: OAuth token responses missing `access_token`, device-code\n * responses missing `device_code`, registry responses with unexpected\n * schemas.\n */\nexport class ParseError extends WrongStackError {\n readonly source?: string | undefined;\n\n constructor(opts: {\n message: string;\n /**\n * What was being parsed \u2014 e.g. `'oauth-token-response'`,\n * `'device-code-response'`. Lets consumers distinguish parse failures\n * from different upstream APIs without parsing the message.\n */\n source?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.PARSE_FAILED,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { source: opts.source, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ParseError';\n this.source = opts.source;\n }\n}\n\n// \u2500\u2500 Type guards \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function isWrongStackError(err: unknown): err is WrongStackError {\n return err instanceof WrongStackError;\n}\n\nexport function isToolError(err: unknown): err is ToolError {\n return err instanceof ToolError;\n}\n\nexport function isConfigError(err: unknown): err is ConfigError {\n return err instanceof ConfigError;\n}\n\nexport function isPluginError(err: unknown): err is PluginError {\n return err instanceof PluginError;\n}\n\nexport function isSessionError(err: unknown): err is SessionError {\n return err instanceof SessionError;\n}\n\nexport function isAgentError(err: unknown): err is AgentError {\n return err instanceof AgentError;\n}\n\nexport function isFsError(err: unknown): err is FsError {\n return err instanceof FsError;\n}\n\nexport function isToolValidationError(err: unknown): err is ToolValidationError {\n return err instanceof ToolValidationError;\n}\n\nexport function isFetchError(err: unknown): err is FetchError {\n return err instanceof FetchError;\n}\n\nexport function isParseError(err: unknown): err is ParseError {\n return err instanceof ParseError;\n}\n\nexport function isSddError(err: unknown): err is SddError {\n return err instanceof SddError;\n}\n", "/**\n * Centralized constants for the mailbox system.\n *\n * Previously these magic numbers were scattered across global-mailbox.ts,\n * mailbox-attach.ts, mailbox-hooks.ts, and mailbox-health.ts. Keeping them\n * in one place ensures every surface agrees on timeouts, intervals, and\n * thresholds \u2014 and makes tuning a single-file change.\n *\n * @module mailbox-constants\n */\n\n/**\n * Agents without a heartbeat for this long are no longer live and are removed\n * from the registry. Presence registries are not history stores: retaining an\n * offline row makes dead agents and shadow workers look actionable in HQ.\n */\nexport const AGENT_STALE_MS = 60_000;\n\n/** Clients without a heartbeat for this long are considered offline. */\nexport const CLIENT_STALE_MS = 60_000;\n\n/** Heartbeat updates are throttled to at most this interval (per agent/client). */\nexport const HEARTBEAT_THROTTLE_MS = 5_000;\n\n/**\n * How long a read may be served from the in-process registry cache before\n * re-reading the shared file. Kept well below HEARTBEAT_THROTTLE_MS so\n * cross-process registrations become visible promptly.\n */\nexport const REGISTRY_CACHE_TTL_MS = 2_000;\n\n/** JSONL line separator. */\nexport const LINE_SEPARATOR = '\\n';\n\n/**\n * Soft cap on the in-memory message cache. The cache mirrors the JSONL\n * message file; under normal load it stays well under this. If a pathological\n * mailbox exceeds the cap we fall back to reading from disk rather than\n * holding an unbounded buffer in memory.\n */\nexport const MESSAGE_CACHE_MAX_ENTRIES = 10_000;\n\n// \u2500\u2500 Polling / heartbeat intervals (used by mailbox-attach.ts) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Background mailbox awareness polling interval (cross-process fallback). */\nexport const MAILBOX_AWARENESS_INTERVAL_MS = 30_000;\n\n/** Agent heartbeat interval in the attach layer. */\nexport const MAILBOX_HEARTBEAT_INTERVAL_MS = 30_000;\n\n/** Min interval between registry reads for the fleet pulse digest. */\nexport const PULSE_MIN_READ_INTERVAL_MS = 30_000;\n\n// \u2500\u2500 Auto-cleanup / compaction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Interval at which the background auto-compaction sweep runs.\n * Default: every 5 minutes.\n */\nexport const AUTO_COMPACT_INTERVAL_MS = 300_000;\n\n/**\n * Messages that have been read by ALL currently-online agents are eligible\n * for auto-removal after this many milliseconds since the last read.\n * Default: 10 minutes.\n */\nexport const AUTO_COMPACT_READ_MAX_AGE_MS = 600_000;\n\n/**\n * Messages whose TTL (time-to-live) has expired are eligible for auto-removal.\n * When a message has `expiresAt` set and that timestamp is in the past, the\n * next compaction sweep drops it. Default TTL for messages without an explicit\n * `expiresAt`: 24 hours.\n */\nexport const AUTO_COMPACT_DEFAULT_TTL_MS = 86_400_000; // 24h\n\n// \u2500\u2500 HTTP bridge rate limiting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Maximum requests per minute from a single external agent (bearer token). */\nexport const HTTP_RATE_LIMIT_PER_MINUTE = 120;\n\n/** Window size for the sliding-window rate limiter. */\nexport const HTTP_RATE_LIMIT_WINDOW_MS = 60_000;\n", "import type {\n AckRecord,\n MailboxMessage,\n MailboxMessageType,\n MailboxTaskContext,\n ReadReceipts,\n} from './mailbox-types.js';\nimport { normalizeRecipient, validateSendType } from './mailbox-types.js';\n\nconst MESSAGE_TYPES = new Set<MailboxMessageType>([\n 'note',\n 'ask',\n 'assign',\n 'steer',\n 'btw',\n 'broadcast',\n 'status',\n 'result',\n 'review',\n 'control',\n]);\n\nconst PRIORITIES = new Set<MailboxMessage['priority']>(['low', 'normal', 'high']);\nconst TASK_STATUSES = new Set([\n 'pending',\n 'in_progress',\n 'completed',\n 'failed',\n 'idle',\n 'running',\n 'streaming',\n 'waiting_user',\n 'error',\n 'offline',\n 'busy',\n]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction requiredString(record: Record<string, unknown>, key: string): string {\n const value = record[key];\n if (typeof value !== 'string') {\n throw new TypeError(`mailbox message field \"${key}\" must be a string`);\n }\n return value;\n}\n\nfunction optionalString(record: Record<string, unknown>, key: string): Record<string, string> {\n const value = record[key];\n if (value === undefined) return {};\n if (typeof value !== 'string') {\n throw new TypeError(`mailbox message field \"${key}\" must be a string when present`);\n }\n return { [key]: value };\n}\n\nfunction parseMessageType(value: unknown): MailboxMessageType {\n if (value === 'info') return 'note';\n if (value === 'task') return 'assign';\n if (typeof value === 'string' && MESSAGE_TYPES.has(value as MailboxMessageType)) {\n return value as MailboxMessageType;\n }\n throw new TypeError('mailbox message field \"type\" is invalid');\n}\n\n/** Normalize message types emitted by pre-union mailbox builds. */\nexport function normalizeMailboxMessageType(value: unknown): MailboxMessageType {\n return parseMessageType(value);\n}\n\n/**\n * Resolve the message type for a SEND operation, applying default-type logic\n * and cross-field validation.\n *\n * ** Default-type rules ** (mirror the `mail_send` tool's logic):\n * - When `type` is explicitly provided, use it directly.\n * - When `type` is omitted AND the resolved `to` is `\"*\"` or starts with\n * `\"@session:\"`, the default is `\"broadcast\"`.\n * - Otherwise (omitted, non-broadcast target), the default is `\"note\"`.\n *\n * **Send-side validation** (from `validateSendType`):\n * - `control` is rejected \u2014 it is reserved for runtime use.\n * - `assign` and `steer` with `to=\"*\"` are rejected \u2014 these types require a\n * specific recipient.\n *\n * @returns The resolved type (explicit or defaulted).\n * @throws {TypeError} When the type is reserved or the (type, to) pair is\n * semantically invalid.\n */\nexport function resolveSendType(\n type: MailboxMessageType | undefined,\n to: string,\n): MailboxMessageType {\n // Normalize recipient aliases (\"all\" \u2192 \"*\", \"@session\" \u2192 \"@session:<id>\")\n // BEFORE default-type selection and cross-field validation, so every\n // caller (mail_send, mailbox tool, HTTP bridge) gets consistent behavior\n // even when they forget to normalize beforehand.\n const normalizedTo = normalizeRecipient(to);\n const resolved: MailboxMessageType =\n type ?? (normalizedTo === '*' || normalizedTo.startsWith('@session:') ? 'broadcast' : 'note');\n // Validate the resolved type against the CANONICAL recipient \u2014 after\n // normalization \u2014 so \"all\" with type \"assign\" is correctly rejected\n // as a multi-recipient target.\n validateSendType(resolved, normalizedTo);\n return resolved;\n}\n\n/**\n * Resolve the message type for a SEND, returning a descriptive error instead\n * of throwing. Convenience wrapper for use in tool handlers where a thrown\n * TypeError would be awkward to catch.\n *\n * Returns `{ ok: true, type }` on success, or `{ ok: false, error }` when\n * the (type, to) pair is invalid.\n */\nexport function resolveSendTypeSafe(\n type: MailboxMessageType | undefined,\n to: string,\n): { ok: true; type: MailboxMessageType } | { ok: false; error: string } {\n try {\n return { ok: true, type: resolveSendType(type, to) };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n\nfunction parsePriority(value: unknown): MailboxMessage['priority'] {\n if (typeof value === 'string' && PRIORITIES.has(value as MailboxMessage['priority'])) {\n return value as MailboxMessage['priority'];\n }\n // Older callers were intentionally tolerant here and ranked unknown values\n // as normal. Normalize rather than dropping an otherwise valid message.\n if (typeof value === 'string') return 'normal';\n throw new TypeError('mailbox message field \"priority\" must be a string');\n}\n\nfunction parseReadReceipts(record: Record<string, unknown>, to: string): ReadReceipts {\n const value = record['readBy'];\n if (value === undefined) {\n const legacyReadAt = record['readAt'];\n return record['read'] === true && typeof legacyReadAt === 'string'\n ? { [to || 'unknown']: legacyReadAt }\n : {};\n }\n if (!isRecord(value)) {\n throw new TypeError('mailbox message field \"readBy\" must be an object');\n }\n\n const receipts: ReadReceipts = {};\n for (const [agentId, timestamp] of Object.entries(value)) {\n if (typeof timestamp !== 'string') {\n throw new TypeError('mailbox message read receipt timestamps must be strings');\n }\n receipts[agentId] = timestamp;\n }\n return receipts;\n}\n\nfunction parseTaskContext(value: unknown): MailboxTaskContext | undefined {\n if (value === undefined) return undefined;\n if (!isRecord(value)) {\n throw new TypeError('mailbox message field \"taskContext\" must be an object');\n }\n\n const status = value['status'];\n if (\n status !== undefined &&\n (typeof status !== 'string' ||\n !TASK_STATUSES.has(status as NonNullable<MailboxTaskContext['status']>))\n ) {\n throw new TypeError('mailbox message taskContext status is invalid');\n }\n\n return {\n ...optionalString(value, 'agentRole'),\n ...optionalString(value, 'agentName'),\n ...optionalString(value, 'taskId'),\n ...(status === undefined\n ? {}\n : { status: status as NonNullable<MailboxTaskContext['status']> }),\n };\n}\n\n/** Parse, migrate, and structurally validate one persisted mailbox message. */\nexport function parseMailboxMessage(value: unknown): MailboxMessage {\n if (!isRecord(value)) throw new TypeError('mailbox message must be an object');\n\n const to = value['to'] === undefined ? '' : requiredString(value, 'to');\n const completed = value['completed'];\n if (typeof completed !== 'boolean') {\n throw new TypeError('mailbox message field \"completed\" must be a boolean');\n }\n\n const taskContext = parseTaskContext(value['taskContext']);\n return {\n id: requiredString(value, 'id'),\n from: requiredString(value, 'from'),\n to,\n type: parseMessageType(value['type']),\n subject: requiredString(value, 'subject'),\n body: requiredString(value, 'body'),\n priority: parsePriority(value['priority']),\n readBy: parseReadReceipts(value, to),\n completed,\n timestamp: requiredString(value, 'timestamp'),\n ...optionalString(value, 'completedBy'),\n ...optionalString(value, 'outcome'),\n ...optionalString(value, 'completedAt'),\n ...optionalString(value, 'deletedAt'),\n ...optionalString(value, 'deletedBy'),\n ...optionalString(value, 'replyTo'),\n ...optionalString(value, 'senderSessionId'),\n ...optionalString(value, 'expiresAt'),\n ...(taskContext === undefined ? {} : { taskContext }),\n };\n}\n\n/** Parse one JSONL line and validate the decoded mailbox message. */\nexport function parseMailboxMessageLine(line: string): MailboxMessage {\n return parseMailboxMessage(JSON.parse(line) as unknown);\n}\n\n// \u2500\u2500 Ack record helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Check if a parsed JSONL value is an append-only ack record (not a message).\n * Ack records carry a `__ack: true` discriminator.\n */\nexport function isAckRecord(value: unknown): value is AckRecord {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n (value as Record<string, unknown>)['__ack'] === true\n );\n}\n\n/**\n * Parse one JSONL line, returning either a MailboxMessage or an AckRecord.\n * Returns null when the line is neither (corrupt/malformed).\n */\nexport function parseMailboxLine(line: string): MailboxMessage | AckRecord | null {\n try {\n const parsed = JSON.parse(line) as unknown;\n if (isAckRecord(parsed)) return parsed;\n return parseMailboxMessage(parsed);\n } catch {\n return null;\n }\n}\n\n/**\n * Apply an ack record's effects to a MailboxMessage in-place.\n * This mutates the message object (readBy, completed, completedBy, completedAt,\n * outcome, deletedAt, deletedBy).\n */\nexport function applyAckToMessage(msg: MailboxMessage, ack: AckRecord): void {\n if (ack.read && !(ack.readerId in msg.readBy)) {\n msg.readBy[ack.readerId] = ack.timestamp;\n }\n if (ack.completed && !msg.completed) {\n msg.completed = true;\n msg.completedBy = ack.completedBy ?? ack.readerId;\n msg.completedAt = ack.timestamp;\n }\n if (ack.outcome !== undefined && msg.outcome !== ack.outcome) {\n msg.outcome = ack.outcome;\n }\n // Soft-delete: set deletedAt/deletedBy.\n if (ack.deleted === true) {\n msg.deletedAt = ack.timestamp;\n msg.deletedBy = ack.deletedBy ?? ack.readerId;\n }\n // Restore: clear deletedAt/deletedBy.\n if (ack.deleted === false) {\n delete msg.deletedAt;\n delete msg.deletedBy;\n }\n}\n\n/**\n * Serialize an ack record to a JSONL line.\n */\nexport function serializeAckRecord(ack: AckRecord): string {\n return JSON.stringify(ack) + '\\n';\n}\n", "/**\n * HQ auth-store \u2014 persistent `auth.json` for the HQ command center.\n *\n * Holds:\n * - Operator-configured redaction policy override (applied server-side\n * even when a publisher claims rawContent:true).\n * - Browser tokens + client tokens. Separate lists so a browser-only token\n * cannot be replayed on /ws/client and vice versa.\n * - Operator-configured alert-rule thresholds (`alertRules`), live-reloaded.\n * - Live reload hook: callers can `watchHqAuthFile()` to re-read on change.\n *\n * Storage layout (under the HQ data directory, default `~/.wrongstack/hq/`):\n * <dataDir>/auth.json \u2014 this file (atomic write, mode 0o600)\n * <dataDir>/events.jsonl \u2014 persistent event log (rotated)\n * <dataDir>/snapshot.json \u2014 persisted latest snapshot (cache)\n *\n * The file is written atomically (tmp + rename) with mode 0o600 so a\n * shared host cannot read issued tokens or the redaction policy. Reads\n * are lenient: a missing file yields an empty document; a corrupt file\n * yields an empty document plus a warning so the operator can recover.\n *\n * @module hq/auth-store\n */\nimport { randomBytes, randomUUID, scrypt, timingSafeEqual } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as syncFs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { atomicWrite } from '../utils/atomic-write.js';\nimport { wstackGlobalRoot } from '../utils/wstack-paths.js';\nimport type { HqAlertRuleConfig } from './alerts.js';\nimport type { HqRedactionPolicy } from './protocol.js';\n\n/** Current auth-file schema version. Bump on breaking shape changes. */\nexport const HQ_AUTH_FILE_VERSION = 1 as const;\n\n/** Default HQ data directory: `~/.wrongstack/hq` (honors WRONGSTACK_HOME). */\nexport function defaultHqDataDir(): string {\n return path.join(wstackGlobalRoot(), 'hq');\n}\n\n/**\n * Resolve an HQ data directory from an optional override.\n *\n * Resolution order:\n * 1. Explicit `override` (from `--data-dir`) \u2014 resolved against\n * `process.cwd()` if relative.\n * 2. `WRONGSTACK_HQ_DATA_DIR` env var (same resolution rules).\n * 3. `defaultHqDataDir()` \u2014 `~/.wrongstack/hq`.\n *\n * The env var exists so tests (and sandboxed runs) can redirect HQ state\n * away from the real user home without threading a CLI flag everywhere.\n */\nexport function resolveHqDataDir(override?: string, env: NodeJS.ProcessEnv = process.env): string {\n const raw = override ?? env['WRONGSTACK_HQ_DATA_DIR']?.trim();\n if (!raw) return defaultHqDataDir();\n return path.isAbsolute(raw) ? path.resolve(raw) : path.resolve(process.cwd(), raw);\n}\n\n/**\n * A generic HQ-issued token. Used for both browser tokens (validated on\n * `/ws/browser`) and client tokens (validated on `/ws/client`). The two\n * are stored in separate lists so a browser-only token cannot be replayed\n * against the client channel and vice versa.\n *\n * `capabilities` scopes what a token may do. When absent the token is\n * unrestricted (backward-compat with tokens minted before Phase 3). Known\n * capability strings:\n * - `control.enqueue` \u2014 browser token may enqueue commands to clients\n * - `control.execute` \u2014 client token may execute `run-command` commands\n * - `telemetry.publish` \u2014 client token may publish telemetry\n */\nexport interface HqToken {\n id: string;\n token: string;\n label?: string;\n createdAt: string;\n lastUsedAt?: string;\n /**\n * Optional capability scope. When absent, the token is unrestricted\n * (backward-compat). When present, only the listed capabilities are\n * granted.\n */\n capabilities?: string[];\n}\n\n/**\n * Check whether a token grants a capability. A token with no `capabilities`\n * field is unrestricted (backward-compat). Otherwise the capability must be\n * explicitly listed.\n */\nexport function tokenHasCapability(token: HqToken | undefined, capability: string): boolean {\n if (token === undefined) return false;\n if (token.capabilities === undefined) return true;\n return token.capabilities.includes(capability);\n}\n\n/**\n * Alias kept for backward-compat with Phase 3 callers/tests. New code\n * should prefer `HqToken`.\n */\nexport type HqBrowserToken = HqToken;\n\n/** On-disk shape of `<dataDir>/auth.json`. */\nexport interface HqRuntimeFile {\n url: string;\n updatedAt: string;\n pid?: number;\n}\n\nexport interface HqAuthFile {\n version: typeof HQ_AUTH_FILE_VERSION;\n updatedAt: string;\n /**\n * Operator-configured redaction policy override. When present, the HQ\n * server applies these settings AFTER any publisher-declared policy \u2014\n * i.e. the operator can always tighten, never loosen.\n */\n redactionPolicy?: Partial<HqRedactionPolicy>;\n /** Browser tokens \u2014 validated on `/ws/browser` upgrades (Phase 3). */\n browserTokens?: HqToken[];\n /** Client tokens \u2014 validated on `/ws/client` upgrades (Phase 4). */\n clientTokens?: HqToken[];\n /** scrypt hash of the optional browser password login. */\n passwordHash?: string;\n /** Secret used to sign browser session cookies. */\n cookieSecret?: string;\n /**\n * Operator-configured alert-rule thresholds. When present, these override\n * the built-in defaults for the alert engine (cost ceiling, stale-machine\n * window, concurrency limit). Live-reloaded with the rest of the file.\n */\n alertRules?: HqAlertRuleConfig;\n}\n\n/** An empty auth file \u2014 what a brand-new HQ install starts with. */\nexport function emptyHqAuthFile(): HqAuthFile {\n return {\n version: HQ_AUTH_FILE_VERSION,\n updatedAt: new Date().toISOString(),\n };\n}\n\n/** Path to `auth.json` under the given data directory. */\nexport function hqAuthFilePath(dataDir: string): string {\n return path.join(dataDir, 'auth.json');\n}\n\n/** Path to the best-effort runtime endpoint marker under the given data directory. */\nexport function hqRuntimeFilePath(dataDir: string): string {\n return path.join(dataDir, 'runtime.json');\n}\n\nexport async function writeHqRuntimeFile(dataDir: string, file: Omit<HqRuntimeFile, 'updatedAt'>): Promise<void> {\n const payload: HqRuntimeFile = {\n ...file,\n updatedAt: new Date().toISOString(),\n };\n await atomicWrite(hqRuntimeFilePath(dataDir), `${JSON.stringify(payload, null, 2)}\\n`, { mode: 0o600 });\n}\n\nfunction isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readHqRuntimeFileSync(dataDir: string): HqRuntimeFile | undefined {\n try {\n const parsed = JSON.parse(syncFs.readFileSync(hqRuntimeFilePath(dataDir), 'utf8')) as Partial<HqRuntimeFile>;\n if (typeof parsed.url !== 'string' || parsed.url.trim().length === 0) return undefined;\n if (typeof parsed.pid === 'number' && !isProcessAlive(parsed.pid)) return undefined;\n return {\n url: parsed.url,\n updatedAt: typeof parsed.updatedAt === 'string' ? parsed.updatedAt : '',\n ...(typeof parsed.pid === 'number' ? { pid: parsed.pid } : {}),\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Read `auth.json` from disk. Returns `emptyHqAuthFile()` when the file does\n * NOT exist (ENOENT) \u2014 the only case treated as intentional open mode.\n *\n * Throws for all other read failures (EACCES, EIO, etc.), malformed JSON,\n * and unsupported schema versions. A corrupt or unreadable auth file must\n * never silently open the server.\n *\n * Callers that want to handle errors gracefully (e.g. the live-reload\n * watcher which should preserve the last-known-good state) should catch\n * the thrown error.\n */\nexport async function readHqAuthFile(\n dataDir: string,\n _opts: { warn?: (msg: string) => void } = {},\n): Promise<HqAuthFile> {\n const file = hqAuthFilePath(dataDir);\n let raw: string;\n try {\n raw = await fs.readFile(file, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return emptyHqAuthFile();\n // Non-ENOENT (EACCES, EIO, \u2026) \u2014 fail closed.\n throw new Error(\n `HQ auth file at ${file} cannot be read: ${(err as Error).message}. ` +\n 'Fix the file permissions or delete it to start with an empty auth state.',\n );\n }\n let parsed: HqAuthFile;\n try {\n parsed = JSON.parse(raw) as HqAuthFile;\n } catch (err) {\n throw new Error(\n `HQ auth file at ${file} is not valid JSON: ${(err as Error).message}. ` +\n 'Fix the file or delete it to start with an empty auth state.',\n );\n }\n if (parsed.version !== HQ_AUTH_FILE_VERSION) {\n throw new Error(\n `HQ auth file at ${file} has unsupported version ${String(parsed.version)} ` +\n `(expected ${String(HQ_AUTH_FILE_VERSION)}). ` +\n 'Remove or update the file to match the current schema version.',\n );\n }\n return parsed;\n}\n\n/**\n * Write `auth.json` atomically with mode 0o600. Creates the data directory\n * if needed. Throws on I/O failure \u2014 callers (CLI commands) should surface\n * the error to the operator.\n */\nexport async function writeHqAuthFile(dataDir: string, file: HqAuthFile): Promise<void> {\n const target = hqAuthFilePath(dataDir);\n const payload: HqAuthFile = {\n ...file,\n version: HQ_AUTH_FILE_VERSION,\n updatedAt: new Date().toISOString(),\n };\n await atomicWrite(target, `${JSON.stringify(payload, null, 2)}\\n`, { mode: 0o600 });\n}\n\nexport interface EnsureHqFirstRunAuthOptions {\n warn?: (msg: string) => void;\n /** Optional browser password login. Hashed with scrypt before storage. */\n password?: string;\n}\n\nexport interface EnsureHqFirstRunAuthResult {\n authFile: HqAuthFile;\n created: boolean;\n browserToken?: HqToken;\n clientToken?: HqToken;\n}\n\n/**\n * Ensure a brand-new HQ data directory has the auth required for safe\n * first-run operation. Only a missing auth.json is bootstrapped; an existing\n * file, including one with empty token arrays, is treated as operator intent.\n */\nexport async function ensureHqFirstRunAuthFile(\n dataDir: string,\n opts: EnsureHqFirstRunAuthOptions = {},\n): Promise<EnsureHqFirstRunAuthResult> {\n const file = hqAuthFilePath(dataDir);\n try {\n await fs.access(file);\n const existing = await readHqAuthFile(dataDir, opts);\n if (opts.password) {\n const passwordUnchanged =\n existing.passwordHash !== undefined &&\n (await verifyHqPassword(opts.password, existing.passwordHash));\n if (!passwordUnchanged) {\n const authFile: HqAuthFile = {\n ...existing,\n passwordHash: await hashHqPassword(opts.password),\n // Rotating the cookie secret invalidates sessions created with the\n // previous password. This matters when --password is used to\n // recover or deliberately change an existing HQ installation.\n cookieSecret: mintHqCookieSecret(),\n };\n await writeHqAuthFile(dataDir, authFile);\n return { authFile: await readHqAuthFile(dataDir, opts), created: false };\n }\n }\n return { authFile: existing, created: false };\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n opts.warn?.(`HQ auth file access failed at ${file}: ${(err as Error).message}`);\n return { authFile: await readHqAuthFile(dataDir, opts), created: false };\n }\n }\n\n // First-run credentials are deliberately least-privilege. Operators can\n // mint an execution-capable client token explicitly when remote command\n // execution is required; a freshly started HQ must never grant it by\n // accident.\n const browserToken = { ...mintHqToken('first-run browser'), capabilities: ['control.enqueue'] };\n const clientToken = { ...mintHqToken('first-run client'), capabilities: ['telemetry.publish'] };\n const authFile: HqAuthFile = {\n version: HQ_AUTH_FILE_VERSION,\n updatedAt: new Date().toISOString(),\n browserTokens: [browserToken],\n clientTokens: [clientToken],\n };\n if (opts.password) {\n authFile.passwordHash = await hashHqPassword(opts.password);\n authFile.cookieSecret = mintHqCookieSecret();\n }\n await writeHqAuthFile(dataDir, authFile);\n return { authFile: await readHqAuthFile(dataDir, opts), created: true, browserToken, clientToken };\n}\n\n/**\n * Load \u2192 mutate \u2192 write. The mutator receives the current file (or an empty\n * one) and returns the next file. Use this for any read-modify-write cycle\n * to avoid clobbering concurrent edits from another CLI invocation.\n *\n * Note: this does NOT take a file lock. HQ auth edits are rare (operator\n * running `wstack --hq-token add` etc.) and the atomic rename protects\n * against torn writes; a race between two concurrent edits would be\n * last-write-wins, which is acceptable for this low-frequency file.\n */\nexport async function mutateHqAuthFile(\n dataDir: string,\n mutator: (current: HqAuthFile) => HqAuthFile | Promise<HqAuthFile>,\n opts: { warn?: (msg: string) => void } = {},\n): Promise<HqAuthFile> {\n const current = await readHqAuthFile(dataDir, opts);\n const next = await mutator(current);\n await writeHqAuthFile(dataDir, next);\n return next;\n}\n\nconst HQ_PASSWORD_SALT_BYTES = 16;\nconst HQ_PASSWORD_HASH_BYTES = 32;\nconst HQ_PASSWORD_SCRYPT_PARAMS = { N: 16384, r: 8, p: 1 };\n\n/**\n * Hash a browser password for storage in `auth.json`. Uses scrypt with a\n * random salt; the returned string is `scrypt$<salt>$<hash>` in base64url.\n */\nexport function hashHqPassword(password: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const salt = randomBytes(HQ_PASSWORD_SALT_BYTES);\n scrypt(password, salt, HQ_PASSWORD_HASH_BYTES, HQ_PASSWORD_SCRYPT_PARAMS, (err, derivedKey) => {\n if (err) return reject(err);\n const payload = `scrypt$${salt.toString('base64url')}$${derivedKey.toString('base64url')}`;\n resolve(payload);\n });\n });\n}\n\n/**\n * Verify a browser password against a stored scrypt hash.\n */\nexport async function verifyHqPassword(password: string, hash: string): Promise<boolean> {\n const parts = hash.split('$');\n if (parts.length !== 3 || parts[0] !== 'scrypt' || !parts[1] || !parts[2]) return false;\n let salt: Buffer;\n let expected: Buffer;\n try {\n salt = Buffer.from(parts[1], 'base64url');\n expected = Buffer.from(parts[2], 'base64url');\n } catch {\n return false;\n }\n if (salt.length === 0 || expected.length === 0) return false;\n const derived = await new Promise<Buffer>((resolve, reject) => {\n scrypt(password, salt, expected.length, HQ_PASSWORD_SCRYPT_PARAMS, (err, key) => {\n if (err) reject(err);\n else resolve(key);\n });\n });\n return timingSafeEqual(derived, expected);\n}\n\n/** Mint a secret used to sign browser session cookies. */\nexport function mintHqCookieSecret(): string {\n return randomBytes(32).toString('base64url');\n}\n\n/**\n * Mint a fresh token. Used for both browser and client tokens; the caller\n * decides which list to append to.\n */\nexport function mintHqToken(label?: string): HqToken {\n const now = new Date().toISOString();\n return {\n id: randomUUID(),\n token: randomUUID().replace(/-/g, '') + randomUUID().replace(/-/g, ''),\n ...(label ? { label } : {}),\n createdAt: now,\n };\n}\n\n/**\n * Backward-compat alias for `mintHqToken`. Phase 3 callers/tests use this.\n */\nexport const mintHqBrowserToken = mintHqToken;\n\n/**\n * Watch `auth.json` for changes and invoke `onChange` with the freshly-read\n * file. Returns a `close()` function that stops watching.\n *\n * The watcher debounces events (default 200ms) because most editors do a\n * tmp+rename dance that emits multiple events. On any read failure (file\n * deleted, corrupt, etc.) the `warn` callback is invoked with the same\n * semantics as `readHqAuthFile`; the watcher stays active so a future\n * valid write re-triggers the callback.\n *\n * Notes:\n * - `fs.watch` is best-effort across platforms. On some network\n * filesystems events may not fire; the operator must restart the server\n * to pick up changes in that case.\n * - The watcher polls the parent directory (not the file itself) so that\n * atomic rename events surface reliably.\n */\nexport function watchHqAuthFile(\n dataDir: string,\n onChange: (file: HqAuthFile) => void,\n opts: { warn?: (msg: string) => void; debounceMs?: number } = {},\n): { close: () => void } {\n const file = hqAuthFilePath(dataDir);\n const debounceMs = opts.debounceMs ?? 200;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let closed = false;\n\n let watcher: syncFs.FSWatcher;\n try {\n // Watch the directory (not the file) so atomic-rename events surface\n // reliably. `fs.watch` is best-effort across platforms \u2014 on some\n // network filesystems events may not fire; the operator must restart\n // the server in that case.\n watcher = syncFs.watch(path.dirname(file), { recursive: false });\n } catch (err) {\n opts.warn?.(`HQ auth watcher could not start: ${(err as Error).message}`);\n return { close: () => {} };\n }\n\n const trigger = (): void => {\n if (closed) return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = undefined;\n const readOpts = opts.warn ? { warn: opts.warn } : {};\n void readHqAuthFile(dataDir, readOpts).then(\n (next) => {\n if (!closed) onChange(next);\n },\n () => {\n // readHqAuthFile never throws for routine I/O \u2014 this is a\n // belt-and-braces guard.\n },\n );\n }, debounceMs);\n };\n\n watcher.on('change', (eventType: string, filename: string | Buffer | null) => {\n const name = typeof filename === 'string' ? filename : '';\n // Only react to events that touch auth.json (rename, change).\n if (eventType === 'rename' || eventType === 'change') {\n if (!name || name === 'auth.json' || name === path.basename(file)) {\n trigger();\n }\n }\n });\n\n watcher.on('error', (err: Error) => {\n opts.warn?.(`HQ auth watcher error: ${err.message}`);\n });\n\n return {\n close: () => {\n closed = true;\n if (timer) clearTimeout(timer);\n watcher.close();\n },\n };\n}\n", "/**\n * HQ network-exposure guard.\n *\n * HQ binds to all interfaces by default so a fleet dashboard is reachable\n * from a phone or a second machine. That default is only safe because a\n * first run mints random browser + client tokens.\n *\n * The hole it leaves is the *open mode* an operator can configure by hand:\n * with no browser tokens and no password, `hq-server` skips its 401 branch\n * entirely \u2014 including on `POST /api/command`, which enqueues commands into\n * live sessions. Open mode was tolerable while HQ was loopback-only; paired\n * with a non-loopback bind it is unauthenticated remote command execution\n * reachable by any peer on the network.\n *\n * So: refuse that one combination, and warn about the merely-unencrypted\n * ones. Nothing here changes the default bind \u2014 it guards the case where the\n * default silently turns a local-only setup into a public one.\n */\n\n/**\n * The bind the HQ *CLI* surfaces choose on purpose: HQ is the deliberate\n * cross-machine surface, so `wstack hq` and the launch menu reach every\n * interface without an extra flag.\n *\n * This deliberately does not live in `startHqServer`'s default. A caller\n * that never mentions a host \u2014 a test, an embedder \u2014 has not asked to be\n * published to its network, and that library default stays loopback. Keep\n * the two apart: collapsing them is what turns \"HQ is reachable from my\n * phone\" into \"every embedder silently binds 0.0.0.0\".\n */\nexport const HQ_CLI_DEFAULT_HOST = '0.0.0.0';\n\n/**\n * Thrown when the bind host and the auth configuration combine into an\n * unauthenticated, network-reachable HQ.\n *\n * Lives here rather than beside the server so callers can identify it\n * without importing (or successfully mocking) the whole hq-server module.\n */\nexport class HqInsecureExposureError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'HqInsecureExposureError';\n }\n}\n\nexport interface HqExposureInput {\n /** Host HQ is about to bind. */\n host: string;\n /** At least one browser token is configured. */\n hasBrowserTokens: boolean;\n /** A browser password hash is configured. */\n hasPassword: boolean;\n /** Operator opt-in that downgrades a refusal to a warning. */\n allowInsecure?: boolean | undefined;\n}\n\nexport type HqExposureVerdict =\n | { kind: 'ok' }\n | { kind: 'warn'; message: string }\n | { kind: 'refuse'; message: string };\n\n/** Hosts that cannot receive traffic from another machine. */\nexport function isLoopbackHost(host: string): boolean {\n const normalized = host.trim().toLowerCase().replace(/^\\[/, '').replace(/\\]$/, '');\n if (normalized === 'localhost' || normalized === '::1') return true;\n // The whole 127.0.0.0/8 block is loopback, not just 127.0.0.1.\n return /^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/.test(normalized);\n}\n\n/** True when HQ would serve every request unauthenticated. Mirrors the\n * `(inBrowserTokenMode || inPasswordMode) && !auth` gate in hq-server. */\nexport function isOpenMode(input: Pick<HqExposureInput, 'hasBrowserTokens' | 'hasPassword'>): boolean {\n return !input.hasBrowserTokens && !input.hasPassword;\n}\n\nexport function assessHqExposure(input: HqExposureInput): HqExposureVerdict {\n if (isLoopbackHost(input.host)) return { kind: 'ok' };\n\n if (isOpenMode(input)) {\n const detail =\n `HQ is configured in open mode (no browser tokens and no password), so every ` +\n `request \u2014 including POST /api/command, which runs commands in your live ` +\n `sessions \u2014 is served unauthenticated. Binding that to ${input.host} exposes it ` +\n `to every peer on the network.`;\n if (input.allowInsecure) {\n return {\n kind: 'warn',\n message: `${detail} Continuing because --insecure-open was passed.`,\n };\n }\n return {\n kind: 'refuse',\n message:\n `${detail}\\n\\nFix one of these, then retry:\\n` +\n ` \u2022 bind locally: wstack hq --host 127.0.0.1\\n` +\n ` \u2022 mint a token: wstack hq token create\\n` +\n ` \u2022 set a password: wstack hq --password <value>\\n` +\n ` \u2022 accept the risk: wstack hq --insecure-open`,\n };\n }\n\n // Authenticated, but the token still crosses the network in cleartext and\n // rides in the URL query \u2014 worth saying out loud once at startup.\n return {\n kind: 'warn',\n message:\n `HQ is bound to ${input.host} (all interfaces) without TLS. Access tokens ` +\n `travel in cleartext and appear in the URL query. Prefer --host 127.0.0.1 ` +\n `unless you intend HQ to be reachable from other machines.`,\n };\n}\n", "/**\n * SessionTelemetryBridge \u2014 streams a surface's own live session state and full\n * chat transcript to HQ over the `/ws/client` plane, so the command center can\n * render every machine \u2192 terminal \u2192 agent \u2192 full-history across all connected\n * machines (not only the one HQ runs on).\n *\n * Two streams, both best-effort and self-contained:\n * 1. `session.snapshot` \u2014 the terminal's live state + agents, sourced from the\n * in-process `session.agents_updated` bus event (no registry file reads).\n * 2. `session.transcript` \u2014 incremental conversation turns, tailed cheaply\n * from this process's own session JSONL by byte offset.\n *\n * @module hq/session-bridge\n */\nimport * as fs from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport type { EventBus, TrackedAgentSnapshot } from '../kernel/events.js';\nimport { sessionScopedPath } from '../utils/session-scoped-path.js';\nimport { resolveWstackPaths } from '../utils/wstack-paths.js';\nimport type {\n HqSessionAgentLiveStatus,\n HqSessionAgentSummary,\n HqSessionLiveStatus,\n HqSessionSnapshotPayload,\n HqTranscriptEntry,\n} from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\nimport { mapSessionEventToEntries } from './transcript-mapper.js';\n\nexport interface SessionTelemetryBridgeOptions {\n publisher: HqPublisher;\n /** Local bus carrying `session.agents_updated`. When omitted, snapshots\n * still publish (with empty/last-known agents) and the transcript still\n * streams from disk. */\n events?: EventBus | undefined;\n sessionId: string;\n projectRoot: string;\n projectName?: string | undefined;\n /** Override the global root used to resolve the session JSONL path. */\n globalRoot?: string | undefined;\n /** Last-known agents to publish immediately before the next bus update. */\n initialAgents?: readonly TrackedAgentSnapshot[] | undefined;\n gitBranch?: string | undefined;\n startedAt?: string | undefined;\n /** Snapshot republish interval (also refreshes lastActivity). Default 2500ms. */\n snapshotIntervalMs?: number | undefined;\n /** Transcript tail poll interval. Default 1200ms. */\n transcriptIntervalMs?: number | undefined;\n now?: (() => string) | undefined;\n}\n\nconst VALID_AGENT_STATUS = new Set<HqSessionAgentLiveStatus>([\n 'idle',\n 'running',\n 'streaming',\n 'waiting_user',\n 'error',\n]);\nconst MAX_TRANSCRIPT_BATCH_ENTRIES = 32;\nconst MAX_TRANSCRIPT_BATCH_BYTES = 512 * 1024;\n\nfunction toAgentSummary(a: TrackedAgentSnapshot): HqSessionAgentSummary {\n const status = (\n VALID_AGENT_STATUS.has(a.status as HqSessionAgentLiveStatus) ? a.status : 'idle'\n ) as HqSessionAgentLiveStatus;\n return {\n id: a.id,\n name: a.name,\n status,\n iterations: a.iterations,\n toolCalls: a.toolCalls,\n lastActivityAt: a.lastActivityAt,\n ...(a.startedAt !== undefined ? { startedAt: a.startedAt } : {}),\n ...(a.currentTool !== undefined ? { currentTool: a.currentTool } : {}),\n ...(a.costUsd !== undefined ? { costUsd: a.costUsd } : {}),\n ...(a.tokensIn !== undefined ? { tokensIn: a.tokensIn } : {}),\n ...(a.tokensOut !== undefined ? { tokensOut: a.tokensOut } : {}),\n ...(a.ctxPct !== undefined ? { ctxPct: a.ctxPct } : {}),\n ...(a.model !== undefined ? { model: a.model } : {}),\n ...(a.partialText !== undefined ? { partialText: a.partialText } : {}),\n };\n}\n\nfunction deriveSessionStatus(agents: readonly HqSessionAgentSummary[]): HqSessionLiveStatus {\n return agents.some(\n (a) => a.status === 'running' || a.status === 'streaming' || a.status === 'waiting_user',\n )\n ? 'active'\n : 'idle';\n}\n\n/**\n * Start streaming this surface's session telemetry to HQ. Returns a disposer\n * that stops both streams and publishes a final `session.ended`.\n */\nexport function startSessionTelemetryBridge(opts: SessionTelemetryBridgeOptions): () => void {\n const now = opts.now ?? (() => new Date().toISOString());\n const publisher = opts.publisher;\n const identity = publisher.identity;\n const project = publisher.project;\n const startedAt = opts.startedAt ?? now();\n\n const wpaths = resolveWstackPaths({\n projectRoot: opts.projectRoot,\n ...(opts.globalRoot !== undefined ? { globalRoot: opts.globalRoot } : {}),\n });\n const sessionFile = sessionScopedPath(wpaths.projectSessions, opts.sessionId, '.jsonl');\n\n let agents: HqSessionAgentSummary[] = (opts.initialAgents ?? []).map(toAgentSummary);\n let lastActivityAt = agents.reduce(\n (latest, agent) => agent.lastActivityAt > latest ? agent.lastActivityAt : latest,\n startedAt,\n );\n let lastSnapshotHash = '';\n let disposed = false;\n\n function buildSnapshot(): HqSessionSnapshotPayload {\n return {\n sessionId: opts.sessionId,\n clientKind: identity.kind,\n machineId: identity.machineId,\n projectId: project.projectId,\n projectName: opts.projectName ?? project.projectName,\n projectRoot: opts.projectRoot,\n status: deriveSessionStatus(agents),\n startedAt,\n lastActivityAt,\n agentCount: agents.length,\n agents,\n ...(identity.hostname !== undefined ? { hostname: identity.hostname } : {}),\n ...(identity.pid !== undefined ? { pid: identity.pid } : {}),\n ...(opts.gitBranch !== undefined ? { gitBranch: opts.gitBranch } : {}),\n };\n }\n\n function publishSnapshot(force = false): void {\n if (disposed) return;\n const snap = buildSnapshot();\n // Hash on everything except lastActivityAt so identical state isn't\n // republished by the heartbeat tick, but real changes always go out.\n const hash = JSON.stringify({ ...snap, lastActivityAt: '' });\n if (!force && hash === lastSnapshotHash) return;\n lastSnapshotHash = hash;\n try {\n publisher.publishSessionSnapshot(snap);\n } catch {\n /* best-effort */\n }\n }\n\n function publishTranscriptEntries(entries: HqTranscriptEntry[]): void {\n let batch: HqTranscriptEntry[] = [];\n let batchFromSeq = seqEmitted;\n\n const publishBatch = (): void => {\n if (batch.length === 0) return;\n try {\n publisher.publishTranscriptAppend({\n sessionId: opts.sessionId,\n fromSeq: batchFromSeq,\n entries: batch,\n });\n } catch {\n /* best-effort */\n }\n seqEmitted += batch.length;\n batch = [];\n batchFromSeq = seqEmitted;\n };\n\n for (const entry of entries) {\n const candidate = [...batch, entry];\n const candidatePayload = {\n sessionId: opts.sessionId,\n fromSeq: batchFromSeq,\n entries: candidate,\n };\n const tooManyEntries = candidate.length > MAX_TRANSCRIPT_BATCH_ENTRIES;\n const tooLarge =\n batch.length > 0 &&\n Buffer.byteLength(JSON.stringify(candidatePayload), 'utf8') >\n MAX_TRANSCRIPT_BATCH_BYTES;\n if (tooManyEntries || tooLarge) publishBatch();\n batch.push(entry);\n }\n\n publishBatch();\n }\n\n const offAgents = opts.events?.on('session.agents_updated', (payload) => {\n agents = payload.agents.map(toAgentSummary);\n lastActivityAt = now();\n publishSnapshot();\n });\n\n // Announce the terminal immediately so its node appears even before any\n // agent activity.\n publishSnapshot(true);\n\n // \u2500\u2500 Transcript tail \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let offset = 0;\n let partial = '';\n let seqEmitted = 0;\n let tailing = false;\n let watcher: fs.FSWatcher | null = null;\n let watchPending = false;\n\n // Once the session file exists, watch it so new turns are streamed within\n // milliseconds of being written \u2014 the interval poll is only a safety net.\n function setupWatcher(): void {\n if (disposed || watcher) return;\n try {\n const nextWatcher = fs.watch(sessionFile, () => {\n if (watchPending || disposed) return;\n watchPending = true;\n setTimeout(() => {\n watchPending = false;\n void tail();\n }, 25);\n });\n // fs.watch surfaces transient failures (EPERM/ENOENT on rename/delete,\n // common on Windows) as async 'error' events \u2014 swallow them so they\n // never become uncaught exceptions. The interval poll keeps us live.\n nextWatcher.on('error', () => {\n try {\n nextWatcher.close();\n } catch {\n /* ignore */\n }\n if (watcher === nextWatcher) watcher = null;\n });\n watcher = nextWatcher;\n } catch {\n watcher = null;\n }\n }\n\n async function tail(): Promise<void> {\n if (disposed || tailing) return;\n tailing = true;\n try {\n const stat = await fsp.stat(sessionFile).catch(() => null);\n if (disposed) return;\n if (!stat) return;\n setupWatcher();\n if (stat.size <= offset) return;\n const fd = await fsp.open(sessionFile, 'r');\n try {\n if (disposed) return;\n const len = stat.size - offset;\n const buf = Buffer.allocUnsafe(len);\n await fd.read(buf, 0, len, offset);\n offset = stat.size;\n partial += buf.toString('utf8');\n const lines = partial.split('\\n');\n partial = lines.pop() ?? '';\n const entries: HqTranscriptEntry[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n let obj: Record<string, unknown>;\n try {\n obj = JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n continue;\n }\n for (const entry of mapSessionEventToEntries(obj)) entries.push(entry);\n }\n if (entries.length > 0) {\n publishTranscriptEntries(entries);\n lastActivityAt = now();\n }\n } finally {\n await fd.close();\n }\n } catch {\n /* best-effort */\n } finally {\n tailing = false;\n }\n }\n\n const snapshotTimer = setInterval(() => publishSnapshot(true), opts.snapshotIntervalMs ?? 2500);\n const tailTimer = setInterval(() => void tail(), opts.transcriptIntervalMs ?? 500);\n snapshotTimer.unref?.();\n tailTimer.unref?.();\n void tail();\n\n return () => {\n if (disposed) return;\n disposed = true;\n offAgents?.();\n if (watcher) {\n try {\n watcher.close();\n } catch {\n /* ignore */\n }\n watcher = null;\n }\n clearInterval(snapshotTimer);\n clearInterval(tailTimer);\n try {\n publisher.publishSessionEnded({ sessionId: opts.sessionId, endedAt: now() });\n } catch {\n /* best-effort */\n }\n };\n}\n", "/**\n * Transcript mapper \u2014 converts raw session JSONL events into the canonical\n * {@link HqTranscriptEntry} shape used by HQ for full chat-history rendering.\n *\n * On-disk reality (see `types/session.ts` + `core/agent-tools.ts`):\n * - A tool CALL (with its arguments) is NOT a standalone event \u2014 it is a\n * `tool_use` content block inside the assistant's `llm_response`.\n * - The tool RESULT is a separate `tool_result` event carrying the matching\n * `id`.\n * So we extract each `tool_use` block as a tool entry (args) at the assistant's\n * position, then merge the later `tool_result` (matched by `id`) INTO that same\n * entry \u2014 giving one box per tool (args + result) in strict chronological order.\n *\n * @module hq/transcript-mapper\n */\nimport type { HqTranscriptEntry, HqTranscriptRole } from './protocol.js';\n\nfunction blocksToText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .filter(\n (b): b is { type: string; text: string } =>\n !!b &&\n typeof b === 'object' &&\n (b as { type?: unknown }).type === 'text' &&\n typeof (b as { text?: unknown }).text === 'string',\n )\n .map((b) => b.text)\n .join('\\n');\n }\n return '';\n}\n\nfunction asString(v: unknown): string {\n if (typeof v === 'string') return v;\n try {\n return JSON.stringify(v, null, 2);\n } catch {\n return String(v);\n }\n}\n\nfunction argsEntry(ts: string, name: unknown, input: unknown, id: unknown): HqTranscriptEntry {\n return {\n ts,\n role: 'tool',\n tool: String(name ?? 'tool'),\n toolInput: input !== undefined && input !== null ? asString(input) : '{}',\n text: '',\n ...(typeof id === 'string' ? { toolUseId: id } : {}),\n };\n}\n\n/**\n * Map a single raw JSONL session event to zero or more transcript entries.\n * An `llm_response` can yield an assistant text entry PLUS one tool entry per\n * embedded `tool_use` block.\n */\nexport function mapSessionEventToEntries(ev: Record<string, unknown>): HqTranscriptEntry[] {\n const ts = typeof ev['ts'] === 'string' ? (ev['ts'] as string) : '';\n const make = (\n role: HqTranscriptRole,\n text: string,\n extra?: Partial<HqTranscriptEntry>,\n ): HqTranscriptEntry => ({\n ts,\n role,\n text,\n ...extra,\n });\n\n switch (ev['type']) {\n case 'user_input': {\n const t = blocksToText(ev['content']);\n return t.trim() ? [make('user', t)] : [];\n }\n case 'llm_response': {\n const out: HqTranscriptEntry[] = [];\n const content = ev['content'];\n // Thinking blocks precede text/tool_use in an assistant message (provider\n // contract) \u2014 surface them first so the transcript preserves that order.\n if (Array.isArray(content)) {\n const thinking = content\n .filter(\n (b): b is { type: string; thinking: string } =>\n !!b &&\n typeof b === 'object' &&\n (b as { type?: unknown }).type === 'thinking' &&\n typeof (b as { thinking?: unknown }).thinking === 'string',\n )\n .map((b) => b.thinking)\n .join('\\n');\n if (thinking.trim()) out.push(make('thinking', thinking));\n }\n const t = blocksToText(content);\n if (t.trim()) out.push(make('assistant', t));\n if (Array.isArray(content)) {\n for (const b of content) {\n if (b && typeof b === 'object' && (b as { type?: unknown }).type === 'tool_use') {\n const block = b as { id?: unknown; name?: unknown; input?: unknown };\n out.push(argsEntry(ts, block.name, block.input, block.id));\n }\n }\n }\n return out;\n }\n case 'tool_use':\n return [argsEntry(ts, ev['name'], ev['input'], ev['id'])];\n case 'tool_call_start':\n return [argsEntry(ts, ev['name'], ev['input'] ?? ev['args'], ev['id'])];\n case 'tool_result': {\n const isError = ev['isError'] === true;\n const content = ev['content'] ?? ev['output'];\n const outStr = content !== undefined && content !== null ? asString(content) : '';\n return [\n make(isError ? 'error' : 'tool', outStr, {\n tool: '\u21B3 result',\n ...(isError ? { isError: true } : {}),\n ...(typeof ev['id'] === 'string' ? { toolUseId: ev['id'] } : {}),\n }),\n ];\n }\n case 'tool_call_end': {\n const isError = ev['isError'] === true;\n const content = ev['output'] ?? ev['content'];\n const outStr = content !== undefined && content !== null ? asString(content) : '';\n if (!outStr.trim() && !isError && typeof ev['durationMs'] !== 'number') return [];\n return [\n make(isError ? 'error' : 'tool', outStr, {\n tool: typeof ev['name'] === 'string' ? String(ev['name']) : '\u21B3 result',\n ...(typeof ev['durationMs'] === 'number' ? { durationMs: ev['durationMs'] } : {}),\n ...(isError ? { isError: true } : {}),\n ...(typeof ev['id'] === 'string' ? { toolUseId: ev['id'] } : {}),\n }),\n ];\n }\n case 'error':\n case 'provider_error':\n return [make('error', String(ev['message'] ?? 'error'))];\n case 'agent_spawned':\n return [make('system', `spawned ${String(ev['role'] ?? 'agent')}`)];\n case 'task_completed':\n return [make('system', `task done: ${String(ev['title'] ?? '')}`)];\n case 'task_failed':\n return [make('system', `task failed: ${String(ev['title'] ?? '')}`)];\n default:\n return [];\n }\n}\n\n/**\n * Identify a \"result\" entry \u2014 a tool/error entry that carries a tool-use id but\n * no args (it's the output half of a tool call, to be merged into the args\n * half).\n */\nfunction isResultEntry(e: HqTranscriptEntry): boolean {\n return (\n (e.role === 'tool' || e.role === 'error') &&\n e.toolUseId !== undefined &&\n e.toolInput === undefined\n );\n}\n\n/**\n * Merge each tool result into its matching args entry (by `toolUseId`),\n * keeping the args entry's chronological position. Results with no matching\n * args entry are kept as their own entries. Mutates/keeps order; pure w.r.t.\n * input ordering.\n */\nexport function mergeToolResults(flat: readonly HqTranscriptEntry[]): HqTranscriptEntry[] {\n const out: HqTranscriptEntry[] = [];\n const argsById = new Map<string, HqTranscriptEntry>();\n for (const src of flat) {\n const e: HqTranscriptEntry = { ...src };\n if (isResultEntry(e) && e.toolUseId !== undefined) {\n const tgt = argsById.get(e.toolUseId);\n if (tgt) {\n tgt.text = e.text || '';\n if (e.durationMs !== undefined) tgt.durationMs = e.durationMs;\n if (e.isError) {\n tgt.role = 'error';\n tgt.isError = true;\n }\n continue; // merged into the existing args box \u2014 no new entry\n }\n }\n out.push(e);\n if (e.role === 'tool' && e.toolUseId !== undefined && e.toolInput !== undefined) {\n argsById.set(e.toolUseId, e);\n }\n }\n return out;\n}\n\n/**\n * Map + merge an array of raw JSONL events into the final transcript-entry\n * list: strict chronological order, with each tool's args and result combined\n * into a single entry.\n */\nexport function buildTranscriptFromEvents(\n events: Iterable<Record<string, unknown>>,\n): HqTranscriptEntry[] {\n const flat: HqTranscriptEntry[] = [];\n for (const ev of events) {\n for (const e of mapSessionEventToEntries(ev)) flat.push(e);\n }\n return mergeToolResults(flat);\n}\n", "/**\n * FleetTelemetryBridge \u2014 forwards local multi-agent coordinator stats to the\n * HQ publisher as `fleet.snapshot` envelopes, so the command center can render\n * a global fleet roll-up (queued/completed/failed tasks, per-subagent status,\n * fleet cost) across every connected machine.\n *\n * Source: the `coordinator.stats` EventBus event (originating on the FleetBus\n * and re-emitted onto the host EventBus by `fleet/host.ts`). All payload\n * fields are plain serializable data \u2014 no closures, no decoupled relay needed.\n *\n * The snapshot is republished on every `coordinator.stats` change (hash-dedup,\n * mirroring {@link startSessionTelemetryBridge}) so the HQ browser sees live\n * fleet counters without polling.\n *\n * @module hq/fleet-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport type { HqEventEnvelope, HqFleetSnapshotPayload, HqSubagentSummary } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface FleetTelemetryBridgeOptions {\n /** Local EventBus emitting `coordinator.stats` (host EventBus after the FleetBus hop). */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Coordinator run id \u2014 identifies this fleet instance. Falls back to a stable per-session id. */\n runId: string;\n /** Optional sessionId to tag envelopes with. */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\n/**\n * Start forwarding coordinator stats to HQ. Returns a disposer that\n * unsubscribes the listener \u2014 call on shutdown.\n */\nexport function startFleetTelemetryBridge(opts: FleetTelemetryBridgeOptions): () => void {\n const { events, publisher, runId } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n let lastHash = '';\n\n function buildPayload(stats: {\n total: number;\n running: number;\n idle: number;\n stopped: number;\n inFlight: number;\n pending: number;\n completed: number;\n totalCostUsd?: number | undefined;\n subagentStatuses: {\n subagentId: string;\n taskId: string;\n status: string;\n assigned: boolean;\n model?: string | undefined;\n costUsd?: number | undefined;\n runtimeMs?: number | undefined;\n lastActivityAt?: string | undefined;\n iterations?: number | undefined;\n toolCalls?: number | undefined;\n }[];\n }): HqFleetSnapshotPayload {\n const subagents: HqSubagentSummary[] = stats.subagentStatuses.map((s) => ({\n subagentId: s.subagentId,\n ...(s.taskId ? { task: s.taskId } : {}),\n status: normalizeSubagentStatus(s.status),\n ...(s.model !== undefined ? { model: s.model } : {}),\n ...(s.costUsd !== undefined ? { costUsd: s.costUsd } : {}),\n ...(s.runtimeMs !== undefined ? { runtimeMs: s.runtimeMs } : {}),\n ...(s.lastActivityAt !== undefined ? { lastActivityAt: s.lastActivityAt } : {}),\n }));\n return {\n runId,\n activeSubagents: stats.running + stats.idle,\n queuedTasks: stats.pending,\n completedTasks: stats.completed,\n failedTasks: stats.stopped,\n ...(stats.totalCostUsd !== undefined ? { totalCostUsd: stats.totalCostUsd } : {}),\n subagents,\n };\n }\n\n const off = events.on('coordinator.stats', (stats) => {\n try {\n const payload = buildPayload(stats);\n // Hash-dedup so identical fleet state isn't republished.\n const hash = JSON.stringify(payload);\n if (hash === lastHash) return;\n lastHash = hash;\n publisher.publishFleetSnapshot(payload, {\n ...(opts.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n timestamp: now(),\n });\n } catch {\n /* best-effort \u2014 HQ telemetry must never break the host */\n }\n });\n\n return () => {\n off();\n };\n}\n\nconst FLEET_STATUS_MAP: Record<string, HqSubagentSummary['status']> = {\n running: 'running',\n idle: 'idle',\n pending: 'pending',\n completed: 'completed',\n failed: 'failed',\n stopped: 'stopped',\n timeout: 'stopped',\n budget_exhausted: 'stopped',\n};\n\nfunction normalizeSubagentStatus(raw: string): HqSubagentSummary['status'] {\n return FLEET_STATUS_MAP[raw] ?? 'idle';\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * BrainTelemetryBridge \u2014 forwards local Brain (decision layer) events to the\n * HQ publisher as `brain.event` envelopes, so the command center can observe\n * decision requests, answers, denials, ask-human escalations, and\n * self-activated interventions across every connected machine.\n *\n * Source: the `brain.*` EventBus events emitted by `ObservableBrainArbiter`\n * (`coordination/brain.ts`) and `BrainMonitor` (`coordination/brain-monitor.ts`).\n * All payloads are plain serializable data (request id, question, source, risk,\n * decision kind, rationale) \u2014 no closures, no decoupled relay needed.\n *\n * The webui `setup-events.ts` already forwards these verbatim to its browser;\n * this bridge does the same for the cross-machine HQ plane.\n *\n * @module hq/brain-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport type { BrainDecision, BrainDecisionRequest } from '../coordination/brain.js';\nimport type { HqBrainEventKind, HqBrainEventPayload, HqEventEnvelope } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface BrainTelemetryBridgeOptions {\n /** Local EventBus emitting `brain.*` events. */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Optional sessionId to tag envelopes with. */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\nfunction extractRequestFields(req: BrainDecisionRequest | undefined): {\n requestId?: string;\n question?: string;\n source?: string;\n risk?: string;\n} {\n if (req === undefined) return {};\n const out: { requestId?: string; question?: string; source?: string; risk?: string } = {};\n if (typeof req.id === 'string') out.requestId = req.id;\n if (typeof req.question === 'string') out.question = req.question;\n if (typeof req.source === 'string') out.source = req.source;\n if (typeof req.risk === 'string') out.risk = req.risk;\n return out;\n}\n\nfunction extractDecisionFields(dec: BrainDecision | undefined): { decision?: string; detail?: string } {\n if (dec === undefined) return {};\n const out: { decision?: string; detail?: string } = {};\n // BrainDecision is a discriminated union on `type` (answer | ask_human | deny).\n out.decision = dec.type;\n if (dec.type === 'answer') {\n out.detail = dec.text;\n } else if (dec.type === 'ask_human') {\n out.detail = dec.prompt;\n } else if (dec.type === 'deny') {\n out.detail = dec.reason;\n }\n return out;\n}\n\n/**\n * Start forwarding brain events to HQ. Returns a disposer that unsubscribes\n * all listeners \u2014 call on shutdown.\n */\nexport function startBrainTelemetryBridge(opts: BrainTelemetryBridgeOptions): () => void {\n const { events, publisher } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n\n function publish(kind: HqBrainEventKind, payload: Partial<HqBrainEventPayload>, at: number): void {\n try {\n const full: HqBrainEventPayload = { kind, at, ...payload } as HqBrainEventPayload;\n publisher.publishEvent({\n type: 'brain.event',\n payload: full,\n ...(opts.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n }\n\n const offs: Array<() => void> = [];\n\n offs.push(\n events.on('brain.decision_requested', (p) => {\n publish('decision_requested', extractRequestFields(p.request), p.at);\n }),\n );\n offs.push(\n events.on('brain.decision_answered', (p) => {\n publish('decision_answered', {\n ...extractRequestFields(p.request),\n ...extractDecisionFields(p.decision),\n }, p.at);\n }),\n );\n offs.push(\n events.on('brain.decision_ask_human', (p) => {\n publish('decision_ask_human', {\n ...extractRequestFields(p.request),\n ...extractDecisionFields(p.decision),\n }, p.at);\n }),\n );\n offs.push(\n events.on('brain.decision_denied', (p) => {\n publish('decision_denied', {\n ...extractRequestFields(p.request),\n ...extractDecisionFields(p.decision),\n }, p.at);\n }),\n );\n offs.push(\n events.on('brain.human_answered', (p) => {\n const detail = typeof p.text === 'string' ? p.text : p.optionId;\n publish('human_answered', {\n requestId: p.id,\n ...(detail !== undefined ? { detail } : {}),\n ...(p.deny === true ? { decision: 'deny' } : {}),\n }, p.at);\n }),\n );\n offs.push(\n events.on('brain.intervention', (p) => {\n publish('intervention', {\n ...extractRequestFields(p.request),\n ...extractDecisionFields(p.decision),\n interventionKind: p.kind,\n intervened: p.intervened,\n }, p.at);\n }),\n );\n\n return () => {\n for (const off of offs) off();\n };\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * WorktreeTelemetryBridge \u2014 forwards local git-worktree lifecycle events to\n * the HQ publisher as `worktree.event` envelopes, so the command center can\n * render live build phase swim-lanes / DAG across every connected machine.\n *\n * Source: the `worktree.*` EventBus events emitted by `WorktreeManager`\n * (`worktree/worktree-manager.ts`): allocated, committed, merged, conflict,\n * released, failed. All payload fields are plain serializable data\n * (handleId, ownerId, branch, diff stats, conflict files) \u2014 no closures, no\n * decoupled relay needed.\n *\n * @module hq/worktree-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport type { HqEventEnvelope, HqWorktreeEventPayload } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface WorktreeTelemetryBridgeOptions {\n /** Local EventBus emitting `worktree.*` events. */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Optional sessionId to tag envelopes with. */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\ntype WorktreeAllocated = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n ownerLabel: string;\n slug: string;\n dir: string;\n branch: string;\n baseBranch: string;\n};\ntype WorktreeCommitted = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch: string;\n committed: boolean;\n insertions: number;\n deletions: number;\n files: number;\n sha?: string | undefined;\n};\ntype WorktreeMerged = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch: string;\n baseBranch: string;\n squash: boolean;\n};\ntype WorktreeConflict = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch: string;\n conflictFiles: string[];\n};\ntype WorktreeReleased = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch: string;\n kept: boolean;\n};\ntype WorktreeFailed = {\n sessionId?: string | undefined;\n handleId: string;\n ownerId: string;\n branch?: string | undefined;\n error: string;\n};\n\n/**\n * Start forwarding worktree lifecycle events to HQ. Returns a disposer that\n * unsubscribes all listeners \u2014 call on shutdown.\n */\nexport function startWorktreeTelemetryBridge(opts: WorktreeTelemetryBridgeOptions): () => void {\n const { events, publisher } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n\n function publish(payload: HqWorktreeEventPayload, sessionId?: string): void {\n try {\n publisher.publishEvent({\n type: 'worktree.event',\n payload,\n ...(sessionId !== undefined && sessionId !== '' ? { sessionId } : {}),\n ...(opts.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n }\n\n const offs: Array<() => void> = [];\n\n offs.push(\n events.on('worktree.allocated', (p: WorktreeAllocated) => {\n publish(\n {\n kind: 'allocated',\n handleId: p.handleId,\n ownerId: p.ownerId,\n ownerLabel: p.ownerLabel,\n slug: p.slug,\n branch: p.branch,\n baseBranch: p.baseBranch,\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.committed', (p: WorktreeCommitted) => {\n publish(\n {\n kind: 'committed',\n handleId: p.handleId,\n ownerId: p.ownerId,\n branch: p.branch,\n insertions: p.insertions,\n deletions: p.deletions,\n files: p.files,\n ...(p.sha !== undefined ? { sha: p.sha } : {}),\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.merged', (p: WorktreeMerged) => {\n publish(\n {\n kind: 'merged',\n handleId: p.handleId,\n ownerId: p.ownerId,\n branch: p.branch,\n baseBranch: p.baseBranch,\n squash: p.squash,\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.conflict', (p: WorktreeConflict) => {\n publish(\n {\n kind: 'conflict',\n handleId: p.handleId,\n ownerId: p.ownerId,\n branch: p.branch,\n conflictFiles: p.conflictFiles,\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.released', (p: WorktreeReleased) => {\n publish(\n {\n kind: 'released',\n handleId: p.handleId,\n ownerId: p.ownerId,\n branch: p.branch,\n kept: p.kept,\n },\n p.sessionId,\n );\n }),\n );\n\n offs.push(\n events.on('worktree.failed', (p: WorktreeFailed) => {\n publish(\n {\n kind: 'failed',\n handleId: p.handleId,\n ownerId: p.ownerId,\n ...(p.branch !== undefined ? { branch: p.branch } : {}),\n error: p.error,\n },\n p.sessionId,\n );\n }),\n );\n\n return () => {\n for (const off of offs) off();\n };\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * ToolTelemetryBridge \u2014 forwards local tool execution events to the HQ\n * publisher as `tool.started` and `tool.completed` envelopes, so the command\n * center can surface live tool activity (what's running, durations, success\n * rates) across every connected machine.\n *\n * Sources:\n * - `tool.started` (EventBus) \u2192 `tool.started` envelope. Raw tool input is\n * shaped via {@link summarizeHqToolArgs} according to the active HQ policy.\n * - `tool.executed` (EventBus) \u2192 `tool.completed` envelope (carries the\n * richer post-execution signal: duration, ok/error, output bytes).\n *\n * All payload fields are plain serializable data \u2014 no closures. The\n * `tool.started.input` raw args follow the publisher redaction policy before\n * publishing.\n *\n * @module hq/tool-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport { resolveHqRedactionPolicy, scrubAndTruncateHqPreview, summarizeHqToolArgs } from './redaction.js';\nimport type { HqEventEnvelope, HqRedactionPolicy, HqToolCompletedPayload, HqToolStartedPayload } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface ToolTelemetryBridgeOptions {\n /** Local EventBus emitting `tool.started` and `tool.executed` events. */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Project root for path redaction in tool input summaries. */\n projectRoot?: string;\n /** Optional sessionId to tag envelopes with. */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\ninterface ToolStartedEvent {\n sessionId?: string | undefined;\n name: string;\n id: string;\n input?: unknown | undefined;\n}\n\ninterface ToolExecutedEvent {\n sessionId?: string | undefined;\n id?: string | undefined;\n name: string;\n durationMs: number;\n ok: boolean;\n input?: unknown | undefined;\n output?: string | undefined;\n outputBytes?: number | undefined;\n}\n\n/** Track in-flight tool calls so we can attach start info to completion. */\ninterface InFlightTool {\n name: string;\n startedAt: number;\n}\n\n/**\n * Start forwarding tool execution events to HQ. Returns a disposer that\n * unsubscribes all listeners \u2014 call on shutdown.\n */\nexport function startToolTelemetryBridge(opts: ToolTelemetryBridgeOptions): () => void {\n const { events, publisher } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n const inFlight = new Map<string, InFlightTool>();\n\n function sessionIdTag(sessionId?: string): { sessionId?: string } {\n const tag = sessionId ?? opts.sessionId;\n return tag !== undefined ? { sessionId: tag } : {};\n }\n\n const offStarted = events.on('tool.started', (p: ToolStartedEvent) => {\n inFlight.set(p.id, { name: p.name, startedAt: Date.now() });\n try {\n const payload: HqToolStartedPayload = {\n toolName: p.name,\n ...(p.input !== undefined\n ? {\n inputSummary: summarizeHqToolArgs(p.input, {\n policy: publisher.redactionPolicy,\n ...(opts.projectRoot !== undefined ? { projectRoot: opts.projectRoot } : {}),\n }),\n }\n : {}),\n };\n publisher.publishEvent({\n type: 'tool.started',\n payload,\n ...sessionIdTag(p.sessionId),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n });\n\n const offExecuted = events.on('tool.executed', (p: ToolExecutedEvent) => {\n const id = p.id;\n if (id !== undefined) inFlight.delete(id);\n try {\n const payload: HqToolCompletedPayload = {\n toolName: p.name,\n status: p.ok ? 'success' : 'error',\n durationMs: p.durationMs,\n ...(p.output !== undefined && p.output.length > 0\n ? { outputSummary: truncateForSummary(p.output, publisher.redactionPolicy) }\n : {}),\n };\n publisher.publishEvent({\n type: 'tool.completed',\n payload,\n ...sessionIdTag(p.sessionId),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n });\n\n return () => {\n offStarted();\n offExecuted();\n inFlight.clear();\n };\n}\n\nfunction truncateForSummary(output: string, policy?: Partial<HqRedactionPolicy>, max = 280): unknown {\n const resolved = resolveHqRedactionPolicy(policy);\n if (resolved.rawContent) {\n if (output.length <= max) return output;\n return `${output.slice(0, max)}\u2026[truncated:${output.length - max}]`;\n }\n return scrubAndTruncateHqPreview(output, max) ?? '';\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * CostTelemetryBridge \u2014 forwards local token/cost accounting events to the HQ\n * publisher as `session.usage` envelopes, giving the command center the\n * granular per-call cost signal it needs to render live cost trends and\n * roll-ups across every connected machine.\n *\n * Source: the `token.accounted` EventBus event, emitted by the TokenCounter\n * (`infrastructure/token-counter.ts`) after every provider call. The payload\n * is plain serializable data (usage counts + a cost breakdown, plus the\n * provider/model that priced it and cache token counts) \u2014 no closures.\n *\n * This is the high-frequency cost feed; HQ's persistence layer time-buckets\n * these into trend series (per-bucket totals + per-model/per-provider\n * breakdowns).\n *\n * @module hq/cost-bridge\n */\nimport type { EventBus } from '../kernel/events.js';\nimport type { Usage } from '../types/provider.js';\nimport type { HqEventEnvelope, HqUsagePayload } from './protocol.js';\nimport type { HqPublisher } from './publisher.js';\n\nexport interface CostTelemetryBridgeOptions {\n /** Local EventBus emitting `token.accounted`. */\n events: EventBus;\n /** HQ publisher to forward envelopes to. */\n publisher: HqPublisher;\n /** Optional sessionId to tag envelopes with (overrides the event's, when set). */\n sessionId?: string;\n /** Override `now()` for deterministic tests. */\n now?: () => string;\n}\n\ninterface TokenAccountedEvent {\n sessionId?: string | undefined;\n usage: Usage;\n cost: { input: number; output: number; total: number };\n /** Provider id that produced this usage (e.g. 'anthropic'), when known. */\n provider?: string | undefined;\n /** Model id the cost was priced against, when known. */\n model?: string | undefined;\n}\n\n/**\n * Start forwarding token/cost events to HQ. Returns a disposer that\n * unsubscribes the listener \u2014 call on shutdown.\n */\nexport function startCostTelemetryBridge(opts: CostTelemetryBridgeOptions): () => void {\n const { events, publisher } = opts;\n const now = opts.now ?? (() => new Date().toISOString());\n\n const off = events.on('token.accounted', (p: TokenAccountedEvent) => {\n try {\n const payload: HqUsagePayload = {\n inputTokens: p.usage.input,\n outputTokens: p.usage.output,\n totalTokens: p.usage.input + p.usage.output,\n costUsd: p.cost.total,\n };\n // Forward the dimensions HQ needs for per-model/per-provider cost charts\n // and cache-hit-ratio cards. All optional \u2014 older counters omit them.\n if (p.provider !== undefined) payload.provider = p.provider;\n if (p.model !== undefined) payload.model = p.model;\n if (p.usage.cacheRead !== undefined) payload.cacheRead = p.usage.cacheRead;\n if (p.usage.cacheWrite !== undefined) payload.cacheWrite = p.usage.cacheWrite;\n const sessionId = opts.sessionId ?? p.sessionId;\n publisher.publishEvent({\n type: 'session.usage',\n payload,\n ...(sessionId !== undefined ? { sessionId } : {}),\n timestamp: now(),\n });\n } catch {\n /* best-effort */\n }\n });\n\n return () => {\n off();\n };\n}\n\n/** Re-export for type-only consumers. */\nexport type { HqEventEnvelope };\n", "/**\n * HQ persistence layer \u2014 survives HQ server restarts so the command center\n * keeps its event history, snapshot state, cost/activity trends, and (later)\n * alert + command-audit logs across reboots.\n *\n * Three stores, all file-backed under the HQ dataDir\n * (`~/.wrongstack/hq/` by default \u2014 see {@link resolveHqDataDir}):\n *\n * - {@link HqEventLog} \u2014 append-only JSONL of every received event\n * envelope, rotated when it exceeds a cap.\n * - {@link HqSnapshotStore} \u2014 atomic checkpoint of the latest snapshot,\n * written on every debounced broadcast.\n * - {@link HqTimeseriesStore}\u2014 time-bucketed cost + activity samples for\n * trend charts.\n *\n * Design constraints (mirrors the codebase conventions):\n * - All disk writes go through {@link withFileLock} + {@link atomicWrite}\n * (shared primitives from `utils/atomic-write.ts`) for cross-process safety.\n * - Every write is best-effort and never throws into the HQ server hot path \u2014\n * callers wrap in try/catch and degrade to in-memory-only on failure.\n * - Appends use a FIFO write chain (single in-flight writer) so concurrent\n * event arrivals don't interleave lines.\n *\n * @module hq/persistence\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite, withFileLock } from '../utils/atomic-write.js';\nimport type { HqEventEnvelope, HqSnapshot } from './protocol.js';\n\n/** Maximum event-log lines before a rotation compacts it down to the tail. */\nconst DEFAULT_EVENT_LOG_MAX_LINES = 50_000;\n/** How many lines to retain after a rotation. */\nconst DEFAULT_EVENT_LOG_ROTATE_KEEP = 20_000;\n\n// \u2500\u2500 HqEventLog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqEventLogOptions {\n dataDir: string;\n maxLines?: number;\n rotateKeep?: number;\n}\n\n/**\n * Append-only JSONL event log. Every received event envelope is appended to\n * `events.jsonl`; when the file exceeds `maxLines` it is rotated under a file\n * lock to keep only the most recent `rotateKeep` lines.\n *\n * Writes are serialized through a FIFO chain so concurrent appends never\n * interleave. All operations are best-effort: a rejected append resolves\n * (never rejects) and the caller's `await` never breaks the server loop.\n */\nexport class HqEventLog {\n private readonly filePath: string;\n private readonly maxLines: number;\n private readonly rotateKeep: number;\n private writeChain: Promise<void> = Promise.resolve();\n private lineCount = 0;\n private counted = false;\n\n constructor(opts: HqEventLogOptions) {\n this.filePath = path.join(opts.dataDir, 'events.jsonl');\n this.maxLines = opts.maxLines ?? DEFAULT_EVENT_LOG_MAX_LINES;\n this.rotateKeep = opts.rotateKeep ?? DEFAULT_EVENT_LOG_ROTATE_KEEP;\n }\n\n /** Append an event envelope as one JSON line. Best-effort, never rejects. */\n append(event: HqEventEnvelope): void {\n this.writeChain = this.writeChain\n .then(() => this.appendInternal(event))\n .catch(() => {\n /* best-effort: a failed append must not break the write chain */\n });\n }\n\n /** Resolves once all queued appends have settled. For tests. */\n async drain(): Promise<void> {\n await this.writeChain.catch(() => {\n /* best-effort */\n });\n }\n\n private async appendInternal(event: HqEventEnvelope): Promise<void> {\n if (!this.counted) {\n this.lineCount = await this.countLines();\n this.counted = true;\n }\n const line = JSON.stringify(event) + '\\n';\n await fs.appendFile(this.filePath, line, { encoding: 'utf8' });\n this.lineCount += 1;\n if (this.lineCount >= this.maxLines) {\n await this.rotate();\n }\n }\n\n private async rotate(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n try {\n const content = await fs.readFile(this.filePath, 'utf8');\n const lines = content.split('\\n').filter((l) => l.length > 0);\n if (lines.length <= this.rotateKeep) {\n this.lineCount = lines.length;\n return;\n }\n const kept = lines.slice(lines.length - this.rotateKeep);\n await atomicWrite(this.filePath, kept.join('\\n') + '\\n');\n this.lineCount = kept.length;\n } catch {\n /* best-effort */\n }\n });\n }\n\n private async countLines(): Promise<number> {\n try {\n const content = await fs.readFile(this.filePath, 'utf8');\n return content.split('\\n').filter((l) => l.length > 0).length;\n } catch {\n return 0;\n }\n }\n\n /**\n * Read the most recent `limit` events, optionally filtered by envelope\n * `type`. Newest first. Returns `[]` if the file doesn't exist yet.\n */\n async recent(limit: number, typeFilter?: string): Promise<HqEventEnvelope[]> {\n let content: string;\n try {\n content = await fs.readFile(this.filePath, 'utf8');\n } catch {\n return [];\n }\n const lines = content.split('\\n').filter((l) => l.length > 0);\n const out: HqEventEnvelope[] = [];\n // Walk newest-first so we can stop early once we have `limit` matches.\n for (let i = lines.length - 1; i >= 0 && out.length < limit; i--) {\n try {\n const env = JSON.parse(lines[i]!) as HqEventEnvelope;\n if (typeFilter === undefined || env.type === typeFilter) {\n out.push(env);\n }\n } catch {\n /* skip malformed lines */\n }\n }\n return out;\n }\n\n /** Initialize the line count cache from disk (call once at boot). */\n async hydrate(): Promise<void> {\n this.lineCount = await this.countLines();\n this.counted = true;\n }\n}\n\n// \u2500\u2500 HqSnapshotStore \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqSnapshotStoreOptions {\n dataDir: string;\n}\n\n/**\n * Atomic checkpoint of the latest snapshot, written to `snapshot.json`.\n * The HQ server writes on every debounced broadcast and reads on boot to\n * re-seed its in-memory state. Best-effort, never rejects.\n */\nexport class HqSnapshotStore {\n private readonly filePath: string;\n private writeChain: Promise<void> = Promise.resolve();\n\n constructor(opts: HqSnapshotStoreOptions) {\n this.filePath = path.join(opts.dataDir, 'snapshot.json');\n }\n\n /** Persist a snapshot. Best-effort, never rejects. */\n save(snapshot: HqSnapshot): void {\n this.writeChain = this.writeChain\n .then(() => atomicWrite(this.filePath, JSON.stringify(snapshot), { mode: 0o600 }))\n .catch(() => {\n /* best-effort */\n });\n }\n\n /** Resolves once all queued saves have settled. For tests. */\n async drain(): Promise<void> {\n await this.writeChain.catch(() => {\n /* best-effort */\n });\n }\n\n /** Read the last persisted snapshot, or `null` if none. */\n async load(): Promise<HqSnapshot | null> {\n try {\n const content = await fs.readFile(this.filePath, 'utf8');\n return JSON.parse(content) as HqSnapshot;\n } catch {\n return null;\n }\n }\n}\n\n// \u2500\u2500 HqTimeseriesStore \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqTimeseriesSample {\n /** Bucket start (epoch ms, floored to the bucket width). */\n ts: number;\n /** Total cost (USD) accumulated in this bucket. */\n costUsd: number;\n /** Total input tokens in this bucket. */\n inputTokens: number;\n /** Total output tokens in this bucket. */\n outputTokens: number;\n /** Number of tool executions in this bucket. */\n toolCalls: number;\n /** Snapshot of active agents at bucket close (last-write per bucket). */\n activeAgents?: number;\n /** Per-dimension cost/token breakdowns for richer trend charts. */\n byModel?: Record<string, HqTimeseriesBreakdownEntry>;\n byProvider?: Record<string, HqTimeseriesBreakdownEntry>;\n}\n\n/**\n * One row of a per-dimension breakdown inside a {@link HqTimeseriesSample}\n * (e.g. the cost + tokens attributed to a single model or provider within the\n * bucket). Sums of these across a dimension equal the bucket's totals when\n * every cost signal carried that dimension.\n */\nexport interface HqTimeseriesBreakdownEntry {\n costUsd: number;\n inputTokens: number;\n outputTokens: number;\n cacheRead?: number | undefined;\n cacheWrite?: number | undefined;\n}\n\nexport interface HqTimeseriesStoreOptions {\n dataDir: string;\n /** Bucket width in ms. Default 5 minutes. */\n bucketMs?: number;\n /** How many buckets to retain. Default 2016 (1 week of 5-min buckets). */\n maxBuckets?: number;\n}\n\n/**\n * Time-bucketed cost + activity samples for trend charts. Each {@link record}\n * call folds a cost/tool signal into the current bucket; {@link flush} writes\n * the accumulated buckets to `timeseries.jsonl` (append under lock) and prunes\n * to `maxBuckets`.\n *\n * The store keeps an in-memory ring of buckets for cheap reads; {@link load}\n * rehydrates them on boot.\n */\nexport class HqTimeseriesStore {\n private readonly filePath: string;\n private readonly bucketMs: number;\n private readonly maxBuckets: number;\n private readonly buckets = new Map<number, HqTimeseriesSample>();\n private flushChain: Promise<void> = Promise.resolve();\n\n constructor(opts: HqTimeseriesStoreOptions) {\n this.filePath = path.join(opts.dataDir, 'timeseries.jsonl');\n this.bucketMs = opts.bucketMs ?? 5 * 60 * 1000;\n this.maxBuckets = opts.maxBuckets ?? 2016;\n }\n\n private bucketStart(ts: number): number {\n return Math.floor(ts / this.bucketMs) * this.bucketMs;\n }\n\n /** Fold a cost/tool signal into the current bucket. Best-effort. */\n record(signal: {\n ts?: number;\n costUsd?: number;\n inputTokens?: number;\n outputTokens?: number;\n toolCalls?: number;\n activeAgents?: number;\n /** When present, this signal is also attributed to a model dimension. */\n model?: string;\n /** When present, this signal is also attributed to a provider dimension. */\n provider?: string;\n cacheRead?: number;\n cacheWrite?: number;\n }): void {\n const start = this.bucketStart(signal.ts ?? Date.now());\n let bucket = this.buckets.get(start);\n if (!bucket) {\n bucket = { ts: start, costUsd: 0, inputTokens: 0, outputTokens: 0, toolCalls: 0 };\n this.buckets.set(start, bucket);\n }\n if (signal.costUsd !== undefined) bucket.costUsd += signal.costUsd;\n if (signal.inputTokens !== undefined) bucket.inputTokens += signal.inputTokens;\n if (signal.outputTokens !== undefined) bucket.outputTokens += signal.outputTokens;\n if (signal.toolCalls !== undefined) bucket.toolCalls += signal.toolCalls;\n if (signal.activeAgents !== undefined) bucket.activeAgents = signal.activeAgents;\n // Attribute this cost signal to its model / provider dimension when known,\n // so trend charts can break spend down without scraping the event log.\n if (signal.model !== undefined || signal.provider !== undefined) {\n const entry: HqTimeseriesBreakdownEntry = {\n costUsd: signal.costUsd ?? 0,\n inputTokens: signal.inputTokens ?? 0,\n outputTokens: signal.outputTokens ?? 0,\n ...(signal.cacheRead !== undefined ? { cacheRead: signal.cacheRead } : {}),\n ...(signal.cacheWrite !== undefined ? { cacheWrite: signal.cacheWrite } : {}),\n };\n if (signal.model !== undefined) {\n bucket.byModel = foldBreakdown(bucket.byModel, signal.model, entry);\n }\n if (signal.provider !== undefined) {\n bucket.byProvider = foldBreakdown(bucket.byProvider, signal.provider, entry);\n }\n }\n // Prune in-memory buckets beyond retention so a long-lived HQ doesn't\n // accumulate unbounded history. Keep the most-recent maxBuckets.\n if (this.buckets.size > this.maxBuckets) {\n const sorted = Array.from(this.buckets.keys()).sort((a, b) => a - b);\n while (this.buckets.size > this.maxBuckets && sorted.length > 0) {\n const oldest = sorted.shift();\n if (oldest === undefined) break;\n this.buckets.delete(oldest);\n }\n }\n }\n\n /** Persist accumulated buckets to disk (append under lock), prune to maxBuckets. */\n flush(): void {\n const snapshot = Array.from(this.buckets.values()).sort((a, b) => a.ts - b.ts);\n if (snapshot.length === 0) return;\n this.flushChain = this.flushChain\n .then(() => this.flushInternal(snapshot))\n .catch(() => {\n /* best-effort */\n });\n }\n\n /** Resolves once all queued flushes have settled. For tests. */\n async drain(): Promise<void> {\n await this.flushChain.catch(() => {\n /* best-effort */\n });\n }\n\n private async flushInternal(toWrite: HqTimeseriesSample[]): Promise<void> {\n const lines = toWrite.map((b) => JSON.stringify(b)).join('\\n') + '\\n';\n await withFileLock(this.filePath, async () => {\n await fs.appendFile(this.filePath, lines, { encoding: 'utf8' });\n });\n // Prune in-memory buckets beyond retention.\n const sorted = Array.from(this.buckets.keys()).sort((a, b) => a - b);\n while (this.buckets.size > this.maxBuckets) {\n const oldest = sorted.shift();\n if (oldest === undefined) break;\n this.buckets.delete(oldest);\n }\n }\n\n /** Read buckets within `[since, now]`, oldest-first. */\n async read(sinceMs?: number): Promise<HqTimeseriesSample[]> {\n // Prefer in-memory (always most current); supplement from disk on first call.\n if (this.buckets.size === 0) await this.load();\n const since = sinceMs ?? 0;\n return Array.from(this.buckets.values())\n .filter((b) => b.ts >= since)\n .sort((a, b) => a.ts - b.ts);\n }\n\n /** Rehydrate buckets from disk (deduped, latest-per-bucket wins). */\n async load(): Promise<void> {\n let content: string;\n try {\n content = await fs.readFile(this.filePath, 'utf8');\n } catch {\n return;\n }\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const sample = JSON.parse(trimmed) as HqTimeseriesSample;\n // Last-write-wins per bucket (file is append-only, so later lines win).\n this.buckets.set(sample.ts, sample);\n } catch {\n /* skip malformed */\n }\n }\n // Prune to retention.\n const sorted = Array.from(this.buckets.keys()).sort((a, b) => a - b);\n while (this.buckets.size > this.maxBuckets) {\n const oldest = sorted.shift();\n if (oldest === undefined) break;\n this.buckets.delete(oldest);\n }\n }\n}\n\n/**\n * Fold a breakdown entry into a per-dimension map (model or provider), summing\n * cost/token fields and merging cache counts. Returns a new map so the caller\n * can assign it back immutably.\n */\nfunction foldBreakdown(\n map: Record<string, HqTimeseriesBreakdownEntry> | undefined,\n key: string,\n entry: HqTimeseriesBreakdownEntry,\n): Record<string, HqTimeseriesBreakdownEntry> {\n const next: Record<string, HqTimeseriesBreakdownEntry> = { ...map };\n const existing = next[key];\n if (existing === undefined) {\n next[key] = { ...entry };\n } else {\n next[key] = {\n costUsd: existing.costUsd + entry.costUsd,\n inputTokens: existing.inputTokens + entry.inputTokens,\n outputTokens: existing.outputTokens + entry.outputTokens,\n cacheRead:\n existing.cacheRead !== undefined || entry.cacheRead !== undefined\n ? (existing.cacheRead ?? 0) + (entry.cacheRead ?? 0)\n : undefined,\n cacheWrite:\n existing.cacheWrite !== undefined || entry.cacheWrite !== undefined\n ? (existing.cacheWrite ?? 0) + (entry.cacheWrite ?? 0)\n : undefined,\n };\n }\n return next;\n}\n\n// \u2500\u2500 HqSimpleLog (generic append-only JSONL for audit/alert records) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * A minimal append-only JSONL log used for records that don't need rotation\n * compaction \u2014 command-audit entries and fired alerts. Each record is one\n * JSON line appended under a FIFO write chain; {@link readAll} parses them\n * oldest-first. Best-effort: a rejected append resolves (never rejects) so the\n * HQ server hot path is never broken.\n */\nexport class HqSimpleLog<T> {\n private readonly filePath: string;\n private writeChain: Promise<void> = Promise.resolve();\n\n constructor(dataDir: string, filename: string) {\n this.filePath = path.join(dataDir, filename);\n }\n\n /** Append one record as a JSON line. Best-effort, never rejects. */\n append(record: T): void {\n this.writeChain = this.writeChain\n .then(() => fs.appendFile(this.filePath, `${JSON.stringify(record)}\\n`, { encoding: 'utf8' }))\n .catch(() => {\n /* best-effort: a failed append must not break the write chain */\n });\n }\n\n /** Resolves once all queued appends have settled. For tests. */\n async drain(): Promise<void> {\n await this.writeChain.catch(() => {\n /* best-effort */\n });\n }\n\n /** Read all records oldest-first. Returns `[]` if the file doesn't exist. */\n async readAll(): Promise<T[]> {\n let content: string;\n try {\n content = await fs.readFile(this.filePath, 'utf8');\n } catch {\n return [];\n }\n const out: T[] = [];\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n out.push(JSON.parse(trimmed) as T);\n } catch {\n /* skip malformed lines */\n }\n }\n return out;\n }\n}\n\n// \u2500\u2500 Aggregate persistence facade \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqPersistence {\n eventLog: HqEventLog;\n snapshotStore: HqSnapshotStore;\n timeseries: HqTimeseriesStore;\n commandLog: HqSimpleLog<unknown>;\n alertLog: HqSimpleLog<unknown>;\n}\n\nexport function createHqPersistence(dataDir: string): HqPersistence {\n return {\n eventLog: new HqEventLog({ dataDir }),\n snapshotStore: new HqSnapshotStore({ dataDir }),\n timeseries: new HqTimeseriesStore({ dataDir }),\n commandLog: new HqSimpleLog(dataDir, 'commands.jsonl'),\n alertLog: new HqSimpleLog(dataDir, 'alerts.jsonl'),\n };\n}\n", "/**\n * HQ control-plane command definitions \u2014 typed payloads for the commands the\n * HQ dashboard can enqueue to connected machines (Phase 3+ of the HQ command\n * center). These are carried over the existing `HqQueuedCommand` wire shape\n * (`{commandId, type, payload, \u2026}`) whose `type`/`payload` were previously\n * type-erased. This module gives them a discriminated union for type-safe\n * dispatch on the client side (Phase 4).\n *\n * Security model: `run-command` (raw shell) is gated by a per-token\n * `control.execute` capability AND an operator opt-in; the other four commands\n * route through the agent's own decision loop / mailbox and inherit their\n * existing guardrails. See `docs/plans/hq-command-center-2026-07.md`.\n *\n * @module hq/commands\n */\nimport type { HqQueuedCommand } from './protocol/fleet.js';\n\n// \u2500\u2500 Command types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** HQ_COMMAND_TYPES \u2014 the full set of recognized command `type` strings. */\nexport const HQ_COMMAND_TYPES = [\n 'steer',\n 'btw',\n 'queue',\n 'abort',\n 'spawn',\n 'broadcast',\n 'run-command',\n] as const;\n\nexport type HqCommandType = (typeof HQ_COMMAND_TYPES)[number];\n\n/** Inject a steer text into a target agent's conversation. */\nexport interface HqSteerCommand {\n type: 'steer';\n /** Target agent address: a unique id (`leader@<tag>`), an alias (`leader`), or `*` for all. */\n to: string;\n subject: string;\n body: string;\n priority?: 'low' | 'normal' | 'high';\n}\n\n/**\n * Post a non-urgent FYI (`btw`) into a target agent's mailbox. Unlike a steer,\n * a btw is absorbed as context \u2014 it does not demand the agent change course.\n * Same wire shape as steer; only the emitted mailbox `type` differs.\n */\nexport interface HqBtwCommand {\n type: 'btw';\n /** Target agent address: a unique id (`leader@<tag>`), an alias (`leader`), or `*` for all. */\n to: string;\n subject: string;\n body: string;\n priority?: 'low' | 'normal' | 'high';\n}\n\n/**\n * Queue a prompt/note (`queue`) for a target agent. Delivered as a plain\n * `note` mailbox message the agent picks up before its next step \u2014 used when\n * the prompt should wait its turn rather than steer the current operation.\n */\nexport interface HqQueueCommand {\n type: 'queue';\n /** Target agent address: a unique id (`leader@<tag>`), an alias (`leader`), or `*` for all. */\n to: string;\n subject: string;\n body: string;\n priority?: 'low' | 'normal' | 'high';\n}\n\n/** Abort a running agent run or fleet. */\nexport interface HqAbortCommand {\n type: 'abort';\n /** `'leader'` aborts the session leader; a subagentId aborts one agent; `'fleet'` stops all. */\n target: 'leader' | 'fleet' | string;\n}\n\n/** Spawn a subagent of the given role. */\nexport interface HqSpawnCommand {\n type: 'spawn';\n role: string;\n /** Optional task description for dispatch routing. */\n task?: string;\n maxIterations?: number;\n}\n\n/** Broadcast a mailbox message to all agents on the target's project. */\nexport interface HqBroadcastCommand {\n type: 'broadcast';\n subject: string;\n body: string;\n priority?: 'low' | 'normal' | 'high';\n}\n\n/** Run a shell command on the target machine. GATED by `control.execute`. */\nexport interface HqRunCommandCommand {\n type: 'run-command';\n command: string;\n /** Optional working directory (defaults to the agent's project root). */\n cwd?: string;\n}\n\nexport type HqCommand =\n | HqSteerCommand\n | HqBtwCommand\n | HqQueueCommand\n | HqAbortCommand\n | HqSpawnCommand\n | HqBroadcastCommand\n | HqRunCommandCommand;\n\n// \u2500\u2500 Validation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst HQ_COMMAND_TYPE_SET = new Set<string>(HQ_COMMAND_TYPES);\n\n/**\n * Validate that an inbound `HqQueuedCommand` has a recognized `type` and a\n * minimally well-formed payload. Returns the narrowed command on success, or\n * `null` when the command should be rejected.\n *\n * This is a shape check, not a security gate \u2014 capability enforcement happens\n * at enqueue time (browser token must have `control.enqueue`) and at execute\n * time (`run-command` requires `control.execute`).\n */\nexport function validateHqCommand(queued: HqQueuedCommand): HqCommand | null {\n if (!HQ_COMMAND_TYPE_SET.has(queued.type)) return null;\n const p = queued.payload as Record<string, unknown>;\n if (p === null || typeof p !== 'object') return null;\n switch (queued.type as HqCommandType) {\n case 'steer': {\n if (typeof p['to'] !== 'string' || typeof p['subject'] !== 'string' || typeof p['body'] !== 'string') {\n return null;\n }\n const result: HqSteerCommand = { type: 'steer', to: p['to'], subject: p['subject'], body: p['body'] };\n if (p['priority'] === 'low' || p['priority'] === 'normal' || p['priority'] === 'high') {\n result.priority = p['priority'];\n }\n return result;\n }\n case 'btw': {\n if (typeof p['to'] !== 'string' || typeof p['subject'] !== 'string' || typeof p['body'] !== 'string') {\n return null;\n }\n const result: HqBtwCommand = { type: 'btw', to: p['to'], subject: p['subject'], body: p['body'] };\n if (p['priority'] === 'low' || p['priority'] === 'normal' || p['priority'] === 'high') {\n result.priority = p['priority'];\n }\n return result;\n }\n case 'queue': {\n if (typeof p['to'] !== 'string' || typeof p['subject'] !== 'string' || typeof p['body'] !== 'string') {\n return null;\n }\n const result: HqQueueCommand = { type: 'queue', to: p['to'], subject: p['subject'], body: p['body'] };\n if (p['priority'] === 'low' || p['priority'] === 'normal' || p['priority'] === 'high') {\n result.priority = p['priority'];\n }\n return result;\n }\n case 'abort':\n if (typeof p['target'] !== 'string') return null;\n return { type: 'abort', target: p['target'] };\n case 'spawn': {\n if (typeof p['role'] !== 'string') return null;\n const result: HqSpawnCommand = { type: 'spawn', role: p['role'] };\n if (typeof p['task'] === 'string') result.task = p['task'];\n if (typeof p['maxIterations'] === 'number') result.maxIterations = p['maxIterations'];\n return result;\n }\n case 'broadcast': {\n if (typeof p['subject'] !== 'string' || typeof p['body'] !== 'string') return null;\n const result: HqBroadcastCommand = { type: 'broadcast', subject: p['subject'], body: p['body'] };\n if (p['priority'] === 'low' || p['priority'] === 'normal' || p['priority'] === 'high') {\n result.priority = p['priority'];\n }\n return result;\n }\n case 'run-command': {\n if (typeof p['command'] !== 'string') return null;\n const result: HqRunCommandCommand = { type: 'run-command', command: p['command'] };\n if (typeof p['cwd'] === 'string') result.cwd = p['cwd'];\n return result;\n }\n default:\n return null;\n }\n}\n\n// \u2500\u2500 Audit log \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqCommandAuditEntry {\n commandId: string;\n type: HqCommandType;\n clientId: string;\n /** Who enqueued the command (browser token id, or 'anonymous' in open mode). */\n enqueuedBy: string;\n enqueuedAt: string;\n status: 'queued' | 'delivered' | 'acked';\n /** Ack status when the client has responded. */\n ackStatus?: 'accepted' | 'completed' | 'failed' | 'rejected';\n ackMessage?: string;\n ackedAt?: string;\n}\n\n/**\n * In-memory command audit ring. Capped for cheap reads. When an `onPersist`\n * callback is wired, every record/update also sinks a snapshot of the entry to\n * the caller's durable store (e.g. HQ's `commands.jsonl`) so history survives\n * restarts. The ring remains the read path for `/api/commands`.\n */\nexport class HqCommandAuditLog {\n private readonly entries: HqCommandAuditEntry[] = [];\n private readonly max: number;\n private readonly onPersist?: ((entry: HqCommandAuditEntry) => void) | undefined;\n\n constructor(max = 1000, onPersist?: ((entry: HqCommandAuditEntry) => void) | undefined) {\n this.max = max;\n this.onPersist = onPersist;\n }\n\n record(entry: HqCommandAuditEntry): void {\n this.entries.push(entry);\n if (this.entries.length > this.max) {\n this.entries.splice(0, this.entries.length - this.max);\n }\n this.onPersist?.(entry);\n }\n\n update(commandId: string, patch: Partial<HqCommandAuditEntry>): void {\n const entry = this.entries.find((e) => e.commandId === commandId);\n if (entry) {\n Object.assign(entry, patch);\n this.onPersist?.(entry);\n }\n }\n\n get(commandId: string): HqCommandAuditEntry | undefined {\n return this.entries.find((entry) => entry.commandId === commandId);\n }\n\n /** Update only when the command belongs to the authenticated client. */\n updateForClient(\n commandId: string,\n clientId: string,\n patch: Partial<HqCommandAuditEntry>,\n ): boolean {\n const entry = this.entries.find(\n (candidate) => candidate.commandId === commandId && candidate.clientId === clientId,\n );\n if (!entry) return false;\n Object.assign(entry, patch);\n this.onPersist?.(entry);\n return true;\n }\n\n /** Seed the ring from a durable store on boot (no persist callback fired). */\n seed(entries: readonly HqCommandAuditEntry[]): void {\n for (const entry of entries) {\n this.entries.push(entry);\n }\n if (this.entries.length > this.max) {\n this.entries.splice(0, this.entries.length - this.max);\n }\n }\n\n recent(limit = 200): HqCommandAuditEntry[] {\n return this.entries.slice(-limit);\n }\n}\n", "/**\n * HQ alerting engine \u2014 evaluates the current snapshot against a set of\n * operator-configurable rules and emits `hq.alert` messages when a threshold\n * is crossed. Mirrors the BrainMonitor's self-activation logic (tool-failure\n * streaks, error storms) but at the fleet-wide command-center scope.\n *\n * Rules are evaluated on a periodic tick (default 15s, unref'd) against the\n * latest in-memory snapshot. Deduplication prevents alert storms: a rule that\n * is still firing is not re-emitted until it clears (state machine per rule).\n *\n * @module hq/alerts\n */\nimport type { HqAlertMessage, HqSnapshot } from './protocol.js';\n\n/** Severity levels for alerts, mirroring {@link HqAlertMessage}. */\nexport type HqAlertSeverity = HqAlertMessage['severity'];\n\nexport interface HqAlert {\n id: string;\n ruleId: string;\n severity: HqAlertSeverity;\n message: string;\n /** Epoch ms when the alert first fired in its current episode. */\n firstFiredAt: number;\n /** Epoch ms of the most recent evaluation that confirmed the alert. */\n lastFiredAt: number;\n}\n\nexport interface HqAlertRuleConfig {\n /** Maximum cost (USD) across the whole fleet before alerting. Default 50. */\n costThresholdUsd?: number;\n /** Seconds of silence from ALL machines before a stale alert fires. Default 120. */\n staleMachineSeconds?: number;\n /** Minimum number of active agents before concurrency alert fires. Default: disabled (0). */\n maxAgents?: number;\n}\n\n/** The fully-resolved config passed to rule.evaluate (no optional fields). */\ntype ResolvedAlertConfig = Required<Pick<HqAlertRuleConfig, 'costThresholdUsd' | 'staleMachineSeconds' | 'maxAgents'>>;\n\n/** A rule is a pure function: snapshot + config \u2192 optional firing. */\ninterface HqAlertRule {\n id: string;\n severity: HqAlertSeverity;\n evaluate: (snapshot: HqSnapshot | null, config: ResolvedAlertConfig, now: number) => string | null;\n}\n\nconst DEFAULT_CONFIG: ResolvedAlertConfig = {\n costThresholdUsd: 50,\n staleMachineSeconds: 120,\n maxAgents: 0,\n};\n\nfunction resolveConfig(config?: HqAlertRuleConfig): ResolvedAlertConfig {\n return { ...DEFAULT_CONFIG, ...(config ?? {}) };\n}\n\nconst RULES: readonly HqAlertRule[] = [\n {\n id: 'fleet-cost-threshold',\n severity: 'warn',\n evaluate: (snapshot, config) => {\n if (snapshot === null) return null;\n const cost = snapshot.totals.totalCostUsd ?? 0;\n if (cost >= config.costThresholdUsd) {\n return `Fleet cost $${cost.toFixed(2)} exceeded threshold $${config.costThresholdUsd.toFixed(2)}`;\n }\n return null;\n },\n },\n {\n id: 'all-machines-stale',\n severity: 'warn',\n evaluate: (snapshot, config, now) => {\n if (snapshot === null) return null;\n const machines = snapshot.machines ?? [];\n if (machines.length === 0) return null;\n const cutoff = now - config.staleMachineSeconds * 1000;\n const stale = machines.filter((m) => Date.parse(m.lastActivityAt) < cutoff);\n if (stale.length === machines.length) {\n return `All ${machines.length} machine(s) silent for ${config.staleMachineSeconds}s`;\n }\n return null;\n },\n },\n {\n id: 'high-concurrency',\n severity: 'info',\n evaluate: (snapshot, config) => {\n if (snapshot === null || config.maxAgents <= 0) return null;\n const agents = snapshot.totals.activeAgents ?? 0;\n if (agents >= config.maxAgents) {\n return `High fleet concurrency: ${agents} active agents (limit ${config.maxAgents})`;\n }\n return null;\n },\n },\n {\n id: 'fleet-failure-spike',\n severity: 'warn',\n evaluate: (snapshot) => {\n if (snapshot === null) return null;\n // Aggregate failed tasks across all reported fleets.\n const fleets = snapshot.fleets ?? [];\n const failed = fleets.reduce((sum, f) => sum + f.failedTasks, 0);\n if (failed >= 5) {\n return `${failed} failed task(s) across the fleet`;\n }\n return null;\n },\n },\n];\n\n/**\n * In-memory alert state. Tracks which rules are currently firing so the same\n * alert is not re-emitted every tick \u2014 only state transitions (cleared \u2192\n * firing) emit. Optionally persists to disk via a callback.\n */\nexport class HqAlertEngine {\n private readonly active = new Map<string, HqAlert>();\n private readonly history: HqAlert[] = [];\n private readonly maxHistory: number;\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly onAlert: (alert: HqAlert) => void;\n private readonly onPersist?: ((alert: HqAlert) => void) | undefined;\n\n constructor(opts: {\n onAlert: (alert: HqAlert) => void;\n maxHistory?: number;\n /** Optional durable sink \u2014 fires when an alert transitions to firing. */\n onPersist?: ((alert: HqAlert) => void) | undefined;\n }) {\n this.onAlert = opts.onAlert;\n this.maxHistory = opts.maxHistory ?? 500;\n this.onPersist = opts.onPersist;\n }\n\n /**\n * Evaluate all rules against the snapshot. Emits (via the `onAlert`\n * callback) only for rules that newly transition to firing. Clears rules\n * that are no longer firing. Returns the list of newly-fired alerts.\n */\n evaluate(snapshot: HqSnapshot | null, config?: HqAlertRuleConfig, now: number = Date.now()): HqAlert[] {\n const resolved = resolveConfig(config);\n const fired: HqAlert[] = [];\n const firingIds = new Set<string>();\n\n for (const rule of RULES) {\n const message = rule.evaluate(snapshot, resolved, now);\n if (message !== null) {\n firingIds.add(rule.id);\n const existing = this.active.get(rule.id);\n if (existing === undefined) {\n // New transition \u2192 emit.\n const alert: HqAlert = {\n id: `${rule.id}-${now}`,\n ruleId: rule.id,\n severity: rule.severity,\n message,\n firstFiredAt: now,\n lastFiredAt: now,\n };\n this.active.set(rule.id, alert);\n this.history.push(alert);\n if (this.history.length > this.maxHistory) this.history.splice(0, this.history.length - this.maxHistory);\n fired.push(alert);\n this.onAlert(alert);\n this.onPersist?.(alert);\n } else {\n // Already firing \u2014 refresh timestamp, don't re-emit.\n existing.lastFiredAt = now;\n }\n }\n }\n\n // Clear rules no longer firing.\n for (const id of Array.from(this.active.keys())) {\n if (!firingIds.has(id)) {\n this.active.delete(id);\n }\n }\n\n return fired;\n }\n\n /** Currently-active (firing) alerts. */\n activeAlerts(): HqAlert[] {\n return Array.from(this.active.values());\n }\n\n /** Historical alerts (newest-last), capped at maxHistory. */\n recentAlerts(limit = 100): HqAlert[] {\n return this.history.slice(-limit);\n }\n\n /** Seed the history from a durable store on boot (no alert callbacks fired). */\n seed(alerts: readonly HqAlert[]): void {\n for (const alert of alerts) {\n this.history.push(alert);\n }\n if (this.history.length > this.maxHistory) {\n this.history.splice(0, this.history.length - this.maxHistory);\n }\n }\n\n /**\n * Start periodic evaluation against a snapshot getter. The timer is\n * unref'd so it never keeps the process alive. Returns a disposer.\n */\n startPeriodic(\n getSnapshot: () => HqSnapshot | null,\n config?: HqAlertRuleConfig | (() => HqAlertRuleConfig | undefined),\n intervalMs = 15_000,\n ): () => void {\n if (this.timer !== null) return () => undefined;\n const tick = (): void => {\n try {\n const cfg = typeof config === 'function' ? config() : config;\n this.evaluate(getSnapshot(), cfg);\n } catch {\n /* best-effort \u2014 alert evaluation must never crash the server */\n }\n };\n this.timer = setInterval(tick, intervalMs);\n this.timer.unref?.();\n return () => {\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n };\n }\n}\n\n/** Map an internal {@link HqAlert} to the wire {@link HqAlertMessage}. */\nexport function toAlertMessage(alert: HqAlert): HqAlertMessage {\n return {\n type: 'hq.alert',\n severity: alert.severity,\n message: `[${alert.ruleId}] ${alert.message}`,\n timestamp: new Date(alert.lastFiredAt).toISOString(),\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["redacted", "out", "createHash", "randomUUID", "fs", "basename", "randomUUID", "path", "fs", "path", "path", "projectHash", "stat", "stat", "resolve", "randomUUID", "randomBytes", "randomUUID", "fs", "path", "authFile", "resolve", "randomBytes", "randomUUID", "createHash", "basename", "randomUUID", "fs", "fsp", "stat", "fs", "path"]
|
|
7
7
|
}
|